我试图在Unity(版本4)中注册一个通用的ILogger(来自Microsoft.Extensions.Logging,而不是来自Serilog)。
我有以下课程:
public class MyClass
{
private readonly Microsoft.Extensions.Logging.ILogger<MyClass> _logger;
public MyClass(Microsoft.Extensions.Logging.ILogger<MyClass> logger)
{
_logger = logger;
}
}
以下Unity注册和测试:
// Arrange
IUnityContainer container = new UnityContainer();
// provider from Serilog.Extensions.Logging nuget package
var provider = new Serilog.Extensions.Logging.SerilogLoggerProvider();
container.RegisterType(typeof(Microsoft.Extensions.Logging.ILogger<>),
new InjectionFactory((ctr, type, name) =>
{
var loggerType = type.GetGenericArguments()[0].FullName;
Microsoft.Extensions.Logging.ILogger logger = provider.CreateLogger(loggerType);
return logger;
}));
container.RegisterType<MyClass, MyClass>(); // just for demo purpose.
// Assert
container.Resolve<MyClass>();
这对我来说似乎没关系,太糟糕了我在解决时遇到以下错误:
例外情况是:InvalidCastException - 无法将类型为“Serilog.Extensions.Logging.SerilogLogger”的对象强制转换为“Microsoft.Extensions.Logging.ILogger`1 [MyNamespace.MyClass]”。
如何解决这个问题?
完全例外:
Microsoft.Practices.Unity.ResolutionFailedException:依赖项的解析失败,type =“MyNamespace.MyClass”,name =“(none)”。发生异常时:解析构造函数MyNamespace.MyClass的参数“logger”(Microsoft.Extensions.Logging.ILogger
1[[MyNamespace.MyClass, MyNamespace.Infra.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=edbaf8e9a324553f]] logger). Exception is: InvalidCastException - Unable to cast object of type 'Serilog.Extensions.Logging.SerilogLogger' to type 'Microsoft.Extensions.Logging.ILogger
1 [MyNamespace.MyClass]'。
使用Microsoft.Extensions.DependencyInjection时,这适用:
// Arrange
var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection()
.AddLogging(builder => builder.AddSerilog())
.AddTransient<MyClass, MyClass>();
var serviceProvider = serviceCollection.BuildServiceProvider();
// Assert
serviceProvider.GetService<MyClass>();
所以我尝试使用Unity而不是Microsoft.Extensions.DependencyInjection
不幸的是,Unity没有AddSerilog
,我必然会选择Unity
我在MakeGenericMethod
和帮助方法的帮助下解决了这个问题:
private static ILogger<T> CreateLogger<T>(ILoggerFactory factory)
{
return new Logger<T>(factory);
}
最后的代码(没有反射缓存等):
// Arrange
IUnityContainer container = new UnityContainer();
var logfactory = new LoggerFactory();
var provider = new Serilog.Extensions.Logging.SerilogLoggerProvider();
logfactory.AddProvider(provider);
container.RegisterType(typeof(Microsoft.Extensions.Logging.ILogger<>),
new InjectionFactory((ctr, type, name) =>
{
var loggerType = type.GetGenericArguments()[0];
var myType = this.GetType();
var createLoggerMethod1 = myType.GetMethod(nameof(CreateLogger),BindingFlags.Static | BindingFlags.NonPublic);
var createLoggerMethod = createLoggerMethod1.MakeGenericMethod(loggerType);
var logger = createLoggerMethod.Invoke(this, new object[] {logfactory});
return logger;
}));
container.RegisterType<MyClass, MyClass>();
// Assert
container.Resolve<MyClass>();