[英]how can I bind a complex class to a view, while preserving my custom validation attributes?
在我的項目中,我有一個使用另一個類的模型類,如下面的示例所示。 模型中的一個屬性取決於對子對象屬性的驗證 - 在此示例中,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始終為null。 這是控制器代碼。
[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,我想應該有一種方法可以實現這一點,而不必編寫所有這些繁瑣的代碼而不破壞自定義驗證機制。
您需要使用屬性而不是公共字段才能使默認模型綁定正常工作。
將您的AddressType
類更改為:
public class AddressType
{
public string streetName { get; set; }
public string streetNumber { get; set; }
public string postalCode { get; set; }
}
一種解決方案是在我的子類中使用屬性而不是公共字段 - 感謝Oded的答案!
另一個解決方案是在控制器中調用TryValidateModel,即使存在綁定器,也可以啟用我的驗證代碼。
[HttpPost]
public ActionResult Create(User user)
{
if (TryValidateModel(user))
{
// creation code here
return RedirectToAction("Index");
}
else
{
return View(user);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.