【问题标题】:StructureMap proxy all instances or modify instances just before returningStructureMap 在返回之前代理所有实例或修改实例
【发布时间】:2019-07-17 14:32:27
【问题描述】:

在 StructureMap 中,我们可以使用 TProxy 代理 TInterface 和 TConcreteImpl 这个:

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)
    {

    }
}

非常感谢

【问题讨论】:

    标签: c# .net-core structuremap


    【解决方案1】:

    看起来像实现自定义 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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-24
      • 2019-09-25
      • 1970-01-01
      相关资源
      最近更新 更多