Разрешите универсальный Microsoft.Extensions.Logging.ILogger <T>с Unity - получите InvalidCastException - PullRequest
2 голосов
/ 08 апреля 2019

Я пытаюсь зарегистрировать универсальный ILogger (из Microsoft.Extensions.Logging, а не из Serilog) в Unity (версия 4).

У меня есть следующий класс:

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)". Исключительная ситуация во время: Разрешение параметра "logger" конструктора MyNamespace.MyClass (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

1 Ответ

0 голосов
/ 08 апреля 2019

Я решил это с помощью 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>();

...