我正在更新使用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>();
BTW:我在SLF4Net后面使用NLog并不是真正需要解决主要问题但是......
答案 0 :(得分:9)
感谢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>();
答案 1 :(得分:1)
似乎使用Autofac 4.3.0你可以简单地使用OnComponentPreparing()回调而不使用特殊的属性注入技术。将注入ctor()和属性值:
public class LoggingModule : Module
{
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
registration.Preparing += Registration_Preparing;
}
private static void Registration_Preparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => p.ParameterType == typeof (ILog),
(p, i) => LogFactory.CreateWithType(t))
});
}
}
另外,我发现了一些很好的技巧,只有当你需要控制记录器的生命周期时才可以用于属性注入。
public class LoggingModule : Module
{
protected override void Load(ContainerBuilder builder)
{
const string propertyNameKey = "Autofac.AutowiringPropertyInjector.InstanceType";
builder.RegisterType<NLogLogger>()
.As<ILog>()
.OnPreparing(x =>
{
var firstParam = x.Parameters?
.OfType<NamedParameter>()
.FirstOrDefault(p => p.Name == propertyNameKey);
if (null == firstParam)
{
return;
}
var valueType = firstParam.Value;
x.Parameters = x.Parameters.Union(
new[]
{
new ResolvedParameter(
(p, i) => p.Name == "type",
(p, i) => valueType)
});
})
.InstancePerDependency();
其中NLogLogger本身是
public class NLogLogger : ILog
{
private readonly Logger _log;
public NLogLogger()
{
_log = LogManager.GetCurrentClassLogger();
}
public NLogLogger(Type type)
{
_log = LogManager.GetLogger(type.FullName);
}
}