ASP.NET MVC基於標註特性的Model驗證:將ValidationAttribute應用到參數上

來源:互聯網
上載者:User

ASP.NET MVC預設採用基於標準特性的Model驗證機制,但是只有應用在Model類型及其屬性上的ValidationAttribute才有效。如果我們能夠將ValidationAttribute特性直接應用到參數上,我們不但可以實現簡單類型(比如int、double等)資料的Model驗證,還能夠實現“一個Model類型,多種驗證規則”,本篇文章將為你提供相關的解決方案(原始碼從這裡下載)。

一、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: }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.