在我的项目中,我有一个使用另一个类的模型类,如下面的示例所示。模型中的属性之一取决于对子对象的一个属性的验证——在此示例中,LastName 属性取决于对 Address.PostalCode 属性值的验证。我实现了一个自定义验证属性来验证我的 LastName 属性,它工作得很好。
public class User
{
public static ValidationResult ValidateLastName(string lastName, ValidationContext context)
{
// Grab the model instance
var user = context.ObjectInstance as User;
if (user == null)
throw new NullReferenceException();
// Cross-property validation
if (user.Address.postalCode.Length < 10000)
return new ValidationResult("my LastName custom validation message.");
return ValidationResult.Success;
}
[Display(Name = "Last name")]
[CustomValidationAttribute(typeof(User), "ValidateLastName")]
public string LastName { get; set; }
[Display(Name = "First name")]
public string FirstName { get; set; }
[Display(Name = "Address:")]
[CustomValidationAttribute(typeof(User), "ValidateAddress")]
public AddressType Address { get; set; }
}
public class AddressType
{
public string streetName = "";
public string streetNumber = "";
public string postalCode = "";
}
问题在于控制器中的 Address 属性不是从视图中构造的,并且它始终为 null。在此示例中,无论我在视图中发送什么,user.Address 始终为空。这是控制器代码。
[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
// creation code here
return RedirectToAction("Index");
}
else
{
return View(user);
}
}
这是视图:
<div class="editor-label">
@Html.LabelFor(model => model.Address.postalCode)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Address.postalCode)
@Html.ValidationMessageFor(model => model.Address.postalCode)
</div>
为了解决这个问题,我创建了一个自定义的虚拟绑定器,将视图中的字段映射到模型中的属性,如下所示:
public class UserBinder : IModelBinder
{
private string GetValue(ModelBindingContext bindingContext, string key)
{
var result = bindingContext.ValueProvider.GetValue(key);
return (result == null) ? null : result.AttemptedValue;
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
User instance = new User();
instance.FirstName = GetValue(bindingContext, "FirstName"); //controllerContext.HttpContext.Request["FirstName"];
instance.LastName = GetValue(bindingContext, "LastName"); //controllerContext.HttpContext.Request["LastName"];
instance.Address = new AddressType();
string streetName = controllerContext.HttpContext.Request["Address.streetName"];
//ModelStateDictionary mState = bindingContext.ModelState;
//mState.Add("LastName", new ModelState { });
//mState.AddModelError("LastName", "There's an error.");
instance.Address.streetName = streetName;
...
return instance;
}
活页夹工作正常,但验证属性不再工作。我认为必须有比这更好的绑定方法,是吗?
这个活页夹只是将 LastName 映射到 LastName 并将 Address.streetName 映射到 Address.streetName,我想应该有一种方法可以实现这一点,而不必编写所有这些繁琐的代码,也不会破坏自定义验证机制。