简体   繁体   中英

Autofac - How to get class name while creating instance

I have question about Autofac : How can I get name of class which request instance from container?

Is it possible to get name of the class "Autofac_Test" passed into constructor by autofac when object is created?

My code:

using System;
using System.Diagnostics;
using System.Reflection;
using Autofac;
using Xunit;

public class BootStrap
{
    public IContainer Configure()
    {
        var builder = new ContainerBuilder();
        builder.Register(b => new MyLogger(MethodBase.GetCurrentMethod().ReflectedType)).As<ILog>();
        return builder.Build();
    }
}
public class Autofac_Test
{
    private IContainer _containter;
    public Autofac_Test()
    {
        _containter = new BootStrap().Configure();
    }
    [Fact]
    public void Should_create_class_with_Name_BlaBla()
    {
        var logger = _containter.Resolve<ILog>();
        Assert.True(logger.Name == "Autofac_Test");
    }
}
public class MyLogger : ILog
{
    public string Name { get; private set; }
    public MyLogger(Type name)
    {
        Name = name.FullName;
    }
    public void Info(string message)
    {
        Debug.WriteLine(string.Format("{0} {1}", Name, message));
    }
}

public interface ILog
{
    void Info(string message);
    string Name { get; }
}

For your specific case it will be quite difficult to obtain this information. But as I understand the question, MyLogger need to know the type name where it will be injected and the code sample may not be relevant.

In this case you can use a module and the Preparing event :

public class LoggingModule : Autofac.Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistry componentRegistry, IComponentRegistration registration)
    {
        registration.Preparing += (sender, e) =>
        {
            Type limitType = e.Component.Activator.LimitType;
            e.Parameters = e.Parameters.Union(new[] {
                new ResolvedParameter((pi, c) => pi.ParameterType == typeof(ILogger), 
                                      (pi, c) => c.Resolve<ILogger>(new NamedParameter("name", limitType.Name))),
            });
        };
    }
}

Then you will have to register your module like this :

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule<LoggingModule>();
builder.RegisterType<MyLogger>().As<ILogger>();

Now each time a ILogger will be injected to a type it will have the correct name.

class Foo
{
    public Foo(ILogger logger)
    {
        this._loggerName = logger.Name;
    }

    private readonly String _loggerName; 

    public String LoggerName 
    {
        get 
        {
            return this._loggerName;
        }
    }
}

LoggerName will be Foo .

Your test can now look like this :

[Fact]
public void Should_create_class_with_Name_BlaBla()
{
    var foo = _containter.Resolve<Foo>();
    Assert.AreEquals("foo", foo.LoggerName, "invalid loggerName");
}

UPDATE

@Cyril Durand has proved it possible. Suggestion below is still correct but not that good.

It doesn't look like autofac supports what you want. You can of cause parse call stack in MyLogger constructor but this will cost you performance.

There's already a question about very similar thing and factory was suggested instead

Autofac. Register class with constructor with params

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM