WithMappings.FromMatchingInterface
我想使用约定将所有实现特定接口的类注册到 Unity 中。此外,我希望使用接口拦截行为来拦截所有已注册的对象。问题是 Unity 还注册了具体类之间的映射,当这些类被解析时,会抛出异常并显示以下消息:
“[type] 不可拦截”
我意识到使用具体类类型解析对象不是最佳实践,但我想知道为什么 Unity 在按约定注册时会自动为接口 -> 具体类以及具体类 -> 具体类添加映射?这意味着如果您添加接口拦截器并使用具体类型进行解析,它将永远无法工作。
我想要的结果是 Unity 在按照约定注册并给它一个接口拦截器时没有添加具体类型 -> 具体类型映射,这样我们可以使用它的具体类型解析类,如果我们愿意,我们只需不被拦截。
我不想使用 ,VirtualMethodInterceptor
因为我不想对类进行更改以使拦截起作用,这包括继承自MarshalByRef
. 我还想避免单独注册所有对象。
因此,我的问题是,按惯例注册时如何仅注册接口映射?
更新:单独注册类会产生同样的问题,因此假设一旦一个对象注册了一个接口拦截器,那么它就不能通过使用具体类型来解决。
新注册码:
container.RegisterType<ISomeService, SomeService>(new InjectionMember[]
{
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<TraceInterceptor>()
});
container.RegisterType<ISomeRepository, SomeRepository>(new InjectionMember[]
{
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<TraceInterceptor>()
});
更新 2为所有接口添加默认拦截器似乎可行,尽管此解决方案相当 hacky。此解决方案需要在按约定进行标准注册之前的一些代码,并InterfaceInterceptor
在基于约定的注册中删除。
预注册码
foreach (var type in types)
{
container
.Configure<Interception>()
.SetDefaultInterceptorFor(type.GetInterface("I" + type.Name), new InterfaceInterceptor());
}
一些解释困境的代码:
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using System;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
var types = AllClasses.FromAssemblies(typeof(ISomeService).Assembly).Where(type => type == typeof(SomeService) || type == typeof(SomeRepository));
container.RegisterTypes(
types,
WithMappings.FromMatchingInterface,
getLifetimeManager: WithLifetime.ContainerControlled,
getInjectionMembers: c => new InjectionMember[]
{
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<TraceInterceptor>()
});
// this works fine, the interceptor does what it is supposed to.
var someService1 = container.Resolve<ISomeService>();
someService1.SomeServiceMethod("Hello from main method");
// should I by any chance resolve using the concrete service directly, it has a meltdown due to the interface interceptor.
var someService2 = container.Resolve<SomeService>();
someService2.SomeServiceMethod("This will never be shown due to a hissy fit thrown by the container about the concrete SomeService is not interceptable.");
}
}
public class TraceInterceptor : IInterceptionBehavior
{
public System.Collections.Generic.IEnumerable<System.Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Trace.WriteLine(string.Format("Hello from trace interception behavior for type [{0}]!", input.Target.GetType().FullName));
return getNext().Invoke(input, getNext);
}
public bool WillExecute
{
get { return true; }
}
}
public interface ISomeService
{
string SomeServiceMethod(string someParameter);
}
public class SomeService : ISomeService
{
private ISomeRepository _someRepository;
public SomeService(ISomeRepository someRepository)
{
_someRepository = someRepository;
}
public string SomeServiceMethod(string someParameter)
{
return _someRepository.SomeRepositoryMethod(someParameter);
}
}
public interface ISomeRepository
{
string SomeRepositoryMethod(string someParameter);
}
public class SomeRepository : ISomeRepository
{
public string SomeRepositoryMethod(string someParameter)
{
Trace.WriteLine(someParameter);
return "Hello from repository!";
}
}
}