Unity容器:使用PerResolveLifetimeManager和自定义拦截

时间:2010-06-17 13:51:58

标签: c# unity-container

我正在尝试在仍使用Unity容器的同时实现自己的拦截。我希望以尊重所使用的终身经理的方式这样做。即如果它是PerResolveLifetimeManager,那么我想将实例包装一次,并且我希望在整个解析过程中使用该包装实例。

到目前为止,我实现了一个BuilderStrategy,我使用自定义UnityContainerExtension类添加到我的容器中(我将PostInitialization传递给AddNew方法;我不确定最合适的值是什么,但这似乎有效)。在我的BuilderStrategy中的PostBuildUp覆盖中,我将context.Existing替换为我的包装值。

当我在PerResolve生命周期中使用它时,会发生一次换行,但只有第一次使用依赖项才能获取包装的实例,其余的则获得一个非包装的实例。即如果我的ctor接收IFoo foo1和IFoo foo2,则只有foo1是我的包装实例,而foo2是未包装的实例。

这是一个示例repro(为简单起见,我使用另一个类的实例,Foo2,而不是包装):

public class MyInterception : UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Strategies.AddNew<MyInterceptionStrategy>(UnityBuildStage.PostInitialization);
    }
}

public class MyInterceptionStrategy : BuilderStrategy
{
    public override void PostBuildUp(IBuilderContext context)
    {
        if (!context.OriginalBuildKey.Type.IsInterface)
        {
            return;
        }

        context.Existing = new Foo2();
    }
}

public class Bar
{
    public Bar(IFoo f1, IFoo f2, IFoo f3)
    {
    }
}

public interface IFoo
{
}

public class Foo1 : IFoo
{
}

public class Foo2 : IFoo
{
}

public void Main()
{
    UnityContainer container = new UnityContainer();
    container.AddNewExtension<MyInterception>();
    container.RegisterType(typeof (IFoo), typeof (Foo1), new PerResolveLifetimeManager());

    container.Resolve<Bar>();
}

如果你在PostBuildUp和Bar的构造函数中放置一个断点并通过Bar的解析调试Main,你可以看到PostBuildUp只被调用一次。但是,在Bar的构造函数中,f1是Foo2的实例(“包装”实例),而f2和f3是Foo1(unwrapped)的实例。

我想知道我想要的是否可行以及我是否采取了正确的方法?我的问题与生命周期和/或我添加了BuilderStrategy的UnityBuildStage有关吗?

由于

1 个答案:

答案 0 :(得分:2)

您在构建策略中执行拦截策略的时间太晚了。不幸的是,此时我没有更详细的理由为什么代码在 ObjectBuilder 程序集中以这种方式运行。

希望我有更多时间分析Unity ObjectBuilder时会返回,但要在过渡期间解决您的问题,只需将UnityBuildStage枚举值从 PostInitialization 更改为 设置 TypeMapping

Context.Strategies.AddNew<MyInterceptionStrategy>(UnityBuildStage.Setup);

我的完整代码:

using System;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.ObjectBuilder;

namespace UnityInterceptors
{
    class Program
    {
        public class MyInterception : UnityContainerExtension
        {
            protected override void Initialize()
            {
                Context.Strategies.AddNew<MyInterceptionStrategy>(UnityBuildStage.Setup);
            }
        }
        public class MyInterceptionStrategy : BuilderStrategy
        {
            public override void PostBuildUp(IBuilderContext context)
            {
                if (!context.OriginalBuildKey.Type.IsInterface)
                {
                    return;
                }

                context.Existing = new Foo2();
            }
        }

        public class Bar
        {
            public Bar(IFoo f1, IFoo f2, IFoo f3)
            {
                Console.WriteLine(f1.GetType().Name);
                Console.WriteLine(f2.GetType().Name);
                Console.WriteLine(f3.GetType().Name);
            }
        }

        public interface IFoo
        {
        }

        public class Foo1 : IFoo
        {
        }

        public class Foo2 : IFoo
        {
        }

        public static void Main()
        {
            UnityContainer container = new UnityContainer();
            container.AddNewExtension<MyInterception>();
            container.RegisterType(typeof(IFoo), typeof(Foo1), new PerResolveLifetimeManager());

            container.Resolve<Bar>();

            Console.ReadLine();
        }
    }
}
  • 另请注意,我正在使用Unity 2.0库。可能是某种已经解决的bug。