Controller for serving images doesn't work with extensions - asp.net-mvc

I'd like to serve my images by using an ImageController:
public class ImageController : Controller
{
// GET: Image
public ActionResult Render(string fileName)
{
byte[] image = System.IO.File.ReadAllBytes(/*some path*/);
return this.Image(image, "image/png");
}
}
I added the route:
routes.MapRoute(
name: "Images",
url: "images/{action}/{fileName}",
defaults: new { controller = "Image", action = "Render", fileName = UrlParameter.Optional }
);
So this image path works:
http://xxx.xxx/images/render/x
But a path with this extension doesn't:
http://xxx.xxx/images/render/x.png
A "HTTP Error 404.0 - Not Found" error appears.
What should I do to enable file extensions?

Try following steps:
Enable custom file routing inside RouteConfig.cs
routes.RouteExistingFiles = true;
Add the following handler inside your web.config
<system.webServer>
<handlers>
<add name="ProtectedImages" path="images/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>

Related

Custom route that match a single specific url

In my mvc app, I want to dynamically generate a specific url :
https://myapp.corp.com/.well-known/microsoft-identity-association.json
This endpoint should produce a small file based on values in the web.config file. So I created this controller :
public class HostingController : Controller
{
// GET: Hosting
[OutputCache(Duration = 100, VaryByParam = "none")]
public ActionResult MicrosoftIdentityAssociation() => Json(new
{
associatedApplications = new[]
{
new { applicationId = WebConfigurationManager.AppSettings.Get("ClientId") }
}
});
}
And I changed the routing configuration like this :
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Azure domain registration",
".well-known/microsoft-identity-association.json",
new { controller = "Hosting", action= "MicrosoftIdentityAssociation" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I expect the url to produce json like :
{
"associatedApplications": [
{
"applicationId": "1562019d-44f7-4a9d-9833-64333f52181d"
}
]
}
But when I target the url, I got a 404 error.
What's wrong ? how to fix ?
You can use a route attribute:
[Route("~/.well-known/microsoft-identity-association.json")]
[OutputCache(Duration = 100, VaryByParam = "none")]
public ActionResult MicrosoftIdentityAssociation()
{
..... your code
}
It was tested in postman.
Asp.Net MVC can't create route that have extension. I had to edit my Web.config to plug the MVC framework on this very specific file.
Specifically :
<system.webServer>
<handlers>
<add name="Azure domain verifier"
path=".well-known/microsoft-identity-association.json"
verb="GET" type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0"
/>
</handlers>
</system.webServer>
From this point, I was able to route to my custom controller action using either routeconfig.cs file or the [RouteAttribute]

RouteConfig and filename with extension - MVC5

I have the following URLs:
/Meetings/doc1.pdf
/Meetings/doc2.pdf
I tried to set up the following in my RoouteConfig
var route = routes.MapRoute(
name: "RedirectMeetingDocs",
url: "Meetings/{filename}",
defaults: new { action= "GetAttachmentByName", controller = "Generic" },
constraints: new { filename = #"(.*?)\.(pdf|ppt)" }
);
With the following function:
[HttpGet]
public ActionResult GetAttachmentByName(string fileName)
{
...
}
However, it nevers work and I keep getting a 404 error.
I also tried:
var route = routes.MapRoute(
name: "RedirectMeetingDocs",
url: "Meetings/{filename}.{extension}",
defaults: new { action= "GetAttachmentByName", controller = "Generic" },
constraints: new { filename = new AlphaRouteConstraint(), extension = new AlphaRouteConstraint() }
);
with
public ActionResult GetAttachmentByName(string fileName, string extension)
{
But nothing works.
Any advices?
Ok I solve it by adding the following in my Web.config:
<add name="IATTCRedirectOldMeetingFiles" path="meetings/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Now, both RouteConfig shown above work.

Creating multilingual not found page in MVC

We have a multilingual website that has content in four languages.Every language is understood by the language name that we add at the first of our url.
This is our routeConfig.cs:
routes.MapRoute(
name: "Default",
url: "{lang}/{controller}/{action}/{id}/{title}",
defaults: new { lang = "fa", controller = "Home", action = "Index", id = UrlParameter.Optional,title = UrlParameter.Optional }
and this is generated the url: /en/ContactUs/Index
Also, in our controllers we get the language name from url and change the currentCulture and currentUiCulture based on it.
Now, we want to have a not found page in all of the languages. Normally, to make it happen we add an error contoller and a NotFound action and view, then we add this section in our web.config:
<customErrors mode="On" defaultRedirect="error">
<error statusCode="404" redirect="error/notfound" />
<error statusCode="403" redirect="error/forbidden" />
</customErrors>
We have added a NotFound page that we use .resx files in it to make rtl/ltr and to show the messages in four languages.
But the problem here is that in a multilingual website we are not allowed to use this address "error/notfound" because there is no languagename in it and we don't know how to add the language name in redirect="error/notfound" in the web.config file to create something like "en/error/notfound" or "fa/error/notfound".
every help would be highly appreciated
First of all, have a look at this answer for info about localizing your site via URL.
Next, <customErrors> is a catch-all for ASP.NET error messages. But in general, you have control over a 404 (routing miss) within ASP.NET MVC by using a catch-all route. In this case, you can simply localize the catch-all route and get rid of this configuration in web.config.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Localized-Default",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = new CultureConstraint(defaultCulture: "fa", pattern: "[a-z]{2}") }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { lang = "fa", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
// Catch-all route (for routing misses)
routes.MapRoute(
name: "Localized-404",
url: "{lang}/{*url}",
defaults: new { controller = "Error", action = "PageNotFound" },
constraints: new { lang = new CultureConstraint(defaultCulture: "fa", pattern: "[a-z]{2}") }
);
routes.MapRoute(
name: "Default-404",
url: "{*url}",
defaults: new { lang = "fa", controller = "Error", action = "PageNotFound" }
);
}
}
ErrorController
public class ErrorController : Controller
{
public ActionResult PageNotFound()
{
Response.CacheControl = "no-cache";
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
}
That takes care of the route misses within ASP.NET. For those that don't hit ASP.NET (assuming you are hosting using IIS), you should use the <httpErrors> section of web.config rather than <customErrors>. <httpErrors> is localizable via the prefixLanguageFilePath setting.
Optional string attribute.
Specifies the initial path segment when generating the path for a custom error. This segment appears before the language-specific portion of the custom error path. For example, in the path C:\Inetpub\Custerr\en-us\404.htm, C:\Inetpub\Custerr is the prefixLanguageFilePath.
<configuration>
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File" >
<remove statusCode="404" />
<error statusCode="404"
prefixLanguageFilePath="C:\Contoso\Content\errors"
path="404.htm" />
</httpErrors>
</system.webServer>
</configuration>
Which means you would need to set up a file structure with language prefix, and use static files as targets.
C:\Contoso\Content\errors\fa\404.htm
C:\Contoso\Content\errors\en\404.htm
AFAIK, this unfortunately means you need to have physical files at these locations. However, you could have the content of these pages setup to do both a meta-refresh redirect and a JavaScript redirect to the correct controller action.
<html>
<head>
<title>404 Not Found</title>
<meta http-equiv="refresh" content="1;http://www.example.com/fa/Error/PageNotFound" />
</head>
<body>
<!-- Add localized message (for those browsers that don't redirect). -->
<script>
//<!--
setTimeout(function () {
window.location = "http://www.example.com/fa/Error/PageNotFound";
}, 1000);
//-->
</script>
</body>
</html>
The customErrors section in web.config is the static data about some status-code and how they will be handled. The responsibility of this section can be generated dynamically by the Application_EndRequest method in Global.asax.
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var routeData = new RouteData();
HttpContextBase currentContext = new HttpContextWrapper(HttpContext.Current);
var lang = RouteTable.Routes.GetRouteData(currentContext).Values["lang"];
routeData.Values["lang"] = lang;
routeData.Values["controller"] = "CustomError";
routeData.Values["action"] = "NotFound";
IController customErrorController = new CustomErrorController();
customErrorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
I believe you can use a session variable to hold current user's ui-culture data.
I don't see a point but, if you don't want to do that, you can follow this tutorial to generate your own routes for MVC custom error page handling.
http://setiabud.blogspot.com.tr/2013/04/handling-404-error-in-aspnet-mvc.html

Asp.net mvc routing - how to allow .html extension in mvc routing

Controller Name is : TestController
Action Name is :HtmlContent
and Url : localhost:53907/en_US/Index.html
I would like to call HtmlContent action from TestController if url which contains .html extension.
I have placed breakpoint in HtmlContent but its not hitting if i enter url like mentioned above,
routes.MapRoute(
name: "MyCustomRoute",
url: "en_US/{pagename}",
defaults: new { controller = "Test", action = "HtmlContent" },
constraints: new {pagename = #".*?$(?<=\.html)" }
);
How to write routing for this requirement?
routes.MapRoute(
name: "MyCustomRoute",
url: "en_US/{pagename}.html",
defaults: new { controller = "Test", action = "HtmlContent" },
constraints: new {pagename = #".*?$(?<=\.html)" }
);
and add code on web.config
<add name="HtmlFileHandler" path="*.html" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
its work for me if any query .please comment

MVC Razor View not found if filename contains a dot

I have problems accessing a route, if it contains a dot. For reproducing, create a default MVC4 WebApi application. Take the default route...
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
write the controller as follows...
public class HomeController : Controller
{
public ActionResult Index(string id)
{
if (id == null)
{
return View();
}
else
{
return PartialView(id);
}
}
}
and create two files "test.cshtml" and "test.menu.cshtml" next to the existing "index.cshtml".
Opening /home/index/test works as expected. It brings back the contents of "test.cshtml".
However, opening /home/index/test.menu brings back a 404 error.
Why does this happen? And how can it be avoided?
The 404 error that you are seeing is from IIS. The module for MVC routing is never getting control.
Adding the following option to the modules section of the <system.webServer> section in web.config will make sure that the MVC routing gets attempted and should fix your problem:
runAllManagedModulesForAllRequests="true"
in my web.config there was no existing modules section so I added the following line to the <system.webServer> section:
<modules runAllManagedModulesForAllRequests="true" />
And now it works for me.

Resources