在我们正在开发的当前项目上,我们还没有升级到MVC 2.0,所以我正在使用1.0中提供的工具实现一些简单的验证。
我正在寻找有关我这样做的反馈。
我有一个代表用户个人资料的模型。在该模型中,我有一个方法可以验证所有字段等。我想要做的是将控制器传递给验证方法,以便模型可以在控制器中设置模型验证属性。目标是将控制器的验证转化为模型。
这是一个简单的例子
public FooController : Controller
{
public ActionResult Edit(User user)
{
user.ValidateModel(this);
if (ModelState.IsValid)
.......
.......
}
}
我的模型验证签名就像
public void ValidateModel(Controller currentState)
您可以看到哪些问题?我可以出去吃午餐吗?
答案 0 :(得分:1)
我可以通过这种方法看到的问题是您的验证逻辑耦合到控制器。实际上验证器不需要控制器,只需要IDictionary<string, ModelState>
来设置错误。
我建议您查看fluent validation library,它允许您将验证逻辑与控制器完全分离。它使用模型绑定器,它可以访问控制器以设置错误。
因此,您的操作代码将如下所示:
public FooController : Controller
{
public ActionResult Edit(User user)
{
if (ModelState.IsValid)
{
}
return View();
}
}
在绑定期间添加模型错误。 Here's a nice article演示了此库与ASP.NET MVC的集成。 Unit testing您的验证逻辑也非常简单易读。
答案 1 :(得分:0)
对于MVC 1.0项目,我们执行以下操作:
/* In model class */
public void Validate(string dealerId)
{
ExceptionList exceptions = new ExceptionList();
if (String.IsNullOrEmpty(this.UserName))
{
exceptions.Exceptions.Add(new InvalidFieldException("Error message", "ContractType"));
}
... other validations ...
if (exceptions.Exceptions.Count > 0)
{
throw exceptions;
}
}
/* In controller */
public virtual ActionResult UpdateProfile(User user)
{
try
{
user.Validate();
}
catch (ExceptionList ex)
{
ex.CopyToModelState(ModelState);
}
}
/* Custom types (ExceptionList / InvalidFieldException) */
[Serializable]
public class ExceptionList : Exception
{
private List<Exception> exceptions;
public List<Exception> Exceptions
{
get { return exceptions; }
set { exceptions = value; }
}
public ExceptionList() { Init(); }
public ExceptionList(string message) : base(message) { Init(); }
public ExceptionList(string message,
System.Exception inner)
: base(message, inner) { Init(); }
protected ExceptionList(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { Init(); }
private void Init()
{
Exceptions = new List<Exception>();
}
}
[Serializable]
public class InvalidFieldException : Exception
{
private string fieldName;
public string FieldName
{
get
{
return fieldName;
}
set
{
fieldName = value;
}
}
private string fieldId;
public string FieldId
{
get
{
return fieldId;
}
set
{
fieldId = value;
}
}
public InvalidFieldException() { }
public InvalidFieldException(string message) : base(message) { }
public InvalidFieldException(string message, string fieldName)
: base(message)
{
this.fieldName = fieldName;
}
public InvalidFieldException(string message, string fieldName, string fieldId)
: base(message)
{
this.fieldName = fieldName;
this.fieldId = fieldId;
}
public InvalidFieldException(string message, System.Exception inner)
: base(message, inner) { }
public InvalidFieldException(string message, string fieldName,
System.Exception inner)
: base(message, inner)
{
this.fieldName = fieldName;
}
public InvalidFieldException(string message, string fieldName, string fieldId,
System.Exception inner)
: base(message, inner)
{
this.fieldName = fieldName;
this.fieldId = fieldId;
}
protected InvalidFieldException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
/* Extension method (to copy ExceptionList exceptions to ModelState) */
/// <summary>
/// Copies an ExceptionList to ModelState for MVC
/// </summary>
/// <param name="exList">List of exceptions</param>
/// <param name="modelState">Model state to populate</param>
/// <param name="collection">Form collection of data posted to the action</param>
/// <param name="prefix">Prefix used in view (if any)</param>
/// <param name="isCollection">Indicates whether a collection of objects are being returned from the view (requires prefix)</param>
[CLSCompliant(false)]
public static void CopyToModelState(this ExceptionList exList, ModelStateDictionary modelState, FormCollection collection, string prefix, bool isCollection)
{
foreach (InvalidFieldException ex in exList.Exceptions)
if (String.IsNullOrEmpty(prefix))
{
modelState.AddModelError(ex.FieldName, ex.Message);
modelState.SetModelValue(ex.FieldName, collection.ToValueProvider()[ex.FieldName]);
}
else
{
if (isCollection)
{
modelState.AddModelError(prefix + "[" + ex.FieldId + "]." + ex.FieldName, ex.Message);
modelState.SetModelValue(prefix + "[" + ex.FieldId + "]." + ex.FieldName, collection.ToValueProvider()[ex.FieldName]);
}
else
{
modelState.AddModelError(prefix + "." + ex.FieldName, ex.Message);
modelState.SetModelValue(prefix + "." + ex.FieldName, collection.ToValueProvider()[ex.FieldName]);
}
}
}
/// <summary>
/// Copies an ExceptionList to ModelState for MVC
/// </summary>
/// <param name="exList">List of exceptions</param>
/// <param name="modelState">Model state to populate</param>
[CLSCompliant(false)]
public static void CopyToModelState(this ExceptionList exList, ModelStateDictionary modelState)
{
CopyToModelState(exList, modelState, null, false);
}
/// <summary>
/// Copies an ExceptionList to ModelState for MVC
/// </summary>
/// <param name="exList">List of exceptions</param>
/// <param name="modelState">Model state to populate</param>
/// <param name="collection">Form collection of data posted to the action</param>
[CLSCompliant(false)]
public static void CopyToModelState(this ExceptionList exList, ModelStateDictionary modelState, FormCollection collection)
{
CopyToModelState(exList, modelState, collection, null, false);
}
基本上,我们只是将一组异常抛回控制器并让控制器将它们添加到ModelState。非常简单和模块化。