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??..
Just instance the other controller and execute it's action method.
How about a TransferResult class? (based on Stans answer)
Updated: Now works with MVC3 (using code from Simon's post). It should (haven't been able to test it) also work in MVC2 by looking at whether or not it's running within the integrated pipeline of IIS7+.
For full transparency; In our production environment we've never use the TransferResult directly. We use a TransferToRouteResult which in turn calls executes the TransferResult. Here's what's actually running on my production servers.
And if you're using T4MVC (if not... do!) this extension might come in handy.
Using this little gem you can do
Edit: Updated to be compatible with ASP.NET MVC 3
Provided you are using IIS7 the following modification seems to work for ASP.NET MVC 3. Thanks to @nitin and @andy for pointing out the original code didn't work.
Edit 4/11/2011: TempData breaks with Server.TransferRequest as of MVC 3 RTM
Modified the code below to throw an exception - but no other solution at this time.
Here's my modification based upon Markus's modifed version of Stan's original post. I added an additional constructor to take a Route Value dictionary - and renamed it MVCTransferResult to avoid confusion that it might just be a redirect.
I can now do the following for a redirect:
My modified class :
I achieved this by harnessing the
Html.RenderAction
helper in a View:And in my controller:
I wanted to re-route the current request to another controller/action, while keeping the execution path exactly the same as if that second controller/action was requested. In my case, Server.Request wouldn't work because I wanted to add more data. This is actually equivalent the current handler executing another HTTP GET/POST, then streaming the results to the client. I'm sure there will be better ways to achieve this, but here's what works for me:
Your guess is right: I put this code in
and I'm using it to display errors to developers, while it'll be using a regular redirect in production. Note that I didn't want to use ASP.NET session, database, or some other ways to pass exception data between requests.
Couldn't you just create an instance of the controller you would like to redirect to, invoke the action method you want, then return the result of that? Something like: