从属性处理程序访问Unity容器

时间:2013-06-30 07:29:09

标签: .net unity-container unity-interception

我使用Unity设置来在使用特定属性修饰方法时拦截方法调用。我希望所有Unity代理对象都在每个线程中保留(而不是瞬态)。

问题是,decoration属性创建的对象每次都创建为“new”。我看不到从属性中访问UnityContainer的方法。如果可以的话,我会将LogHandler创建为每线程实体并通过Unity请求它。 (这是否有意义?使用Unity来解析统一拦截中使用的对象?)。

如果运行此代码,则记录器的计数输出始终为“1”。要清楚,这个'LogHandler'就是我想要坚持的。

如何通过代码中的其他地方统一解析对象?你绕过统一容器吗?我可以使用一种模式从我的代码中的任何地方请求它吗?

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace UnityTest2
{
    class Program
    {
        private static UnityContainer _uC;

        static void Main(string[] args)
        {
            _uC = new UnityContainer();
            _uC.AddNewExtension<Interception>();

            _uC.Configure<Interception>().SetInterceptorFor<ICalc>(new InterfaceInterceptor());
            _uC.RegisterType<ICalc, Calc>( new PerThreadLifetimeManager() );
            var c = _uC.Resolve<ICalc>();
            Console.WriteLine(c.Add(3, 7));
            Console.WriteLine(c.Sub(3, 7));
            Console.ReadKey();
        }
    }

    public class LogAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            // I want this to persist per thread
            return new LogHandler();
        }
    }

    public class LogHandler : ICallHandler
    {
        private int runCount = 0;
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {

            runCount++;

            // this is always '1'
            Console.WriteLine(runCount);
            return getNext()(input, getNext);
        }

        public int Order { get; set; }
    }

    public interface ICalc
    {
        int Add(int x, int y);
        int Sub(int x, int y);
        int Mul(int x, int y);
    }

    public class Calc : ICalc
    {
        [Log]
        public int Add(int x, int y)
        {
            return x + y;
        }
        [Log]
        public int Sub(int x, int y)
        {
            return x - y;
        }

        public int Mul(int x, int y)
        {
            return x * y;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您可以在启动期间使用PerThreadLifetimeManager向Unity注册您的呼叫处理程序。

_uC.RegisterType<LoggingCallHandler>(new PerThreadLifetimeManager());

然后该属性可以从容器中解析处理程序:

public class LoggingAttribute : HandlerAttribute
{        
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return container.Resolve<LoggingCallHandler>();
    }
}

通常,您不希望传递容器的实例,因为这会将您的应用程序与所使用的特定容器紧密耦合。这将使用容器作为Service Locator。很多人认为这是anti-pattern

调用处理程序属性是Unity基础结构的一部分(适用于您的应用程序);它们扩展了Unity的抽象HandlerAttribute并要求CreateHandler方法接受IUnityContainer,因此使用HandlerAttribute中的容器并不是意料之外的。