sitemap.xml url returns 404 Error - asp.net-mvc

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>

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

Unable to map route for robots.txt in asp.net mvc

I am developing an asp.net mvc application. I am creating robots.txt for my application to prevent from bots because my current site is getting many robot requests. So I found this link, Robots.txt file in MVC.NET 4 to create robots.txt. But I when I access my application like this entering url, "www.domain.com/robots.txt", it is always returning 404 page.
This is my action method in HomeController
public ActionResult Robots()
{
Response.ContentType = "text/plain";
return View();
}
This is my robots view
#{
Layout = null;
}
User-agent:*
Disallow:/
I configured route for robots.txt like this in RouteConfig
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapMvcAttributeRoutes();
routes.MapRoute(
"Robots.txt",
"robots.txt",
new { controller = "Home", action = "Robots" },
new string[] { "AyarDirectory.Web.Controllers" }
);
//other routes
}
But when I access this url, "www.domain.com/robots.txt", it is always returning 404 page. How can I add robots.txt correctly to my application?
Creating a route ending with a file extension is not allowed by default in ASP.NET MVC. To get around this security restriction, you need to add the following to the Web.config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- ...Omitted -->
<system.webServer>
<!-- ...Omitted -->
<handlers>
<!-- ...Omitted -->
<add name="RobotsText"
path="robots.txt"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</configuration>
In Asp.net Core you can simply add your robots.txt file to the wwwroot directory.
Would say same thing as above you need to change the web.config to allow the route with .txt to work. I had same issue with a project I was working on and I got it to work.
However if you using a view for the output of the robots without a model you might as well keep a static robots.txt as it will give you no advantage. Another way is to output the text direct from the action using a string builder.
Nkosi's System.Web.Handlers.TransferRequestHandler approach in web.config approach did not work for me due to the environment I was working in, resulting in 500 errors.
An alternative of using a web.config url rewrite rule worked for me instead:
<rewrite>
<rules>
<rule name="Dynamic robots.txt" stopProcessing="true">
<match url="robots.txt" />
<action type="Rewrite" url="/DynamicFiles/RobotsTxt" />
</rule>
</rules>
</rewrite>

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;

ASP.NET MVC IgnoreRoute method doesn't work correctly when URL starts with "/Views/"

I use ASP.NET MVC in my application.
Users can specify their own images, styles, scripts by including them on the page.
But when they specify URL to the file which not exists then routing mechanism tries to find controller and action by URL to image or styles etc.
I've added a method IgnoreRoute and specified there all extensions I don't want to handle by routing.
It works correctly until URL doesn't starts with "Views/...".
In this case URL passes into application and executes error 404 inside of application.
But I want to handle this error with IIS.
This can be tested with empty project.
You can simply use this code for Global.asax.cs file:
using System;
using System.Web.Mvc;
using System.Web.Routing;
namespace MvcApplication1
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute(
"{*staticfile}",
new { staticfile = #".*\.(jpg|gif|jpeg|png|js|css|htm|html|htc)$" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
void Application_Error(object sender, EventArgs e)
{
}
}
}
Now we need to host this application at IIS, for example at http://localhost/testmvc/
You can place a break-point inside of Application_Error method to see when error executes inside of application
So now open test URL:
http://localhost/testmvc/test.css
We can see that IIS handled that error:
Now we open another test URL with "/Views/..." in the path:
http://localhost/testmvc/Views/test.css
And we see that error was handled by ASP.NET:
So the question is: maybe there exists some setting to tell MVC to not handle URL with "Views" in the path?
MVC by default will not allow you to directly address items under the /Views folder because of the mapping of all file types to the System.Web.HttpNotFoundHandler.
To get around this change your definition in your /Views/web.config to tell it to ignore basically everything else in that location
<add path="*.cshtml" verb="*" type="System.Web.HttpNotFoundHandler"/>
I wrote up a blog entry based on this since IIS 6 is different than 7 if you want to include multiple file types. See:
http://completedevelopment.blogspot.com/2011/06/using-views-outside-of-views-or-other.html
Here are my way :
1- Make a new folder in Views folder, eg. myFolder
2- Add your static page into this new folder, eg. filename.cshtml
3- Copy the web.config file from "Views" folder and paste it to the new folder you just
created (myFolder)
4- In the new web.config Replace
this :
<add path="*.*" verb="*" type="System.Web.HttpNotFoundHandler"/>
with this :
<add path="*.*" verb="*" type="System.Web.DefaultHttpHandler"/>
5- delete these line if you found it :
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
Resault :
Now any file in this folder will work without routing!

How do I block requests for all *.php, *.cgi, etc. pages from inside an ASP.NET MVC 1.0 app hosted in IIS7?

I'd like to block requests to any .php or .cgi regardless of the pathing information.
For example, when the following url is used:
http://mysite/Admin/Scripts/Setup.php
It matches an existing route:
routeCollection.MapRoute("Admin", "admin/{controller}/{action}/{uid}/{*pathInfo}", new { controller = "Admin", action = "Index", uid = "" });
However there is no controller for scripts so MVC throws the following:
The IControllerFactory '' did
not return a controller for a
controller named 'scripts'.
What I'd really prefer is that the request is simply met with a hard fail before MVC ever got to the controller.
I know that I can do this by hooking the Application_BeginRequest in the Global.asax and throwing a new HttpException(404, "Not Found") but that's not quite the elegant solution I'm looking for.
I was really hoping that this would work:
routeCollection.IgnoreRoute("{resource}.php/{*pathInfo}");
But it doesn't.
NOTE: Sean Lynch's answer works great but I still would really like a System.Web.Routing or System.Web.Mvc based solution. That way I can allow my users to add their own exclusions at runtime.
I know this is an old post but if you're looking for an ignore route for php requests (and some others) including requests within sub folders then I have found the code below works well (adapted from the ignore routes post from Phil Haack)
I also added a specific ignore route for the occasional apple touch icon request (using a wildcard for the different dimensions) and allowed for the different file extensions for the favicon (Google toolbar and some other browsers look for png and gif favicons).
Of course you could add an ignore route for all image file extensions but in my case I still want to route some of the other requests.
routes.IgnoreRoute("{*allphp}", new { allphp = #".*\.php(/.*)?" });
routes.IgnoreRoute("{*allcgi}", new { allcgi = #".*\.cgi(/.*)?" });
routes.IgnoreRoute("{*allaspx}", new { allaspx = #".*\.aspx(/.*)?" });
routes.IgnoreRoute("{*favicons}", new { favicons = #".*favicon\.(ico|gif|png)(/.*)?" });
routes.IgnoreRoute("{*allappleicon}", new { allappleicon = #"apple-touch-icon-.*\.png(/.*)?" });
Despite having these ignore routes, I still think that using request blocking for php files is preferable if you have access to do it.
If you hosting provider supports the IIS7 URL Rewrite module then you could check out this link:
http://learn.iis.net/page.aspx/499/request-blocking---rule-template/
Update here is what you would put into your web.config in the system.webserver section:
<system.webServer>
<rewrite>
<rules>
<rule name="RequestBlockingRule1" patternSyntax="Wildcard">
<match url="*" />
<conditions>
<add input="{URL}" pattern="*.php*" />
</conditions>
<action type="CustomResponse" statusCode="403" />
</rule>
</rules>
</rewrite>
</system.webServer>
I found How to ignore route in asp.net forms url routing which might work for this, it uses the StopRoutingHandler class, and as long as the requests to .php do run through the routing this will probably work.
If the .php requests are not going through the routing handler then this probably wouldn't work.
You could block these extensions before it even hits IIS with Microsoft's UrlScan ISAPI Filter.

Resources