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すべてのインターフェイスにデフォルトのインターセプターを追加することは機能しているようですが、このソリューションはややハックです。このソリューションでは、規約による標準登録の直前に少しコードを追加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!";
}
}
}