Используйте Unity для перехвата всех вызовов в IMyInterface.SomeMethod - программирование

Используйте Unity для перехвата всех вызовов в IMyInterface.SomeMethod

Я пытаюсь изучить Unity Interceptors, и у меня есть трудный путь.

Скажем, у меня есть такой интерфейс:

public interface IMyInterface
{
   void SomeMethod();
}

И у меня есть неизвестное количество классов, которые реализуют этот интерфейс следующим образом:

public class SpecificClass1 : IMyInterface
{
   public void SomeMethod()
   {
       Console.WriteLine("Method Called");
   }
}

Я ищу способ сказать: "для всех экземпляров IMyInterface (я не хочу перечислять их), когда SomeMethod называется run my interceptor.

Это неперечисление класса, что вызывает у меня проблемы. (Существует множество примеров, если вы можете перечислить все ваши классы.)

Я прочитал "Перехват типа", но я не могу понять, будет ли он делать то, что я ищу.

Специалисты Unity знают, как делать то, что я ищу?

4b9b3361

Ответ 1

Вы можете создать InterceptionBehavior, а затем зарегистрировать его в определенном классе. Обратите внимание, что вы можете фильтровать исполняемые методы в Invoke thru IMethodInvocation input

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using NUnit.Framework;

namespace UnitTests
{
    [TestFixture]
    public class ForTest
    {
        [Test]
        public void Test()
        {
            IUnityContainer container = new UnityContainer().AddNewExtension<Interception>();
            container.RegisterType<IMyInterface, SpecificClass1>(
                new Interceptor<InterfaceInterceptor>(),
                new InterceptionBehavior<MyInterceptionBehavior>());
            var myInterface = container.Resolve<IMyInterface>();
            myInterface.SomeMethod();
        }
    }

    public interface IMyInterface
    {
        void SomeMethod();
    }

    public class SpecificClass1 : IMyInterface
    {
        #region IMyInterface

        public void SomeMethod()
        {
            Console.WriteLine("Method Called");
        }

        #endregion
    }

    public class MyInterceptionBehavior : IInterceptionBehavior
    {
        public bool WillExecute
        {
            get { return true; }
        }

        #region IInterceptionBehavior

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Enumerable.Empty<Type>();
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            IMethodReturn result = getNext()(input, getNext);
            Console.WriteLine("Interception Called");
            return result;
        }

        #endregion
    }
}

Консольный выход

Method Called
Interception Called

Подробнее о Перехват с единством

Ответ 2

@GSerjo, изложил подход перехвата Unity, который работает хорошо. Если вы хотите автоматизировать настройку перехвата, вы можете использовать UnityContainerExtension, чтобы автоматически подключать весь перехват интерфейса, а также поведение. Если вы хотите перейти к более конкретному перехвату (имена методов, подписи, возвращаемые значения и т.д.), Вам, вероятно, потребуется посмотреть на "Инъекции политики" (используя соответствующие правила с CallHandlers).

Итак, в этом случае расширение контейнера будет выглядеть так:

public class UnityInterfaceInterceptionRegisterer : UnityContainerExtension
{
    private List<Type> interfaces = new List<Type>();
    private List<IInterceptionBehavior> behaviors = 
        new List<IInterceptionBehavior>();

    public UnityInterfaceInterceptionRegisterer(Type interfaceType, 
        IInterceptionBehavior interceptionBehavior)
    {
        interfaces.Add(interfaceType);
        behaviors.Add(interceptionBehavior);
    }

    public UnityInterfaceInterceptionRegisterer(Type[] interfaces, 
        IInterceptionBehavior[] interceptionBehaviors)
    {            
        this.interfaces.AddRange(interfaces);
        this.behaviors.AddRange(interceptionBehaviors);

        ValidateInterfaces(this.interfaces);
    }

    protected override void Initialize()
    {
        base.Container.AddNewExtension<Interception>();

        base.Context.Registering += 
            new EventHandler<RegisterEventArgs>(this.OnRegister);
    }

    private void ValidateInterfaces(List<Type> interfaces)
    {
        interfaces.ForEach((i) =>
        {
            if (!i.IsInterface)
                throw new ArgumentException("Only interface types may be configured for interface interceptors");
        }
        );
    }

    private bool ShouldIntercept(RegisterEventArgs e)
    {
        return e != null && e.TypeFrom != null && 
               e.TypeFrom.IsInterface && interfaces.Contains(e.TypeFrom);
    }

    private void OnRegister(object sender, RegisterEventArgs e)
    {
        if (ShouldIntercept(e))
        {
            IUnityContainer container = sender as IUnityContainer;

            var i = new Interceptor<InterfaceInterceptor>();
            i.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies);

            behaviors.ForEach( (b) =>
                {
                    var ib = new InterceptionBehavior(b);
                    ib.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies);
                }
            );
        }
    }
}

Тогда вы можете использовать его так:

IUnityContainer container = new UnityContainer()
    .AddExtension(new UnityInterfaceInterceptionRegisterer(
        new Type[] { typeof(IMyInterface), 
                     typeof(IMyOtherInterface) }, 
        new IInterceptionBehavior[] { new MyInterceptionBehavior(), 
                                      new AnotherInterceptionBehavior() }
        ));

container.RegisterType<IMyInterface, SpecificClass1>();

var myInterface = container.Resolve<IMyInterface>();
myInterface.SomeMethod();

Теперь, когда интерфейс зарегистрирован, в контейнер будут добавлены соответствующие политики перехвата. Таким образом, в этом случае, если зарегистрированный интерфейс имеет тип IMyInterface или IMyOtherInterface, тогда будут установлены политики для перехвата интерфейса, а также будут добавлены Interception Behaviors MyInterceptionBehavior и AnotherInterceptionBehavior.

Обратите внимание, что Unity 3 (выпущенный после этого вопроса/ответа) добавил "Регистрация по Конвенции" , которая может делать то, что делает это расширение (без для написания любого пользовательского кода). Пример из Руководство разработчика по внедрению зависимостей с использованием единства:

var container = new UnityContainer();

container.AddNewExtension<Interception>();
container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
      t => t.Namespace == "OtherUnitySamples"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
      new Interceptor<VirtualMethodInterceptor>(),
      new InterceptionBehavior<LoggingInterceptionBehavior>()
    });

Ответ 3

Настройка перехвата требует нескольких действий, включая. конфигурации перехваченных типов, политик и обработчиков.

Сначала просмотрите Использование перехвата в приложениях для получения общих сведений о типах ситуаций, в которых поддерживается перехват (например, с контейнером DI или без него), Затем см. Type Interception для получения более подробной информации о перехватчиках поддерживаемого типа. Особенно обратите внимание на то, какие перехватчики могут использоваться с типом вашего класса (иначе обработчики никогда не будут запускаться).

Когда вы решили, какой перехватчик использовать, настройте его и создайте достаточный обработчик вызовов в соответствии с приведенными выше ссылками. Если у вас все еще есть проблемы, отправьте более подробный вопрос. Если вы уже это сделали, отправьте конфиги и код как "не перечисление класса", просто не давайте никаких намеков на то, что вы на самом деле спрашиваете. Вы случайно имеете ввиду "перечисление", что вы назначаете политику, основанную на атрибутах, и не можете достичь того, чего хотите без нее?