2009-07-05 32 views
10

Tengo un cuadro de inicio de sesión en mi página maestra. Cuando la información de inicio de sesión no es correcta, valorizo ​​ViewData["loginError"] para mostrar el mensaje de error al usuario.ASP.NET MVC: return Redirect y ViewData

El inicio de sesión es una acción del UserController, por lo que el formulario que contiene el inicio de sesión tiene action = "/User/Login".

Como un usuario puede intentar iniciar sesión desde cualquier página, en caso de éxito lo redirigiré a su página personal, pero en caso de error quiero que permanezca en la misma página donde intentó iniciar sesión. He encontrado que esto funciona:

return Redirect(Request.UrlReferrer.ToString()); 

pero parece que, ya que no estoy devolviendo visualizar correctamente, los datos sobre ViewData se pierde, así que no puedo mostrar el mensaje de error.

¿Alguna sugerencia sobre cómo solucionar este y problemas similares?

Gracias

Respuesta

14

Probablemente desee utilizar la propiedad TempData, esto se mantendrá hasta la siguiente solicitud HTTP.

+1

+1 Justo lo que estaba pensando. También hay un conjunto de filtros de acción útiles en MvcContrib que copia ModelState ay desde TempState para que tenga la información de validación disponible después de la redirección. Consulte el elemento 13 de este artículo para ver un ejemplo http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx –

+4

Recuerde TempData usa la sesión estado sin embargo, con todas las implicaciones. – UpTheCreek

2

Por qué no manejar la entrada a través de AJAX en vez de un post completo? Puede proporcionar fácilmente el estado, una URL de redireccionamiento y cualquier mensaje de error a través de JSON.

public ActionResult Logon(string username, string password) 
{ 
    ... 

    // Handle master page login 
    if (Request.IsAjaxRequest()) 
    { 
      if (success) 
      { 
       return Json(new { Status = true, Url = Url.Action("Index", "Home") }); 
      } 
      else 
      { 
       return Json(new { Status = false, Message = ... }); 
      } 
    } 
    else // handle login page logon or no javascript 
    { 
      if (success) 
      { 
       return RedirectToAction("Index", "Home"); 
      } 
      else 
      { 
       ViewData["error"] = ... 
       return View("Logon"); 
      } 
     } 
    } 

-lado del cliente

$(function() { 
     $('#loginForm input[type=submit]').click(function() { 
      $('#loginError').html(''); 
      $.ajax({ 
      url: '<%= Url.Action("Logon","Account") %>', 
      dataType: 'json', 
      type: 'post', 
      data: function() { return $('#loginForm').serialize(); }, 
      success: function(data,status) { 
       if (data.Status) { 
        location.href = data.Url; 
       } 
       else { 
        $('#loginError').html(data.Message); 
       } 
      } 
      }); 
      return false; 
     }); 
    }); 
+1

Hola, Sé que puedo manejar esto a través de ajax y eso es lo que estoy a punto de hacer, pero me gustaría saber cómo resolver el problema, ya que puede haber ocasiones en las que usar un POST simple es más apropiado, o incluso simplemente requerido por un cliente. – pistacchio

+0

Puede tener la Vista que debe mostrarse al establecer el error como un parámetro oculto del formulario que se envía. Desafortunadamente, es probable que también necesite serializar cualquier dato de modelo contenido en esa vista para pasar junto con la solicitud de inicio de sesión ya que, de lo contrario, no hay forma de mantenerlo entre las solicitudes. Hacerlo con AJAX va a ser mucho más limpio. Tenga en cuenta que el código anterior se redireccionará a la página de inicio de sesión (no a la vista original, sin embargo) si JavaScript no está disponible. Así es como lo manejaría: coloque el error en la página de inicio de sesión y permita que el usuario vuelva a autenticarse desde allí. – tvanfosson

1

Normalmente, para la mayoría de los sitios web, cuando el usuario deja de autenticar (debido a la contraseña o algo así), se irá a otra página que ayudan al usuario (como la contraseña recuperar, o pedirle al usuario que se registre) que es raro quedarse en la misma página. Creo que puedes volver a considerar que realmente necesitas la navegación que estás usando.

OK, una solución si realmente quiere apegarse a su modelo, es que puede adjuntar el error de inicio de sesión a la URL. Por ejemplo, http://www.example.com/index.aspx?login_error=1 indica se produce ese error, y se puede utilizar BEGIN_REQUEST (o módulo HTTP) para capturar este, y decirle al modelo de estado acerca del error:

ModelState.AddModelError(...); 

Por cierto, añadir el error del modelo es en realidad una forma más adecuada informar a la vista sobre cualquier error en lugar de usar ViewState (esto es similar a lanzar una excepción vs devolver un entero sobre el resultado de la ejecución en días pasados).

Si bien utilizar AJAX para iniciar sesión (como lo sugiere tvanfosson) es perfectamente alcanzable y a veces se destaca en la experiencia del usuario, la publicación completa clásica sigue siendo irremplazable (considérese que algunos usuarios inhabilitarán javascript o incluso en mi volcado el teléfono WM6 que no es compatible con javascript).

+0

Si bien mi ejemplo de código no está completo, creo que la estructura del mismo manejará el caso donde javascript no esté disponible. En ese caso, el formulario de inicio de sesión hará una publicación completa y los errores serán redirigidos a la página de inicio de sesión tal como usted lo describe. – tvanfosson

+0

Estoy de acuerdo con el uso de la publicación de formularios AJAX + si no tiene JS, y para mis proyectos también los usaría. Pero el problema del pistacho aún persiste. – xandy

1

Estoy confundido. No

return View(); 

¿Devolver la página actual a usted?

Por lo tanto, en su caso, cuando falla el inicio de sesión, configure su viewdata y llame a return View();

decir

if (!FailedLogin) { 
    //Go to success page 
}else{ 
    //Add error to View Data or use ModelState to add error 
    return View(); 
} 

¿Está utilizando el [Autorizar] decorador? El proceso de inicio de sesión de MVC solicita automáticamente con la página de inicio de sesión y luego lo regresa a la acción del controlador que estaba tratando de ejecutar. Disminuye un montón de redirigir.

+2

View() devuelve la vista predeterminada para la acción, que puede ser o no la vista actual. Si usa vistas con modelos, tampoco incluirá el modelo que está utilizando la vista actual ni ningún otro parámetro. – Suncat2000

1

El siguiente ejemplo es de esperar que ayudaría a cabo para resolver este problema:

View.aspx

<%= Html.ValidationSummary("Login was unsuccessful. Please correct the errors and try again.") %> 
<% using (Html.BeginForm()) { %> 
    <div> 
     <fieldset> 
      <legend>Account Information</legend> 
      <p> 
       <label for="username">Username:</label> 
       <%= Html.TextBox("username") %> 
       <%= Html.ValidationMessage("username") %> 
      </p> 
      <p> 
       <label for="password">Password:</label> 
       <%= Html.Password("password") %> 
       <%= Html.ValidationMessage("password") %> 
      </p> 
      <p> 
       <%= Html.CheckBox("rememberMe") %> <label class="inline" for="rememberMe">Remember me?</label> 
      </p> 
      <p> 
       <input type="submit" value="Log On" /> 
      </p> 
     </fieldset> 
    </div> 
<% } %> 

AccountController.cs

private bool ValidateLogOn(string userName, string password) 
{ 
    if (String.IsNullOrEmpty(userName)) 
    { 
     ModelState.AddModelError("username", "You must specify a username."); 
    } 
    if (String.IsNullOrEmpty(password)) 
    { 
     ModelState.AddModelError("password", "You must specify a password."); 
    } 
    if (!MembershipService.ValidateUser(userName, password)) 
    { 
     ModelState.AddModelError("_FORM", "The username or password provided is incorrect."); 
    } 
    return ModelState.IsValid; 
} 

Usted no será capaz de capturar la información agregada en ViewData después de la acción Redirigir. por lo tanto, el enfoque correcto es devolver la misma Vista() y usar el Estado del modelo para los errores mencionados también por "xandy".

Espero que esto le de una ventaja con la validación de formulario.

Cuestiones relacionadas