Используйте 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 знают, как делать то, что я ищу?
Ответы
Ответ 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 для получения более подробной информации о перехватчиках поддерживаемого типа. Особенно обратите внимание на то, какие перехватчики могут использоваться с типом вашего класса (иначе обработчики никогда не будут запускаться).
Когда вы решили, какой перехватчик использовать, настройте его и создайте достаточный обработчик вызовов в соответствии с приведенными выше ссылками. Если у вас все еще есть проблемы, отправьте более подробный вопрос. Если вы уже это сделали, отправьте конфиги и код как "не перечисление класса", просто не давайте никаких намеков на то, что вы на самом деле спрашиваете. Вы случайно имеете ввиду "перечисление", что вы назначаете политику, основанную на атрибутах, и не можете достичь того, чего хотите без нее?