我开始玩knockout.js,在这样做的时候我使用了FromJsonAttribute(由Steve Sanderson创建).我遇到一个问题,自定义属性不执行模型验证.我把一个简单的例子放在一起 – 我知道它看起来像很多代码 – 但是基本的问题是如何强制在自定义模型绑定器中验证模型.
using System.ComponentModel.DataAnnotations; namespace BindingExamples.Models { public class Widget { [required] public string Name { get; set; } } }
这里是我的控制器:
using System; using System.Web.Mvc; using BindingExamples.Models; namespace BindingExamples.Controllers { public class WidgetController : Controller { public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(Widget w) { if(this.ModelState.IsValid) { TempData["message"] = String.Format("Thanks for inserting {0}",w.Name); return RedirectToAction("Confirmation"); } return View(w); } [HttpPost] public ActionResult PostJson([koListEditor.FromJson] Widget w) { //the ModelState.IsValid even though the widget has an empty Name if (this.ModelState.IsValid) { TempData["message"] = String.Format("Thanks for inserting {0}",w.Name); return RedirectToAction("Confirmation"); } return View(w); } public ActionResult Confirmation() { return View(); } } }
我的问题是模型总是在我的PostJson方法中有效.为了完整性,这里是FromJson属性的Sanderson代码:
using System.Web.Mvc; using System.Web.Script.Serialization; namespace koListEditor { public class FromJsonAttribute : CustomModelBinderAttribute { private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer(); public override IModelBinder GetBinder() { return new JsonModelBinder(); } private class JsonModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext) { var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName]; if (string.IsNullOrEmpty(stringified)) return null; var model = serializer.Deserialize(stringified,bindingContext.ModelType); return model; } } } }
解决方法
描述
FromJsonAttribute只绑定到模型,如你所说,没有验证.
您可以向FromJsonAttribute添加验证,以便根据其DataAnnotations属性验证模型.
这可以使用TypeDescriptor类完成.
TypeDescriptor Provides information about the characteristics for a component,such as its attributes,properties,and events.
查看我的解决方案我已经测试了
解
private class JsonModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext) { var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName]; if (string.IsNullOrEmpty(stringified)) return null; var model = serializer.Deserialize(stringified,bindingContext.ModelType); // DataAnnotation Validation var validationResult = from prop in TypeDescriptor.GetProperties(model).Cast<PropertyDescriptor>() from attribute in prop.Attributes.OfType<ValidationAttribute>() where !attribute.IsValid(prop.GetValue(model)) select new { Propertie = prop.Name,ErrorMessage = attribute.FormatErrorMessage(string.Empty) }; // Add the ValidationResult's to the ModelState foreach (var validationResultItem in validationResult) bindingContext.ModelState.AddModelError(validationResultItem.Propertie,validationResultItem.ErrorMessage); return model; } }
更多信息
> TypeDescriptor Class
> System.ComponentModel.DataAnnotations Namespace