MVC C# custom MvcRouteHandler - How to? - c#

Does anyone have experiences in providing a custom MvcRouteHandler? In my application I'd like to implement a globalization-pattern like http://mydomain/en/about or http://mydomain/de/about.
As for persistance, I'd like to have a cookie read as soon as a request arrives and if there is a language setting in this cookie apply it (so a user arriving at http://mydomain/ would be transferred to http://mydomain/en/ for example). If there is no cookie present, I'd like to get the first language the browser supports, apply this one and store it in this cookie.
I guess this can't be done with the standard routing mechanism mvc provides in it's initial project template. In a newsgroup I got the tip to have a look at the MvcRouteHandler and implement my own. But its hard to find a sample on how to do that.
Any ideas?

I don't believe a custom route handler is required for what you are doing.
For your "globalized" URIs, a regular MVC route, with a constraint that the "locale" parameter must be equal to "en", "de", etc., will do. The constraint will prevent non-globalized URIs from matching the route.
For a "non-globalized" URI, make a "catch-all" route which simply redirects to the default or cookie-set locale URI.
Place the "globalized" route above the "catch-all" route in Global.asax, so that "already-globalized" URIs don't fall through to the redirection.
You would need to make a new route handler if you want a certain URI pattern to trigger something that is not an action on a controller. But I don't think that's what you're dealing with, here.

You should be able to do this with ASP.NET MVC's default template, I'm doing something similar. Just build your routes as {language}/{controller}/{action}/{id}
Just set a default route that goes to a controller that checks for the language cookie, and redirects the user based on that cookie.

Related

ASP.NET MVC routing conflict

I have two routes in my application, each in a different Controller, that look like this:
[Route("forgot-password", Order = 1)]
[Route("{variable}", Order = 2)]
When I run the application I get the exception:
Multiple controller types were found that match the URL. This can
happen if attribute routes on multiple controllers match the requested
URL.
Remember these actions are in different Controllers. The Order attribute doesn't seem to work across Controllers!.
How can I get this scenario to work in asp.net mvc routing? I want to use attribute based routing and I don't want to change my urls.
The mechanism behind the error is explained here (I guess you are using Web API). Shortly put, precedence is honored only inside a controller.
Also, it is unclear for me why you want such a generic route like:
[Route("{variable}")]
The problem is that all routes in your application have been stored together. Even if it is located in different controllers, it is the same type, so they can "see" each other. In your case "forgot-password" and "{variable}" have the same format, that's why error about multiple routes has been displayed. As #NightOwl888 said, you may use RouteConfig to create a routes, but in that case you have to change your routing values.

ASP.NET WebApi specify action

I need to create ASP.NET WebApi with couple operation, for example RegisterAppStart, RegisterStep and RegisterAppEnd. And I want to place all this actions in one controller. As I read, usually in WebApi action name is not using.
And my question - is this a bad idea to rewrite default route config with actions using?
ps. sorry for my English
You can give actions arbitrary names using the [Route("/api/FooController/BarMethod"] attribute routing.
This usually overrides the "REST"yness of your service (where the request method indicates which method should be called), but as you aren't really building a REST service, you shouldn't care.

How to set custom cache response headers for virtual paths?

We have a virtual URL, /bundles. We want to be able to check, at some point during the .NET lifecycle, if the url starts with /bundles and then set headers. We've thought about using HttpCachePolicy Class and using setCacheability and setMaxAge. I'm wondering how we can apply that to any file served via the /bundles route? Where is the best place to handle this?
Sounds like you want a "different" caching behavior for this Route.
I assume that you have a special Controller for this Route.
If so then you could use the OutputCache Attribute on your Action Methods inside the Controller.
[OutputCache(Duration=[InSeconds], ...)]
public ActionResult YourMethod()
{
...
}
this will result in using the ASP.NET Cache Framework.
Optional: You could use a Profile which you set in the IIS WebSite Konfiguration, then you would have to use the Attribute with the Profile Parameter.
[OutputCache(Profile="YOUR_PROFILE")
IIS will add the associated Response Headers like Expire / Cache-Control / Last-Modified...
Also you would gain the Output Cache Feature which is a performance boost.
But if you want to get "full" Control over your Response Headers then you have to create an own IIS Handler where you override the Output Methods.
Because if you have an enabled Dynamic Compression, then the IIS will remove all Response Headers during ASP.NET lifecyle and add "needed" Response Headers after Compression which happens after ASP.NET processes.
Somewhere on the MSDN is a visualization of the IIS Cache Tiers. But you have to make a "deep" search on the MSDN. I would give you a link but that will take a longer time.. ;)

MapPageRoute() vs. Site's Root Directory Repeatedly Loads Target Resource

I have the following line in Global.asax.cs:
routes.MapPageRoute( "Resorts", "{resortname}", "~/Pages/ViewResort.aspx" );
The intention is to allow a request like:
www.mysite.com/some-resort-name
to load this resource (more or less)
www.mysite.com/Pages/ViewResort.aspx?resortname=some-resort-name
This behavior works fine. However, I'm noticing that ViewResort.aspx is being loaded every time any resource is requested, presumably because my route doesn't contain a literal path segment, like this alternative would:
routes.MapPageRoute( "Resorts", "Resort/{resortname}", "~/Pages/ViewResort.aspx" );
My client is insistent that the only thing after the hostname in the URL be the resort name, so going with the alternate route is not a possibility.
So my question is: is there something special one needs to do to the RouteUrl when it refers to the site's root directory? Failing that, is there a particular pattern that can be implemented on the target page (ViewResort.aspx in this case) to prevent it from being loaded and discarded with each page request?
Your route is acting as a catch-all. In situations like this, you'll need to provide specific routes before the catch-all route in order to give the proper responses for those specific routes. In other words, the only routes that should get through to your catch-all are routes that must redirect to Pages/ViewResort.aspx.

ASP.NET MVC. Data driven subdomains?

We are creating a multi-tennant web application where we identify tenants via a subdomain (customer1.ourapp.com, customer2.ourapp.com, etc).
Setup of subdomains has to be data driven - i.e. we don't want to have to modify IIS config (manually or programmatically) every time we get a new customer.
In MVC where is the best place to check that a subdomain in a request is valid (i.e. the subdomain exists in some table in the database)
Some options I've considered,
OnActionExecuting in the controller
In a custom action filter
IIS module
As part of the routing setup - a custom route class that knows about the valid sub-domains - similar to this approach - http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx
I think that conceptually this is a routing task so the last option seems right ?? i.e. a request with a subdomain that doesn't exist is essentially an invalid url so it shouldn't match against a route and should instead fall through to a 404. This would also allow us to explicitly define routes that do or don't require a valid subdomain.
I would create a custom action filter and registered it globally in Global.asax (no worries when adding new controllers).
You can also consider creating a custom MvcHandler and specify it when declaring routes. This will allow you to specify a few routes (ie. for static content), which can be shared between all clients.
Other solution is to use only routing and stick to the single domain, so you don't have to shell out for the expensive SSL certificate for wildcard domain.
I was doing it like this in my Base Controller Class before, however, like #Jakub said, using subdomain will be expensive if you or your client need SSL certificate thereafter.
var dotIndex = HostingEnvironment.SiteName.IndexOf('.');
if (dotIndex > 0)
{
var subdomain = HostingEnvironment.SiteName.Substring(0, dotIndex);
customerCode = subdomain;
}

Categories

Resources