. NET Core middleware registration and pipeline construction (2) ---- use UseMiddleware Extension Method to register the middleware class. netcoremiddleware

Source: Internet
Author: User

. NET Core middleware registration and pipeline construction (2) ---- use UseMiddleware Extension Method to register the middleware class. netcoremiddleware
. NET Core middleware registration and pipeline construction (2) ---- use UseMiddleware Extension Method to register the middleware Class 0x00 why should we introduce the extension method?

Some middleware functions are relatively simple, others are complicated, and dependent on other components. In addition to registering the middleware directly using the Use () method of ApplicationBuilder, you can also Use the extended method UseMiddleware () of ApplicationBuilder to register the middleware. In this case, you can register a type. This method will parse this type through reflection, package it into Func <ReuqestDelegate, RequestDelegate>, and then call the Use () method for registration.

In this case, we intuitively write a middleware by inheriting an abstract class and implementing the method. However, this is not the case with. NET Core. The middleware class uses conventions rather than inheritance constraints. The Convention mentioned here is the original meaning of the Convention. For example, if it is agreed that the middleware class must contain a method called Invoke, it won't work if it is called anything else, and it won't work if there is heavy load. Because the middleware class does not have any inheritance constraints, in the registration process, the method called Invoke is searched through reflection, and then packaged into RequestDelegate. This article is about the conventions for writing a middleware class and the registration of the middleware class.

0x01 A simple example

Let's take a look at the simplest example of a middleware class:

 

As mentioned in the previous article, middleware is essentially a method. This method receives an HttpContext parameter and returns a Task. In the middleware class above, Invoke is the method. In order to be able to call the next middleware, the current middleware also needs to save the reference of the next middleware. This reference is passed through the constructor. If the current middleware does not need to call the later middleware, this reference can be completely left empty. To register this middleware, we can do this:

However, if our middleware is complex and dependent on many other modules, we need to construct the instances of the dependent modules during registration and pass these dependencies in the constructor of the middleware class. This enhances the coupling between middleware and dependency modules. To reduce this coupling and enjoy the convenience of dependency injection, the UseMiddleware <T> extension method is provided to register the middleware class T.

The UseMiddleware extension method finds the Invoke method in the middleware class above, creates an instance of the above class, tries to inject the type to be injected when creating the instance, and then packs the Invoke method as ReuqestDelegate, packaged as Func <RequestDelegate, RequestDelegate>, and then registered to IList <Func <RequestDelegaet, RequestDelegate> through the Use method of ApplicatonBuilder (discussed in the previous article.

From the above SimpleMiddleware, we can see that this class does not show any inheritance relationships. What constraints should we pay attention to when writing a middleware class? We only need to take a look at the UseMiddleware registration middleware process to understand. The following is an analysis of the UseMiddleware () method. If you are not interested in code analysis, you can skip the following conclusions and tests.

0x02 process of registering the middleware class using the Extension Method

Using the UseMiddleware <T> Extension Method to register a middleware class T mainly includes the following key steps:

1. Find the Invoke method of the middleware class. The UseMiddleware method obtains a list of all public and non-static methods of the registered middleware class through reflection, finds the method named Invoke from it, and confirms that the Invoke method is not overloaded, confirm that the Invoke method returns the Task. confirm that the first parameter of the Invoke method is HttpContext. The last two checks are used to encapsulate the Invoke method as RequestDelegate.

2. Select the best constructor. Insert the reference next of the next middleware to the first parameter list passed in from UseMiddleware as the given parameter list.

Then, retrieve all constructors of the middleware class, obtain parameters from the given parameter list in sequence, and match the type with the parameters of the constructor. Select the most matched constructor as the best constructor. If the matching is the same, the preceding constructor prevails (many details matching the best constructor are omitted, and you can check the Code if you are interested ).

It is worth noting that if a parameter P exists in the given parameter list, no matching type is found in the current constructor parameter list, therefore, this constructor cannot be used as the best constructor. That is to say, the parameter list of the selected optimal constructor must be a superset of the given parameter list. As mentioned above, the next middleware next is inserted to the first in the given parameter list. Therefore, the selected optimal constructor parameter must contain the RequestDelegate parameter. If all constructors do not contain RequestDelegate, an exception is thrown.

3. Construct an instance of the middleware class. After finding the optimal constructor, we will use this constructor to construct the middleware class instance. All parameters in the constructor can be found from the given parameter list that match the type and obtained from the given parameter list. If it is not found in the parameter list, try to get it from the dependency injection container. Check whether the default value is not found in the dependency injection container. If the default value is not found, an exception is thrown.

4. after the instance is constructed, if the Invoke method has only one parameter (HttpContext), The Invoke method of this instance will be packaged as RequestDelegate, and then packaged as Func <RequestDelegate, RequestDelegate> and then registered using the Use method. If multiple parameters do not comply with the RequestDelegate constraint, the Invoke is repackaged to conform to RequestDelegate. In the second package, you will try to obtain the dependency in the Invoke parameter from the dependency injection container.

0x03 some conclusions

The following summarizes some of the conventions of the middleware class, mainly based on the understanding of the Code. please correct me if there are errors or errors.

Middleware methods:

1. the middleware method must be called Invoke and public or non-static.

2. The first parameter of the Invoke method must be of the HttpContext type.

3. The Invoke method must return a Task.

4. The Invoke method can have multiple parameters. Other parameters except HttpContext are obtained from the dependency injection container.

5. The Invoke method cannot be overloaded.

 

Constructor:

1. the constructor must contain the RequestDelegate parameter, which is passed into the next middleware.

2. The RequestDelegate parameter in the constructor parameter must not be placed in the first one, but can be any position.

3. the constructor can have multiple parameters. parameters are first retrieved from the given parameter list, and then from the dependency injection container. If the constructor fails to obtain the default value, if both of them fail, an exception is thrown.

4. the constructor can have multiple constructor types. Then, the highest matching degree is selected based on the constructor parameter list and the given parameter list.

 

Personal suggestions are only personal suggestions:

1. Only one constructor is retained except in special cases to save extra constructor matching checks.

2. Inject the required dependencies into the constructor instead of the Invoke.

3. put RequestDelegate In the first parameter order of the constructor, followed by the parameters given in the UseMiddleware method, and the parameter order in the constructor should be the same as the order in the given parameter list; then there are the parameters to be injected, and finally the parameters with default values. The above sequence is not required except that the default values must be placed at the end. However, the sequence above is clear and minimizes the overhead of instance creation.

4. The Invoke method retains only one HttpContext parameter. This saves the trouble of secondary packaging for the Invoke method.

5. Expand ApplicationBuilder to create more semantic methods instead of Use/UseMiddleware, such as UseMVC and UseStaticFiles.

What I can think of as described in section 1 and special cases is to provide UseMiddleware with different parameter lists and match different constructors to create instances. I did not think of specific use cases.

0x04 Test

In the previous article, we wrote a record of all the time-consuming middleware Products. At that time, it was directly registered using the Use method. Now we write it into a middleware class, write the timing function into a StopWatch class, and add it to the dependency injection container.

The following is the timer code:

The following is the middleware code.

The following is how to add StopWatch to the dependency injection container:

The following is how to add TimeMiddleware middleware code using UseMiddleware extension method:

You can also directly provide parameters in the UserMiddleware method instead of adding StopWatch to the dependency injection container.

If you have added StopWatch to the dependency injection container and provided StopWatch during UseMiddleware registration, the StopWatch provided during registration is used in the order of parameter matching.

Run the command to see the same effect as the previous article.

0x05 written at the end

The UseMiddleware method makes it easy to register middleware. colleagues also reduce the coupling between middleware and other dependent modules. However, no matter which extension method is used, the Use method is used to register the middleware. In the next article, we will write other extension methods Map, MapWhen, and Run for registering middleware.

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.