StructureMap是代理所有实例还是在返回之前修改实例?

9
在StructureMap中,我们可以使用TProxy代理TInterfaceTConcreteImpl,代码如下:
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)
    {

    }
}

非常感谢您。
1个回答

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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接