說到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 }
表單參數和自定義驗證類完成了,接下來就是用戶提交訂單,就需要請求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 }
因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 }
定義了過濾器后,我們如何把截取到的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 }
至此整個AOP過濾器編碼全部完成,在用戶提交表單之前,API接口會首先進入CHKFormInput 過濾器驗證參數合法性,如驗證失敗,將不進入提交訂單的API接口
感謝您的閱讀!