views:

243

answers:

3

Here's the situation...

Site 1) ASP.NET MVC application for customers to login, view and pay bills, etc. This site is using cookieless ASP sessions to allow multiple sessions to run in tabbed browsers.

Site 2) Corporate web site with standard static content. This will have a small form at the top of each page with a username/password form that will post to the MVC application.

When posting to the MVC app, a new session is being generated and the site is returning a 302 redirect with the session ID in the URL (as expected). The controller has two Login methods, one for handling a GET, one for handling a POST. Because of the redirect, it's hitting the GET method and it loses the form values.

By changing the method on the corporate site to do a form GET rather than a POST, the username and password are preserved in the query string after the redirect and I could handle the requests that way, but I would rather do a POST and not pass that data around in the URL.

My gut says that implementing some sort of custom HttpHandler would allow me to do this, but I'm not sure where I'd be able to tie into the session creation. A breakpoint at Session_Start in global.asax shows that the session ID has already been crated and the redirect already happened at that point.

A: 

When the MVC site issues the redirect are you handling that yourself with a controller or is it being routed automatically by your membership provider?

If you can intercept the request before the redirect you could place the username and password in the TempData variable and process it after the redirect.

Nathan Taylor
It's being redirected automatically.
Pete Nelson
What controller/action does the remote site post to when the user attempts to log in?
Nathan Taylor
Right now I'm just using the VS web server, so the form has a post to "http://localhost:2600/Home/Login" and the method looks like...'[HttpPost]public ActionResult Login(HomeLoginData loginData){// snip}'but it never gets there because of the redirect with the new session ID. For example, the corporate site form POSTs to http://localhost:2600/Home/Login and I get a 302 redirect to http://localhost:2600/%28S%28lkcfoer1mb1gbf55hi1bqsbn%29%29/Home/Login
Pete Nelson
A: 

You're looking for a Server.Transfer equivalent in MVC (see Simon's answer.)

It's like Request.Redirect but simply transfers the .NET processing to another page. It also allows for maintaining the form variables even on POST between transfers (in this case a RouteValueDictionary).

EDIT: (response to your comment #1)

Here is an example of Forms Authentication with MVC. Without knowing the internals of your authorization mechanism, I'm not entirely sure. At any point of the "DoLogin" process, you would be able to do a transfer instead of a redirect.

Peter J
Where would I intercept the first sessionless form post to prevent the default 302 redirect after the session is created?
Pete Nelson
See my edit - maybe it will point you in the right direction.
Peter J
A: 

I believe I found where the redirect was happening as well as a possible solution to it. The ISessionIDManager interface has a SaveSessionID method with an "out bool redirected" parameter on it. It appears that when a new session is created, the default session manager rewrites the URL inside this method and does a redirect. I played around with implementing my own ISessionIDManager and I was able to suppress the redirect, but there's no way (that I could tell) of inserting the session ID into the URL for the cookieless session without doing the redirect. Server.Transfer is not allowed at that point in the request lifecycle. I tried that but received an "Error Executing Child Request" message.

Later on, I found this article on Enabling POST in cookieless ASP.NET Applications. Basically by tying in to the Application_EndRequest event, you can detect the redirect, clear the response and fake a form post to the new URL that contains the session ID.

void MvcApplication_EndRequest(object sender, EventArgs e)
{

    HttpApplication application = (HttpApplication)sender;

    if (application.Request.Form["CorpLogin"] == "1"
        && application.Response.RedirectLocation != null
        && application.Response.IsRequestBeingRedirected)
    {

        StringBuilder build = new StringBuilder();
        build.Append("<html>\n<body>\n<form name='Redirect' method='post' action='");
        build.Append(application.Response.RedirectLocation);

        build.Append("' id='Redirect' >");
        foreach (string key in application.Request.Form)
        {
            if (key != "CorpLogin")
                build.Append(string.Format("\n<input type='hidden' name='{0}' value = '{1}'>", (string)key, application.Request.Form[(string)key]));
        }

        build.Append("\n<noscript><h2>Object moved <input type='submit' value='here'></h2></noscript>");
        build.Append(@"</form>
      <script language='javascript'>
      <!--
        document.Redirect.submit();
      // -->
      </script>
      ");
        build.Append("</body></html>");

        application.Response.Clear();
        application.Response.ClearHeaders();
        application.Response.Output.Flush();

        application.Response.Write(build.ToString());

    }
}

This isn't an ideal solution IMHO but it might be workable enough to meet the requirements.

Pete Nelson