3

在这种情况下,我的应用程序收到了一个已经初始化UnityContainer的已注册类型,归结为:

container.RegisterType<IService>(new InjectionFactory(c => new Service()));

我需要实现的是ServiceInterceptorIService注册中添加一个拦截器。我想显而易见的答案是:通过运行第二个RegisterType<IService>并将拦截器应用为注入成员来做到这一点。然而,不幸的是,如下所述重新创建提供的注入工厂和委托是不可行的。new Service()我目前无法获得该声明。

container.RegisterType<IService>(
    new InjectionFactory(c => new Service()),
    new Interceptor<InterfaceInterceptor>(),
    new InterceptionBehavior<ServiceInterceptor>());

所以:我正在寻找一种方法来将更多的注入成员添加到现有的ContainerRegistration.

// 1. Get the current container registration
var containerRegistration = container.Registrations
    .First(cr => cr.RegisteredType == typeof(IService));

// 2. Is this even possible?
ApplyInterception(
    containerRegistration,
    new Interceptor<InterfaceInterceptor>(),
    new InterceptionBehavior<ServiceInterceptor>());

// 3. Profit!
4

1 回答 1

4

您最初可以将类型注册为命名注册(使用 InjectionFactory),同时还提供仅解析命名注册的默认注册(没有名称):

container.RegisterType<IService>("original",
                      new InjectionFactory(c => new Service()));
container.RegisterType<IService>(
                      new InjectionFactory(c => c.Resolve<IService>("original")));

所以你可以IService像往常一样解决。但是,您现在可以在保留原始命名注册的同时替换默认注册。IService通过这种方式,您可以解决您的问题,由于当时工厂声明不可用,您无法重新注册。

使用这种方法,稍后您可以IService使用已注册拦截的默认注册来覆盖默认注册,并且仍使用原始命名注册来解析实例:

container.RegisterType<IService>(
    new InjectionFactory(c => c.Resolve<IService>("original")),
    new Interceptor<InterfaceInterceptor>(),
    new InterceptionBehavior<ServiceInterceptor>());

如果您现在 resolve IService,您仍将使用原始工厂方法c => new Service(),因为它正在解析“原始”命名注册,但这次您ServiceInterceptor也适用。

我创建了这个小提琴,所以你可以检查一个完整的工作示例。


还有第二种方法使用策略注入(请参阅msdn中的策略注入部分)。

首先像往常一样配置您的类型,但要为使用策略注入敞开大门:

container.RegisterType<IService>(
    new InjectionFactory(c => new Service()),       
    new InterceptionBehavior<PolicyInjectionBehavior>(),
    new Interceptor<InterfaceInterceptor>());

此时您的服务已注册,没有应用任何拦截。但是,稍后您可以添加一个策略注入规则,例如匹配您的服务类型名称,以添加拦截:

container.Configure<Interception>()
    .AddPolicy("yourInterceptor")
    .AddMatchingRule<TypeMatchingRule>
        (new InjectionConstructor("MyNamespace.Service", true))
    .AddCallHandler<ServiceInterceptorHandler>(
        new ContainerControlledLifetimeManager(),
        new InjectionConstructor(),
        new InjectionProperty("Order", 1));

现在如果你 resolve IService,将应用中的拦截逻辑(这个类与第一种方法ServiceInterceptorHandler基本相同,但实现而不是)ServiceInterceptorICallHandlerIInterceptionBehavior

再次,检查这个小提琴中的例子


看看这两个选项,我个人觉得第一种方法更舒服,避免了匹配规则的开销。

第一种方法还允许您通过再次覆盖注册轻松地完全关闭拦截,IService如果您希望完全关闭它,可以节省拦截器的开销。(这两种方法都允许您实现WillExecute拦截器/处理程序类的属性,但仍然有拦截器的开销)。您可以使用策略注入来执行此操作,但您需要另一个中间调用处理程序,请参阅这篇文章

但是,使用第二种方法,您可以使用匹配规则将此解决方案应用于多个类(例如,命名空间中的所有类,或名称遵循特定模式的所有类等。您可以在此处查看匹配规则)

最后,您需要决定哪一个最适合您。(可能还有其他方法,希望看到它们发布!)

于 2014-10-31T10:13:34.050 回答