我正在尝试使用接口拦截器向我的Prism应用程序的所有组件添加跟踪拦截器。我几乎有这个工作但是拦截器遇到了声明事件的接口问题。有没有人成功实现了所有组件的aop跟踪而不需要属性?
这是我的代码:
private void AddTracingInterceptor(Type from, IUnityContainer container)
{
container.AddNewExtension<Interception>();
if (from.ToString().StartsWith("StockTraderRI")
&& !from.ToString().EndsWith("View")
&& from.IsInterface)
{
try
{
container.Configure<Interception>().SetInterceptorFor(from, new InterfaceInterceptor())
.AddPolicy("SomePolicy")
.AddMatchingRule(new AllMembersMatchingRule())
.AddCallHandler(new TraceCallHandler());
}
catch (Exception ex)
{
Debug.WriteLine("$$$" + from.ToString() + " " + ex.Message);
}
}
else
{
Debug.WriteLine("---" + from.ToString());
}
}
这是例外:
内部例外 --------------- 类型:System.TypeLoadException,mscorlib,Version = 2.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089 消息:来自程序集'Unity_ILEmit_InterfaceProxies,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'的类型'DynamicModule.ns.Wrapped_IAccountPositionService_4c0175f8eca24b809f7a3875747d41c1'中的方法'add_Updated'没有实现。 资料来源:mscorlib 帮助链接: TypeName:DynamicModule.ns.Wrapped_IAccountPositionService_4c0175f8eca24b809f7a3875747d41c1 数据:System.Collections.ListDictionaryInternal TargetSite:System.Type _TermCreateClass(Int32,System.Reflection.Module) 堆栈跟踪:在System.Reflection.Emit.TypeBuilder._TermCreateClass(Int32句柄,模块模块) 在System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() 在System.Reflection.Emit.TypeBuilder.CreateType() 在Microsoft.Practices.Unity.InterceptionExtension.InterfaceInterceptorClassGenerator.CreateProxyType() 在Microsoft.Practices.Unity.InterceptionExtension.InterfaceInterceptor.CreateProxy(Type t,Object target) 在Microsoft.Practices.Unity.InterceptionExtension.InstanceInterceptionStrategy.PostBuildUp(IBuilderContext context) 在Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
答案 0 :(得分:2)
调查问题在于Unity InterceptionExtension中的InterfaceInterceptorClassGenerator,它绕过具有特殊名称的方法,并且没有定义事件所需的添加和删除方法。
我能看到的可能解决方案是 1)编辑Unity源代码并编写代码以定义事件IL代码。 (见下文) 2)将要拦截的接口中的所有事件更改为显式的“添加和删除”委托方法(由实际事件实现)。对INotifyPropertyChanged的WPF绑定使得这对Prism来说是不切实际的。 3)Scrap Unity并使用更好的IoC容器。
您是否找到了更好的解决方案?
编辑:我现在一直坚持使用Unity 1.2所以我最终修复了它,并且可能会发布代码,这也解决了派生接口的问题。
你需要修改Unity.Extensions.Interception中的InterfaceInterceptorClassGenerator类,首先添加CreateProxyType
public Type CreateProxyType()
{
int memberCount = 0;
foreach (MethodInfo method in MethodsToIntercept())
{
OverrideMethod(method, memberCount++);
}
foreach (PropertyInfo property in PropertiesToIntercept())
{
OverrideProperty(property, memberCount++);
}
// Add this
foreach (EventInfo evt in EventsToIntercept())
{
AddEvent(evt);
}
// -- SNIP --
}
修改内容以获取'基础'接口的方法。
private IEnumerable<MethodInfo> MethodsToIntercept()
{
return typeToIntercept.GetInterfaces()
.SelectMany(t => t.GetMethods())
.Union(typeToIntercept.GetMethods())
.Where(m => !m.IsSpecialName);
}
private IEnumerable<PropertyInfo> PropertiesToIntercept()
{
return typeToIntercept.GetInterfaces()
.SelectMany(t => t.GetProperties())
.Union(typeToIntercept.GetProperties());
}
private IEnumerable<EventInfo> EventsToIntercept()
{
return typeToIntercept.GetInterfaces()
.SelectMany(t => t.GetEvents())
.Union(typeToIntercept.GetEvents());
}
然后添加创建事件方法的方法。这开始使用Implementing an Interface on a dynamic type with events中的代码,但实际上将添加/删除转发给基础对象:
private void AddEvent(EventInfo interfaceEvent)
{
MethodAttributes eventMethodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.SpecialName;
MethodImplAttributes eventMethodImpAtr = MethodImplAttributes.Managed | MethodImplAttributes.Synchronized;
string qualifiedEventName = string.Format("{0}.{1}", typeToIntercept.Name, interfaceEvent.Name);
string addMethodName = string.Format("add_{0}", interfaceEvent.Name);
string remMethodName = string.Format("remove_{0}", interfaceEvent.Name);
EventBuilder eBuilder = typeBuilder.DefineEvent(qualifiedEventName, EventAttributes.None, interfaceEvent.EventHandlerType);
// ADD method
MethodBuilder addMethodBuilder = typeBuilder.DefineMethod(addMethodName, eventMethodAttr, null, new[] { interfaceEvent.EventHandlerType });
addMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
// Code generation
ILGenerator ilgen = addMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, targetField);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Callvirt, interfaceEvent.GetAddMethod());
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);
// REMOVE method
MethodBuilder removeMethodBuilder = typeBuilder.DefineMethod(remMethodName, eventMethodAttr, null, new[] { interfaceEvent.EventHandlerType });
removeMethodBuilder.SetImplementationFlags(eventMethodImpAtr);
// Code generation
ilgen = removeMethodBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, targetField);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Callvirt, interfaceEvent.GetRemoveMethod());
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);
// Finally, setting the AddOn and RemoveOn methods for our event
eBuilder.SetAddOnMethod(addMethodBuilder);
eBuilder.SetRemoveOnMethod(removeMethodBuilder);
}
如果您在索引中使用它们,您可能还需要为索引器执行类似的操作,但只需将接口修改为get / set方法就很容易。