Home  >  Article  >  Backend Development  >  The use and execution sequence of Filter in Asp.Net WebAPI (Favorite)

The use and execution sequence of Filter in Asp.Net WebAPI (Favorite)

PHPz
PHPzOriginal
2018-05-14 15:39:584301browse

In WEB Api, the idea of ​​aspect-oriented programming (AOP) is introduced, and specific filters can be inserted in certain locations for process interception processing. The introduction of this mechanism can better implement the DRY (Don't Repeat Yourself) idea. Through Filter, some common logic can be processed uniformly, such as: permission verification, parameter encryption and decryption, parameter verification, etc. We all This feature can be used for unified processing. Today we will introduce the development and use of Filter and discuss their execution sequence.

1. Development and calling of Filter

In the default WebApi, the framework provides three types of Filters. Their functions and operating conditions are as shown in the following table:

##ActionRun when an exception occurs

##Filter Type

##Implemented interface

##Description

Authorization

##IAuthorizationFilter

The first
Filter

is used to request permission verification

##IActionFilter

at

Action
Before and after running

##Exception

IExceptionFilter

First, we implement an AuthorizatoinFilter that can be used for simple permission control:

       
             (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute> verifyResult = actionContext.Request.Headers.Authorization!= &&  == ; 

             (!= HttpError(

A simple Filter for user authentication has been developed. This Filter requires the user's request to contain the Authorization header and parameters. It is 123456. If it passes, it will be released. If it does not pass, it will return a 401 error and prompt that the Token is incorrect in the Content. Next, we need to register this Filter. There are three ways to register a Filter:

The first one: put the AuthFilterAttribute on the Action we want to control permissions:

    public class PersonController : ApiController
    {
        [AuthFilter]        public CreateResult Post(CreateUser user)
        {            return new CreateResult() {Id = "123"};
        }
    }

This method is suitable for a single Action permission control.

The second method is to find the corresponding Controller and add this Attribute:

    [AuthFilter]    public class PersonController : ApiController
    {        public CreateResult Post(CreateUser user)
        {            return new CreateResult() {Id = "123"};
        }
    }

This method is suitable for controlling the entire Controller. After adding this Attribute, all Actions in the entire Controller will have permissions. control.

The third method is to find App_Start\WebApiConfig.cs and add a Filter instance under the Register method:

   { id =

This method is suitable for controlling all APIs. Any Controller and any Action are accepted. This permission control.

In most scenarios, the permission verification logic of each API is the same. Under this premise, it is the simplest and most convenient method to use global registration of Filter. However, there is an obvious problem: if certain users What should I do if an API does not require control (such as login)? We can do this on such an API:

[AllowAnonymous]public CreateResult PostLogin(LoginEntity entity)
{      //TODO:添加验证逻辑
      return new CreateResult() {Id = "123456"};
}

I marked AllowAnonymousAttribute for this Action, and the verification logic ignored this API without performing permission verification.

In actual development, we can design a mechanism similar to Session to obtain Token through user login, add the Authorization header and bring this Token in subsequent interactive HTTP requests, and customize To verify the Token in the AuthFilterAttribute, a standard Token verification process can be implemented.

Next we introduce ActionFilter:

ActionFilterAttrubute provides two methods for interception: OnActionExecuting and OnActionExecuted, both of which provide synchronous and asynchronous methods.

The OnActionExecuting method is executed before the Action is executed, and the OnActionExecuted method is executed after the Action is executed.

Let’s look at an application scenario: Students who have used MVC must be familiar with MVC’s model binding and model verification. It is very convenient to use. After defining the Entity, you can mark it where verification is required. For the corresponding Attribute, check the IsValid attribute of ModelState when the Action starts. If the verification fails, the View is returned directly. The front end can parse and display the reason for the failure of verification. The Web API also inherits this convenient feature, making it more convenient to use:

 public class CustomActionFilterAttribute : ActionFilterAttribute
{    public override void OnActionExecuting(HttpActionContext actionContext)
    {        if (!actionContext.ModelState.IsValid)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest,  actionContext.ModelState);
        }
    }
}

This Filter provides the function of model verification. If the model verification is not passed, a 400 error will be returned, and the relevant error message to the caller. Its usage is the same as AuthFilterAttribute, and can be used for Action, Controller, and globally. We can use the following example to verify:

The code is as follows:

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"};
}

Of course, you can also follow You need to parse the ModelState and then return the error message to the user through Request.CreateResponse() in your own format.

I have rarely used the OnActionExecuted method in actual work. Currently, it has only been used in a scenario where partial response data is encrypted. The usage method is the same, reading the existing response, encrypting it and then giving it. Just assign the encrypted response to actionContext.Response.

I will give you a 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的Content
        actionExecutedContext.Response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("Encrypt/Bytes"); //并修改Content-Type}

Through this method, we perform an XOR operation on each Byte of the response Content, and then perform an XOR operation on the response content. After a simple encryption, you can perform more reliable encryption according to your own needs, such as AES, DES or RSA... Through this method, you can flexibly process the results of an Action and encrypt the response content through Filter. It has strong flexibility and versatility. It can obtain a lot of information about the current Action, and then select the encryption method based on this information, obtain the parameters required for encryption, and so on. If the parameters used for encryption have no dependence on the currently executed Action, you can also use HttpMessageHandler for processing, which I will introduce in a subsequent tutorial.

The last Filter: ExceptionFilter

顾名思义,这个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、对于ActionFilter,OnActionExecuting总是先于OnActionExecuted执行;

4、对于ExceptionFilter和ActionFilter.OnActionExcuted而言执行顺序为Action->Controller->Global;

5、对于所有Filter来说,如果阻止了请求:即对Response进行了赋值,则后续的Filter不再执行。

关于默认情况下的Filter相关知识我们就讲这么一些,如果在文章中有任何不正确的地方或者疑问,欢迎大家为我指出。

The above is the detailed content of The use and execution sequence of Filter in Asp.Net WebAPI (Favorite). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:Asp.net (3) Web displayNext article:Asp.net (3) Web display