transfer sitemap.xml http request to route handler in ASP.NET MVC - asp.net-mvc

I'm trying to add a route that will transfer all sitemap.xml requests to a custom request handler I made.
I tried using the following code:
routes.Add(new Route("sitemap.xml", new Helpers.SiteMapRouteHandler()));
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
But when I make a link using Url.Action():
Url.Action("Index", new { controller = "About"})
I get the following when I try to navigate to the XML file:
/sitemap.xml?action=Index&controller=About
What am I doing wrong?
ANSWER:
I used this solution:
Specifying exact path for my ASP.NET Http Handler

If you want to route to and action instead to a request handler
You could add a route like this
routes.MapRoute(
"Sitemap",
"sitemap.xml",
new { controller = "Home", action = "SiteMap" }
);
as mentioned here - MVC: How to route /sitemap.xml to an ActionResult? and it worked for me
Update: Also ensure that <modules runAllManagedModulesForAllRequests="true"> is set.

I'm not sure if this will solve the problem, but it's worth a try:
routes.Add(
new Route(
"{request}",
new RouteValueDictionary(new { id = "" }), // this might be the tricky part to change
new RouteValueDictionary(new { request = "sitemap.xml" }),
new Helpers.SiteMapRouteHandler()
));

You have to add a handler to web.config file.
<add name="SitemapFileHandler" path="sitemap.xml" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/>
And configure your routes:
routes.RouteExistingFiles = true;
Read more here:
http://weblogs.asp.net/jongalloway//asp-net-mvc-routing-intercepting-file-requests-like-index-html-and-what-it-teaches-about-how-routing-works

Related

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

MVC action not getting called

I have only 1 controller and have 1 action only in my example like this:
//
// GET: /Home/
public ActionResult Index(string source,string id)
{
return View();
}
I have 2 routes registered for this action like -:
routes.MapRoute(
name: "Default2",
url: "{source}/{id}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "",
defaults: new { controller = "Home", action = "Index", source="source1", id = UrlParameter.Optional }
);
When I call default, it calls Index action, which is OK
when I call like this, /source1/12 - it works.
But when I call like this /source1/12.0 - it does not work and shows up 404 ..
Can anyone suggest why is this happening ?
It's probably interpreting the .0 as a file extension, and thus looking for a file on disk. Can you replace "." with "_" for the purposes of redirection, and replace back in your action method? Otherwise, you have to look at ways you can get the routing not to interpret ".0" as a file extension. Not sure exactly how off of the top of my head...
MVC routes errors like this to special methods. One is in the controller: HandleUnknownAction, which is called when the action can't be matched. You can override it and handle the action (logging it, etc.) there.
Check this article, it has a solution for you:
From the link:
<configuration>
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true"/>
<!-- ... your other settings ... -->
</system.web>
</configuration>
change the ROuteCOnfig to:
routes.MapRoute(
name: "Default2",
url: "{source}/{id}/",
defaults: new { controller = "Home", action = "Index" }
);
Should solve your issue.
You can also check this SO Thread

loginpage first in mvc3

I'm working with an MVC3 (razor) application. In the default sample program, how can a user get the login page first, then to allow registered users to enter into homepage?
I tried to create one but landed in bunch of errors.
in Global.asax file, RegisterRoutes method
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Account", action = "LogOn", id = UrlParameter.Optional }
);
you just need to change controller and action for default route.
You have to modify the default action in the route config.
routes.MapRoute(
"Home",
"{controller}/{action}/{id}",
new { controller = "LoginController", action = "loginView", id = UrlParameter.Optional }
);
Add the following code in the Application_Start method in your Global.asax:
GlobalFilters.Filters.Add(new System.Web.Mvc.AuthorizeAttribute())
and decorate your login action with [AllowAnonymous] attribute

MVC RouteConfig allow /Controller/Action.html

I have an MVC application and am using the standard routeconfig that routes /Controller/Action/Id
I want it to additionally capture /Controller/Action.html as the url and as well and point to /controller/action also.
I am using a jquery library that I have no control over, and a function requires a url that points to a webpage or an image. However, it doesn't appear to understand that ends without an extension(.html, .php etc) is a link to html and throws an error.
Edit: I tried as the commenter below suggested, and still can't seem to get it to work. Here is my route config.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("routeWithHtmlExtension",
"{controller}/{action}.html",
new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
This Url works:
http://localhost:14418/Album/Test
This one does not:
http://localhost:14418/Album/Test.html
In web.config
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
...
</system.webServer>
If you set up the following route, it will work:
routes.MapRoute("routeWithHtmlExtension",
"{controller}/{action}.html",
new {controller = "Home", action = "Index" }
);

routing to blank request in mvc asp.net using IIS 6.0

I'm attempting to connect to my published website using the following url.
http://www.mywebsite.com/
I keep getting:
The incoming request does not match any route.
Here are my routing rules:
routes.MapRoute(
"Default", // Route name
"{controller}.aspx/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
routes.MapRoute(
"Default2", // Route name
"/", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
I'm using authentication as such:
<authentication mode="Forms" >
<forms loginUrl="~/Home.aspx/Index"
protection="All"
timeout="300"/>
</authentication>
When I'm not authenticated it goes to the correct page, but when I am authenticated it throws the above error. I'm using IIS 6.0 and doing the whole rewriting url workaround option.
What am I missing?
Change "/" in "Default2" route to "":
routes.MapRoute("Default2", "", new { ... });
Also make sure you have followed this guide: http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx for Default.aspx file if you are on IIS6.

Resources