tags:

views:

274

answers:

2

Imagine a scenario where I have a sub-form on a page. This sub form is contained in a partial user control and posts to its own dedicated controller action. In the event that a business rule is violated, I want to return the same view the user was previously on.

Example:

  • User is at /example/page1 which renders partial "SignOnForm"
  • SignOn form posts to "Accounts/SignOn".
  • In the event that something is invalid, I want to return the user to /example/page1 with the model state in tact. However, I cannot hard code the view because the user might be on a different page such as /othercontroller/page10.
A: 
public SignOn(string username, string password)
{
  //login logic here
  ...

  //Now check if the user is authenticated.
  if(User.IsAuthenticated)
  {
    //Redirect to the next page
    return RedirectToAction("page10", "Other");
  }
  else
  {
    // You could also pass things such as a message indicating the user was not authenticated.
    return RedirectToAction("page1", "Example");
  }
}

Also, you could always dump out the form data from the last 'good' posted page into hidden form fields, and have the user click the 'go back' button, which effectively posts them forward to the previous page. I don't particularly like this though as this means that you have to maintain the previous form fields.

Dan Atkinson
+1  A: 

You could bring on the return URL all the way through the SignOn process, using the request query string.

First, specify the page to return to whenever you render your SignOn partial:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="Microsoft.Web.Mvc"%>

<!-- Your Example/Page1 page -->

<% if (!User.IsAuthenticated) %>
    <%= Html.RenderAction("SignOn", "Account", new { returnUrl = Request.Url.PathAndQuery }); %>

Use RenderAction if the current context is not the Account Controller. The feature is currently not in the MVC release, so you need to include the ASP.NET MVC's Future library in your solution.

Next, the SignOn controller:

public ActionResult SignOn(string returnUrl)
{
    if (User.Identity.IsAuthenticated)
    {
        User user = userRepository.GetItem(u => u.aspnet_UserName == User.Identity.Name);
        return !string.IsNullOrEmpty(returnUrl)
               ? Redirect(returnUrl)
               : (ActionResult) RedirectToAction("Index", "Home");
    }
    return PartialView();
}

SignOn form:

 <% using (Html.BeginForm("SignOn", "Account", new { returnUrl = Request.QueryString["returnUrl"] },FormMethod.Post,new {@class="my_signOn_class"}))
    { %>
         <!-- Form -->
 <% } %>

Finally, in your SignOn controller that processes the Form POST, you can return the user to the 'returnURL' using the following code:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SignOn(FormCollection formCollection, string returnUrl)
{
    if (BusinessRuleViolated(formCollection))
    {
        if(!string.IsNullOrEmpty(returnUrl))
        {
            return Redirect(returnUrl);
        }
        return RedirectToAction("Index", "Home");
    }

    // SignIn(...)
}
matthew.perron