zoukankan      html  css  js  c++  java
  • 如何在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接口

    感谢您的阅读!
  • 相关阅读:
    数组
    css动画
    mui 常用手势
    ejs 用到的语法
    css 高度塌陷
    SQL 用到的操作符
    position: relative;导致页面卡顿
    h5 图片生成
    li之间的间隙问题
    虚拟机扩容mac
  • 原文地址:https://www.cnblogs.com/dzycwy/p/5336181.html
Copyright © 2011-2022 走看看