How to add route to dynamic robots.txt in ASP.NET MVC? - asp.net-mvc

I have a robots.txt that is not static but generated dynamically. My problem is creating a route from root/robots.txt to my controller action.
This works:
routes.MapRoute(
name: "Robots",
url: "robots",
defaults: new { controller = "Home", action = "Robots" });
This doesn't work:
routes.MapRoute(
name: "Robots",
url: "robots.txt", /* this is the only thing I've changed */
defaults: new { controller = "Home", action = "Robots" });
The ".txt" causes ASP to barf apparently

You need to add the following to your web.config file to allow the route with a file extension to execute.
<?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>
See my blog post on Dynamically Generating Robots.txt Using ASP.NET MVC for more details.

Answer here: url with extension not getting handled by routing. Basically, when asp sees the "." it calls the static file handler, so the dynamic route is never used. The web.config files needs to be modified so /robots.txt will not be intercepted by the static file handler.

Muhammad Rehan Saeed'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>

Related

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>

IIS reverse proxy configuration issues with MVC 5 app

I cannot properly configure reverse proxy in IIS 8.5 for my MVC5 application. We use 3rd party application Tibco Spotfire WebPlayer 7.0.1 to integrate into our MVC webapp. To do so we use Javascript API to open report from WebPlayer and insert it into iframe.
We have to configure reverse proxy to allow requests go to backend server with WebPlayer installed. Our main webapp located at http://mywebapp.com/ and all requests that should be rewrite looks like http://mywebapp.com/SpotfireWeb/..., backend server located at private ip http://172.29.1.7/SpotfireWeb/...
The main issue that I configured reverse proxy using ARR 3.0 and URL Rewrite Module 2.0, but it doesn't work for *.ashx, *.aspx, *.axd, *.asmx files. It looks like some handler conflicts with ARR/RewriteModule and doesn't allow to pass requests to different server
Details:
When I try to load static html file like http://mywebapp.com/SpotfireWeb/secret.html the request is been rewrote to 172.29.1.7 server and I got content of this file. But once I request something like http://mywebapp.com/SpotfireWeb/GetJavaScriptApi.ashx?Version=6.0 I got 404 error from mywebapp.com. I run Wireshark and discovered that requests to back-end server 172.29.1.7 don't go at all if requests contains *.ashx file.
I installed Failed Requests Trace and found that event HANDLER_CHANGED occurred which changed ApplicationRequestRoutingHandler to System.Web.Mvc.MvcHandler
Playing with this I removed some handlers and now Wireshark catches requests to the back-end server. I believe this approach of removing handlers is not correct. May be I configured something in wrong way?
Anyway, removing one module by one I faced issue when POST request to http://mywebapp.com/SpotfireWeb/AjaxService.asmx/InitiateOpen didn't processed and I got 404 error from my initial app. When I removed *.asmx handler I still got the same error. This is point where I get stuck right now.
My rewrite rules from web.config of mywebapp.com. I configured it at website level:
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
<match url="SpotfireWeb/?(.*)$" />
<action type="Rewrite" url="http://172.29.1.7/SpotfireWeb/{R:1}" logRewrittenUrl="true" />
<serverVariables>
<set name="ORIGINAL_HOST" value="{HTTP_HOST}" />
</serverVariables>
</rule>
</rules>
<outboundRules>
<clear />
<rule name="ReverseProxyOutboundRule1" preCondition="" enabled="true">
<match filterByTags="A, Area, Base, Form, IFrame, Img, Input, Link, Script" pattern="SpotfireWeb/?(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
<action type="Rewrite" value="http://mywebapp.com/SpotfireWeb/{R:1}" />
</rule>
<rule name="ReverseProxy_Redirection" preCondition="IsRedirection" enabled="true">
<match filterByTags="A, Area, Base, Form, IFrame, Img, Input, Link, Script" serverVariable="RESPONSE_Location" pattern="^http://[^/]+/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true">
<add input="{ORIGINAL_HOST}" pattern=".+" />
<add input="{URL}" pattern="^/(SpotfireWeb)/?.*" />
</conditions>
<action type="Rewrite" value="http://{ORIGINAL_HOST}/{C:1}/{R:1}" />
</rule>
<preConditions>
<preCondition name="IsRedirection">
<add input="{RESPONSE_STATUS}" pattern="3\d\d" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
Have anyone saw something similar ?
I assume that root cause in MVC handler, but can't understand where.
I fixed this. Obviously we don't need to remove modules. The answer basically into logs of failed requests.
During MAP_REQUEST_HANDLER event ASP.NET infrastructure determines the request handler for the current request. In my case MVC handler selected every time I requested URL like /SpotfireWeb/... regardless of ARR was current handler. Here I found that:
..the handler mapping can be changed during request execution in the MAP_REQUEST_HANDLER event. This allows scenarios such as URL rewriting to work.
My fix was removing SpotfireWeb from MVC routes completely. Thus I added following code into RouteConfig.cs
routes.IgnoreRoute("SpotfireWeb/{*pathInfo}");
And the whole class looks like:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// ignore everything under 'SpotfireWeb' because this request will be routed
// to separate server via reverse proxy ARR/Rewrite module
routes.IgnoreRoute("SpotfireWeb/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { area = string.Empty, controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "GKSPortal.Controllers" });
}
}

W3C Validation Not working for RazorView

I am using MVC4 project and doing URL rewrite on Server side in RouteConfig and appending .html at the end of url of every page..
www.mysite.com/home.html
I have couple of pages and those pages are linked with home page (every think is working find in browser).
But when I validate using W3C link checker, I get broken link error message.
I really don't know what can be issue. One more thing if I replace .html with .aspx or any other extension it is validated by W3C. I don't know what is issue.
My code is:
routes.MapRoute(
name: "features",
url: "features.html",
defaults: new { controller = "Home", action = "features", page = UrlParameter.Optional }
);
Web.config:
<add name="HtmlFileHandler" path="*.html" verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
Any help is highly appreciated
Ok I solved it some what like this.
I replaced
<add name="HtmlFileHandler"
path="*.html"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
in webconfig with
<add name="HtmlFileHandler"
path="*.html"
verb="*"
type="System.Web.UI.PageHandlerFactory" />
and it works ... my page is validated by W3C now. :)

ASP.NET MVC 4 - 301 Redirects in RouteConfig.cs

How can I add a route to the RouteConfig.cs file in an ASP.NET MVC 4 app to perform a permanent 301 redirect to another route?
I would like certain different routes to point at the same controller action - it seems a 301 would be best practice for this, specially for SEO?
Thanks.
You have to use RedirectPermanent, here's an example:
public class RedirectController : Controller
{
public ActionResult News()
{
// your code
return RedirectPermanent("/News");
}
}
in the global asax:
routes.MapRoute(
name: "News old route",
url: "web/news/Default.aspx",
defaults: new { controller = "Redirect", action = "News" }
);
I know you specifically asked how to do this on the RouteConfig, but you can also accomplish the same using IIS Rewrite Rules. The rules live on your web.config so you don't even need to use IIS to create the rules, you can simply add them to the web.config and will move with the app through all your environments (Dev, Staging, Prod, etc) and keep your RouteConfig clean. It does require the IIS Module to be installed on IIS 7, but I believe it comes pre installed on 7.5+.
Here's an example:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect t and c" stopProcessing="true">
<match url="^terms_conditions$" />
<action type="Redirect" url="/TermsAndConditions" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

ApiController returns 404 when ID contains period

I have an ApiController and I want to use email addresses as the ID parameter for requests:
// GET api/employees/email#address.com
public CompactEmployee Get(string id) {
var email = id;
return GetEmployeeByEmail(email);
}
However, I cannot get this to work (returns 404):
http://localhost:1080/api/employees/employee#company.com
The following all work:
http://localhost:1080/api/employees/employee#company
http://localhost:1080/api/employees/employee#company.
http://localhost:1080/api/employees?id=employee#company.com
I have set relaxedUrlToFileSystemMapping="true" in my web.config as detailed by Phil Haack.
I would very much love the full email address to work, but any time the period is followed by any other character, the request returns a 404. Any help would be greatly appreciated!
Solution
Due to a lack of other options, I've headed in the direction Maggie suggested and used the answer from this question to create a rewrite rule to automatically append a trailing slash when I need an email in the URL.
<system.webServer>
....
<rewrite>
<rules>
<rule name="Add trailing slash" stopProcessing="true">
<match url="^(api/employees/.*\.[a-z]{2,4})$" />
<action type="Rewrite" url="{R:1}/" />
</rule>
</rules>
</rewrite>
</system.webServer>
Would adding a trailing slash work for your scenario?
http://localhost:33021/api/employees/employee#company.com/
Check your IIS settings:
Home Directory -> Configuration
Edit the .aspx application extension and ensure that the setting Verify that file exists is off.
UPDATE
I've just tested with a default MVC4 Web API project
URL: http://localhost:10983/api/values/cool#email.com
Action in ValuesController:
public string Get(string id)
{
return id;
}
This was the response:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">cool#email.com</string>
This is what worked for me:
I was running on targetFramework = 4.6.1. I have upgraded to 4.6.2 and added this in web.config:
<system.web>
<customErrors mode="Off"/>
<compilation debug="true" targetFramework="4.6.2"/>
<!-- This will allow to search for stuff that contains . & etc.-->
<httpRuntime targetFramework="4.6.2" maxRequestLength="100000" maxUrlLength="2048" relaxedUrlToFileSystemMapping="true" requestPathInvalidCharacters=""/>
</system.web>
The requestPathInvalidCharacters="" is to be able to have stuff like & etc in URI, in encoded form, of course.

Resources