CacheInterceptor体现了一个典型的Interceptor的定义方式:
由于依赖的服务对象(比如CacheInterceptor依赖IMemoryCache 和IOptions<MemoryCacheEntryOptions>对象)可以直接注入到InvokeAsync方法中,所以上述这个CacheInterceptor也可以定义成如下的形式
1: public class CacheInterceptor 2: { 3: private readonly InterceptDelegate _next; 4: public CacheInterceptor(InterceptDelegate next) 5: { 6: _next = next; 7: } 8: 9: public async Task InvokeAsync(InvocationContext context, IMemoryCache cache, IOptions<MemoryCacheEntryOptions> optionsAccessor) 10: { 11: if (!context.Method.GetParameters().All(it => it.IsIn)) 12: { 13: await _next(context); 14: } 15: 16: var key = new Cachekey(context.Method, context.Arguments); 17: if (cache.TryGetValue(key, out object value)) 18: { 19: context.ReturnValue = value; 20: } 21: else 22: { 23: await _next(context); 24: _cache.Set(key, context.ReturnValue, optionsAccessor.Value); 25: } 26: } 27: }
五、定义InterceptorAttribute我们采用Attribute的形式来将对应的Intercepor应用到某个类型或者方法上,每个具体的Interceptor类型都具有对应的Attribute。这样的Attribute直接继承基类InterceptorAttribute。如下这个CacheReturnValueAttribute就是上面这个CacheInterceptor对应的InterceptorAttribute。
1: [AttributeUsage(AttributeTargets.Method)] 2: public class CacheReturnValueAttribute : InterceptorAttribute 3: { 4: public override void Use(IInterceptorChainBuilder builder) 5: { 6: builder.Use<CacheInterceptor>(this.Order); 7: } 8: }
具体的InterceptorAttribute只需要重写Use方法将对应的Interceptor添加到Interceptor管道之中,这个功能可以直接调用作为参数的InterceptorChainBuilder对象的泛型方法Use<TInterceptor>来实现。对于这个泛型方法来说,泛型参数类型代表目标Interceptor的类型,而第一个参数表示注册的Interceptor在整个管道中的位置。如果创建目标Interceptor而调用的构造函数的参数尚未采用Dependency Injection的形式注册,我们需要在这个方法中提供。对于CacheInterceptor依赖的两个对象(IMemoryCache 和IOptions<MemoryCacheEntryOptions>)都可以采用Dependency Injection的形式注入,所以我们在调用Use<CacheInterceptor>方法是并不需要提供这个两个参数。