<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驗證:將ValidationAttribute應用到參數上

      ASP.NET MVC默認采用基于標準特性的Model驗證機制,但是只有應用在Model類型及其屬性上的ValidationAttribute才有效。如果我們能夠將ValidationAttribute特性直接應用到參數上,我們不但可以實現簡單類型(比如int、double等)數據的Model驗證,還能夠實現“一個Model類型,多種驗證規則”,本篇文章將為你提供相關的解決方案(源代碼從這里下載)。[本文已經同步到《How ASP.NET MVC Works?》中]

      目錄
      一、ValidationAttribute本身是可以應用到參數上的
      二、為什么需要基于參數的Model驗證?
      三、如何得到應用在參數上的ValidationAttribute?
      四、自定義ModelValidatorProvider
      五、自定義ModelBinder
      六、實例演示

      一、ValidationAttribute本身是可以應用到參數上的

      如果你夠細心應該會發現我們常用的驗證特性都可以直接應用到方法的參數上。以如下所示的RangeAttribute的定義為例,應用在該類型上的AttributeUsageAttribute的定義表明可以標注該特性的目標元素包括參數、字段和屬性。

         1: [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property,AllowMultiple=false)]
         2: public class RangeAttribute : ValidationAttribute
         3: {
         4:    //省略成員
         5: }

      但是對于ASP.NET MVC的Model驗證來說,應用在Action方法參數上的驗證特性起不到任何作用,原因很簡單:用于進行Model驗證的ModelValidator對象是通過基于參數類型的Model元數據來創建的,根本不會去解析應用在參數本身上的驗證特性

      二、為什么需要基于參數的Model驗證?

      但是在我看到,直接針對Action參數的Model驗證具有很高的實用意義:

      • 有些情況下我們不能對作為Model的數據類型進行修改(比如像int、double和字符串這樣的原生類型);
      • 相同的Model類型在不同的Action方法調用中需要采用不同的驗證規則。

      如果我們可以直接將驗證特性應用到參數上面,這兩個問題在一定程度上都可以得到解決。

      三、如何得到應用在參數上的ValidationAttribute?

      到目前為止,我們對ASP.NET MVC的可擴展的Model驗證系統已經有了一個全面的了解,現在我們通過對它進行相應的擴展使直接應用到參數上的驗證特性能夠生效。我們需要自定義一個ModelValidatorProvider將提供基于應用到參數上的驗證特性的ModelValidator,但在這之前需要解決的另一個問題是如何將應用于參數的特性提供給我們自定義的ModelValidatorProvider。在這里我們將當前ControllerContext作為這些特性的載體。

      Action方法的執行通過ActionInvoker來實現,默認的ControllerActionInvoker和AsyncControllerActionInvoker都定義了一個受保護的虛方法GetParameterValue根據用于描述參數的ParameterDescriptor對象和當前的Controller上下文來綁定對應的參數值。那么我們就可以通過繼承ControllerActionInvoker/AsyncControllerActionInvoker以重寫該方法的方式將ParameterDescriptor保存當前的Controller上下文中。

      為此我們定義了一個具有如下定義的兩個自定義的ActionInvoker。ParameterValidationActionInvoker和ParameterValidationAsyncActionInvoker分別繼承自ControllerActionInvoker和AsyncControllerActionInvoker。在重寫的GetParameterValue方法中,我們在調用基類的同名方法之前將作為參數的ParameterDescriptor對象保存到當前Controller上下文中,具體來說是放到了表示當前路由數據的RouteDataDictionary對象的DataTokens集合中。在方法調用之后我們將它從Controller上下文中移除。

         1: public class ParameterValidationActionInvoker : ControllerActionInvoker
         2: {
         3:     protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
         4:     {
         5:         try
         6:         {
         7:             controllerContext.RouteData.DataTokens.Add("ParameterDescriptor",parameterDescriptor);
         8:             return base.GetParameterValue(controllerContext, parameterDescriptor);
         9:         }
        10:         finally
        11:         {
        12:             controllerContext.RouteData.DataTokens.Remove("ParameterDescriptor");
        13:         }
        14:     }
        15: }
        16:  
        17: public class ParameterValidationAsyncActionInvoker : AsyncControllerActionInvoker
        18: {
        19:     protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
        20:     {
        21:         try
        22:         {
        23:             controllerContext.RouteData.DataTokens.Add("ParameterDescriptor", parameterDescriptor);
        24:             return base.GetParameterValue(controllerContext, parameterDescriptor);
        25:         }
        26:         finally
        27:         {
        28:             controllerContext.RouteData.DataTokens.Remove("ParameterDescriptor");
        29:         }
        30:     }
        31: }

      四、自定義ModelValidatorProvider

      ParameterValidationActionInvoker/ParameterValidationAsyncActionInvoker存放到當前Controller上下文中的ParameterDescriptor被我們自定義的ModelValidatorProvider提取出來用于創建相應的ModelValidator。如下面的代碼片斷所示,我們自定義的ParameterValidationModelValidatorProvider直接繼承自DataAnnotationsModelValidatorProvider,在重寫的GetValidators方法中我們將ParameterDescriptor從Controller上下文中提取出來,然后得到應用在參數上的所有的特性并與當前的特性列表進行合并,最后將合并的特性列表作為參數調用積累的GetValidators方法。

         1: public class ParameterValidationModelValidatorProvider : DataAnnotationsModelValidatorProvider
         2: {
         3:     protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
         4:     {    
         5:         object descriptor;
         6:         if (metadata.ContainerType == null && context.RouteData.DataTokens.TryGetValue("ParameterDescriptor", out descriptor))
         7:         {
         8:             ParameterDescriptor parameterDescriptor = (ParameterDescriptor)descriptor;
         9:             DisplayAttribute displayAttribute = parameterDescriptor.GetCustomAttributes(true).OfType<DisplayAttribute>().FirstOrDefault()
        10:                 ?? new DisplayAttribute { Name = parameterDescriptor.ParameterName };
        11:             metadata.DisplayName = displayAttribute.Name;
        12:             var addedAttributes = parameterDescriptor.GetCustomAttributes(true).OfType<Attribute>();
        13:             return base.GetValidators(metadata, context, attributes.Union(addedAttributes));
        14:         }
        15:         else
        16:         {
        17:             return base.GetValidators(metadata, context, attributes);
        18:         }
        19:     }
        20: }

      值得一提的是,應用在參數上的特性是針對最外層的容器類型,而不是針對容器類型的屬性的。比如所以我們在類型為Contact的參數上應用一個驗證特性,該特性應該與應用在Contact類型上的特性具有相同的效果,但是與Address屬性無關。所以ParameterDescriptor的提取以及特性的合并僅僅在當前Model元數據的ContainerType為Null的情況下才會進行。除此之外,我們還利用應用到參數的DisplayAttribute特性對Model元數據的DisplayName屬性進行了相應的設置。

      五、自定義ModelBinder

      在默認的情況下,只有在針對復雜類型的Model綁定過程中才會進行Model驗證。雖然我們通過ParameterValidationModelValidatorProvider能夠根據應用在Action方法參數上的驗證特性生成相應的ModelValidator,但是如果驗證特性是應用在一個簡單類型的參數上,生成出來的ModelValidator也是不會被使用的。為了使Model驗證發生在針對簡單類型的Model綁定過程中,我們不得不創建一個自定義的ModelBinder。為此我們定義了一個具有如下定義的ParameterValidationModelBinder,它直接繼承自DefaultModelBinder,而針對簡單類型的Model驗證定義在重寫的BindModel方法中。

         1: public class ParameterValidationModelBinder : DefaultModelBinder
         2: {
         3:     public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
         4:     {
         5:         object model = bindingContext.ModelMetadata.Model = base.BindModel(controllerContext, bindingContext);
         6:         ModelMetadata metadata = bindingContext.ModelMetadata;
         7:         if (metadata.IsComplexType || null == model)
         8:         {
         9:             return model;
        10:         }
        11:  
        12:         Dictionary<string, bool> dictionary = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
        13:         foreach (ModelValidationResult result in ModelValidator.GetModelValidator(metadata, controllerContext).Validate(null))
        14:         {
        15:             string key = bindingContext.ModelName;
        16:             if (!dictionary.ContainsKey(key))
        17:             {
        18:                 dictionary[key] = bindingContext.ModelState.IsValidField(key);
        19:             }
        20:             if (dictionary[key])
        21:             {
        22:                 bindingContext.ModelState.AddModelError(key, result.Message);
        23:             }
        24:         }
        25:         return model;
        26:     }
        27: }

      到此為止,為了能夠將驗證特性應用于Action方法的參數,我們創建了自定義的ActionInvoker、ModelValidatorProvider和ModelBinder。為了驗證它們是否能夠最終實現我們期望的驗證效果,我們將它們應用到一個簡單的ASP.NET MVC應用中。

      六、實例演示

      在通過Visual Studio的ASP.NET MVC項目模板創建的空的Web應用中,我們創建了一個具有如下定義的HomeController。我們重寫了CreateActionInvoker方法,如果調用基類同名方法返回一個ControllerActionInvoker對象,那么我們返回一個ParameterValidationActionInvoker對象,否則返回一個ParameterValidationAsyncActionInvoker對象,這是與默認的同步/異步Action執行方式保持一致。

         1: public class HomeController : Controller
         2: {
         3:     protected override IActionInvoker CreateActionInvoker()
         4:     {
         5:         IActionInvoker actionInvoker = base.CreateActionInvoker();
         6:         if (actionInvoker is ControllerActionInvoker)
         7:         {
         8:             return new ParameterValidationActionInvoker();
         9:         }
        10:         else
        11:         {
        12:             return new ParameterValidationAsyncActionInvoker();
        13:         }
        14:     }
        15:  
        16:     public ActionResult Add(
        17:         [Range(10, 20, ErrorMessage="{0}必須在{1}和{2}之間!")]
        18:         [ModelBinder(typeof(ParameterValidationModelBinder))]
        19:         [Display(Name = "第一個操作數")]
        20:         double x,
        21:  
        22:         [Range(20, 30,ErrorMessage="{0}必須在{1}和{2}之間!")]
        23:         [ModelBinder(typeof(ParameterValidationModelBinder))]
        24:         [Display(Name = "第二個操作數")]
        25:         double y)
        26:     {
        27:         return View(x + y);
        28:     }
        29: }

      Action方法Add表示一個用于進行加法運算的操作,表示操作數的兩個參數x和y分別應用了一個RangeAttribute特性將允許值得范圍設置為10到20和20到30,并設置了相應的錯誤消息。此外,兩個參數還通過應用ModelBinderAttribute特性使我們自定義的ParameterValidationModelBinder參與到這兩個參數Model綁定中。DisplayAttribute特性也應用到這兩個參數上對顯示名稱進行了相應的設置。作于執行加法運算后的結果通過默認的View呈現出來。下面的代碼片斷表示Action方法Add對應的View的定義,這是一個Model類型為double的強類型View。我們通過一個ValidationSummary來呈現驗證的錯誤消息,只有在驗證成功的情況下我們才真正顯示運算的結果。

         1: @model double
         2: @Html.ValidationSummary()
         3: @{
         4:    if(ViewData.ModelState.IsValid)
         5:    {
         6:         @:運算結果:@Model
         7:    }
         8: }

      然后我們在Global.asax中對自定義的ParameterValidationModelValidatorProvider進行注冊。如下面的代碼片斷所示,在注冊ParameterValidationModelValidatorProvider之前需要將現有的DataAnnotationsModelValidatorProvider移除。

         1: public class MvcApplication : System.Web.HttpApplication
         2: {
         3:     //其他成員
         4:     protected void Application_Start()
         5:     {
         6:         //其他操作
         7:         DataAnnotationsModelValidatorProvider validatorProvider = ModelValidatorProviders.Providers
         8:            .OfType<DataAnnotationsModelValidatorProvider>().FirstOrDefault();
         9:         if (null != validatorProvider)
        10:         {
        11:             ModelValidatorProviders.Providers.Remove(validatorProvider);
        12:         }
        13:         ModelValidatorProviders.Providers.Add(new ParameterValidationModelValidatorProvider());
        14:     }
        15: }

      我們運行該程序通過在瀏覽器中輸入相應的地址來訪問定義在HomeController中的Add操作,并以查詢字符串的形式指定該Action方法的兩個操作數(x=9,y=31)。由于提供的參數不服務應用在參數上的 RangeAttribute所定義的驗證規則,如下圖所示的錯誤消息會自動呈現出來。

      image

      ASP.NET MVC基于標注特性的Model驗證:ValidationAttribute
      ASP.NET MVC基于標注特性的Model驗證:DataAnnotationsModelValidator
      ASP.NET MVC基于標注特性的Model驗證:DataAnnotationsModelValidatorProvider
      ASP.NET MVC基于標注特性的Model驗證:將ValidationAttribute應用到參數上
      ASP.NET MVC基于標注特性的Model驗證:一個Model,多種驗證規則

      posted @ 2012-06-11 17:22  Artech  閱讀(9317)  評論(19)    收藏  舉報
      主站蜘蛛池模板: 国产毛片精品一区二区色| 无遮高潮国产免费观看| 爆乳日韩尤物无码一区| AV无码不卡一区二区三区| 久久99精品久久久久久琪琪| 中文字幕自拍偷拍福利视频| 精选国产av精选一区二区三区| 中文字幕日韩有码av| 美女自卫慰黄网站| a4yy私人毛片| 国产欧美另类精品久久久| 99在线视频免费观看| 99久久夜色精品国产亚洲| 日韩秘 无码一区二区三区| 久久精品夜色噜噜亚洲aa| 在线播放亚洲成人av| 亚洲国产另类久久久精品网站| 精品国产乱码久久久久久影片| 国产一区二区三区导航| 仙桃市| 亚洲一区中文字幕第十页| 91福利视频一区二区| 日日摸天天爽天天爽视频| 亚洲热无码av一区二区东京热av| 国产欧美日韩亚洲一区二区三区| 亚洲成人av综合一区| 中文人妻AV高清一区二区| 亚洲小说乱欧美另类| 激情综合网激情五月我去也| 四虎成人在线观看免费| 高清偷拍一区二区三区| 国产av一区二区不卡| 日本不卡不二三区在线看| 昆山市| 青青青久热国产精品视频| 久本草在线中文字幕亚洲| 国产一区二区三区综合视频| 国产一区韩国主播| 九九热在线视频只有精品| 韩国无码AV片午夜福利| AV最新高清无码专区|