Dora. Interception: The AOP framework created for. NET Core [3]: registration of Interceptor,

Source: Internet
Author: User

Dora. Interception: The AOP framework created for. NET Core [3]: registration of Interceptor,

In "different Interceptor", we mainly introduce the core object Interceptor in Dora. Interception and some conventions defining Interceptor types. Since Interceptor always intercepts call of a method to inject pre-or post-operations, the Interceptor type we define always needs to be mapped to the corresponding target method. By default, this ing is implemented by marking features on the target type or method. For any Interceptor type, we always need to define a corresponding feature type for it, which has a common base class InterceptorAttribute.

Directory
I. InterceptorAttribute
Ii. How to define and use InterceptorAttribute
Iii. Scope of InterceptorAttribute
4. Shielding certain types of InterceptorAttribute
V. Support for other registration methods

I. InterceptorAttribute

The following is the definition of the InterceptorAttribute feature. We can see that it implements an interface named IInterceptorProvider. As the name suggests, this interface indicates that the building system of the Interceptor Chain of Dora. Interception provides a single Interceptor. Yesterday someone asked me why I didn't define Interceptor as Attribute directly, so I can directly set the standard on the target type or its members? I think so: As an Interceptor, Interceptor only needs to consider how to implement its interception operations, the role of the corresponding Attribute is to provide the corresponding Interceptor to the Interceptor Chain building system. According to the basic design principle of "single responsibility" that we are familiar with, the two should be separated. From another perspective, InterceptorAttribute only reflects Interceptor's "registration method". In addition to this standard registration method, Interceptor can also use other registration methods, for example, based on Matching Rule or configuration file. Although I strictly separate the two at the design level, end users can combine the two when defining the Interceptor type, we only need to define Interceptor as the feature type that inherits InterceptorAttribute at the same time.

The IInterceptorProvider interface has two members. The core member Use implements Interceptor registration. For another attribute named AllowMutiple, it indicates whether Interceptor provided by InterceptorProvider with the same type can be applied to the same method at the same time.

  1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method| AttributeTargets.Property, AllowMultiple = false)]  2 public abstract class InterceptorAttribute : Attribute, IInterceptorProvider  3 {  4    public int Order { get; set; }  5    public bool AllowMultiple {get;}  6    public abstract void Use(IInterceptorChainBuilder builder);  7 }  8   9 public interface IInterceptorProvider 10 { 11     void Use(IInterceptorChainBuilder builder); 12     bool AllowMultiple { get; } 13 }

The Use method of the IInterceptorProvider interface has a parameter of the IInterceptorChainBuilder type, which indicates an InterceptorChainBuilder object used to build the Interceptor Chain. We can call its Use method to provide an Interceptor object to it. The first parameter of the method indicates the provided Interceptor object, while the second parameter (order) indicates the position of the Interceptor in the finally built Interceptor Chain. In addition to this Use method, we also define two extension methods with the same name. Use <T> is the most commonly used method.

  1 public interface IInterceptorChainBuilder  2 {     4     IInterceptorChainBuilder Use(InterceptorDelegate interceptor, int order);  5     ...
  7 }  8   9 public static class InterceptorChainBuilderExtensions 10 { 11     public static IInterceptorChainBuilder Use<TInterceptor>(this IInterceptorChainBuilder builder, int order, params object[] arguments); 12     public static IInterceptorChainBuilder Use(this IInterceptorChainBuilder builder, Type interceptorType, int order, params object[] arguments); 13 }

Now let's look back at the InterceptorAttribute type. This type has an Order attribute that corresponds to the order parameter of the above Use method, and the implemented AllowMultiple method corresponds to AttributeUsage by default. the AllowMultiple property has the same value. All subclasses derived from InterceptorAttribute must override the Use method used to provide the corresponding Interceptor. Generally, we only need to call the Use method corresponding to the IInterceptorChainBuilder parameter. When marking an InterceptorAttribute, we can use the Order attribute to control the execution sequence of Interceptor as follows:

  1 public class Foobar  2 {  3    [Foo(Order = 1)]  4    [Bar(Order = 2)]  5     public virtual void Invoke()  6    {}  7 }
Ii. How to define InterceptorAttribute

When we define an InterceptorProvider attribute for an Interceptor type, we only need to inherit the InterceptorAttribute type and implement its Use method, however, when calling the Use method of IInterceptorChainBuilder, the parameter setting depends on the definition of the Interceptor Type constructor and the Service Registration for DI. For example, the FoobarInterceptor constructor has four parameters, except that the first required parameter is provided by the Interceptor activation system, the other three parameters are provided either through ServiceProvider of DI system or InterceptorProvdier.

  1 public class FoobarInterceptor  2 {  3     public FoobarInterceptor(InterceptDelegate next, IFoo foo, IBar bar, string baz);  4     public Task InvokeAsync(InvocationContext context);  5 }

Assume that the first two parameters foo and bar are provided by ServiceProvider of DI system. When we define InterceptorAttribute for InterceptorProvider, the implemented Use method only needs to provide the value of the baz parameter, we can use the following method to define the InterceptorAttribute.

  1 [AttributeUsage( AttributeTargets.Method| AttributeTargets.Class| AttributeTargets.Parameter, AllowMultiple = false )]  2 public class FoobarAttribute : InterceptorAttribute  3 {  4     public string Baz { get; }  5   6     public FoobarAttribute(string baz)  7     {  8         this.Baz = baz;  9     } 10     public override void Use(IInterceptorChainBuilder builder) 11     { 12         builder.Use<FoobarInterceptor>(this.Order, this.Baz); 13     } 14 }

Suppose we do not want to provide the foo and bar parameters in DI mode. We can call the Use method of IInterceptorChainBuilder in the following way to explicitly provide the values of these two parameters.

  1 [AttributeUsage( AttributeTargets.Method| AttributeTargets.Class| AttributeTargets.Property, AllowMultiple = false )]  2 public class FoobarAttribute : InterceptorAttribute  3 {  4     public string Baz { get; }  5   6     public FoobarAttribute(string baz)  7     {  8         this.Baz = baz;  9     } 10     public override void Use(IInterceptorChainBuilder builder) 11     { 12         builder.Use<FoobarInterceptor>(this.Order, this.Baz, new Bar(), new Foo()); 13     } 14 }
Iii. Scope of InterceptorAttribute

Dora. Interception supports InterceptorAttribute on types, methods, and attributes. For the InterceptorAttribute feature of an application on the type, the Interceptor provided by the application is actually applied to all the methods that can be intercepted on the type. If InterceptorAttribute is labeled as an attribute member, it means that the Get and Set methods of this attribute apply the corresponding Interceptor at the same time. If we only need to apply Interceptor to the Get method or Set method of an attribute, we can apply the corresponding InterceptorAttribute to the Get or Set method separately. In addition, Dora. Interception also supports the inherited InterceptorAttribute, that is, the InterceptorAttribute labeled on the base class will be automatically inherited by the quilt class.

It is worth mentioning that the AllowMultiple attribute of InterceptorAttribute is valid if True is returned for this attribute. If we want the Interceptor provided by an InterceptorAttribute to be executed only once in the final target method, we need to apply the AttributeUsage feature and set its AllowMultiple to False. We know that the AllowMultiple Attribute of AttributeUsage can only control the number of tags for the corresponding feature on the same target Member, that is, for an Attribute with AllowMultiple set to False, we can label it to the type and its members at the same time. Dora. Interception handles this and ensures that only features closer to the target method are effective.

When parsing the InterceptorAttribute feature, I specifically blocked the features of the application on the interface. I think like this: the interface is a multi-party contract, and it should not consider the implementation details, AOP-based interception is a unilateral implementation behavior, so InterceptorAttribute should not be labeled on the interface. I know that many AOP frameworks (such as Unity) can directly apply Interceptor (CallHandler) to interfaces, but I think this is inappropriate.

Take the following definition as an example. If the AllowMultiple of FoobarAttribute is set to False, the corresponding method Foo is valid only for FoobarAttribute applied to its own method. The Get and Set methods of Bar attributes are valid only for FoobarAttribute applied to their attributes. For Baz attributes, FoobarAttribute applied to their own attributes will only be applied to their Set method. As for the Get method, FoobarAttribute applied to their own methods will be used.

  1 [Foobar]  2 public class Demo  3 {  4     [Foobar]  5     public virtual void Foo()  6     {  7         Console.WriteLine("Demo.Invoke() is invoked");  8     }  9  10     [Foobar] 11     public virtual Bar Bar {get;set;} 12  13     [Foobar] 14     public virtual Baz Baz { [Foobar]get; set; } 15 }
4. Shielding certain types of InterceptorAttribute

If the Interceptor provided by a certain type of InterceptorAttribute only applies to a majority of members of a certain type, we can add it to these members separately. We can also exclude the InterceptorAttribute to the type directly, and then mark a NonInterceptableAttribute with the following definitions on a non-applicable type member. When we use the NonInterceptableAttribute feature, if no parameter is specified, it means that the target type or type member (method or attribute) does not need to be intercepted. If the IntercecptorProvider type is specified, it will only block the corresponding IntercecptorProvider type.

  1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method| AttributeTargets.Property)]  2 public class NonInterceptableAttribute : Attribute  3 {  4     public Type[] InterceptorProviderTypes { get; }  5     public NonInterceptableAttribute(params Type[] interceptorProviderTypes)  6 }

Take the following code snippet as an example. The base class Foo is labeled with two InterceptorAttribute (Interceptor1Attribute and Interceptor2Attribute). Since its subclass Bar is labeled with NonInterceptableAttribute, the entire type does not need to be intercepted. As for the other sub-Class Baz, it will inherit two interceptorattributes, but the Invoke is placed with the annotation NonInterceptableAttribute to shield Interceptor1Attribute, so only Interceptor2Attribute is valid for it.

  1 [Interceptor1]  2 [Interceptor2]  3 public class Foo  4 {  5     ...  6 }  7   8 [NonInterceptable]  9 public class Bar : Foo 10 { 11     [Interceptor1] 12     public virtual void Invoke(); 13 } 14  15 public class Baz : Foo 16 { 17     [NonInterceptable(typeof(Interceptor1Attribute))] 18     public virtual void Invoke(); 19 }
V. Support for other registration methods

I have referenced many mainstream AOP frameworks when designing Dora. Interception. I have been a deep user of Unity for many years and have studied the source code of Unity. Interception many times. I think many of the AOP frameworks are too complicated and deliberately add some features that I don't think are suitable for. Therefore, my Dora. Interception is actually doing subtraction in many aspects. In terms of Interceptor registration, MatchingRule-based registration is actually provided during development (this is also a reference to Unity. interception), using various defined MatchingRule, we can adopt various matching modes (such as type/method, attribute name, namespace, assembly name) apply an Interceptor to a type or method that meets the rule. However, according to my personal experience, because this matching mode is too "fuzzy", we can easily expand the scope of Interceptor application, so we are releasing Dora. this registration method is removed during Interception, so only feature annotation is supported so far. However, Dora. Interception provides an extension point in this aspect. You can implement it as needed.

Dora. Interception: The AOP framework for. NET Core [1]: Brand New Version
Dora. Interception: The AOP framework created for. NET Core [2]: Different Interceptor definition methods
Dora. Interception: The AOP framework created for. NET Core [3]: registration of Interceptor

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.