Asp.net MVC源码分析--Model Validation(Client端)实现(1)
2011-12-19 17:36
746 查看
前两篇我们介绍了ModelValidatoin Server 端的实现,那么我们知道在Web.config 中如果我们把ClientValidationEnabled 设置为true时,那么客户端也可以支持表单验证了. 那么这部份功能是如果实现的呢?今天让我们来一起学习Model validation client 端的实现.
ErrorMessage:取得或设定用户端验证规则的错误讯息。
ValidationParameters:取得验证参数清单。
ValidationType:取得或设定验证类型。
我们知道了这个类的数据结构,那么这些数据是如何输出的呢?我们看一下RequiredAttributeAdapter类,在这里定义了有一个GetClientValidationRules方法,这个方法返回了ModelClientValidationRequiredRule对象(包含了Required validation 需要输出到客户端的数据).
让我接下来看一下DataAnnotationsModelValidator.GetClientValidationRules 方法的实现,我们看到下面代码第4行,说明只有我们自定义的ValidationAtribute只有实现了IClientValidatable接口才能够输出客户端数据。
一般我们在View 页面中的代码都是这样的:
也就是说Client Validaton 信息是通过Html.TextBoxFor方法来输出的,那么我们接下来研究一下这个方法是如何实现的。
在InputExtension.cs 方件的InputHelper方法我们找到了一些与Client Validaton有关的代码片段,下面第9行代码的GetUnobtrusiveValidationAttributes方法就实现了输出。
GetUnobtrusiveValidationAttributes方法的源码:
HtmlHelper 构造函数源码:
最终我们看到在GetUnobtrusiveValidationAttributes方法内部,MVC 调用了ClientValidationRuleFactory委托来得到clientRules对象它的类型是IEnumerable<ModelClientValidationRule>,这样我们在Model上标记的Client Validation数据就输出到了浏览器端。
--------------------------------------风搔分割线-------------------------------------------------
那么通过以上这些分析我们知道了Server 端如何输出Client Validation数据,那么JavaScript是怎么来进行验证的呢?
下一篇我们来分析jquery.validate.unobtrusive.js 的源码,这里面实现了MVC的客户端验证逻辑。
转载请注明出处:/article/7081956.html
本文作者: 十一月的雨 http://www.cnblogs.com/RobbinHan
一.ModelClientValidationRule类
这个类定义了如何输出客户端的一些信息:ErrorMessage:取得或设定用户端验证规则的错误讯息。
ValidationParameters:取得验证参数清单。
ValidationType:取得或设定验证类型。
public class ModelClientValidationRule { private readonly Dictionary<string, object> _validationParameters = new Dictionary<string, object>(); private string _validationType; public string ErrorMessage { get; set; } public IDictionary<string, object> ValidationParameters { get { return _validationParameters; } } public string ValidationType { get { return _validationType ?? String.Empty; } set { _validationType = value; } } }
我们知道了这个类的数据结构,那么这些数据是如何输出的呢?我们看一下RequiredAttributeAdapter类,在这里定义了有一个GetClientValidationRules方法,这个方法返回了ModelClientValidationRequiredRule对象(包含了Required validation 需要输出到客户端的数据).
public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute> { public RequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute) : base(metadata, context, attribute) { } public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { return new[] { new ModelClientValidationRequiredRule(ErrorMessage) }; } }
二.如果让得到自定义Client Validaton 信息?
上面我们介绍了一些系统内置(Required)的Validation 的输出,那么我们如果需要自定义验证规则如果来输出客户端数据呢?前面我们介绍了DataAnnotationsModelValidatorProvider.GetValidators 方法里自定义的验证是通过DefaultAttributeFactory委托来构造的,让我们顺着这个代码来继续我们的思路。internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory = (metadata, context, attribute) => new DataAnnotationsModelValidator(metadata, context, attribute);
让我接下来看一下DataAnnotationsModelValidator.GetClientValidationRules 方法的实现,我们看到下面代码第4行,说明只有我们自定义的ValidationAtribute只有实现了IClientValidatable接口才能够输出客户端数据。
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() { IEnumerable<ModelClientValidationRule> results = base.GetClientValidationRules(); IClientValidatable clientValidatable = Attribute as IClientValidatable; if (clientValidatable != null) { results = results.Concat(clientValidatable.GetClientValidationRules(Metadata, ControllerContext)); } return results; }
三.如果输出自定义Client Validaton 信息到浏览器?
以上的分析是我们得到Cient validation 的数据,那么我们怎么输出这些数据到浏览器呢?一般我们在View 页面中的代码都是这样的:
<div class="editor-label"> Name </div> <div class="editor-field"> @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName) </div>
也就是说Client Validaton 信息是通过Html.TextBoxFor方法来输出的,那么我们接下来研究一下这个方法是如何实现的。
在InputExtension.cs 方件的InputHelper方法我们找到了一些与Client Validaton有关的代码片段,下面第9行代码的GetUnobtrusiveValidationAttributes方法就实现了输出。
// If there are any errors for a named field, we add the css attribute. ModelState modelState; if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState)) { if (modelState.Errors.Count > 0) { tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName); } } tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));
GetUnobtrusiveValidationAttributes方法的源码:
// Only render attributes if unobtrusive client-side validation is enabled, and then only if we've // never rendered validation for a field with this name in this form. Also, if there's no form context, // then we can't render the attributes (we'd have no <form> to attach them to). public IDictionary<string, object> GetUnobtrusiveValidationAttributes(string name, ModelMetadata metadata) { Dictionary<string, object> results = new Dictionary<string, object>(); // The ordering of these 3 checks (and the early exits) is for performance reasons. if (!ViewContext.UnobtrusiveJavaScriptEnabled) { return results; } FormContext formContext = ViewContext.GetFormContextForClientValidation(); if (formContext == null) { return results; } string fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name); if (formContext.RenderedField(fullName)) { return results; } formContext.RenderedField(fullName, true); IEnumerable<ModelClientValidationRule> clientRules = ClientValidationRuleFactory(name, metadata); bool renderedRules = false; foreach (ModelClientValidationRule rule in clientRules) { renderedRules = true; string ruleName = "data-val-" + rule.ValidationType; ValidateUnobtrusiveValidationRule(rule, results, ruleName); results.Add(ruleName, HttpUtility.HtmlEncode(rule.ErrorMessage ?? String.Empty)); ruleName += "-"; foreach (var kvp in rule.ValidationParameters) { results.Add(ruleName + kvp.Key, kvp.Value ?? String.Empty); } } if (renderedRules) { results.Add("data-val", "true"); } return results; }
HtmlHelper 构造函数源码:
public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection) { if (viewContext == null) { throw new ArgumentNullException("viewContext"); } if (viewDataContainer == null) { throw new ArgumentNullException("viewDataContainer"); } if (routeCollection == null) { throw new ArgumentNullException("routeCollection"); } ViewContext = viewContext; ViewDataContainer = viewDataContainer; RouteCollection = routeCollection; ClientValidationRuleFactory = (name, metadata) => ModelValidatorProviders.Providers.GetValidators(metadata ?? ModelMetadata.FromStringExpression(name, ViewData), ViewContext).SelectMany(v => v.GetClientValidationRules()); }
最终我们看到在GetUnobtrusiveValidationAttributes方法内部,MVC 调用了ClientValidationRuleFactory委托来得到clientRules对象它的类型是IEnumerable<ModelClientValidationRule>,这样我们在Model上标记的Client Validation数据就输出到了浏览器端。
--------------------------------------风搔分割线-------------------------------------------------
那么通过以上这些分析我们知道了Server 端如何输出Client Validation数据,那么JavaScript是怎么来进行验证的呢?
下一篇我们来分析jquery.validate.unobtrusive.js 的源码,这里面实现了MVC的客户端验证逻辑。
转载请注明出处:/article/7081956.html
本文作者: 十一月的雨 http://www.cnblogs.com/RobbinHan
相关文章推荐
- Asp.net MVC源码分析--Model Validation(Client端)实现(2)
- [ASP.NET]分析MVC5源码,并实现一个ASP.MVC
- asp.net MVC 模拟实现与源码分析
- Asp.net MVC源码分析--Model Validation(Server端)实现(1)
- asp.net mvc源码分析-BeginForm方法 和ClientValidationEnabled 属性
- Asp.net MVC源码分析--Model Validation(Server端)实现(2)
- [ASP.NET]分析MVC5源码,并实现一个ASP.MVC
- asp.net mvc源码分析-BeginForm方法 和ClientValidationEnabled 属性
- asp.net mvc源码分析-Controllerl篇 如何创建Controller实例
- asp.net mvc源码分析-Controller篇 ValueProvider
- Asp.net MVC源码分析--Filter种类以及调用优先级
- asp.net mvc源码分析-Action篇 IModelBinder
- asp.net mvc源码分析-Controllerl篇 TempData数据存储
- asp.net mvc源码分析-Controller篇 ValueProvider
- ASP.NET MVC 4源码分析之如何定位控制器
- asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证
- asp.net mvc源码分析-Action篇 IModelBinder
- asp.net mvc源码分析-Action篇 DefaultModelBinder
- asp.net mvc源码分析-Action篇 Action的执行
- asp.net mvc 之旅 —— 第六站 ActionFilter的应用及源码分析