佛山市网站建设分站多少钱,台州网站优化,什么叫品牌vi设计,沈阳网络科技有限公司在WEB Api中#xff0c;引入了面向切面编程#xff08;AOP#xff09;的思想#xff0c;在某些特定的位置可以插入特定的Filter进行过程拦截处理。引入了这一机制可以更好地践行DRY(Don’t Repeat Yourself)思想#xff0c;通过Filter能统一地对一些通用逻辑进行处理… 在WEB Api中引入了面向切面编程AOP的思想在某些特定的位置可以插入特定的Filter进行过程拦截处理。引入了这一机制可以更好地践行DRY(Don’t Repeat Yourself)思想通过Filter能统一地对一些通用逻辑进行处理如权限校验、参数加解密、参数校验等方面我们都可以利用这一特性进行统一处理今天我们来介绍Filter的开发、使用以及讨论他们的执行顺序。 一、Filter的开发和调用 在默认的WebApi中框架提供了三种Filter他们的功能和运行条件如下表所示 Filter 类型实现的接口描述AuthorizationIAuthorizationFilter最先运行的Filter被用作请求权限校验ActionIActionFilter在Action运行的前、后运行ExceptionIExceptionFilter当异常发生的时候运行 首先我们实现一个AuthorizatoinFilter可以用以简单的权限控制 public class AuthFilterAttribute : AuthorizationFilterAttribute{ public override void OnAuthorization(HttpActionContext actionContext){ //如果用户方位的Action带有AllowAnonymousAttribute则不进行授权验证if (actionContext.ActionDescriptor.GetCustomAttributesAllowAnonymousAttribute().Any()){ return;} var verifyResult actionContext.Request.Headers.Authorization!null //要求请求中需要带有Authorization头actionContext.Request.Headers.Authorization.Parameter 123456; //并且Authorization参数为123456则验证通过if (!verifyResult){ //如果验证不通过则返回401错误并且Body中写入错误原因actionContext.Response actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized,new HttpError(Token 不正确));}} } 一个简单的用于用户验证的Filter就开发完了这个Filter要求用户的请求中带有Authorization头并且参数为123456如果通过则放行不通过则返回401错误并在Content中提示Token不正确。下面我们需要注册这个Filter注册Filter有三种方法 第一种在我们希望进行权限控制的Action上打上AuthFilterAttribute这个Attribute: public class PersonController : ApiController{[AuthFilter] public CreateResult Post(CreateUser user){ return new CreateResult() {Id 123};}} 这种方式适合单个Action的权限控制。 第二种找到相应的Controller并打上这个Attribute [AuthFilter] public class PersonController : ApiController{ public CreateResult Post(CreateUser user){ return new CreateResult() {Id 123};}} 这种方式适合于控制整个Controller打上这个Attribute以后整个Controller里所有Action都获得了权限控制。 第三种找到App_Start\WebApiConfig.cs在Register方法下加入Filter实例 public static void Register(HttpConfiguration config)
{ config.MapHttpAttributeRoutes(); //注册全局Filterconfig.Filters.Add(new AuthFilterAttribute());config.Routes.MapHttpRoute(name: DefaultApi,routeTemplate: api/{controller}/{id},defaults: new { id RouteParameter.Optional });
} 用这种方式适合于控制所有的API任意Controller和任意Action都接受了这个权限控制。 在大多数场景中每个API的权限验证逻辑都是一样的在这样的前提下使用全局注册Filter的方法最为简单便捷可这样存在一个显而易见的问题如果某几个API是不需要控制的例如登录怎么办我们可以在这样的API上做这样的处理 [AllowAnonymous]public CreateResult PostLogin(LoginEntity entity)
{ //TODO:添加验证逻辑return new CreateResult() {Id 123456};
} 我为这个Action打上了AllowAnonymousAttribute验证逻辑就放过了这个API而不进行权限校验。 在实际的开发中我们可以设计一套类似Session的机制通过用户登录来获取Token在之后的交互HTTP请求中加上Authorization头并带上这个Token并在自定义的AuthFilterAttribute中对Token进行验证一套标准的Token验证流程就可以实现了。 接下来我们介绍ActionFilter: ActionFilterAttrubute提供了两个方法进行拦截OnActionExecuting和OnActionExecuted他们都提供了同步和异步的方法。 OnActionExecuting方法在Action执行之前执行OnActionExecuted方法在Action执行完成之后执行。 我们来看一个应用场景使用过MVC的同学一定不陌生MVC的模型绑定和模型校验使用起来非常方便定义好Entity之后在需要进行校验的地方可以打上相应的Attribute在Action开始时检查ModelState的IsValid属性如果校验不通过直接返回View前端可以解析并显示未通过校验的原因。而Web API中也继承了这一方便的特性使用起来更加方便 public class CustomActionFilterAttribute : ActionFilterAttribute
{ public override void OnActionExecuting(HttpActionContext actionContext){ if (!actionContext.ModelState.IsValid){actionContext.Response actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);}}
} 这个Filter就提供了模型校验的功能如果未通过模型校验则返回400错误并把相关的错误信息交给调用者。他的使用方法和AuthFilterAttribute一样可以针对Action、Controller、全局使用。我们可以用下面一个例子来验证 代码如下 public class LoginEntity
{[Required(ErrorMessage 缺少用户名)] public string UserName { get; set; }[Required(ErrorMessage 缺少密码)] public string Password { get; set; }
} [AllowAnonymous]
[CustomActionFilter]public CreateResult PostLogin(LoginEntity entity)
{ //TODO:添加验证逻辑return new CreateResult() {Id 123456};
} 当然你也可以根据自己的需要解析ModelState然后用自己的格式将错误信息通过Request.CreateResponse()返回给用户。 OnActionExecuted方法我在实际工作中使用得较少目前仅在一次部分响应数据加密的场景下进行过使用使用方法一样读取已有的响应并加密后再给出加密后的响应赋值给actionContext.Response即可。 我给大家一个Demo: public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{ var key 10; var responseBody await actionExecutedContext.Response.Content.ReadAsByteArrayAsync(); //以Byte数组方式读取Content中的数据for (int i 0; i responseBody.Length; i){responseBody[i] (byte)(responseBody[i] ^ key); //对每一个Byte做异或运算 }actionExecutedContext.Response.Content new ByteArrayContent(responseBody); //将结果赋值给Response的ContentactionExecutedContext.Response.Content.Headers.ContentType MediaTypeHeaderValue.Parse(Encrypt/Bytes); //并修改Content-Type} 通过这个方法我们将响应的Content每个Byte都做了一个异或运算对响应内容进行了一次简单的加密大家可以根据自己的需要进行更可靠的加密如AES、DES或者RSA…通过这个方法可以灵活地对某个Action的处理后的结果进行处理通过Filter进行响应内容加密有很强的灵活性和通用性他能获取当前Action的很多信息然后根据这些信息选择加密的方式、获取加密所需的参数等等。如果加密所使用参数对当前执行的Action没有依赖也可以采取HttpMessageHandler来进行处理在之后的教程中我会进行介绍。 最后一个FilterExceptionFilter 顾名思义这个Filter是用来进行异常处理的当业务发生未处理的异常我们是不希望用户接收到黄页或者其他用户无法解析的信息的我们可以使用ExceptionFilter来进行统一处理 public class ExceptionFilter : ExceptionFilterAttribute
{ public override void OnException(HttpActionExecutedContext actionExecutedContext){ //如果截获异常为我们自定义可以处理的异常则通过我们自己的规则处理if (actionExecutedContext.Exception is DemoException){ //TODO:记录日志actionExecutedContext.Response actionExecutedContext.Request.CreateResponse(HttpStatusCode.BadRequest, new {Message actionExecutedContext.Exception.Message});} else{ //如果截获异常是我没无法预料的异常则将通用的返回信息返回给用户避免泄露过多信息也便于用户处理 //TODO:记录日志actionExecutedContext.Response actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, new {Message 服务器被外星人拐跑了});}}
} 我们定义了一个ExceptoinFilter用于处理未捕获的异常我们将异常分为两类一类是我们可以预料的异常如业务参数错误越权等业务异常还有一类是我们无法预料的异常如数据库连接断开、内存溢出等异常。我们通过HTTP Code告知调用者以及用相对固定、友好的数据结构将异常信息告诉调用者以便于调用者记录并处理这样的异常。 [CustomerExceptionFilter]public class TestController : ApiController
{ public int Get(int a, int b){ if (a b){ throw new DemoException(A必须要比B大);} if (a b){ throw new NotImplementedException();} return a*b;}
} 我们定义了一个Action在不同的情况下会抛出不同的异常其中一个异常是我们能够预料并认为是调用者传参出错的一个是不能够处理的我们看一下结果 在这样的RestApi中我们可以预先定义好异常的表现形式让调用者可以方便地判断什么情况下是出现异常了然后通过较为统一的异常信息返回方式让调用者方便地解析异常信息形成统一方便的异常消息处理机制。 但是ExceptionFilter只能在成功完成了Controller的初始化以后才能起到捕获、处理异常的作用而在Controller初始化完成之前例如在Controller的构造函数中出现了异常则ExceptionFilter无能为力。对此WebApi引入了ExceptionLogger和ExceptionHandler处理机制我们将在之后的文章中进行讲解。 二、Filter的执行顺序 在使用MVC的时候ActionFilter提供了一个Order属性用户可以根据这个属性控制Filter的调用顺序而Web API却不再支持该属性。Web API的Filter有自己的一套调用顺序规则 所有Filter根据注册位置的不同拥有三种作用域Global、Controller、Action 通过HttpConfiguration类实例下Filters.Add()方法注册的Filter一般在App_Start\WebApiConfig.cs文件中的Register方法中设置就属于Global作用域 通过Controller上打的Attribute进行注册的Filter就属于Controller作用域 通过Action上打的Attribute进行注册的Filter就属于Action作用域 他们遵循了以下规则 1、在同一作用域下AuthorizationFilter最先执行之后执行ActionFilter 2、对于AuthorizationFilter和ActionFilter.OnActionExcuting来说如果一个请求的生命周期中有多个Filter的话执行顺序都是Global-Controller-Action 3、对于ActionFilterOnActionExecuting总是先于OnActionExecuted执行 4、对于ExceptionFilter和ActionFilter.OnActionExcuted而言执行顺序为Action-Controller-Global 5、对于所有Filter来说如果阻止了请求:即对Response进行了赋值则后续的Filter不再执行。 关于默认情况下的Filter相关知识我们就讲这么一些如果在文章中有任何不正确的地方或者疑问欢迎大家为我指出。 相关文章 WebAPI前置知识:HTTP与RestfulAPIWEB API系列一WEB API的适用场景、第一个实例ASP.NET Web API 安全筛选器Web API 基于ASP.NET Identity的Basic AuthenticationASP.NET Web Api使用CacheCow和ETag缓存资源使用 West Wind WebSurge 对 ASP.NET Web API 服务进行压力测试Web API应用支持HTTPS的经验总结Dion Hinchcliffe谈Web API的过去与未来 原文地址http://www.cnblogs.com/UliiAn/p/5402146.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注