Flash
Flash

Reputation: 1675

Using Autofac with Dynamic Proxy that output message automatic

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

I am using Autofac with Castle DynamicProxy, and try to let MyClass Test Method output "BEGIN"/"END" automatic.

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

The following is test code:

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

But result no output "BEGIN"/"END", why ?

and if I create AutoLogModule that try build Log Property Instance automatic

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

The following is test code:

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

The result is Test Method throw "Object reference not set to an instance of an object." in Log.Write("Test")

How to write this feature?

Upvotes: 1

Views: 1553

Answers (1)

Sebastian Inones
Sebastian Inones

Reputation: 1681

I know this is a rather old post but as I was trying to accomplish the same thing with Autofac and I found the documentation that helped me to achieve it. I will answer just in case it helps someone else.

In my case I'm using Autofac 4.92 and and extra package for DynamicProxy called Autofac.Extras.DynamicProxy 4.5.0 as the documentations sates.

I see a difference where you register your Interceptors. Even though what you are doing is what I would have done initially; is not what Autofac Documentation currently says about how to Register Interceptors:

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

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

Lastly, you need to Associate Interceptors with Types to be Intercepted:

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

I hope this answer may help. In any case, the Autofac documentation explains step by step how to do it just in case my code may mistakenly skip some relevant part.

Upvotes: 2

Related Questions