为所有已注册类型注册相同的Unity拦截器和调用处理程序

7
我有一个ICallHandler,我想要将它注册到所有我的Unity容器实例中。
例如,考虑以下处理程序:
public class ProfilerHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        //start timer
        IMethodReturn methodReturn = getNext()(input, getNext);
        //stop timer
    }

    public int Order
    {
        get; set;
    }
}

下面是一个IoC容器的构造函数:

public class IoCContainer : UnityContainer
{
    public IoCContainer()
    {
        this.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager());
        this.RegisterType<IRepository<User>, UserRepository>(new ContainerControlledLifetimeManager());
    }
}

我想要做的就是将这个处理程序注册到所有这些类型中。我可以使用一些冗长的代码来实现:
public class IoCContainer : UnityContainer
{
    public IoCContainer()
    {
        this.AddNewExtension<Interception>();

        this.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager()).Configure<Interception>().SetInterceptorFor<IUserService>(new InterfaceInterceptor());
        this.RegisterType<IRepository<User>, UserRepository>(new ContainerControlledLifetimeManager()).Configure<Interception>().SetInterceptorFor<IRepository<User>>(new InterfaceInterceptor());
    }
}

但是我不仅需要在所有类型注册上编写相同的拦截代码(如果我有100多个类型注册,想象一下),而且我还必须在每个接口上包含一个HandlerAttribute(再次,如果我必须将其应用于100多个接口,那就不好了)。

这是我的唯一选择吗?还是有一种方法可以在容器级别上实现这一点,以避免必须将其应用于每个单独的类型注册和接口?

1个回答

10

Unity 3提供了“按约定注册”的功能,可以在这种情况下有所帮助:(链接)

IUnityContainer container = new UnityContainer();

container.AddNewExtension<Interception>();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
        t => t.Namespace == "My.Namespace.Services"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
        new Interceptor<InterfaceInterceptor>(),
        new InterceptionBehavior<MyBehavior>()
    });
}

你可以结合策略注入(Policy Injection)来使用匹配规则来连接调用处理程序。这样,你就可以使用各种匹配规则来确定哪些调用处理程序适用于哪些类/方法,而不是(或与)属性相结合。
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
        t => t.Namespace == "My.Namespace.Services"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
        new InterceptionBehavior<PolicyInjectionBehavior>(),
        new Interceptor<InterfaceInterceptor>(),
    });
}

container.Configure<Interception>()
    .AddPolicy("profiler")
    .AddMatchingRule<AssemblyMatchingRule>(
        new InjectionConstructor(
            new InjectionParameter("My.Namespace.Services")))
    .AddCallHandler<ProfilerHandler>(
        new ContainerControlledLifetimeManager());

Unity 2同样支持策略注入。

另一种代替按约定注册的方法是编写Unity容器扩展,以在注册期间执行拦截的连接。


谢谢Tuzo。我们使用的是.NET 4.0,所以只能使用Unity 2.0。在发布之前,我尝试使用策略注入来使其工作,但无法使其工作。我会再仔细研究一下,如果无法使用策略注入使其工作,我将更新原始帖子并提供我的解决方案。 - Jerad Rose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接