我正在编写一个控制器和单元测试,当我遇到两种方式(我认为同样有效)做某事。我的所有模型都有一个IsValid属性,我可以检查它是否有效。
在回发到控制器操作方法时,如果模型有效我想保存,否则我想重新显示表单以供用户更正错误。
我最初的想法只是验证模型是否被问及是否有效,但我意识到我还可以检查ModelState.IsValid。
有没有人有任何特别的理由看一个与另一个?
答案 0 :(得分:12)
我认为在您的模型中内置自定义业务验证是一种很好的方法。我处理它的方法是将任何自定义验证错误添加到ModelState:
if (ModelState.IsValid)
{
if (!model.IsValid)
{
ModelState.AddModelError("The model is not valid");
}
else
{
return RedirectToAction("Index");
}
}
return View(model);
这样,您的视图就可以访问验证错误,无论它们是自定义还是内置。
答案 1 :(得分:6)
ModelState
可以转移到TempData
以关注Post-Redirect-Get。例如:
[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));
}
用户可以通过callig / Task / Delete操作删除任务,但如果出现问题并出现错误信息,按F5将不会再次调用删除。在ModelState
转移到Delete
后Edit
时,所有错误都会显示在编辑页面上。
这是导入/导出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);
}
}
对Model
执行相同操作会非常有问题。
答案 2 :(得分:0)
您还可以枚举错误集合并将Exact错误消息写入输出。
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);
}
}
...