2011-10-29 14 views

Respuesta

7

Normalmente solo se redirecciona después de una exitosa publicación (sin errores de validación del modelo); de lo contrario, devuelve la página con un mensaje de error de validación.

El redirigir en el patrón PRG previene-doble desplazamiento, por lo que no hay daño para enviar de vuelta la misma página (+ mensaje de error) debido a que el post no tuvo éxito y no será menos que algo cambie para hacer que pase la validación.

Editar:

Parece que usted está buscando para pasar a la siguiente ModelState petición (redirigida). Esto se puede hacer usando TempData para almacenar ModelState hasta la próxima solicitud. FYI, TempData usa Session.

Esto se puede implementar con ActionFilters. Se pueden encontrar ejemplos en el código MvcContrib proyecto: ModelStateToTempDataAttribute

Esto también ha sido mencionado junto con otros consejos en el artículo A 'mejores prácticas' en weblogs.asp.net (parece que el autor ha movido el blog, pero no podía encontrar el artículo en el nuevo blog). Desde el artículo:

Uno de los problema con este patrón es cuando un error en la validación o cualquier excepción ocurre que tienes que copiar el ModelState en TempData. Si lo está haciendo de forma manual, por favor detenerlo, se puede hacer esto de forma automática con la acción Filtros, como la siguiente:

controlador

[AcceptVerbs(HttpVerbs.Get), OutputCache(CacheProfile = "Dashboard"), StoryListFilter, ImportModelStateFromTempData] 
public ActionResult Dashboard(string userName, StoryListTab tab, OrderBy orderBy, int? page) 
{ 
    //Other Codes 
    return View(); 
} 

[AcceptVerbs(HttpVerbs.Post), ExportModelStateToTempData] 
public ActionResult Submit(string userName, string url) 
{ 
    if (ValidateSubmit(url)) 
    { 
     try 
     { 
      _storyService.Submit(userName, url); 
     } 
     catch (Exception e) 
     { 
      ModelState.AddModelError(ModelStateException, e); 
     } 
    } 

    return Redirect(Url.Dashboard()); 
} 

Filtros de acción

public abstract class ModelStateTempDataTransfer : ActionFilterAttribute 
{ 
    protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName; 
} 

public class ExportModelStateToTempData : ModelStateTempDataTransfer 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     //Only export when ModelState is not valid 
     if (!filterContext.Controller.ViewData.ModelState.IsValid) 
     { 
      //Export if we are redirecting 
      if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult)) 
      { 
       filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState; 
      } 
     } 

     base.OnActionExecuted(filterContext); 
    } 
} 

public class ImportModelStateFromTempData : ModelStateTempDataTransfer 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary; 

     if (modelState != null) 
     { 
      //Only Import if we are viewing 
      if (filterContext.Result is ViewResult) 
      { 
       filterContext.Controller.ViewData.ModelState.Merge(modelState); 
      } 
      else 
      { 
       //Otherwise remove it. 
       filterContext.Controller.TempData.Remove(Key); 
      } 
     } 

     base.OnActionExecuted(filterContext); 
    } 
} 
+2

Eso no es correcto. Hay mucho daño ... todos los POST deben ir seguidos de un redireccionamiento. (1) Esta es solo la forma de eliminar la solicitud POST del historial del navegador (2) De lo contrario, los usuarios presionando ATRÁS o ACTUALIZAR obtendrán una confirmación "reenviar" molesta y molesta (3) Un usuario que elija "reenviar" no tiene forma de saber qué resultado final de la acción podría ser! Este ha sido un sello distintivo de las aplicaciones web de calidad profesional durante más de 15 años. (No es común en las aplicaciones web ASP o ASP.NET) Además, incluso un GET que * intenta * un cambio de estado no repetible debe ser redireccionado. – Jack

+0

Mi punto era simplemente que si la validación del modelo falla, el estado del servidor no cambia y, por lo tanto, incluso si se reenvía la misma solicitud POST, el estado del servidor aún no cambiará.Pero si usted tiene la firme intención de suprimir las molestas confirmaciones de reenvío para este caso particular (POST fallido sin cambios en el estado del servidor), ¿por qué no simplemente redirige? Probablemente necesite una sesión (TempData por ejemplo) para llevar al menos el mensaje de error de validación a la solicitud redirigida e informar al usuario por qué falló la POST. Pero, de nuevo, mostrar el estado de la sesión en una solicitud GET no es muy RESTful ... – marapet

+0

"el estado del servidor no se ha modificado" // esta solicitud no lo está, pero usted está asumiendo que la próxima vez tampoco se cambiará// no se puede hacer esa suposición // también eso es solo una parte del problema // y la captura duplicada tiene que hacerse en el servidor para ser robusto // "simplemente redirigir" ¿cómo accedo a ModelState en la próxima solicitud? – Jack

0

Lo ¿Te refieres a la redirección "obligatoria"? A menudo usamos un try/catch en el controlador, si try tiene éxito, puede redirigir a una Vista (si NECESITA hacerlo) o también puede devolver cualquier vista parcial, o cualquier cosa que necesite. La captura suele volver a mostrar la página original con un mensaje de error, ya que la solicitud no es exitosa.

Espero que no te haya malinterpretado :)

+0

"obligatorio" para aplicaciones web profesionales; consulte con el violinista: mire cómo lo hacen Google o IBM o PayPal o EBay ... es raro que las aplicaciones web ASP o ASP.NET implementen esto correctamente porque Microsoft nunca muestra la técnica en su ejemplos (no quieren confundir a las personas) – Jack