2014-10-29 73 views
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! 

回答

3

你可以开始注册类型为命名注册(使用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>()); 

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

我已经创建this fiddle,所以你可以检查一个完整的工作示例。


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

首先设置你的型像往常一样,但留下的门打开,使用政策注射:

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

此时你的服务是没有应用任何拦截注册。不过在稍后的时候,你可以添加一个策略注入规则,例如符合您服务类型名,增加了拦截:如果你解决IService

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

现在,ServiceInterceptorHandler拦截逻辑将被应用(这班是基本相同的第一种方法ServiceInterceptor,但实施ICallHandler代替IInterceptionBehavior

再次,检查在示例this fiddle


看看这两个选项,我个人对第一种方法感到更加满意,避免了匹配规则的开销。

第一种方法还允许您轻松完全关闭拦截,方法是再次覆盖IService注册,如果您希望完全关闭拦截器,则可以将其从拦截器的开销中解救出来。 (这两种方法都允许你实现拦截器/处理器类的WillExecute属性,但是你仍然有拦截器的开销)。为此,您可以使用策略注入,但你需要另一个中间呼叫处理程序,请参见this post

然而,在第二种方法,可以将这个解决方案使用匹配的规则命名空间中的应用到多个类别(例如,所有类,或所有类别的名称都遵循特定模式,等等。您可以查看匹配规则here

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

+0

谢谢你的提示 - 命名类型注册现在似乎如此明显:) 我添加了一个名为类型注册,包括注射工厂解决原未命名的注册(即反驳您的建议),并将拦截器添加到新的指定注册中。这似乎很好地工作。 但是真的没有办法访问和修改当前的类型注册条目吗? -S – 2014-10-31 12:26:34

+0

我不知道有任何修改当前注册的方式,而不是覆盖它。当然不能通过其成员只读的'ContainerRegistration'类。 – 2014-10-31 12:41:51

+0

也有使用[子容器](http://msdn.microsoft.com/en-us/library/dn507462(v = pandp.30).aspx)的选项,但这基本上是覆盖初始值的另一种方式配置 – 2014-10-31 12:48:41