The use of filter filters in ASP. NET Webapi and the order of execution

Source: Internet
Author: User

Forwarded from: http://www.cnblogs.com/UliiAn/p/5402146.html

In the Web API, the idea of aspect-oriented programming (AOP) is introduced, in which specific filter can be inserted for process interception processing. The introduction of this mechanism can better practice the dry (Don ' t Repeat yourself) thought, through the filter can be unified to some common logic processing, such as: Permission check, parameter and decryption, parameter verification, etc. we can use this feature for unified processing, Today we present the development, use, and discussion of the filter's execution sequence.

Development and invocation of filter

In the default WEBAPI, the framework provides three filters, and their functionality and operating conditions are shown in the following table:

Filter Type the implemented interface Description
Authorization Iauthorizationfilter The first filter to run is used as the request permission check
Action Iactionfilter Run before and after the action is run
Exception Iexceptionfilter Run when an exception occurs

First, we implement a authorizatoinfilter that can be used for simple permission control:

PublicClassAuthfilterattribute:Authorizationfilterattribute {PublicOverridevoidOnauthorization (Httpactioncontext Actioncontext) {//if the user is in the position of the action with Allowanonymousattribute, do not authorize authentication if ( Actioncontext.actiondescriptor.getcustomattributes<allowanonymousattribute> (). Any ()) {return;} var Verifyresult = actioncontext.request.headers.authorization!= null && //request requires a authorization header ActionContext.Request.Headers.Authorization.Parameter = =  "123456"; //and authorization parameter is 123456 verified via if (!verifyresult) {//if the validation does not pass, a 401 error is returned, and the reason for writing the error in body is Actioncontext.response = ActionContext.Request.CreateErrorResponse (Httpstatuscode.unauthorized,new httperror (  "Token incorrect")); } } }

A simple filter for user authentication has been developed, this filter requires the user's request with the authorization header and the parameter is 123456, if passed, pass through, return 401 error, and in the content to prompt token is incorrect.

Below, we need to register this filter, there are three ways to register the filter:

The first: Authfilterattribute this attribute on the action that we want to have permission to control:

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

This approach is appropriate for the permission control of a single action.

Second, find the appropriate controller and hit 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 this attribute, all actions in the controller have access control.

Third, find App_start\webapiconfig.cs and add the filter instance under the Register method:

public static void Register(HttpConfiguration config){     config.MapHttpAttributeRoutes();   //注册全局Filter config.Filters.Add(new AuthFilterAttribute()); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } );}

In this way, it is appropriate to control all the APIs, and any controller and any action accept this permission control.

In most scenarios, the authorization logic for each API is the same, and the easiest and easiest way to use global registration filter is to have an obvious question: what if a few APIs don't need to be controlled (such as login)? We can do this with this API:

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

I have allowanonymousattribute this action, and the validation logic has spared this API without permission checking.

In the actual development, we can design a similar session mechanism, through the user login to obtain token, in the subsequent interactive HTTP request to add authorization head and take this token, Tokens are validated in a custom authfilterattribute, and a standard token verification process can be implemented.

Next we introduce Actionfilter:

Actionfilterattrubute provides two ways to intercept:

    • OnActionExecuting and onactionexecuted, they both provide synchronous and asynchronous methods.
    • The OnActionExecuting method executes before the action executes, and the OnActionExecuted method executes after the action execution completes.

Let's take a look at an application scenario: a classmate who has used MVC is not unfamiliar. MVC model binding and model validation, it is very convenient to use, after the definition of the entity, in need to verify the place can play the corresponding attribute, The IsValid property of the Modelstate is checked at the start of the action, and if the checksum is not returned directly to view, the front end resolves and displays the reason for the failure to pass the checksum. This convenient feature is also inherited in the Web API, which is 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 validation, and returns a 400 error if the model check is not passed, and gives the caller the relevant error information. He uses the same method as Authfilterattribute, which can be used for action, Controller, global use.

We can use one of the following examples to verify:

The code is as follows:

PublicClassloginentity{[Required (errormessage = "Missing user name")] public string UserName { get; set;} [Required (errormessage = "Missing password")] public string Password { get; set;}} [AllowAnonymous] [Customactionfilter] Public Createresult Postlogin (loginentity entity) { //TODO: Add validation logic return new Createresult () {Id = "123456"};}               

Image

Of course, you can also parse modelstate according to your own needs and then return the error message to the user in your own format via Request.createresponse ().

OnActionExecuted method I used in the actual work less, currently only in a partial response to the data encryption scenario is used, using the same method, read the existing response, and encrypt and then give the encrypted response to the actioncontext.response can be assigned.

Let me give you a demo:

PublicOverrideAsync TaskOnactionexecutedasync (Httpactionexecutedcontext ActionExecutedContext, CancellationToken cancellationtoken) {var key = 10; var responsebody = await ActionExecutedContext.Response.Content.ReadAsByteArrayAsync (); //reads data from content in byte array for (0; i < responsebody.length; i++) {Responsebody[i] = (byt e) (Responsebody[i] ^ key); //for each byte do xor or operation} actionExecutedContext.Response.Content = //assigns the result to Response Content ActionExecutedContext.Response.Content.Headers.ContentType = Mediatypeheadervalue.parse ( "encrypt/bytes"); //and modify Content-type}           

In this way we will respond to the content of each byte has made an XOR operation, the response to a simple encryption, you can rely on their own needs for more reliable encryption, such as AES, DES or RSA ... This approach gives you the flexibility to process the processed results of an action, and the flexibility and versatility of responding to content encryption via filter allows him to get a lot of information about the current action, then choose how to encrypt it, get the parameters needed for encryption, and so on. If the parameters used by the encryption are not dependent on the currently executing action, you can also take httpmessagehandler for processing, which I'll cover later in the tutorial.

One last Filter:exceptionfilter.

As the name implies, this filter is used for exception handling, when the business has an unhandled exception, we do not want users to receive the yellow pages or other users cannot parse the information, we can use Exceptionfilter for unified processing:

PublicClassExceptionfilter:exceptionfilterattribute{PublicOverridevoidOnexception (httpactionexecutedcontext ActionExecutedContext) {//if the intercept exception is customized for us, the exception that can be handled is handled by our own rules if ( Actionexecutedcontext.exception is demoexception) {//todo: Log actionexecutedcontext.response = ActionExecutedContext.Request.CreateResponse ( Httpstatuscode.badrequest, new {Message = actionExecutedContext.Exception.Message}); } else {//if the Intercept exception is an exception that I don't anticipate, return the generic return information to the user, avoid revealing too much information, and make it easier for users to handle //todo: Logging actionexecutedcontext.response = ActionExecutedContext.Request.CreateResponse (Httpstatuscode.internalservererror, new {Message =  "The server was abducted by aliens!" "}); } }}

We define a exceptoinfilter to handle uncaught exceptions, and we divide the exceptions into two categories: one is the exception we can anticipate: business exceptions such as business parameter errors, ultra vires, and a class of exceptions that we cannot anticipate: a database connection is broken , memory overflow, and other exceptions. We tell the caller through HTTP code and use a relatively fixed, friendly data structure to inform the caller of the exception, so that the caller can record and handle such an exception.

[customerexceptionfilter]public class testcontroller: ApiController{public int Get ( Span class= "Hljs-params" >int A, int b) {if (A < b) {throw new demoexception ( "A must be bigger than B!" "); } if (a = = b) {throw new NotImplementedException (); } return a*b;}            

We define an action: Different exceptions are thrown in different situations, one of which we can anticipate and think is an error in the caller's argument, one that cannot be handled, and we look at the result:


Image
Image

In such a restapi, we can pre-define the abnormal expression, so that the caller can easily determine what the situation is abnormal, and then through a more uniform return of the exception information to allow the caller to easily parse the exception information, forming a unified and convenient exception message processing mechanism.

= = However, exceptionfilter can only catch and handle exceptions after successfully completing the controller initialization. The exceptionfilter can do nothing until controller initialization is complete, such as when an exception occurs in the Controller's constructor. This webapi introduces the Exceptionlogger and exceptionhandler processing mechanisms, which we will explain in a later article. ==

The execution order of the filter

When using MVC, Actionfilter provides an order property that allows the user to control the order in which the filter is called, while the Web API no longer supports that property. The filter for the WEB API has its own set of call order rules:

All filter has three scopes depending on the registration location: Global, Controller, action:

    • The filter registered by the Filters.add () method under the Httpconfiguration class instance (typically set in the Register method in the App_start\webapiconfig.cs file) belongs to the global scope;

    • The filter that is registered by the attribute that is played by the controller belongs to the controller scope;

    • The filter that is registered by the attribute that is played on the action is the action scope;

They followed the following rules:

    1. Under the same scope, Authorizationfilter is executed first and then executed Actionfilter

    2. For Authorizationfilter and actionfilter.onactionexcuting, if there is more than one filter in the life cycle of a request, the order of execution is global->controller-> Action;

    3. For actionfilter,onactionexecuting is always preceded by onactionexecuted execution;

    4. For Exceptionfilter and actionfilter.onactionexcuted, the order of execution is action->controller->global;

    5. For all filter, if the request is blocked: The response is assigned, the subsequent filter is no longer executed.

The use of filter filters in ASP. NET Webapi and the order of execution

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.