1
public interface ILog
{
    void Write(string msg);
}

public class MyLog : ILog
{
    public void Write(string msg)
    {
        Console.WriteLine(msg);
    }
}

public interface ICanLog
{
    ILog Log { get; set; }
}

public interface IMyClass
{
    void Test();
}

public class MyClass : IMyClass, ICanLog
{
    public ILog Log { get; set; }
    public void Test()
    {
        Log.Write("Test");
    }
}

我正在将AutofacCastle DynamicProxy 一起使用,并尝试让 MyClass 测试方法自动输出“BEGIN”/“END”。

public class MyLogInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine("BEGIN");
        invocation.Proceed();
        Console.WriteLine("END");
    }
}

以下是测试代码:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<MyLog>().As<ILog>();
builder.Register(c =>
{
    ProxyGenerator g = new ProxyGenerator();
    object proxy = g.CreateClassProxy(typeof(MyClass), new MyLogInterceptor());
    ICanLog proxyICanLog = (ICanLog)proxy;
    proxyICanLog.Log = c.Resolve<ILog>();
    return proxy;
}).As<IMyClass>();

using (var container = builder.Build())
{
    objectContext.Container = container;
    IMyClass myclass = container.Resolve<IMyClass>();
    myclass.Test();
}

但是结果没有输出“BEGIN”/“END”,为什么?

如果我创建 AutoLogModule 尝试自动构建日志属性实例

    public class AutoLogModule : Autofac.Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        var type = registration.Activator.LimitType;
        if (HasPropertyDependencyOnClass(type))
        {
            registration.Activated += InjectClassViaProperty;
        }
    }

    private bool HasPropertyDependencyOnClass(Type type)
    {
        return type.GetProperties().Any(property => property.CanWrite && property.PropertyType==typeof(ILog));
    }

    private void InjectClassViaProperty(object sender, ActivatedEventArgs<object> evt)
    {
        var type = evt.Instance.GetType();
        var propertyInfo = type.GetProperties().First(x => x.CanWrite && x.PropertyType==typeof(ILog));

        ILog log = new MyLog();
        propertyInfo.SetValue(evt.Instance, log, null);
    }
}

以下是测试代码:

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<MyLog>().As<ILog>();
builder.RegisterModule(new AutoLogModule());
builder.Register(c =>
{
    ProxyGenerator g = new ProxyGenerator();
    object proxy = g.CreateClassProxy(typeof(MyClass), new MyLogInterceptor());
    //ICanLog proxyICanLog = (ICanLog)proxy;
    //proxyICanLog.Log = c.Resolve<ILog>();
    return proxy;
}).As<IMyClass>();

using (var container = builder.Build())
{
    objectContext.Container = container;
    IMyClass myclass = container.Resolve<IMyClass>();
    myclass.Test();
}

结果是测试方法抛出“对象引用未设置到对象的实例”。在 Log.Write("测试")

这个功能怎么写?

4

1 回答 1

1

我知道这是一篇相当老的帖子,但是当我试图完成同样的事情时Autofac,我找到了帮助我实现它的文档。我会回答以防万一它对其他人有帮助。

在我的情况下,我使用 Autofac 4.92 和DynamicProxy名为 Autofac.Extras.DynamicProxy 4.5.0 的额外包作为文档状态。

我看到您在注册Interceptors. 即使您正在做的事情是我最初会做的事情;不是Autofac 文档目前所说的关于如何注册拦截器的内容:

 builder.RegisterType<MyClass>().As<IMyClass>().EnableInterfaceInterceptors();

// Typed registration
builder.Register(c => new MyLogInterceptor ();

最后,您需要将拦截器与要拦截的类型相关联

[Intercept(typeof(MyLogInterceptor))]
public class MyClass : IMyClass, ICanLog
{
    public ILog Log { get; set; }
    public void Test()
    {
       Log.Write("Test");
    }
}

我希望这个答案可能会有所帮助。在任何情况下,Autofac 文档都会逐步解释如何执行此操作,以防我的代码可能会错误地跳过某些相关部分。

于 2019-08-06T15:24:22.907 回答