2023年6月20日发(作者:)

利⽤过滤器Filter和特性Attribute实现对WebAPI返回结果的封装和统⼀异常处理在我们开发Web API应⽤的时候,我们可以借鉴ABP框架的过滤器Filter和特性Attribute的应⽤,实现对Web API返回结果的封装和统⼀异常处理,本篇随笔介绍利⽤AuthorizeAttribute实现Web API⾝份认证,利⽤ActionFilterAttribute实现对常规Web API返回结果进⾏统⼀格式的封装,利⽤ExceptionFilterAttribute实现对接⼝异常的统⼀处理,实现我们Web API常⽤到的⼏个通⽤处理过程。1、的Web API过滤器介绍过滤器主要有这么⼏种:AuthorizationFilterAttribute 权限验证、ActionFilterAttribute ⽇志参数验证等、ExceptionFilterAttribute 异常处理捕获。ActionFilter 主要实现执⾏请求⽅法体之前(覆盖基类⽅法OnActionExecuting),和之后的事件处理(覆盖基类⽅法OnActionExecuted);ExceptionFilter主要实现触发异常⽅法(覆盖基类⽅法OnException)。ActionFilterAttrubute提供了两个⽅法进⾏拦截:OnActionExecuting和OnActionExecuted,他们都提供了同步和异步的⽅法。OnActionExecuting⽅法在Action执⾏之前执⾏,OnActionExecuted⽅法在Action执⾏完成之后执⾏。在使⽤MVC的时候,ActionFilter提供了⼀个Order属性,⽤户可以根据这个属性控制Filter的调⽤顺序,⽽Web API却不再⽀持该属性。Web API的Filter有⾃⼰的⼀套调⽤顺序规则:所有Filter根据注册位置的不同拥有三种作⽤域:Global、Controller、Action:通过HttpConfiguration类实例下()⽅法注册的Filter(⼀般在App_⽂件中的Register⽅法中设置)就属于Global作⽤域;通过Controller上打的Attribute进⾏注册的Filter就属于Controller作⽤域;通过Action上打的Attribute进⾏注册的Filter就属于Action作⽤域;他们遵循了以下规则:在同⼀作⽤域下,AuthorizationFilter最先执⾏,之后执⾏ActionFilter对于AuthorizationFilter和onExcuting来说,如果⼀个请求的⽣命周期中有多个Filter的话,执⾏顺序都是Global->Controller->Action;对于ActionFilter,OnActionExecuting总是先于OnActionExecuted执⾏;对于ExceptionFilter和onExcuted⽽⾔执⾏顺序为Action->Controller->Global;对于所有Filter来说,如果阻⽌了请求:即对Response进⾏了赋值,则后续的Filter不再执⾏。另外,值得注意的是,由于Web API的过滤器⽆法改变其顺序,那么它是按照 AuthorizationFilterAttribute -> ActionFilterAttribute -> ExceptionFilterAttribute 这个执⾏顺序来处理的,也就是说授权过滤器执⾏在前⾯,再次到⾃定义的ActionFilter,最后才是异常的过滤器处理。

2、Web API的⾝份授权过滤器处理我们通过AuthorizationFilterAttribute 过滤器来处理⽤户Web API接⼝⾝份,⽐每次在代码上进⾏验证省事很多。⼀般情况下,我们只要定义类继承于AuthorizeAttribute即可,由于AuthorizeAttribute是继承于AuthorizationFilterAttribute,如下所⽰。 ///

/// 验证Web Api接⼝⽤户⾝份 /// public class ApiAuthorizeAttribute : AuthorizeAttribute { ........... } ⽽⼀般情况下,我们只需要重写bool IsAuthorized(HttpActionContext actionContext) ⽅法,实现授权处理逻辑即可。 我们在CheckToken的主要逻辑⾥⾯,主要对token令牌进⾏反向解析,并判断⽤户⾝份是否符合,如果不符合抛出异常,就会切换到异常处理器⾥⾯了。 然后在Web API控制器中,需要授权访问的Api控制器定义即可,我们可以把它放到基类⾥⾯声明这个过滤器特性。 那么所有Api接⼝的访问,都会检查⽤户的⾝份了。

2、⾃定义过滤器特性ActionFilterAttribute 的处理这个ActionFilterAttribute 主要⽤于拦截⽤户访问控制器⽅法的处理过程,前⾯说到,OnActionExecuting⽅法在Action执⾏之前执⾏,OnActionExecuted⽅法在Action执⾏完成之后执⾏。那么我们可以利⽤它进⾏函数AOP的处理了,也就是在执⾏前,执⾏后进⾏⽇志记录等,还有就是常规的参数检查、结果封装等,都可以在这个⾃定义过滤器中实现。我们定义⼀个类WrapResultAttribute来标记封装结果,定义⼀个类DontWrapResultAttribute来标记不封装结果。 ///

/// ⽤于判断Web API需要包装返回结果. /// [AttributeUsage( | ace | )] public class WrapResultAttribute : ActionFilterAttribute{} /// /// ⽤于判断Web API不需要包装返回结果. /// [AttributeUsage( | ace | )] public class DontWrapResultAttribute : WrapResultAttribute{}这个处理⽅式是借⽤ABP框架中这两个特性的处理逻辑。利⽤,对于获取⽤户⾝份令牌的基础操作接⼝,我们可以不封装返回结果,如下标记所⽰。 那么执⾏后,返回的结果如下所⽰,就是正常的TokenResult对象的JSON信息{ "access_token": "3MiOiIxIiwiaWF0IjoxNjE3MjY0MDQ4LCJqdGkiOiI0NTBjZmY3OC01OTEwLTQwYzUtYmJjMC01OTQ0YzNjMjhjNTUiLCJuYW1lIjoiYWRtaW4iLCJjb3JwaWQiOiI2IiwiY2hhbm5lb "expires_in": 604800}如果取消这个DontWrapResult的标记,那么它就继承基类BaseApiController的WrapResult的标记定义了。 /// /// 所有接⼝基类 /// [ExceptionHandling] [WrapResult] public class BaseApiController : ApiController那么接⼝定义不变,但是返回的okenResult对象的JSON信息已经经过包装了。{ "result": { "access_token": "3MiOiIxIiwiaWF0IjoxNjE3MjY0NDQ5LCJqdGkiOiJmZTAzYzhlNi03NGVjLTRjNmEtYmMyZi01NTU3MjFiOTM1NDEiLCJuYW1lIjoiYWRtaW4iLCJjb3JwaWQiOiI2IiwiY2hhbm5l "expires_in": 604800 }, "targetUrl": null, "success": true, "error": null, "unAuthorizedRequest": false, "__api": true}这个JSON格式是我们⼀个通⽤的接⼝返回,其中Result⾥⾯定义了返回的信息,⽽Error⾥⾯则定义⼀些错误信息(如果有错误的话),⽽success则⽤于判断是否执⾏成功,如果有错误异常信息,那么success返回为false。这个通⽤返回的定义,是依照ABP框架的返回格式进⾏调整的,可以作为我们普通Web API的⼀个通⽤返回结果的处理。前⾯提到过ActionFilterAttribute⾃定义处理过程,在控制器⽅法完成后,我们对返回的结果进⾏进⼀步的封装处理即可。我们需要重写逻辑实现OnActionExecuted的函数 在做包装返回结果之前,我们需要判断是否⽅法或者控制器设置了不包装的标记DontWrapResultAttribute。 public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { //如果有异常,则退出交给Exception的通⽤处理 if (ion != null) return; //正常完成,那么判断是否需要包装结果输出,如果不需要则返回 var dontWrap = false; var actionContext = Context; if (Descriptor is ReflectedHttpActionDescriptor actionDesc) { //判断⽅法是否包含DontWrapResultAttribute dontWrap = tomAttributes(inherit: false) .Any(a => e().Equals(typeof(DontWrapResultAttribute))); if (dontWrap) return; } if (llerDescriptor is HttpControllerDescriptor controllerDesc) { //判断控制器是否包含DontWrapResultAttribute dontWrap = tomAttributes(inherit: true) .Any(a => e().Equals(typeof(DontWrapResultAttribute))); if (dontWrap) return; }上述代码也就是如果找到⽅法或者控制器有定义DontWrapResultAttribute的,就不要包装结果,否则下⼀步就是对结果进⾏封装了 //需要包装,那么就包装输出结果 AjaxResponse result = new AjaxResponse(); // 状态代码 var statusCode = Code; // 读取返回的内容 var content = Async().Result; // 请求是否成功 s = essStatusCode; // 重新封装回传格式 se = new HttpResponseMessage(statusCode) { Content = new ObjectContent( new AjaxResponse(content), matter()) };其中AjaxResponse是参考ABP框架⾥⾯返回结果的类定义处理的。 public abstract class AjaxResponseBase { public string TargetUrl { get; set; } public bool Success { get; set; } public ErrorInfo Error { get; set; } public bool UnAuthorizedRequest { get; set; } public bool __api { get; } = true; } [Serializable] public class AjaxResponse : AjaxResponseBase { public TResult Result { get; set; } }

3、异常处理过滤器ExceptionFilterAttribute

前⾯介绍到,Web API的过滤器⽆法改变其顺序,它是按照 AuthorizationFilterAttribute -> ActionFilterAttribute -> ExceptionFilterAttribute 这个执⾏顺序来处理的,也就是说授权过滤器执⾏在前⾯,再次到⾃定义的ActionFilter,最后才是异常的过滤器处理。异常处理过滤器,我们定义后,可以统⼀处理和封装异常信息,⽽我们只需要实现OnException的⽅法即可。 ///

/// ⾃定义异常处理 /// public class ExceptionHandlingAttribute : ExceptionFilterAttribute { /// /// 统⼀对调⽤异常信息进⾏处理,返回⾃定义的异常信息 /// /// HTTP上下⽂对象 public override void OnException(HttpActionExecutedContext context) { } }完整的处理过程代码如下所⽰。 /// /// ⾃定义异常处理 /// public class ExceptionHandlingAttribute : ExceptionFilterAttribute { /// /// 统⼀对调⽤异常信息进⾏处理,返回⾃定义的异常信息 /// /// HTTP上下⽂对象 public override void OnException(HttpActionExecutedContext context) { //获取⽅法或控制器对应的WrapResultAttribute属性 var actionDescriptor = Descriptor; var wrapResult = tomAttributes(inherit: true).FirstOrDefault() tomAttributes(inherit: true).FirstOrDefault(); //如设置,记录异常信息 if (wrapResult != null && or) { (ion); } var statusCode = GetStatusCode(context, Error); if (!Error) { se = new HttpResponseMessage(statusCode) {

Content = new StringContent(()) }; ion = null; //Handled! return; } //使⽤AjaxResponse包装结果 var content = new ErrorInfo(e/*, race*/); var isAuth = ion is AuthorizationException; se = new HttpResponseMessage(statusCode) { Content = new ObjectContent( new AjaxResponse(content, isAuth), matter()) }; ion = null; //Handled! }这样我们在BaseApiController⾥⾯声明即可。 这样,⼀旦程序处理过程中,有错误抛出,都会统⼀到这⾥进⾏处理,有异常的返回JSON如下所⽰。

本篇随笔介绍利⽤AuthorizeAttribute实现Web API⾝份认证,利⽤ActionFilterAttribute实现对常规Web API返回结果进⾏统⼀格式的封装,利⽤ExceptionFilterAttribute实现对接⼝异常的统⼀处理,实现我们Web API常⽤到的⼏个通⽤处理过程。

2023年6月20日发(作者:)

利⽤过滤器Filter和特性Attribute实现对WebAPI返回结果的封装和统⼀异常处理在我们开发Web API应⽤的时候,我们可以借鉴ABP框架的过滤器Filter和特性Attribute的应⽤,实现对Web API返回结果的封装和统⼀异常处理,本篇随笔介绍利⽤AuthorizeAttribute实现Web API⾝份认证,利⽤ActionFilterAttribute实现对常规Web API返回结果进⾏统⼀格式的封装,利⽤ExceptionFilterAttribute实现对接⼝异常的统⼀处理,实现我们Web API常⽤到的⼏个通⽤处理过程。1、的Web API过滤器介绍过滤器主要有这么⼏种:AuthorizationFilterAttribute 权限验证、ActionFilterAttribute ⽇志参数验证等、ExceptionFilterAttribute 异常处理捕获。ActionFilter 主要实现执⾏请求⽅法体之前(覆盖基类⽅法OnActionExecuting),和之后的事件处理(覆盖基类⽅法OnActionExecuted);ExceptionFilter主要实现触发异常⽅法(覆盖基类⽅法OnException)。ActionFilterAttrubute提供了两个⽅法进⾏拦截:OnActionExecuting和OnActionExecuted,他们都提供了同步和异步的⽅法。OnActionExecuting⽅法在Action执⾏之前执⾏,OnActionExecuted⽅法在Action执⾏完成之后执⾏。在使⽤MVC的时候,ActionFilter提供了⼀个Order属性,⽤户可以根据这个属性控制Filter的调⽤顺序,⽽Web API却不再⽀持该属性。Web API的Filter有⾃⼰的⼀套调⽤顺序规则:所有Filter根据注册位置的不同拥有三种作⽤域:Global、Controller、Action:通过HttpConfiguration类实例下()⽅法注册的Filter(⼀般在App_⽂件中的Register⽅法中设置)就属于Global作⽤域;通过Controller上打的Attribute进⾏注册的Filter就属于Controller作⽤域;通过Action上打的Attribute进⾏注册的Filter就属于Action作⽤域;他们遵循了以下规则:在同⼀作⽤域下,AuthorizationFilter最先执⾏,之后执⾏ActionFilter对于AuthorizationFilter和onExcuting来说,如果⼀个请求的⽣命周期中有多个Filter的话,执⾏顺序都是Global->Controller->Action;对于ActionFilter,OnActionExecuting总是先于OnActionExecuted执⾏;对于ExceptionFilter和onExcuted⽽⾔执⾏顺序为Action->Controller->Global;对于所有Filter来说,如果阻⽌了请求:即对Response进⾏了赋值,则后续的Filter不再执⾏。另外,值得注意的是,由于Web API的过滤器⽆法改变其顺序,那么它是按照 AuthorizationFilterAttribute -> ActionFilterAttribute -> ExceptionFilterAttribute 这个执⾏顺序来处理的,也就是说授权过滤器执⾏在前⾯,再次到⾃定义的ActionFilter,最后才是异常的过滤器处理。

2、Web API的⾝份授权过滤器处理我们通过AuthorizationFilterAttribute 过滤器来处理⽤户Web API接⼝⾝份,⽐每次在代码上进⾏验证省事很多。⼀般情况下,我们只要定义类继承于AuthorizeAttribute即可,由于AuthorizeAttribute是继承于AuthorizationFilterAttribute,如下所⽰。 ///

/// 验证Web Api接⼝⽤户⾝份 /// public class ApiAuthorizeAttribute : AuthorizeAttribute { ........... } ⽽⼀般情况下,我们只需要重写bool IsAuthorized(HttpActionContext actionContext) ⽅法,实现授权处理逻辑即可。 我们在CheckToken的主要逻辑⾥⾯,主要对token令牌进⾏反向解析,并判断⽤户⾝份是否符合,如果不符合抛出异常,就会切换到异常处理器⾥⾯了。 然后在Web API控制器中,需要授权访问的Api控制器定义即可,我们可以把它放到基类⾥⾯声明这个过滤器特性。 那么所有Api接⼝的访问,都会检查⽤户的⾝份了。

2、⾃定义过滤器特性ActionFilterAttribute 的处理这个ActionFilterAttribute 主要⽤于拦截⽤户访问控制器⽅法的处理过程,前⾯说到,OnActionExecuting⽅法在Action执⾏之前执⾏,OnActionExecuted⽅法在Action执⾏完成之后执⾏。那么我们可以利⽤它进⾏函数AOP的处理了,也就是在执⾏前,执⾏后进⾏⽇志记录等,还有就是常规的参数检查、结果封装等,都可以在这个⾃定义过滤器中实现。我们定义⼀个类WrapResultAttribute来标记封装结果,定义⼀个类DontWrapResultAttribute来标记不封装结果。 ///

/// ⽤于判断Web API需要包装返回结果. /// [AttributeUsage( | ace | )] public class WrapResultAttribute : ActionFilterAttribute{} /// /// ⽤于判断Web API不需要包装返回结果. /// [AttributeUsage( | ace | )] public class DontWrapResultAttribute : WrapResultAttribute{}这个处理⽅式是借⽤ABP框架中这两个特性的处理逻辑。利⽤,对于获取⽤户⾝份令牌的基础操作接⼝,我们可以不封装返回结果,如下标记所⽰。 那么执⾏后,返回的结果如下所⽰,就是正常的TokenResult对象的JSON信息{ "access_token": "3MiOiIxIiwiaWF0IjoxNjE3MjY0MDQ4LCJqdGkiOiI0NTBjZmY3OC01OTEwLTQwYzUtYmJjMC01OTQ0YzNjMjhjNTUiLCJuYW1lIjoiYWRtaW4iLCJjb3JwaWQiOiI2IiwiY2hhbm5lb "expires_in": 604800}如果取消这个DontWrapResult的标记,那么它就继承基类BaseApiController的WrapResult的标记定义了。 /// /// 所有接⼝基类 /// [ExceptionHandling] [WrapResult] public class BaseApiController : ApiController那么接⼝定义不变,但是返回的okenResult对象的JSON信息已经经过包装了。{ "result": { "access_token": "3MiOiIxIiwiaWF0IjoxNjE3MjY0NDQ5LCJqdGkiOiJmZTAzYzhlNi03NGVjLTRjNmEtYmMyZi01NTU3MjFiOTM1NDEiLCJuYW1lIjoiYWRtaW4iLCJjb3JwaWQiOiI2IiwiY2hhbm5l "expires_in": 604800 }, "targetUrl": null, "success": true, "error": null, "unAuthorizedRequest": false, "__api": true}这个JSON格式是我们⼀个通⽤的接⼝返回,其中Result⾥⾯定义了返回的信息,⽽Error⾥⾯则定义⼀些错误信息(如果有错误的话),⽽success则⽤于判断是否执⾏成功,如果有错误异常信息,那么success返回为false。这个通⽤返回的定义,是依照ABP框架的返回格式进⾏调整的,可以作为我们普通Web API的⼀个通⽤返回结果的处理。前⾯提到过ActionFilterAttribute⾃定义处理过程,在控制器⽅法完成后,我们对返回的结果进⾏进⼀步的封装处理即可。我们需要重写逻辑实现OnActionExecuted的函数 在做包装返回结果之前,我们需要判断是否⽅法或者控制器设置了不包装的标记DontWrapResultAttribute。 public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { //如果有异常,则退出交给Exception的通⽤处理 if (ion != null) return; //正常完成,那么判断是否需要包装结果输出,如果不需要则返回 var dontWrap = false; var actionContext = Context; if (Descriptor is ReflectedHttpActionDescriptor actionDesc) { //判断⽅法是否包含DontWrapResultAttribute dontWrap = tomAttributes(inherit: false) .Any(a => e().Equals(typeof(DontWrapResultAttribute))); if (dontWrap) return; } if (llerDescriptor is HttpControllerDescriptor controllerDesc) { //判断控制器是否包含DontWrapResultAttribute dontWrap = tomAttributes(inherit: true) .Any(a => e().Equals(typeof(DontWrapResultAttribute))); if (dontWrap) return; }上述代码也就是如果找到⽅法或者控制器有定义DontWrapResultAttribute的,就不要包装结果,否则下⼀步就是对结果进⾏封装了 //需要包装,那么就包装输出结果 AjaxResponse result = new AjaxResponse(); // 状态代码 var statusCode = Code; // 读取返回的内容 var content = Async().Result; // 请求是否成功 s = essStatusCode; // 重新封装回传格式 se = new HttpResponseMessage(statusCode) { Content = new ObjectContent( new AjaxResponse(content), matter()) };其中AjaxResponse是参考ABP框架⾥⾯返回结果的类定义处理的。 public abstract class AjaxResponseBase { public string TargetUrl { get; set; } public bool Success { get; set; } public ErrorInfo Error { get; set; } public bool UnAuthorizedRequest { get; set; } public bool __api { get; } = true; } [Serializable] public class AjaxResponse : AjaxResponseBase { public TResult Result { get; set; } }

3、异常处理过滤器ExceptionFilterAttribute

前⾯介绍到,Web API的过滤器⽆法改变其顺序,它是按照 AuthorizationFilterAttribute -> ActionFilterAttribute -> ExceptionFilterAttribute 这个执⾏顺序来处理的,也就是说授权过滤器执⾏在前⾯,再次到⾃定义的ActionFilter,最后才是异常的过滤器处理。异常处理过滤器,我们定义后,可以统⼀处理和封装异常信息,⽽我们只需要实现OnException的⽅法即可。 ///

/// ⾃定义异常处理 /// public class ExceptionHandlingAttribute : ExceptionFilterAttribute { /// /// 统⼀对调⽤异常信息进⾏处理,返回⾃定义的异常信息 /// /// HTTP上下⽂对象 public override void OnException(HttpActionExecutedContext context) { } }完整的处理过程代码如下所⽰。 /// /// ⾃定义异常处理 /// public class ExceptionHandlingAttribute : ExceptionFilterAttribute { /// /// 统⼀对调⽤异常信息进⾏处理,返回⾃定义的异常信息 /// /// HTTP上下⽂对象 public override void OnException(HttpActionExecutedContext context) { //获取⽅法或控制器对应的WrapResultAttribute属性 var actionDescriptor = Descriptor; var wrapResult = tomAttributes(inherit: true).FirstOrDefault() tomAttributes(inherit: true).FirstOrDefault(); //如设置,记录异常信息 if (wrapResult != null && or) { (ion); } var statusCode = GetStatusCode(context, Error); if (!Error) { se = new HttpResponseMessage(statusCode) {

Content = new StringContent(()) }; ion = null; //Handled! return; } //使⽤AjaxResponse包装结果 var content = new ErrorInfo(e/*, race*/); var isAuth = ion is AuthorizationException; se = new HttpResponseMessage(statusCode) { Content = new ObjectContent( new AjaxResponse(content, isAuth), matter()) }; ion = null; //Handled! }这样我们在BaseApiController⾥⾯声明即可。 这样,⼀旦程序处理过程中,有错误抛出,都会统⼀到这⾥进⾏处理,有异常的返回JSON如下所⽰。

本篇随笔介绍利⽤AuthorizeAttribute实现Web API⾝份认证,利⽤ActionFilterAttribute实现对常规Web API返回结果进⾏统⼀格式的封装,利⽤ExceptionFilterAttribute实现对接⼝异常的统⼀处理,实现我们Web API常⽤到的⼏个通⽤处理过程。

本文发布于:2023-06-20,感谢您对本站的认可!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:authorizeattribute

发布评论

评论列表(有0条评论)
    拓祥电子编程网

    拓祥电子编程网

    拓祥电子编程提供编程程序员技术分享技术,经验代码。