品牌推广语,站长seo,公司网站登陆后台管理中心不能修改前台主页,货架网站开发Dora.Interception提供了两种拦截器注册方式#xff0c;一种是利用标注在目标类型、属性和方法上的InterceptorAttribute特性#xff0c;另一种采用基于目标方法或者属性的调用表达式。通过提供的扩展点#xff0c;我们可以任何我们希望的拦截器注册方式。目录一、IIntercep…Dora.Interception提供了两种拦截器注册方式一种是利用标注在目标类型、属性和方法上的InterceptorAttribute特性另一种采用基于目标方法或者属性的调用表达式。通过提供的扩展点我们可以任何我们希望的拦截器注册方式。目录一、IInterceptorProvider二、InterceptorProviderBase三、实现一种“万能”的拦截器注册方式四、ConditionalInterceptorProvider一、IInterceptorProvider拦截器最终需要应用到某个具体的目标方法上所以拦截器的注册就是如何建立拦截器与目标方法之间的映射关系Dora.Interception将这一功能体现在如下所示的IInterceptorProvider接口上。顾名思义IInterceptorProvider旨在解决为某个类型的某个方法提供拦截器列表的问题这一个功能体现在GetInterceptors方法上。如下面的代码片段所示该方法返回一组SortableInvokeDelegate对象InvokeDelegate代表拦截器本身SortableInvokeDelegate对象在此基础上添加了必要排序元素。public interface IInterceptorProvider
{bool CanIntercept(Type targetType, MethodInfo method, out bool suppressed);IEnumerableSortableInvokeDelegate GetInterceptors(Type targetType, MethodInfo method);void Validate(Type targetType, ActionMethodInfo methodValidator, ActionPropertyInfo propertyValidator) {}
}public sealed class SortableT
{public int Order { get; }public T Value { get; set; }public Sortable(int order, T value){Order order;Value value;}
}除了GetInterceptors方法IInterceptorProvider接口还定义了额外两个方法CanIntercept方法用来判断指定的方式是否需要被拦截代码生成器会利用这个方法决定如果生成最终可供拦截的代理类。另一个Validate方法用来验证针对指定类型的拦截器注册方式是否合法即拦截器是否应用到一些根本无法被拦截的方法或者属性上具体的检验逻辑由方法提供的两个委托来完成。二、InterceptorProviderBase我们自定义的IInterceptorProvider实现类型一般派生于如下这个抽象基类InterceptorProviderBase后者在接口的基础上提供了一个IConventionalInterceptorFactory接口类型的InterceptorFactory属性。顾名思义IConventionalInterceptorFactory对象帮助我们按照约定定义的拦截器类型或者其实例转换成标准的拦截器表现形式即InvokeDelegate委托。public abstract class InterceptorProviderBase : IInterceptorProvider
{public IConventionalInterceptorFactory InterceptorFactory { get; } protected InterceptorProviderBase(IConventionalInterceptorFactory interceptorFactory) ;public abstract bool CanIntercept(Type targetType, MethodInfo method, out bool suppressed);public abstract IEnumerableSortableInvokeDelegate GetInterceptors(Type targetType, MethodInfo method);
}public interface IConventionalInterceptorFactory
{InvokeDelegate CreateInterceptor(Type interceptorType, params object[] arguments);InvokeDelegate CreateInterceptor(object interceptor);
}三、实现一种“万能”的拦截器注册方式接下来我们通过自定义的IInterceptorProvider类型实现一种“万能”的拦截器注册方式——根据指定的条件表达式将指定的拦截器关联到目标方法上。在提供具体实现之前我们先来体验一下由它达成的编程模型。public class FoobarInterceptor
{public ValueTask InvokeAsync(InvocationContext invocationContext){var method invocationContext.MethodInfo;Console.WriteLine(${method.DeclaringType!.Name}.{method.Name} is intercepted.);return invocationContext.ProceedAsync();}
}public class Foobar
{public virtual void M() { }public virtual object? P { get; set; }}我们依然以上面这个简单的拦截器类型FoobarInterceptor为例现在我们需要将它应用到Foobar类型的M和P属性的Set方法上针对FoobarInterceptor的注册就可以按照如下方式来完成。如代码片段所示我们在调用InterceptionBuilder的RegisterInterceptors扩展方法中提供了一个ActionConditionalInterceptorProviderOptions委托并利用它添加了针对FoobarInterceptor与两个FuncType, MethodInfo, bool委托之间的关系后者用来匹配目标方法含属性方法。var foobar new ServiceCollection().AddSingletonFoobar().BuildInterceptableServiceProvider(interception interception.RegisterInterceptors(RegisterInterceptors)).GetRequiredServiceFoobar();foobar.M();
_ foobar.P;
foobar.P null;
Console.ReadLine();static void RegisterInterceptors(ConditionalInterceptorProviderOptions options)
{options.ForFoobarInterceptor().To(1, (type, method) type typeof(Foobar) method.Name M).To(1, (type, method) type typeof(Foobar) method.IsSpecialName method.Name set_P);
}程序运行后会在控制台输出如下的结果可以看出FoobarInterceptor拦截确实只应用到M和P属性的Set方法上属性的Get方法并未被拦截。四、ConditionalInterceptorProvider上述这种针对匹配条件的“万能”注册方式是通过如下这个ConditionalInterceptorProvider类型实现的。ConditionalInterceptorProviderOptions类型定义了对应的配置选项其核心就是一组ConditionalInterceptorRegistration对象的集合而每一个ConditionalInterceptorRegistration对象是一个表示匹配条件的FuncType, MethodInfo, bool委托与拦截器工厂的FuncIConventionalInterceptorFactory, SortableInvokeDelegate委托之间的映射关系后者利用指定的IConventionalInterceptorFactory来创建一个对应的SortableInvokeDelegate对象。public class ConditionalInterceptorProvider : InterceptorProviderBase
{private readonly ConditionalInterceptorProviderOptions _options;public ConditionalInterceptorProvider(IConventionalInterceptorFactory interceptorFactory, IOptionsConditionalInterceptorProviderOptions optionsAccessor) : base(interceptorFactory) _options optionsAccessor.Value;public override bool CanIntercept(Type targetType, MethodInfo method, out bool suppressed){suppressed false;return _options.Registrations.Any(it it.Condition(targetType, method));}public override IEnumerableSortableInvokeDelegate GetInterceptors(Type targetType, MethodInfo method) _options.Registrations.Where(it it.Condition(targetType, method)).Select(it it.Factory(InterceptorFactory)).ToList();
}public class ConditionalInterceptorProviderOptions
{public IListConditionalInterceptorRegistration Registrations { get; } new ListConditionalInterceptorRegistration();public RegistryTInterceptor ForTInterceptor(params object[] arguments) new(factory factory.CreateInterceptor(typeof(TInterceptor), arguments), this);
}public class RegistryTInterceptor
{private readonly FuncIConventionalInterceptorFactory, InvokeDelegate _factory;private readonly ConditionalInterceptorProviderOptions _options;public Registry(FuncIConventionalInterceptorFactory, InvokeDelegate factory, ConditionalInterceptorProviderOptions options){_factory factory;_options options;}public RegistryTInterceptor To(int order, FuncType, MethodInfo, bool condition){var entry new ConditionalInterceptorRegistration(condition, factorynew SortableInvokeDelegate(order, _factory(factory)));_options.Registrations.Add(entry);return this;}
}public class ConditionalInterceptorRegistration
{public FuncType, MethodInfo, bool Condition { get; }public FuncIConventionalInterceptorFactory, SortableInvokeDelegate Factory { get; }public ConditionalInterceptorRegistration(FuncType, MethodInfo, bool condition, FuncIConventionalInterceptorFactory, SortableInvokeDelegate factory){Condition condition;Factory factory;}
}这一组映射关系利用ConditionalInterceptorProviderOptions的ForTInterceptor方法进行添加该方法返回一个RegistryTInterceptor对象后者提供的To方法指定了作为匹配条件的FuncType, MethodInfo, bool委托和决定拦截器执行顺序的Order值。ConditionalInterceptorProvider利用构造函数注入的IOptionsConditionalInterceptorProviderOptions得到这组映射关系CanIntercept方法利用这组关系的匹配条件确定指定的方法是否应该被拦截另一个GetInterceptors方法则利用匹配的工厂来创建返回的这组SortableInvokeDelegate对象。