2011-02-16 20 views
10

Estoy escribiendo un controlador y las pruebas de unidad para él, cuando me encontré con dos maneras (igualmente válidas, creo) para hacer algo. Todos mis modelos tienen una propiedad IsValid, que puedo verificar para preguntarle a la modelo si es válida o no.ModelState.IsValid o Model.IsValid?

En la devolución de datos a un método de acción del controlador, si el modelo es válido quiero guardar, de lo contrario, quiero volver a mostrar el formulario para que el usuario corrija sus errores.

Mi primer pensamiento fue simplemente verificar que se le pregunta al modelo si es válido, pero me di cuenta de que también podría verificar ModelState.IsValid.

¿Alguien tiene alguna razón en particular para mirar una frente a la otra?

Respuesta

11

Creo que tener una validación comercial personalizada integrada en su modelo es un buen enfoque. La forma en que lo manejaría sería añadir algún error de validación personalizado al ModelState:

if (ModelState.IsValid) 
{ 
    if (!model.IsValid) 
    { 
     ModelState.AddModelError("The model is not valid"); 
    } 
    else 
    { 
     return RedirectToAction("Index"); 
    } 
} 

return View(model); 

De esa manera su punto de vista tiene acceso a los errores de validación, independientemente de si son personalizados o construida en

6

ModelState. se puede transferir a TempData para seguir Post-Redirect-Get. Ejemplo:

[HttpPost] 
    [ExportModelStateToTempData] 
    public ActionResult Delete(int id) 
    { 
     if (_service.DeleteTask(id)) 
      return RedirectToAction(ControllerActions.Index); 

     return RedirectToAction(ControllerActions.Edit, new { id }); 
    } 

    [ImportModelStateFromTempData] 
    public ActionResult Edit(int id) 
    { 
     var task = _service.GetTask(id); 
     return View(ControllerActions.Edit, GetEditModel(task)); 
    } 

El usuario puede eliminar la tarea por callig/Tareas/Eliminar acción, pero si algo va mal y aparece mensaje de error, presionando F5 no llamará eliminación de nuevo. cuando ModelState después de Delete se transfiere a Edit, todos los errores se muestran en la página de edición.

Este es el código para los atributos de importación/exportación de ModelState:

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

public class ExportModelStateToTempDataAttribute : ModelStateTempDataTransferAttribute 
{ 
    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 ImportModelStateFromTempDataAttribute : ModelStateTempDataTransferAttribute 
{ 
    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); 
    } 
} 

Hacer lo mismo con Model sería muy problemático.

+0

¿Cuál es su clase 'ControllerActions'? Esto es nuevo para mí. –

+0

@Matt Greer: Esa es solo una clase con nombres constantes de acciones, solo para tenerlas fuertemente tipadas. si quieres jugar con nombres robustos, T4MVC es probablemente el camino a seguir. – LukLed

+0

¿Tan solo una colección de const strings? Drat, esperaba que tuvieras una solución inteligente para evitar cadenas mágicas. Las cadenas mágicas se han convertido en mi mayor preocupación en .NET :) –

0

También puede enumerar a través de la colección de errores y escribir el mensaje de error exacto en la salida.

else if (!ModelState.IsValid) 
{ 
    List<ModelError> modelErrors = new List<ModelError>(); 
    ModelErrorCollection errors = new ModelErrorCollection(); 
           ; 
    // got to the model and look at the Array of Values 
    foreach (var item in ModelState) 
    { 
     if (item.Value.Errors.Count != 0) 
     { 
      // get the error 
      errors = item.Value.Errors; 
      modelErrors.Add(errors.Single()); 
     } 
    } 

    if (modelErrors.Count != 0) 
    { 
     foreach (var error in modelErrors) 
     { 
      Debug.WriteLine(error.ErrorMessage); 
     } 
     } 

...

Cuestiones relacionadas