In ASP.NET MVC you can return a redirect ActionResult quite easily :
return RedirectToAction("Index");
or
return RedirectToRoute(new { controller = "home", version = Math.Random() * 10 });
This will actually give an HTTP redirect, which is normally fine. However, when using google analytics this causes big issues because the original referer is lost so google doesnt know where you came from. This loses useful information such as any search engine terms.
As a side note, this method has the advantage of removing any parameters that may have come from campaigns but still allows me to capture them server side. Leaving them in the query string leads to people bookmarking or twitter or blog a link that they shouldn't. I've seen this several times where people have twittered links to our site containing campaign IDs.
Anyway, I am writing a 'gateway' controller for all incoming visits to the site which i may redirect to different places or alternative versions.
For now I care more about Google for now (than accidental bookmarking), and I want to be able to send someone who visits /
to the page that they would get if they went to /home/7
, which is version 7 of a homepage.
Like I said before If I do this I lose the ability for google to analyse the referer :
return RedirectToAction(new { controller = "home", version = 7 });
What i really want is a
return ServerTransferAction(new { controller = "home", version = 7 });
which will get me that view without a client side redirect. I don't think such a thing exists though.
Currently the best thing I can come up with is to duplicate the whole controller logic for HomeController.Index(..)
in my GatewayController.Index
Action. This means I had to move 'Views/Home'
into 'Shared'
so it was accessible. There must be a better way??..
You could new up the other controller and invoke the action method returning the result. This will require you to place your view into the shared folder however.
I'm not sure if this is what you meant by duplicate but:
Edit
Another option might be to create your own ControllerFactory, this way you can determine which controller to create.
Server.TransferRequest
is completely unnecessary in MVC. This is an antiquated feature that was only necessary in ASP.NET because the request came directly to a page and there needed to be a way to transfer a request to another page. Modern versions of ASP.NET (including MVC) have a routing infrastructure that can be customized to route directly to the resource that is desired. There is no point of letting the request reach a controller only to transfer it to another controller when you can simply make the request go directly to the controller and action you want.What's more is that since you are responding to the original request, there is no need to tuck anything into
TempData
or other storage just for the sake of routing the request to the right place. Instead, you arrive at the controller action with the original request intact. You also can be rest assured that Google will approve of this approach as it happens entirely on the server side.While you can do quite a bit from both
IRouteConstraint
andIRouteHandler
, the most powerful extension point for routing is theRouteBase
subclass. This class can be extended to provide both incoming routes and outgoing URL generation, which makes it a one stop shop for everything having to do with the URL and the action that URL executes.So, to follow your second example, to get from
/
to/home/7
, you simply need a route that adds the appropriate route values.But going back to your original example where you have a random page, it is more complex because the route parameters cannot change at runtime. So, it could be done with a
RouteBase
subclass as follows.Which can be registered in routing like:
Note in the above example, it might make sense to also store a cookie recording the home page version the user came in on so when they return they receive the same home page version.
Note also that using this approach you can customize routing to take query string parameters into consideration (it completely ignores them by default) and route to an appropriate controller action accordingly.
Additional Examples
You can use Server.TransferRequest on IIS7+ instead.
I found out recently that ASP.NET MVC doesn't support Server.Transfer() so I've created a stub method (inspired by Default.aspx.cs).
For anyone using expression-based routing, using only the TransferResult class above, here's a controller extension method that does the trick and preserves TempData. No need for TransferToRouteResult.
Rather than simulate a server transfer, MVC is still capable of actually doing a Server.TransferRequest: