在StructureMap中,我们可以使用TInterface
来代理TConcreteImpl
和TProxy
:
ConfigurationExpression config = ...
config.For<TInterface().DecorateAllWith<TProxy>();
config.For<TInterface>().Use<TConcreteImpl>();
我想使用DispatchProxy
(并在方法调用之前和调用之后全局记录),并为从StructureMap实例化的所有类型全局注册它,我想知道如何实现此目的?
更具体地说,我要对要实例化的所有类型运行以下命令:
TConcreteImpl instance = ...
TInterface proxy = DispatchProxyGenerator.CreateProxyInstance(typeof (TInterface), typeof (TProxy))
.SetParameters(instance);
我已经尝试过使用StructureMap的IInstancePolicy
,但没有成功,因为Instance
不是实际的对象实例。
public class Policy : IInstancePolicy
{
public void Apply(Type pluginType, Instance instance)
{
}
}
非常感谢您
答案 0 :(得分:5)
看起来像实现自定义IInterceptorPolicy一样适合这里。容器中的所有类型都将调用此方法,并且可能会为某些/全部类型产生装饰器。 使用虚拟记录器进行控制台的示例:
public class CustomInterception : IInterceptorPolicy
{
public string Description => "test interception Console.WriteLine each method' arguments and return value";
public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, StructureMap.Pipeline.Instance instance)
{
Type dispatchProxyType = DummyDispatchProxyDontUseAtWork.GenerateStructureMapCompatibleDispatchProxyType(pluginType);
yield return new DecoratorInterceptor(pluginType, dispatchProxyType);
}
}
称为:
var container = new StructureMap.Container(cntnr =>
{
cntnr.Policies.Interceptors(new CustomInterception());
cntnr.For<IFoo>().Use<Foo>();
cntnr.For<IBar>().Use<Bar>();
});
var foo = container.GetInstance<IFoo>();
foo.FooFoo("1", "2");
产生的输出:
FooFoo(1,2)
BarBar(2,1)
BarBar -> 21
FooFoo -> 21
其余示例在下面,因此可以执行。
DispatchProxy
的棘手之处在于它创建了一种新类型,而StructureMap
很难构造这种新类型。在.Net Core 2.1
中,DispatchProxy
使构造函数具有Action...
参数,但是StructureMap
希望可以创建一些东西。您肯定需要一个替代的代理生成器,该代理生成器可以更顺利地与StructureMap
一起使用。
public interface IBar
{
string BarBar(string a1, string a2);
}
public class Bar : IBar
{
public string BarBar(string a1, string a2) => a1 + a2;
}
public interface IFoo
{
string FooFoo(string a1, string a2);
}
public class Foo : IFoo
{
public IBar Bar { get; private set; }
public Foo(IBar bar)
{
Bar = bar;
}
public string FooFoo(string a1, string a2) => Bar.BarBar(a2, a1);
}
public class DummyDispatchProxyDontUseAtWork : DispatchProxy
{
public object Instance { get; protected set; }
public DummyDispatchProxyDontUseAtWork() : base()
{}
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
Console.WriteLine($"{targetMethod.Name}({string.Join(',', args)})");
var result = targetMethod.Invoke(this.Instance, args);
Console.WriteLine($" {targetMethod.Name} -> {result}");
return result;
}
private static readonly ConcurrentDictionary<Type, Type> generatedProxyTypes = new ConcurrentDictionary<Type, Type>();
protected static readonly ConcurrentDictionary<string, object> privateHackedState = new ConcurrentDictionary<string, object>();
private static readonly AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
private static readonly ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(Guid.NewGuid().ToString());
private static Type EmitDispatchProxyType(Type interfaceType)
{
object dispatchProxyObj = typeof(DispatchProxy).GetMethod("Create", BindingFlags.Static | BindingFlags.Public)
.MakeGenericMethod(interfaceType, typeof(DummyDispatchProxyDontUseAtWork))
.Invoke(null, null);
string typeId = "DummyDispatchProxyDontUseAtWork" + Guid.NewGuid().ToString("N");
privateHackedState[typeId] =
dispatchProxyObj.GetType().GetField("invoke", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dispatchProxyObj);
var resultTypeBuilder = moduleBuilder.DefineType(
typeId,
TypeAttributes.Public,
dispatchProxyObj.GetType());
var baseCtor = dispatchProxyObj.GetType().GetConstructors().First();
var ctor = resultTypeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
new[] {interfaceType});
var il = ctor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldsfld, typeof(DummyDispatchProxyDontUseAtWork).GetField(nameof(privateHackedState), BindingFlags.NonPublic | BindingFlags.Static));
il.Emit(OpCodes.Ldstr, typeId);
il.Emit(OpCodes.Callvirt, typeof(ConcurrentDictionary<,>).MakeGenericType(typeof(string), typeof(object)).GetMethod("get_Item"));
il.Emit(OpCodes.Call, baseCtor);
var setInstanceMethodInfo = dispatchProxyObj.GetType()
.GetMethod("set_" + nameof(Instance),BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, setInstanceMethodInfo);
il.Emit(OpCodes.Ret);
return resultTypeBuilder.CreateType();
}
public static Type GenerateStructureMapCompatibleDispatchProxyType(Type interfaceType)
{
return generatedProxyTypes.GetOrAdd(interfaceType, EmitDispatchProxyType);
}
}