views:

1687

answers:

4

Simple enough, it would seem, but it turns out not to be - mainly due to the fact that the View can't possibly know which way through Model and Controller you got there. Regardless, it is a problem that needs a solution:

I have a login link, that takes the user to a form to enter username and password. When the user clicks "submit", I want to redirect to the page he was viewing. The easiest way to do so seems to be specifying the url to the current page as a querystring (...?returnUrl=...) and everything else is already built.

But where do I find this url from my view, when rendering the link? I naturally can't use a RedirectToActionResult as I don't want to actually transfer the user - only render the url in a link. How to?


EDIT:

I have now started a bounty on this question, and therefore I see fit to clarify my needs as well.

I have a UserControl named Login.ascx in my Shared folder. In it, I render an ActionLink to the login form, and it is included in the footer on my Masterpage. What I want to accomplish is the following:

When the ActionLink is rendered, the querystring returnUrl is appended with the a route to the view that is currently being rendered. If this is accomplished, the user will be taken back to the page he/she was viewing after successful login with functionality that is already build into the ASP.NET MVC Framework.

The reason the previous answers have not been sufficient is mainly that they have not provided a way to build the route url to the current view. I do know how to append a querystring, but I do not know how to find out what to put in that string.

In order to mark an answer as the answer, I want a method to re-construct the route to the currently shown view, from a usercontrol in the masterpage.

+3  A: 

One way would be to build the links that send the user to the login form, with returnUrl=/PageToReturnTo (<a href="/Account/Login/?returnUrl=/Product/10">Login</a> for example). You'd want to write it so the return url was constructed from your routes though, manually writing those links on every page could be cumbersome.

The default login action in MVC has the returnUrl functionality already built. Just need to pass it a value and it will do the rest. Here's a copy'n paste of the method signature from a fresh project.

public ActionResult Login(string username, string password, bool rememberMe, string returnUrl)

Hope that helps ya!

Chad
Thanks for your reply! I have already gotten this far - it's the constructing of returnUrl from my routes that I don't how to do. The link is on my MasterPage, so hard-coding the link on every page is not an option.
Tomas Lycken
Also, the standard authorization in ASP will add ?returnURL to any request that is in a protected area (i.e. has a web.config file with allow/deny rules).
Jarrett Meyer
+6  A: 

The solution is to use HttpContext.Current.Request.RawUrl like this:

<%= Html.ActionLink("log on", "LogIn", new { controller = "User", returnUrl = HttpContext.Current.Request.RawUrl }) %>

Or with an extension method from MVC futures (Microsoft.Web.Mvc.dll):

<%= Html.ActionLink<AccountController>(c => c.LogOn("name", "password", false, HttpContext.Current.Request.RawUrl), "login here")%>

ActionController is the default one in mvc but just add returnUrl to your own.

Dala
I had no generic version of the ActionLink helper method (should I, in an MVC RC Refresh project? Am I missing something?) but this worked: <%= Html.ActionLink("log on", "LogIn", new { controller = "User", returnUrl = HttpContext.Current.Request.RawUrl }) %>
Tomas Lycken
Clarification - if you edit the post to this code, you'll get the goodies =)
Tomas Lycken
A: 

I don't know about ASPX, but there are a couple of problems we encountered building this:

When the user gets their password wrong, and loops-round the Login page to have another go, the Target must still be preserved.

We also decided to preserve POST variables to a page that then required the just-in-time login

Kristen
+1  A: 

You can use Page.Request.Url to get the route that resulted in the currently rendered view.

Though that's more of a cosmetic detail, you might want to unify the requests that came through the '/' and '/default.aspx' routes and always return to the '/' route. I have a helper property in my master page that does exactly that.

    protected Uri RouteUrl
    {
        get
        {
            if (Page.Request.Url.AbsolutePath.StartsWith("/default.aspx", StringComparison.OrdinalIgnoreCase))
            {
                return new Uri(Request.Url, new Uri(Response.ApplyAppPathModifier("~/")));
            }

            return Page.Request.Url;
        }
    }
Franci Penov