views:

477

answers:

2

How do redirections work in ASP.Net MVC?

I've copied and modified the code bit from Scott Henselman's blog that uses DotNetOpenId to login via OpenID. Debugging, I find that when executing this code segment:

// Stage 2: user submitting Identifier
var openId = Request.Form["openId"];
new OpenIdRelyingParty().CreateRequest(openId).RedirectToProvider();
throw new Exception("Should never get here");

I never get to the throw clause, but rather continue with the redirection. How does that work?

Then, when I get the response from the OpenId provider, I'm debugging through this code segment:

switch (response.Status)
{
  case AuthenticationStatus.Authenticated:
    FormsAuthentication.RedirectFromLoginPage(response.ClaimedIdentifier, false);
    // am I supposed to reach this line? What should I return here?
    // (The method expects a View to be returned)

And I find that the call to FormsAuthentication.RedirectFromLoginPage() does return and I need to return something from the Action. What should I return here?

A: 

Check this site link text they cover redirecting to another action and passing information to it.

Adnan
A: 

In your first example, the RedirectToProvider() method calls the ASP.NET Response.Redirect() method. This method, as implemented by ASP.NET itself, throws an exception (ThreadAbortException specifically). That's why you never get to throw new Exception("Should never get here"); line. Note however that that although it is never reached, throw must still appear because it allows C# to know that no return statement is necessary for the method to be verifiable and safe code.

The FormsAuthentication.RedirectFromLoginPage method also ultimately calls Response.Redirect, which means it also throws an exception. But because you don't have a throw statement beneath it, C# requires that you return something instead. When you're in a method with a return type, C# demands you return or throw at every possible exit point.

In ASP.NET web forms, Response.Redirect was your only option (well, not really but it seemed like it). But ASP.NET MVC offers a RedirectAction that allows you to issue a browser redirect without ever throwing an exception. And DotNetOpenAuth (the successor to DotNetOpenId) offers a way to leverage this feature.

As shown here you can redirect to the provider by returning the result of IAuthenticationRequest.RedirectingResponse.AsActionResult() from your controller's action to initiate login instead of calling IAuthenticationRequest.RedirectToProvider().

Also, you can log the user into your site without using FormsAuthentication.RedirectFromLoginPage by calling FormsAuthentication.SetAuthCookie and then return Redirect(...) within your controller's action to send the user onto his destination.

Andrew Arnott
I find that FormsAuthentication.RedirectFromLoginPage() does not throw an exception, but rather the execution does continue after it. What could cause this?
ripper234
Hmmm... in that case that method may set `Response.RedirectLocation` property and just return, which will result in a redirect but not an exception, allowing the execution to continue.
Andrew Arnott
But then what should I return from the controller action?
ripper234
I suspect you can `return new EmptyAction()` and it (I think) should work. If that doesn't work, well you can always `return Redirect(Request.QueryString["ReturnUrl"] ?? FormsAuthentication.DefaultUrl)` yourself.
Andrew Arnott
There are two types of Response.Redirect, 1 is immediate and causes the thread abort exception, the other allows the request to continue executing but will send a redirect when finished. RedirectFromLoginPage uses Response.Redirect(url, false), Response.Redirect(url) is the same as Response.Redirect(url,true). The boolean parameter determines if the redirect is immediate.
Neal