国产亚洲欧美人成在线,免费视频爱爱太爽了无码,日本免费一区二区三区高清视频 ,国产真实伦对白精彩视频

歡迎您光臨深圳塔燈網(wǎng)絡(luò)科技有限公司!
電話圖標(biāo) 余先生:13699882642

網(wǎng)站百科

為您解碼網(wǎng)站建設(shè)的點(diǎn)點(diǎn)滴滴

通過擴(kuò)展改善ASP.NET MVC的驗(yàn)證機(jī)制[實(shí)現(xiàn)篇]

發(fā)表日期:2019-09 文章編輯:小燈 瀏覽次數(shù):2119

“基于某個(gè)規(guī)則的驗(yàn)證”是本解決方案一個(gè)最大的賣點(diǎn)。為了保持以驗(yàn)證規(guī)則名稱為核心的上下文信息,我定義了如下一個(gè)ValidatorContext(我們本打算將其命名為ValidationContext,無奈這個(gè)類型已經(jīng)存在)。ValidatorContext的屬性RuleName和Culture表示當(dāng)前的驗(yàn)證規(guī)則和語言文化(默認(rèn)值為當(dāng)前線程的CurrentUICulture),而字典類型的屬性Properties用戶存放一些額外信息。當(dāng)前ValidationContext的獲取與設(shè)置通過靜態(tài)Current完成。

 1: public class ValidatorContext
 2: {
 3: [ThreadStatic]
 4: private static ValidatorContext current;
 5:? 
 6: public string RuleName { get; private set; }
 7: public CultureInfo Culture { get; private set; }
 8: public IDictionary<string, object> Properties { get; private set; }
 9:? 
10: public ValidatorContext(string ruleName, CultureInfo culture=null)
11: {
12: this.RuleName = ruleName;
13: this.Properties = new Dictionary<string, object>();
14: this.Culture = culture??CultureInfo.CurrentUICulture;
15: }
16:? 
17: public static ValidatorContext Current
18: {
19: get { return current; }
20: set { current = value; }
21: }
22: }

我們?yōu)閂alidatorContext定義了如下一個(gè)匹配的ValidatorContextScope對象用于設(shè)置ValidatorContext的作用范圍。

 1: public class ValidatorContextScope : IDisposable
 2: {
 3: private ValidatorContext current = ValidatorContext.Current;
 4: public ValidatorContextScope(string ruleName, CultureInfo culture = null)
 5: {
 6: ValidatorContext.Current = new ValidatorContext(ruleName, culture);
 7: }
 8: public void Dispose()
 9: {
10: if (null == current)
11: {
12: foreach (object property in ValidatorContext.Current.Properties.Values)
13: {
14: IDisposable disposable = property as IDisposable;
15: if (null != disposable)
16: {
17: disposable.Dispose();
18: }
19: }
20: }
21: ValidatorContext.Current = current;
22: }
23: }

二、通過自定義ActionInvoker在進(jìn)行操作執(zhí)行之前初始化上下文

通過《使用篇》中我們知道當(dāng)前的驗(yàn)證規(guī)則名稱是通過ValidationRuleAttribute來設(shè)置的,該特性不僅僅可以應(yīng)用在Action方法上,也可以應(yīng)用在Controller類型上。當(dāng)然Action方法上的ValidationRuleAttribute具有更高的優(yōu)先級。如下面的代碼片斷所示,ValidationRuleAttribute就是一個(gè)包含Name屬性的普通Attribute而已。

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

很顯然,以當(dāng)前驗(yàn)證規(guī)則驗(yàn)證規(guī)則為核心的ValidatorContext需要在Action操作之前設(shè)置(嚴(yán)格地說應(yīng)該在進(jìn)行Model綁定之前),而在Action操作完成后清除。很自然地,我們可以通過自定義ActionInvoker來完成,為此我定義了如下一個(gè)直接繼承自ControllerActionInvoker的ExtendedControllerActionInvoker類。

 1: public class ExtendedControllerActionInvoker : ControllerActionInvoker
 2: {
 3: public ExtendedControllerActionInvoker()
 4: { 
 5: this.CurrentCultureAccessor= (context=>
 6: {
 7: string culture = context.RouteData.GetRequiredString("culture");
 8: if(string.IsNullOrEmpty(culture))
 9: {
10: return null;
11: }
12: else
13: {
14: return new CultureInfo(culture);
15: }
16: });
17: }
18: public virtual Func<ControllerContext, CultureInfo> CurrentCultureAccessor { get; set; }
19: public override bool InvokeAction(ControllerContext controllerContext, string actionName)
20: {
21: CultureInfo originalCulture = CultureInfo.CurrentCulture;
22: CultureInfo originalUICulture = CultureInfo.CurrentUICulture;
23: try
24: {
25: CultureInfo culture = this.CurrentCultureAccessor(controllerContext);
26: if (null != culture)
27: {
28: Thread.CurrentThread.CurrentCulture = culture;
29: Thread.CurrentThread.CurrentUICulture = culture;
30: }
31: var controllerDescriptor = this.GetControllerDescriptor(controllerContext);
32: var actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);
33: ValidationRuleAttribute attribute = actionDescriptor.GetCustomAttributes(true).OfType<ValidationRuleAttribute>().FirstOrDefault() as ValidationRuleAttribute;
34: if (null == attribute)
35: {
36: attribute = controllerDescriptor.GetCustomAttributes(true).OfType<ValidationRuleAttribute>().FirstOrDefault() as ValidationRuleAttribute;
37: }
38: string ruleName = (null == attribute) ? string.Empty : attribute.Name;
39: using (ValidatorContextScope contextScope = new ValidatorContextScope(ruleName))
40: {
41: return base.InvokeAction(controllerContext, actionName);
42: }
43: }
44: catch
45: {
46: throw;
47: }
48: finally
49: {
50: Thread.CurrentThread.CurrentCulture = originalCulture;
51: Thread.CurrentThread.CurrentUICulture = originalUICulture;
52: }
53: }
54: }

如上面的代碼片斷所示,在重寫的InvokeAction方法中我們通過ControllerDescriptor/ActionDescriptor得到應(yīng)用在Controller類型/Action方法上的ValidationRuleAttribute特性,并或者到設(shè)置的驗(yàn)證規(guī)則名稱。然后我們創(chuàng)建ValidatorContextScope對象,而針對基類InvokeAction方法的執(zhí)行就在該ValidatorContextScope中執(zhí)行的。初次之外,我們還對當(dāng)前線程的Culture進(jìn)行了相應(yīng)地設(shè)置,默認(rèn)的Culture 信息來源于當(dāng)前RouteData。

為了更方便地使用ExtendedControllerActionInvoker,我們定義了一個(gè)抽象的Controller基類:BaseController。BaseController是Controller的子類,在構(gòu)造函數(shù)中我們將ActionInvoker屬性設(shè)置成我們自定義的ExtendedControllerActionInvoker對象。

 1: public abstract class BaseController: Controller
 2: {
 3: public BaseController()
 4: {
 5: this.ActionInvoker = new ExtendedControllerActionInvoker();
 6: }
 7: }

三、為Validator創(chuàng)建基類:ValidatorBaseAttribute

接下來我們才來看看真正用于驗(yàn)證的驗(yàn)證特性如何定義。我們的驗(yàn)證特性都直接或者間接地繼承自具有如下定義的ValidatorBaseAttribute,而它使ValidationAttribute的子類。如下面的代碼片斷所示,ValidatorBaseAttribute還實(shí)現(xiàn)了IClientValidatable接口,以提供對客戶端驗(yàn)證的支持。屬性RuleName、MessageCategory、MessageId和Culture分別代表驗(yàn)證規(guī)則名稱、錯(cuò)誤消息的類別和ID號(hào)(通過這兩個(gè)屬性通過MessageManager這個(gè)獨(dú)立的組件獲取完整的錯(cuò)誤消息)和基于的語言文化。

 1: [AttributeUsage(AttributeTargets.Class|AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
 2: public abstract class ValidatorBaseAttribute : ValidationAttribute, IClientValidatable
 3: {
 4: 
 5: public string RuleName { get; set; }
 6: public string MessageCategory { get; private set; }
 7: public string MessageId { get; private set; }
 8: public string Culture { get; set; }
 9:? 
10: public ValidatorBaseAttribute(MessageManager messageManager, string messageCategory, string messageId, params object[] args)
11: : base(() => messageManager.FormatMessage(messageCategory, messageId, args))
12: {
13: this.MessageCategory = messageCategory;
14: this.MessageId = messageId;
15: }
16:? 
17: public ValidatorBaseAttribute(string messageCategory, string messageId, params object[] args)
18: : this(MessageManagerFactory.GetMessageManager(), messageCategory, messageId, args)
19: { }
20:? 
21: public virtual bool Match(ValidatorContext context, IEnumerable<ValidatorBaseAttribute> validators)
22: {
23: if (!string.IsNullOrEmpty(this.RuleName))
24: {
25: if (this.RuleName != context.RuleName)
26: {
27: return false;
28: }
29: }
30:? 
31: if (!string.IsNullOrEmpty(this.Culture))
32: {
33: if (string.Compare(this.Culture, context.Culture.Name, true) != 0)
34: {
35: return false;
36: }
37: }
38:? 
39: if (string.IsNullOrEmpty(this.Culture))
40: {
41: if (validators.Any(validator => validator.GetType() == this.GetType() && string.Compare(validator.Culture, context.Culture.Name, true) == 0))
42: {
43: return false;
44: }
45: }
46: return true;
47: }
48: public abstract IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context);
49: private object typeId;
50: public override object TypeId
51: {
52: get { return (null == typeId) ? (typeId = new object()) : typeId; }
53: }
54: }

由于我們需要將多個(gè)相同類型的Validator特性應(yīng)用到某個(gè)類型或者字段/屬性上,我們需要通過AttributeUsageAttribute將AllowMultiple屬性設(shè)置為True,此外需要重寫TypeId屬性。至于為什么需需要這么做,可以參考我的上一篇文章《在ASP.NET MVC中如何應(yīng)用多個(gè)相同類型的ValidationAttribute?》。對于應(yīng)用在同一個(gè)目標(biāo)元素的多個(gè)相同類型的Validator特性,只有與當(dāng)前ValidatorContext相匹配的才能執(zhí)行,我們通過Match方法來進(jìn)行匹配性的判斷,具體的邏輯是這樣的:

  • 在顯式設(shè)置了RuleName屬性情況下,如果不等于當(dāng)前驗(yàn)證規(guī)則,直接返回False;
  • 在顯式設(shè)置了Culture屬性情況下,如果與當(dāng)前語言文化不一致,直接返回False;
  • 在沒有設(shè)置Culture屬性(語言文化中性)情況下,如果存在另一個(gè)同類型的Validator與當(dāng)前的語言文化一致,也返回False;
  • 其余情況返回True

四、通過自定義ModelValidatorProvider在驗(yàn)證之前將不匹配Validator移除

應(yīng)用在Model類型或其屬性/字段上的ValidationAttribute最終通過對應(yīng)的ModelValidatorProvider(DataAnnotationsModelValidatorProvider)用于創(chuàng)建ModelValidator(DataAnnotationsModelValidator)。我們必須在ModelValidator創(chuàng)建之前將不匹配的Validator特性移除,才能確保只有與當(dāng)前ValidatorContext相匹配的Validator特性參與驗(yàn)證。為此我們通過繼承DataAnnotationsModelValidator自定義了如下一個(gè)ExtendedDataAnnotationsModelValidator。

 1: public class ExtendedDataAnnotationsModelValidatorProvider : DataAnnotationsModelValidatorProvider
 2: {
 3: protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
 4: {
 5: var validators = attributes.OfType<ValidatorBaseAttribute>();
 6: var allAttributes = attributes.Except(validators).ToList();
 7: foreach (ValidatorBaseAttribute validator in validators)
 8: {
 9: if (validator.Match(ValidatorContext.Current, validators))
10: {
11: allAttributes.Add(validator);
12: }
13: }
14: return base.GetValidators(metadata, context, allAttributes);
15: }
16: }

如上面的代碼片斷所示,在重寫的GetClientValidationRules方法中,輸入?yún)?shù)attributes表示所有的ValidationAttribute,在這里我們根據(jù)調(diào)用ValidatorBaseAttribute的Match方法將不匹配的Validator特性移除,然后根據(jù)余下的ValidationAttribute列表調(diào)用基類GetValidators方法創(chuàng)建ModelValidator列表。值得一提的是,關(guān)于System.Attribute的Equals/GetHashCode方法的問題就從這個(gè)方法中發(fā)現(xiàn)的(詳情參見《為什么System.Attribute的GetHashCode方法需要如此設(shè)計(jì)?》)。自定義ExtendedDataAnnotationsModelValidator在Global.asax的Application_Start方法中通過如下的方式進(jìn)行注冊。

 1: protected void Application_Start()
 2: {
 3://...
 4: var provider = ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().FirstOrDefault();
 5: if (null != provider)
 6: {
 7: ModelValidatorProviders.Providers.Remove(provider);
 8: }
 9: ModelValidatorProviders.Providers.Add(new ExtendedDataAnnotationsModelValidatorProvider());
10: }

五、RequiredValidatorAttribute的定義

最后我們來看看用于驗(yàn)證必需字段的RequiredValidatorAttribute如何定義。IsValid用于服務(wù)端驗(yàn)證,而GetClientValidationRules生成調(diào)用客戶端驗(yàn)證規(guī)則。

 1: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
 2: public class RequiredValidatorAttribute : ValidatorBaseAttribute
 3: {
 4: public RequiredValidatorAttribute(string messageCategory, string messageId, params object[] args)
 5: : base(messageCategory, messageId, args)
 6: { } 
 7:? 
 8: public override bool IsValid(object value)
 9: {
10: if (value == null)
11: {
12: return false;
13: }
14: string str = value as string;
15: if (str != null)
16: {
17: return (str.Trim().Length != 0);
18: }
19: return true;
20: }
21:? 
22: public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
23: {
24: return new ModelClientValidationRequiredRule[] { new ModelClientValidationRequiredRule(this.ErrorMessageString) };
25: }
26: }

本頁內(nèi)容由塔燈網(wǎng)絡(luò)科技有限公司通過網(wǎng)絡(luò)收集編輯所得,所有資料僅供用戶學(xué)習(xí)參考,本站不擁有所有權(quán),如您認(rèn)為本網(wǎng)頁中由涉嫌抄襲的內(nèi)容,請及時(shí)與我們聯(lián)系,并提供相關(guān)證據(jù),工作人員會(huì)在5工作日內(nèi)聯(lián)系您,一經(jīng)查實(shí),本站立刻刪除侵權(quán)內(nèi)容。本文鏈接:http://jstctz.cn/19692.html
相關(guān)開發(fā)語言
 八年  行業(yè)經(jīng)驗(yàn)

多一份參考,總有益處

聯(lián)系深圳網(wǎng)站公司塔燈網(wǎng)絡(luò),免費(fèi)獲得網(wǎng)站建設(shè)方案及報(bào)價(jià)

咨詢相關(guān)問題或預(yù)約面談,可以通過以下方式與我們聯(lián)系

業(yè)務(wù)熱線:余經(jīng)理:13699882642

Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.    

  • QQ咨詢
  • 在線咨詢
  • 官方微信
  • 聯(lián)系電話
    座機(jī)0755-29185426
    手機(jī)13699882642
  • 預(yù)約上門
  • 返回頂部