Доступ к UnityContainer из AttributeHandler

У меня есть настройки Unity для перехвата вызовов методов, когда метод украшен определенным атрибутом. Я хочу, чтобы все прокси-объекты Unity сохранялись в каждом потоке (а не были временными).

Проблема в том, что объект, созданный атрибутом художественного оформления, создается каждый раз как "новый". Я не вижу способа получить доступ к 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 ответ

Решение

Вы можете зарегистрировать свой обработчик вызовов в Unity с помощью PerThreadLifetimeManager во время запуска.

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

Затем атрибут может разрешить обработчик из контейнера:

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

Обычно вы не хотите передавать экземпляры контейнера, поскольку это тесно связывает ваше приложение с конкретным используемым контейнером. Это будет использовать контейнер в качестве локатора службы. Многие люди считают, что это анти-паттерн.

Атрибуты обработчика вызовов являются частью инфраструктуры Unity (для вашего приложения); они расширяют абстрактный Unity HandlerAttribute и требуют, чтобы метод CreateHandler принял IUnityContainer, поэтому использование контейнера в HandlerAttribute не является неожиданным.

Другие вопросы по тегам