<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      ASP.NET MVC基于標注特性的Model驗證:一個Model,多種驗證規(guī)則

      對于Model驗證,理想的設計應該是場景驅(qū)動的,而不是Model(類型)驅(qū)動的,也就是對于同一個Model對象,在不同的使用場景中可能具有不同的驗證規(guī)則。舉個簡單的例子,對于一個表示應聘者的數(shù)據(jù)對象來說,針對應聘的崗位不同,肯定對應聘者的年齡、性別、專業(yè)技能等方面有不同的要求。但是ASP.NET MVC的Model驗證確是Model驅(qū)動的,因為驗證規(guī)則以驗證特性的形式應用到Model類型及其屬性上。這樣的驗證方式實際上限制了Model類型在基于不同驗證規(guī)則的使用場景中的重用。通過上一篇文章《將ValidationAttribute應用到參數(shù)上》的擴展我們將驗證特性直接應用在參數(shù)上變成了可能,這從一定程度上解決了這個問題,但是只能解決部分問題,因為應用到參數(shù)的驗證特性只能用于針對參數(shù)類型級別的驗證,而不能用于針對參數(shù)類型屬性級別的驗證(源代碼從這里下載)。[本文已經(jīng)同步到《How ASP.NET MVC Works?》中]

      目錄
      一、同一個Model在采用不同的驗證規(guī)則
      二、新的基類ValidatorAttribute
      三、指定當前采用的驗證規(guī)則:ValidationRuleAttribute
      四、新的Controller基類:RuleBasedController
      五、自定義ModelValidatorProvider:RuleBasedValidatorProvider

      一、同一個Model在采用不同的驗證規(guī)則

      現(xiàn)在我們通過利用對ASP.NET MVC的擴展來實現(xiàn)一種基于不同驗證規(guī)則的Model驗證。為了讓讀者對這種認證方式有一個感官的認識,我們來看看這個擴展最終實現(xiàn)怎樣的驗證效果。在通過Visual Studio的ASP.NET MVC 項目模板創(chuàng)建的空Web應用中,我們定義了如下一個Person類型作為Model。

         1: public class Person
         2: {
         3:     [DisplayName("姓名")]
         4:     public string Name { get; set; }
         5:  
         6:     [DisplayName("性別")]
         7:     public string Gender { get; set; }
         8:  
         9:     [DisplayName("年齡")]
        10:     [RangeValidator(10, 20, RuleName = "Rule1",  ErrorMessage = "{0}必須在{1}和{2}之間!")]
        11:     [RangeValidator(20, 30, RuleName = "Rule2", ErrorMessage = "{0}必須在{1}和{2}之間!")]
        12:     [RangeValidator(30, 40, RuleName = "Rule3", ErrorMessage = "{0}必須在{1}和{2}之間!")]
        13:     public int Age { get; set; }     
        14: }

      在表示年齡的Age屬性上應用了三個RangeValidatorAttribute(不是RangeAttribute),它們對應針對年齡的三種不同的驗證規(guī)則,RuleName屬性表示規(guī)則名稱。三種驗證規(guī)則(Rule1、Rule2和Rule3)分別要求年齡分別在10到20、20到30和30到40歲之間。

      然后我們定義了具有如下定義HomeController,它具有三組Action方法(Index、Rule1和Rule2)。方法Rule1、Rule2和HomeController類上應用了一個ValidationRuleAttribute特性用于指定了當前采用的驗證規(guī)則。用于指定驗證規(guī)則的ValidationRuleAttribute特性可以同時應用于Controller類型和Action方法上,應用于后者的ValidationRuleAttribute特性具有更高的優(yōu)先級。針對HomeController的定義,Action方法Index、Rule1和Rule2分別采用的驗證規(guī)則為Rule3、Rule1和Rule2。

         1: [ValidationRule("Rule3")]
         2: public class HomeController : RuleBasedController
         3: {
         4:     public ActionResult Index()
         5:     {
         6:         return View("person", new Person());
         7:     }
         8:     [HttpPost]
         9:     public ActionResult Index(Person person)
        10:     {
        11:         return View("person", person);
        12:     }
        13:  
        14:     [ValidationRule("Rule1")]
        15:     public ActionResult Rule1()
        16:     {
        17:         return View("person", new Person());
        18:     }
        19:     [HttpPost]
        20:     [ValidationRule("Rule1")]
        21:     public ActionResult Rule1(Person person)
        22:     {
        23:         return View("person", person);
        24:     }
        25:  
        26:     [ValidationRule("Rule2")]
        27:     public ActionResult Rule2()
        28:     {
        29:         return View("person", new Person());
        30:     }
        31:     [HttpPost]
        32:     [ValidationRule("Rule2")]
        33:     public ActionResult Rule2(Person person)
        34:     {
        35:         return View("person", person);
        36:     }
        37: }

      定義在HomeController中的6個方法均將創(chuàng)建的/接收的Person對象呈現(xiàn)到名為Person的View中,該View的定義如下所示。這是一個將Person類型作為Model的強類型View,在該View中我們將作為Model的Person對象以編輯模式呈現(xiàn)在一個表單中,并在表單中提供一個提交按鈕。

         1: @model Person
         2: @using (Html.BeginForm())
         3: { 
         4:     @Html.EditorForModel()
         5:     <input type="submit" value="保存" />
         6: }

      現(xiàn)在運行我們的程序,并通過在瀏覽器中指定相應的地址分別訪問定義在HomeController的三個Action(Index、Rule1和Rule2),一個用于編輯個人信息的表單會呈現(xiàn)出來。然后我們根據(jù)三個Action方法采用的驗證規(guī)則輸入不合法的年齡,然后點擊“保存”按鈕,我們會看到輸入的年齡按照對應的規(guī)則被驗證了,具體的驗證效果如下圖所示。

      image

      二、新的基類ValidatorAttribute

      我們現(xiàn)在就來具體談談上面這個例子所展示的基于不同規(guī)則的Model驗證是如何實現(xiàn)的。首先我們需要重建一套新的驗證特性體系,只為我們能夠指定具體的驗證規(guī)則。為此我們定義了一個抽象的ValidatorAttribute類型,如下面的代碼片斷所示,ValidatorAttribute直接繼承自ValidationAttribute,屬性RuleName表示采用的驗證規(guī)則名稱。我們重寫了TypeId屬性,因為我們需要在相同的屬性或者類型上應用多個同類的ValidatorAttribute。

         1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Property,AllowMultiple = true)]
         2: public abstract class ValidatorAttribute: ValidationAttribute
         3: {
         4:     private object typeId;
         5:     public string RuleName { get; set; }
         6:     public override object TypeId
         7:     { 
         8:         get{return typeId ?? (typeId = new object());}
         9:     }
        10: }

      上面演示實例采用的RangeValidatorAttribute定義如下,我們可以看到它僅僅是對RangeAttribute的封裝。RangeValidatorAttribute具有與RangeAttribute一致的構(gòu)造函數(shù)定義,并直接使用被封裝的RangeAttribute實施驗證。除了能夠通過RuleName指定具體采用的驗證規(guī)則之外,其他的使用方式與RangeAttribute完全一致。

         1: [AttributeUsage( AttributeTargets.Property, AllowMultiple = true)]
         2: public class RangeValidatorAttribute:ValidatorAttribute
         3: {
         4:     private RangeAttribute rangeAttribute;
         5:     public RangeValidatorAttribute(int minimum, int maximum)
         6:     {
         7:         rangeAttribute = new RangeAttribute(minimum, maximum);
         8:     }
         9:     public RangeValidatorAttribute(double minimum, double maximum)
        10:     {
        11:         rangeAttribute = new RangeAttribute(minimum, maximum);
        12:     }
        13:     public RangeValidatorAttribute(Type type, string minimum, string maximum)
        14:     {
        15:         rangeAttribute = new RangeAttribute(type, minimum, maximum);
        16:     }
        17:     public override bool IsValid(object value)
        18:     {
        19:         return rangeAttribute.IsValid(value);
        20:     }
        21:  
        22:     public override string FormatErrorMessage(string name)
        23:     {
        24:         return string.Format(CultureInfo.CurrentCulture, base.ErrorMessageString, new object[] { name, rangeAttribute.Minimum, rangeAttribute.Maximum });
        25:     }
        26: }

      三、指定當前采用的驗證規(guī)則:ValidationRuleAttribute

      ValidatorAttribte的RuleName屬性僅僅指定了驗證特性采用的驗證規(guī)則名稱,當前應在采用的驗證規(guī)則通過應用在Action方法或者Controller類型上的ValidationRuleAttribute特性還指定。如下所示的就是ValidationRuleAttribute的定義,它僅僅包含一個表示當前采用的驗證規(guī)則名稱的RuleName屬性的特性而已。

         1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Method)]
         2: public class ValidationRuleAttribute: Attribute
         3: {
         4:     public string RuleName { get; private set; }
         5:     public ValidationRuleAttribute(string ruleName)
         6:     {
         7:         this.RuleName = ruleName; 
         8:     }
         9: }

      四、新的Controller基類:RuleBasedController

      對于這個用于實現(xiàn)針對不同驗證規(guī)則的擴展來說,其核心是如何將通過ValidationRuleAttribute特性設置的驗證規(guī)則應用到ModelValidator的提供機制中,使之篩選出與當前驗證規(guī)則匹配的驗證特性,在這里我們依然使用Controller上下文來保存這個這個驗證規(guī)則名稱。細心的讀者應該留意到了上面演示實例中創(chuàng)建的HomeController不是繼承自Controller,而是繼承自RuleBasedController,這個自定義的Controller基類定義如下。

         1: public class RuleBasedController: Controller
         2: {
         3:     private static Dictionary<Type, ControllerDescriptor> controllerDescriptors = new Dictionary<Type, ControllerDescriptor>();
         4:     public ControllerDescriptor ControllerDescriptor
         5:     {
         6:         get
         7:         { 
         8:             ControllerDescriptor controllerDescriptor;
         9:             if (controllerDescriptors.TryGetValue(this.GetType(), out controllerDescriptor))
        10:             {
        11:                 return controllerDescriptor;
        12:             }
        13:             lock (controllerDescriptors)
        14:             {
        15:                 if (!controllerDescriptors.TryGetValue(this.GetType(), out controllerDescriptor))
        16:                 {
        17:                     controllerDescriptor = new ReflectedControllerDescriptor(this.GetType());
        18:                     controllerDescriptors.Add(this.GetType(), controllerDescriptor);
        19:                 }
        20:                 return controllerDescriptor;
        21:             }
        22:         }
        23:     }
        24:     protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
        25:     {
        26:         SetValidationRule();
        27:         return base.BeginExecuteCore(callback, state);
        28:     }        
        29:     protected override void ExecuteCore()
        30:     {
        31:         SetValidationRule();
        32:         base.ExecuteCore();
        33:     }
        34:     private void SetValidationRule()
        35:     {
        36:         string actionName = this.ControllerContext.RouteData.GetRequiredString("action");
        37:         ActionDescriptor actionDescriptor = this.ControllerDescriptor.FindAction(this.ControllerContext, actionName);
        38:         if (null != actionDescriptor)
        39:         {
        40:             ValidationRuleAttribute validationRuleAttribute = actionDescriptor.GetCustomAttributes(true).OfType<ValidationRuleAttribute>().FirstOrDefault() ??
        41:                 this.ControllerDescriptor.GetCustomAttributes(true).OfType<ValidationRuleAttribute>().FirstOrDefault() ??
        42:                 new ValidationRuleAttribute(string.Empty);
        43:             this.ControllerContext.RouteData.DataTokens.Add("ValidationRuleName", validationRuleAttribute.RuleName);
        44:         }
        45:     }
        46: }

      在繼承自Controller的RuleBasedController中,ExecuteCore和BeginExecuteCore方法被重寫,在調(diào)用基類的同名方法之前,方法SetValidationRule方法被調(diào)用將應用在當前Action方法或者Controller類型上的ValidationRuleAttribute特性指定的驗證規(guī)則名稱保存到當前Controller上下文中。由于對Action方法和Controller類上特性的解析需要使用到用于描述Controller的ControllerDescriptor對象,處于性能考慮,我們對該對象進行了全局緩存。

      五、自定義ModelValidatorProvider:RuleBasedValidatorProvider

      對于應用在同一個屬性或者類型上的多個基于不同驗證規(guī)則的ValidatorAttribute,對應的驗證規(guī)則名稱并沒有應用到具體的驗證邏輯中。以上面定義的RangeValidatorAttribute為例,具體的驗證邏輯通過被封裝的RangeAttribute來實現(xiàn),如果我們不做任何的處理,所有的基于不同規(guī)則的RangeValidatorAttribute都還參與到最終的Model驗證過程中。我們必須作的是在根據(jù)驗證特性創(chuàng)建ModelValidator的時候只選擇那些與當前驗證規(guī)則一直的ValidatorAttribute,這樣的操作實現(xiàn)在具有如下定義的RuleBasedValidatorProvider中。

         1: public class RuleBasedValidatorProvider : DataAnnotationsModelValidatorProvider
         2: {
         3:     protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
         4:     {
         5:         object validationRuleName = string.Empty;
         6:         context.RouteData.DataTokens.TryGetValue("ValidationRuleName", out validationRuleName);
         7:         string ruleName = validationRuleName.ToString();
         8:         attributes = this.FilterAttributes(attributes, ruleName);
         9:         return base.GetValidators(metadata, context, attributes);
        10:     }
        11:  
        12:     private IEnumerable<Attribute> FilterAttributes(IEnumerable<Attribute> attributes, string validationRule)
        13:     {
        14:             var validatorAttributes = attributes.OfType<ValidatorAttribute>();
        15:             var nonValidatorAttributes = attributes.Except(validatorAttributes);
        16:             List<ValidatorAttribute> validValidatorAttributes = new List<ValidatorAttribute>();
        17:  
        18:         if (string.IsNullOrEmpty(validationRule))
        19:         {
        20:             validValidatorAttributes.AddRange(validatorAttributes.Where(v => string.IsNullOrEmpty(v.RuleName)));                    
        21:         }
        22:         else
        23:         {
        24:             var groups = from validator in validatorAttributesgroup validator by validator.GetType();
        25:             foreach (var group in groups)
        26:             {
        27:                 ValidatorAttribute validatorAttribute = group.Where(v => string.Compare(v.RuleName, validationRule, true) == 0).FirstOrDefault();
        28:                 if (null != validatorAttribute)
        29:                 {
        30:                     validValidatorAttributes.Add(validatorAttribute);
        31:                 }
        32:                 else
        33:                 {
        34:                     validatorAttribute = group.Where(v => string.IsNullOrEmpty(v.RuleName)).FirstOrDefault();
        35:                     if (null != validatorAttribute)
        36:                     {
        37:                         validValidatorAttributes.Add(validatorAttribute);
        38:                     }
        39:                 }
        40:             }
        41:         }
        42:         return nonValidatorAttributes.Union(validValidatorAttributes);
        43:     }
        44: }

      如上面的代碼所示,RuleBasedValidatorProvider繼承自DataAnnotationsModelValidatorProvider,基于當前驗證規(guī)則(從當前的Controller上下文中提取)對ValidatorAttribute的篩選,以及ModelValidator的創(chuàng)建通過重寫的GetValidators方法實現(xiàn)。具體的篩選機制是:如果當前的驗證規(guī)則存在,則選擇與之具有相同規(guī)則名稱的第一個ValidatorAttribute,如果這樣的ValidatorAttribute找不到,則選擇第一個沒有指定驗證規(guī)則的ValidatorAttribute;如果當前的驗證規(guī)則沒有指定,那么也選擇第一個沒有指定驗證規(guī)則的ValidatorAttribute。

      在讓我們的Controller繼承自RuleBasedController之后,我們需要在Global.asax中通過如下的方式對自定義的RuleBasedValidatorProvider進行注冊,然后我們的應用就能按照我們期望的方式根據(jù)你指定的驗證規(guī)則實施Model驗證了。

         1: public class MvcApplication : System.Web.HttpApplication
         2: {
         3:     //其他成員
         4:     protected void Application_Start()
         5:     {
         6:         //其他操作
         7:         DataAnnotationsModelValidatorProvider validator = ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().FirstOrDefault();
         8:         if(null != validator)
         9:         {
        10:             ModelValidatorProviders.Providers.Remove(validator);
        11:         }
        12:         ModelValidatorProviders.Providers.Add(new RuleBasedValidatorProvider());
        13:     }
        14: }
      posted @ 2012-06-12 17:09  Artech  閱讀(11230)  評論(15)    收藏  舉報
      主站蜘蛛池模板: 污网站在线观看视频| 久久精品国产亚洲av成人| 亚洲综合精品成人| 欧美高清精品一区二区| 又污又黄又无遮挡的网站| 2021国产精品视频网站| 少妇熟女视频一区二区三区| 色一伊人区二区亚洲最大| 97午夜理论电影影院| 襄汾县| 亚洲中文无码av永久不收费| 四虎库影成人在线播放| 内射囯产旡码丰满少妇| 九九热免费公开视频在线| 国产成人高清在线观看视频| 2020国产欧洲精品网站| 97国产成人无码精品久久久| 亚洲中文字幕无码专区| 午夜国产精品福利一二| 天堂资源国产老熟女在线| 2022亚洲男人天堂| 国产成人午夜在线视频极速观看| 国产成人综合久久亚洲av| 亚洲国产日韩精品一区二区三区| 欧美日韩一线| 蜜臀av午夜精品福利| 亚洲精品美女久久7777777| 日本免费观看mv免费版视频网站 | 免费无遮挡毛片中文字幕| 亚洲综合一区无码精品| 人妻中文字幕一区二区视频| 草草浮力影院| 日韩精品久久不卡中文字幕| 4hu44四虎www在线影院麻豆| 亚洲欧洲美洲无码精品va| 国产自在自线午夜精品| 成人一区二区三区在线午夜| 亚洲国产成人无码av在线播放 | 九九热在线视频精品免费| 久久精品天天中文字幕人妻| 亚洲一区二区av偷偷|