如何使用AutoFac解决正确的记录器类型? [英] How can I resolve the correct logger type using AutoFac?

查看:108
本文介绍了如何使用AutoFac解决正确的记录器类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在更新一个使用AutoFac的旧项目,并且我想将NLog与简单日志外观(SLF)一起使用

我过去在Ninject上使用过它,并且设置起来非常容易,我只需要做类似的事情:

kernel.Bind<ILogger>().ToMethod(x => LoggerFactory.GetLogger(x.Request.Target.Member.ReflectedType));

输出类似于:

NLogNinjectSlf.Services.MyService 2013-12-30 15:21:10.5782 DEBUG注入的Logger中的日志

蛋糕片

但是现在我必须使用AutoFac,而且我不知道如何获取需要记录器的目标类型.

例如,如果我具有以下接口/类:

public interface IMyService
{
    void DoSomething();
}

public class MyService : IMyService
{
    private readonly ILogger _logger;

    public MyService(ILogger logger)
    {
        _logger = logger;
    }

    public void DoSomething()
    {
        _logger.Debug("Log from injected Logger");
    }
}

我希望能够获得 MyService 类的类型,以将其用作记录器的名称

到目前为止,这是我在AutoFac中尝试过的:

var containerBuilder = new ContainerBuilder();

containerBuilder.RegisterType<MyService>().As<IMyService>();

containerBuilder.Register(x =>
{
    // TODO: Get the correct type
    return LoggerFactory.GetLogger(x.GetType());
}).As<ILogger>();

顺便说一句:我在SLF4Net后面使用了NLog,虽然实际上并不需要解决主要问题...

解决方案

感谢 nemesv 对我有很大帮助

这是我最终使用的代码

顺便说一句.您可以根据需要删除注入属性的代码,然后在所有类中使用DI注入ILogger即可提高性能

public class LoggingModule : Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
        IComponentRegistration registration)
    {
        registration.Preparing += OnComponentPreparing;

        registration.Activated += (sender, e) => InjectLoggerProperties(e.Instance);
    }

    private static void InjectLoggerProperties(object instance)
    {
        var instanceType = instance.GetType();

        // Get all the injectable properties to set.
        // If you wanted to ensure the properties were only UNSET properties,
        // here's where you'd do it.
        var properties = instanceType
          .GetProperties(BindingFlags.Public | BindingFlags.Instance)
          .Where(p => p.PropertyType == typeof(ILogger) && p.CanWrite && p.GetIndexParameters().Length == 0);

        // Set the properties located.
        foreach (var propToSet in properties)
        {
            propToSet.SetValue(instance, LoggerFactory.GetLogger(instanceType), null);
        }
    }

    private void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
        var t = e.Component.Activator.LimitType;

        e.Parameters = e.Parameters.Union(
            new[]
            {
                new ResolvedParameter((p, i) => p.ParameterType == typeof (ILogger),
                    (p, i) => LoggerFactory.GetLogger(t))
            });
    }
}

然后注册模块:

containerBuilder.RegisterModule<LoggingModule>();

I'm updating a legacy project that uses AutoFac and I want to use NLog with Simple Logging Facade (SLF)

I have used this in the past with Ninject and it's really easy to setup, I just have to do something like:

kernel.Bind<ILogger>().ToMethod(x => LoggerFactory.GetLogger(x.Request.Target.Member.ReflectedType));

The output would be something like:

NLogNinjectSlf.Services.MyService 2013-12-30 15:21:10.5782 DEBUG Log from injected Logger

Piece of cake

But now I have to use AutoFac and I don't know how to get the Target type that needs the logger

For example if I have the following interface/class:

public interface IMyService
{
    void DoSomething();
}

public class MyService : IMyService
{
    private readonly ILogger _logger;

    public MyService(ILogger logger)
    {
        _logger = logger;
    }

    public void DoSomething()
    {
        _logger.Debug("Log from injected Logger");
    }
}

I want to be able to get the type of MyService class to use it as the name of my logger

In AutoFac this is what I have tried so far:

var containerBuilder = new ContainerBuilder();

containerBuilder.RegisterType<MyService>().As<IMyService>();

containerBuilder.Register(x =>
{
    // TODO: Get the correct type
    return LoggerFactory.GetLogger(x.GetType());
}).As<ILogger>();

BTW: I'm using NLog behind the SLF4Net not really needed to solve the main issue though...

解决方案

Thanks nemesv that helped me a lot

This is the code that I ended up using

BTW. You can remove the code that inject properties if you wish, and then just use DI in all your classes to inject the ILogger that would increase the performance

public class LoggingModule : Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
        IComponentRegistration registration)
    {
        registration.Preparing += OnComponentPreparing;

        registration.Activated += (sender, e) => InjectLoggerProperties(e.Instance);
    }

    private static void InjectLoggerProperties(object instance)
    {
        var instanceType = instance.GetType();

        // Get all the injectable properties to set.
        // If you wanted to ensure the properties were only UNSET properties,
        // here's where you'd do it.
        var properties = instanceType
          .GetProperties(BindingFlags.Public | BindingFlags.Instance)
          .Where(p => p.PropertyType == typeof(ILogger) && p.CanWrite && p.GetIndexParameters().Length == 0);

        // Set the properties located.
        foreach (var propToSet in properties)
        {
            propToSet.SetValue(instance, LoggerFactory.GetLogger(instanceType), null);
        }
    }

    private void OnComponentPreparing(object sender, PreparingEventArgs e)
    {
        var t = e.Component.Activator.LimitType;

        e.Parameters = e.Parameters.Union(
            new[]
            {
                new ResolvedParameter((p, i) => p.ParameterType == typeof (ILogger),
                    (p, i) => LoggerFactory.GetLogger(t))
            });
    }
}

Then register the module:

containerBuilder.RegisterModule<LoggingModule>();

这篇关于如何使用AutoFac解决正确的记录器类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆