Redirect(relativeUrl) redirecting to wrong path in IIS

11.8k views Asked by At

In the usual AccountController in my MVC3 app, if returnUrl is set (in my case, I set it manually), it will call Redirect(returnUrl).

Assume my return URL is /Admin/HealthCheck (which it really is). When I'm debugging, I get a URL like http://localhost:3279/Admin/HealthCheck from the redirect call.

Then, I deployed my app to http://localhost/Test. In this case, Redirect(returnUrl) redirects me to http://localhost/Admin/HealthCheck and not the expected http://localhost/Test/Admin/HealthCheck.

What's going on here? How do I fix this (if it is fixable)?

Below is a snippet from the (standard) MVC3 AccountController; you can see where I get the return URL from the query string (eg. http://localhost/Test/LogOn?ReturnUrl=/Admin/HealthCheck, albeit URL encoded).

[HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    returnUrl = Request.Params["ReturnUrl"];

                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
            }
4

There are 4 answers

2
Darin Dimitrov On BEST ANSWER

(in my case, I set it manually)

You haven't actually shown how this manual setting happens, but if you have hardcoded an url such as /Admin/HealthCheck instead of using an url helper to generate this url such as Url.Action("HealthCheck", "Admin") don't expect miracles to happen.

Your LogOn is fine. It does what it is supposed to do => it redirects to the url that is passed as argument. Your problem lies in the way you are setting this url.

Conclusion: in an ASP.NET MVC application always use url helpers when dealing with urls. Never hardcode them.

0
FreeClimb On

You need to use Request.UrlReferrer.AbsoluteUri

[HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        string refUri = Request.UrlReferrer.AbsoluteUri;

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                    && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return Redirect(refUri + "#/account/login");
                }
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }
1
AudioBubble On

For your Test URL, you would have to set your ReturnUrl to be Test/Admin/HealthCheck.

Note the MSDN Reference on Controller.Redirect():

Creates a RedirectResult object that redirects to the specified URL.

In other words, if you put "/Admin/HealthCheck" as your parameter, that is exactly where the redirect will be.

1
Josh Mein On

If your end domain is going to be www.domain.com/Test/Admin/HealthCheck you may want to change the virtual directory for your project so that you dont have to make changes in the URL when switching between localhost and your actual server.

If you are using Visual Studio, you can change the virtual path assigned to your project by clicking on the project in the solution explorer and hitting F4. This will display the project properties window which has an option to change the virtual path. In your case, you would want to change it to /Test. You will still have to change your urls to contain the /Test though.

Although just as Darin pointed out, you should use the url helpers.