Complex MVC Routes - asp.net-mvc

I have the following route in my MVC applicaiton:
routes.MapRoute(
name: "Default",
url: "api/{server}/{port}/{route}",
defaults: new {
controller = "Home",
action = "Index",
server = UrlParameter.Optional,
port = UrlParameter.Optional,
route = UrlParameter.Optional }
);
This route gets hit when the URL is http://localhost:80/api/myserver.mydomain.net/8080/mypage but when I change the URL to http://localhost:80/api/myserver.mydomain.svc/8080/mypage the route suddenly does not get hit. Any idea why simply changing an argument in my route from '.net' to '.svc' would stop working?

I found the answer to my question here. All I had to do was remove the .svc build provider from my site:
<system.web>
<compilation debug="true" targetFramework="4.0">
<buildProviders>
<remove extension=".svc"/>
</buildProviders>
...

The .svc is a path extension for WCF end points, so IIS will be processing this via a different mechanism (ISAPI module/handler) not through the MVC/WebAPI route engine.
Try adding the following to your web.config, it will force IIS to run the routing engine with each request.
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
.....
Note: this may add an unnecessary overhead to your page requests.
Another option might be to remove the module itself, but this will affect any WCF endpoints you may be running.
<configuration>
<system.webServer>
<modules>
<remove name="ServiceModel-4.0" />
.....

Related

Using a route to return 408 on a specific file name request

We have an issue whereby Outlook is misbehaving because it is attempting to read an autodiscover.xml on our domain, specifically https://example.com/autodiscover/autodiscover.xml.
The email host says that we should configure the websitefirewall to return a timeout error. However, the site is hosted on Azure, and I don't see any option to do that.
Therefore, I was wondering if this could be done in MVC? I tried the following:
public class AutoDiscoverController : Controller
{
[Route("autodiscover/autodiscover.xml")]
public ActionResult Index()
{
return new HttpStatusCodeResult(HttpStatusCode.RequestTimeout);
}
}
...but it doesn't work; I see a 404 page instead. A breakpoint on the method also never gets hit.
Is it possible to create a route that mimics a non-existent file to return the timeout error?
Duplicate question update
There is a similar question at Dots in URL causes 404 with ASP.NET mvc and IIS. However, this question differs in that:
The answer doesn't work in MVC5
I cannot create a rule to recognise a trailing slash in the URL, because Outlook is generating the URL and I have no control over that
What else I've tried...
In RouteConfig, I defined a custom route. It doesn't work; the route never gets hit.
routes.MapRoute(
name: "AutoDiscover",
url: "autodiscover/autodiscover.xml",
defaults: new { controller = "AutoDiscover", action = "Index" });
As above, but using url: "autodiscover/*"
routes.IgnoreRoute("autodiscover.xml");
Defined a Route attribute on the controller itself, then enable routes.MapMvcAttributeRoutes();
I found an answer, thanks to Rick Strahl's answer here, and related blog post.
For some reason, defining a route in the RouteConfig never hits, but doing it at controller level does work. However, an additional step is needed, as pointed out by Nkosi to get it to work.
1. Enable MVC Attribute Routing
This wires up the routing attributes at controller-level (done in the next step)
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes(); // <-- Added this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
2. Add the Route as an attribute
public class AutoDiscoverController : Controller
{
[Route("autodiscover/autodiscover.xml")]
public ActionResult Index()
{
return new HttpStatusCodeResult(HttpStatusCode.RequestTimeout);
}
}
3. Configure a route based on specific files in web.config
I believe this forces MVC to take over what IIS would usually handle (as XML is considered a "static" file).
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="dotless" path="*.less" verb="GET" type="dotless.Core.LessCssHttpHandler,dotless.Core" resourceType="File" preCondition="" />
<!-- Added this line -->
<add name="AutoDiscoverXmlFileHandler" path="autodiscover.xml" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
</handlers>
</system.webServer>
Result

ASP.NET MVC 5 custom route does not work

I'm trying for hours to get my custom route to work. I always get a 404 and can't see what I'm doing wrong.
The URL scheme I'm trying to get: /Download/fd39kssdf/myfile.zip.
This is the route, defined before the default route:
routes.MapRoute(
name: "Download",
url: "Download/{hash}/{name}",
defaults: new { controller = "Download", action = "Index"}
);
This is the code in the controller named "DownloadController":
public ActionResult Index(string hash, string name)
{
}
I have tried adding the parameters to the route with UrlParameter.Optional and "", but neither does work.
Where is the error?
Thank you!
You problem is that the IIS has file extensions mapped directly, so your request isn't even being passed over to the ASP.NET handler for processing. It's actually looking for a myfile.zip in that directory, which doesn't exist giving you the 404 error.
<configuration>
<system.webServer>
<handlers>
<add name="Download-MVC"
path="/Download/*"
verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</configuration>

sitemap.xml url returns 404 Error

I have a large affiliate marketing site with millions of products hosted on Windows Azure.
For SEO I have to provide a sitemap.xml which is dynamically created.
public ActionResult SiteMap()
{
string sitemapUrl = "https://trendley.blob.core.windows.net/sitemap/sitemap.xml";
byte[] bImage = null;
using (WebClient wc = new WebClient())
{
bImage = wc.DownloadData(sitemapUrl);
}
return File(bImage, "application/octet-stream");
}
I added the follwoing route to my RouteConfig:
routes.MapRoute("Sitemap",
"sitemap.xml",
new { controller = "Home", action = "Sitemap" });
Unfortunately this is not workting.
I get -> HTTP Error 404.0 - Not Found
When I change "sitemap.xml" to sitemapxml (remove the extension) my controller method is invoked.
Already did some research and played with my web.config but nothing seems to work.
First thing I tried was to add:
<modules runAllManagedModulesForAllRequests="true" />
Second thing:
<add
name="AdfsMetadata"
path="sitemap.xml"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
Can someone tell me how to acomplish this.
Do I have to write my own Handler for this?
Cheers,
Stefan
The reason that that route is not working is because by default .xml is handled by the "StaticFileHandler" in IIS so when the request comes in ASP.net is not invoked.
Option 1: Enable runAllManagedModulesForAllRequests - in your web .config add the following
<modules runAllManagedModulesForAllRequests="true" />
It goes inside of the system.webserver node.
option 2: Add a mapping for .xml to IIS and force that file extension into the ASP.net pipeline. See here
Please follow these steps:
1- Delete sitemap.xml from root of website directory (if exists)
2- Put MapRoute for sitemap.xml over other MapRoutes like this :
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Sitemap",
"sitemap.xml",
new { controller = "Home", action = "Sitemap" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The reason of error is when sitemap RouteMap is under other rules , MVC checks the /sitemap.xml with above RouteMap , then throws error 404 for no matching controller/action.
I Know this is an old topic, but I have a solution that is better than "runAllManagedModulesForAllRequests".
Modules Preconditions:
The IIS core engine uses preconditions to determine when to enable a particular module. Performance reasons, for example, might determine that you only want to execute managed modules for requests that also go to a managed handler. The precondition in the following example (precondition="managedHandler") only enables the forms authentication module for requests that are also handled by a managed handler, such as requests to .aspx or .asmx files:
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
If you remove the attribute precondition="managedHandler", Forms Authentication also applies to content that is not served by managed handlers, such as .html, .jpg, .doc, but also for classic ASP (.asp) or PHP (.php) extensions. See "How to Take Advantage of IIS Integrated Pipeline" for an example of enabling ASP.NET modules to run for all content.
You can also use a shortcut to enable all managed (ASP.NET) modules to run for all requests in your application, regardless of the "managedHandler" precondition.
To enable all managed modules to run for all requests without configuring each module entry to remove the "managedHandler" precondition, use the runAllManagedModulesForAllRequests property in the <modules> section:
<modules runAllManagedModulesForAllRequests="true" />
When you use this property, the "managedHandler" precondition has no effect and all managed modules run for all requests.
You can learn more from it's original topic: runAllManagedModulesForAllRequests=“true” Meaning
So, the better way to set a HTTP handler for a .XML url on MVC is the following:
<system.webServer>
<handlers>
<add name="Sitemap" path="sitemap.xml" type="System.Web.UI.PageHandlerFactory" verb="*" />
</handlers>
</system.webServer>

URL Pattern Routing MVC 3

I want to know how to have something like this in the url in asp.net MVC
/Article/12.20.2013
I tried below and its working fine for /Article/12-20-2013 but not for /Article/12.20.2013. I have below in the Global.asax
routes.MapPageRoute("Blog",
"/Article/{entryDate}",
new {controller = "Article", action = "Entry")};
I also tried something like below
routes.MapPageRoute("Blog",
"/Article/{month}.{Date}.{year}",
new {controller = "Article", action = "Entry")};
but no luck..
Please guide me with some sample.
I believe the issue is that IIS might be treating ".2013" as a file extension and trying to find a handler for it. What we need to do is to have MVC process all requests.
If you are on IIS 6 this you will need to do a wildcard mapping to aspnet_isapi.dll. If you are on IIS 7 you can set the runAllManagedModulesForAllRequests="true":
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
You need to change web.config to force every url starting with Article to be treated as a MVC url
<system.webServer>
<handlers>
<add name="UrlRoutingHandler"
type="System.Web.Routing.UrlRoutingHandler,
System.Web, Version=4.0.0.0,
Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
path="/Article/*"
verb="GET"/>
</handlers>
</system.webServer>
Then your routing should be working fine.

How do I redirect all file access request in a subfolder?

currently I have this
routes.MapRoute(
name: "TestRedirect",
url: "Test/{*pathInfo}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I'm hoping all requests to access under Test is redirected to ~/Home/Index.
But unfortunately this doesn't work for file access such as /Test/index.html.
Only aspx files (like /Test/index.aspx) are redirected correctly though.
Can someone help me fix my routing?
Thanks a lot.
The reason for that is because static files are handled directly by IIS, and are not passed to ASP.NET for processing. The request is never reaching your application because IIS thinks it is a static file. If you are using integrated pipeline mode, simply register the following handler to ensure that all requests to /Test go through the managed pipeline and through your routing rules:
<system.webServer>
<handlers>
<add
name="TestFolderHandler"
path="Test/*"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Just adding answer for reference.
Your code is fine, you just need to add
routes.RouteExistingFiles = true;

Resources