如何在WebApi中使用過濾器實現面向切面編程(AOP)


     說到AOP編程,可能大部分人是即熟悉又顯得陌生。

    AOP的作用就是橫切關注點,然后將分離后的關注點以面的形式來呈現,這是概念性的說法,舉個列子來說明吧。

     比如說有個API接口處理場景是提交訂單,在我們提交訂單的時候,首先客戶端要對用戶提交的數據進行合法性驗證,驗證通過后,數據發送到服務端,因客戶端一切操作都是不可信的,必然服務端在錄入訂單信息之前也需要對數據合法性進行驗證。

    針對上述問題我們可以這樣子來編碼

    首先定義訂單表單參數實體對象:

 

 1 /// <summary>
 2     /// Post表單參數
 3     /// </summary>
 4     public class FromOrderInfo
 5 { 6 /// <summary> 7 /// 商品名稱 8 /// </summary> 9 public string ShopName { get; set; } 10 /// <summary> 11 /// 手機號 12 /// </summary> 13 [ValidateMobile(ErrorMessage = "請輸入正確格式的手機號")]//自定義驗證規則 14 public string Mobile { get; set; } 15 /// <summary> 16 /// Address 17 /// </summary> 18 [ValidateMaxLength(20,ErrorMessage = "Address字符超過指定長度")] 19 public string Address { get; set; } 20 } 

 在表單對象FromOrderInfo實體類里面有ValidateMobile和ValidateMaxLength驗證類

接下來我們需要編寫自定義ValidateMobile和ValidateMaxLength驗證類

自定義驗證如下:

 1 /// <summary>
 2     /// 驗證字符長度是否超過指定長度
 3     /// </summary>
 4     public class ValidateMaxLengthAttribute : ValidationAttribute
 5     {
 6         private readonly int MaxLength;
 7 
 8         public ValidateMaxLengthAttribute(int maxLength)
 9             : base("{0}的字符太多了!")
10         {
11             MaxLength = maxLength;
12         }
13 
14         protected override ValidationResult IsValid(object value, ValidationContext validationContext)
15         {
16             if (value != null)
17             {
18                 string content = value.ToString();
19                 int leng = StringTool.GetStringLength(content);
20                 if (leng > MaxLength)
21                 {
22                     string errorMessage = FormatErrorMessage(validationContext.DisplayName);
23                     return new ValidationResult(errorMessage);
24                 }
25             }
26             return ValidationResult.Success;
27         }       
28     }
29 
30 /// <summary>
31    /// 驗證手機號
32    /// </summary>
33    public class ValidateMobileAttribute : ValidationAttribute
34     {
35        public ValidateMobileAttribute()
36             : base("{0}應輸入11位手機號!")
37         {
38         }
39        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
40        {
41            if (value != null)
42            {
43                string content = value.ToString();
44                if (!RegexTool.IsMobile(content))
45                {
46                    string errorMessage = FormatErrorMessage(validationContext.DisplayName);
47                    return new ValidationResult(errorMessage);
48                }
49            }
50            return ValidationResult.Success;
51        }
52     }
View Code

 

表單參數和自定義驗證類完成了,接下來就是用戶提交訂單,就需要請求API接口。
訂單API接口代碼如下:

 1 [CHKFormInput(typeof(FromOrderInfo))]
 2         public HttpResponseMessage TestOrder([FromBody] FromInfo info)
 3         {
 4             var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.OK);
 5 
 6             challengeMessage = new ResponseMessage<string>("json").Response("下單成功");
 7             return challengeMessage;
 8 
 9         }
10 
11 /// <summary>
12     /// Post表單參數
13     /// </summary>
14     public class FromInfo
15     {
16         /// <summary>
17         /// Json數據對象
18         /// </summary>
19         public string JsonFormat { get; set; }
20     }
View Code

 


因API接口中POST請求只能用[FromBody]來包含,所以我們需要把表單參數轉換成Json格式的字符串,用JsonFormat 來接收。。。

 接下來就是編寫CHKFormInput過濾器,在進入之前Action之前對表單參數進行攔截驗證。

定義過濾器代碼:
 1 /// <summary>
 2     /// 驗證表單參數
 3     /// </summary>
 4 public class CHKFormInput : ActionFilterAttribute
 5     {
 6         private Type _type;
 7         /// <summary>
 8         /// 構造函數
 9         /// </summary>
10         /// <param name="type">表單參數驗證對象</param>
11         public CHKFormInput(Type type = null)
12         {
13             if (type != null)
14             {
15                 this._type = type;
16             }
17         }
18         public override void OnActionExecuting(HttpActionContext actionContext)//執行action動作所需執行的操作
19         {
20             #region 檢查表單參數是否合法
21             var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.OK);
22             ErrorResponse errorMsgConvertjson = new ErrorResponse();//返回錯誤信息string errorMsg = string.Empty;
23             try
24             {
25                 if (actionContext == null)
26                 {
27                     throw new System.Web.Http.HttpResponseException(challengeMessage);
28                 }
29                 if (ProjectRequest.IsPost())//驗證是否POST請求
30                 {
31                     var task = actionContext.Request.Content.ReadAsStreamAsync();
32                     var content = string.Empty;
33                     using (System.IO.Stream sm = task.Result)
34                     {
35                         if (sm != null)
36                         {
37                             sm.Seek(0, SeekOrigin.Begin);
38                             int len = (int)sm.Length;
39                             byte[] inputByts = new byte[len];
40                             sm.Read(inputByts, 0, len);
41                             sm.Close();
42                             content = Encoding.UTF8.GetString(inputByts);
43                         }
44                     }
45                     var m = JsonTool.JsonToEntity<FromInfo>(content);
46                     var Json = Serializer.Deserialize(m.JsonFormat, _type);
47                     new TryValidateModelTool().TryValidateModel(Json, ref errorMsg);
48                     if(!string.IsNullOrEmpty(errorMsg))
49                     {
50                         errorMsgConvertjson.Message = errorMsg;
51                         errorMsgConvertjson.State = CallBackServer.InputError;
52                         challengeMessage = new ResponseMessage<ErrorResponse>("json").Response(errorMsgConvertjson);
53                         actionContext.Response = challengeMessage;
54                     }
55                     
56                 }
57                 
58             }
59             catch (Exception ex)
60             {
61             }
62             finally
63             {
64             }
65             base.OnActionExecuting(actionContext);
66             #endregion
67         }
68     }
View Code

 



定義了過濾器后,我們如何把截取到的FromOrderInfo表單參數來進行驗證呢?

  然后我們還需要繼續編寫一個類來執行附加在實體屬性的驗證規則

實體對像屬性驗證類:


 1 /// <summary>
 2     /// 利用特性驗證實體對象參數合法性
 3     /// </summary>
 4     public class TryValidateModelTool : ApiController
 5     {
 6         /// <summary>
 7         /// 利用特性驗證實體對象參數合法性
 8         /// </summary>
 9         /// <param name="model">對象</param>
10         /// <param name="errorMsg">錯誤信息</param>
11         /// <returns></returns>
12         public bool TryValidateModel(object model, ref string errorMsg)
13         {
14             return TryValidateModel(model, null /* prefix */, ref errorMsg);
15         }
16 
17         
18 
19 
20         /// <summary>
21         /// 利用特性驗證實體對象參數合法性
22         /// </summary>
23         /// <param name="model">對象</param>
24         /// <param name="errorMsg">錯誤信息</param>
25         /// <returns></returns>
26         public bool TryValidateModel(object model, string prefix, ref string errorMsg)
27         {
28             if (model == null)
29             {
30                 throw new ArgumentNullException("model");
31             }
32 
33             ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
34             var t = new ModelBindingExecutionContext(new HttpContextWrapper(HttpContext.Current), new System.Web.ModelBinding.ModelStateDictionary());
35             List<string> errorMsgList = new List<string>();
36             foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, t).Validate(null))
37             {
38                 ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
39                 errorMsgList.Add(validationResult.Message);
40             }                       
41             errorMsg = string.Join(",", errorMsgList);
42             return ModelState.IsValid;
43         }
44     }
View Code

 

 

至此整個AOP過濾器編碼全部完成,在用戶提交表單之前,API接口會首先進入CHKFormInput 過濾器驗證參數合法性,如驗證失敗,將不進入提交訂單的API接口

感謝您的閱讀!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM