J'essaye d'enregistrer un ILogger générique (de Microsoft.Extensions.Logging, pas de Serilog) dans Unity (version 4).
J'ai la classe suivante:
// Arrange var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection() .AddLogging(builder => builder.AddSerilog()) .AddTransient<MyClass, MyClass>(); var serviceProvider = serviceCollection.BuildServiceProvider(); // Assert serviceProvider.GetService<MyClass>();
3 Réponses :
J'ai résolu ce problème à l'aide de MakeGenericMethod
et d'une méthode d'assistance:
// 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>();
Et le code final (sans mise en cache de réflexion, etc.):
XXX
Le moyen le plus simple que j'ai trouvé est d'enregistrer une fabrique et de refléter sa méthode d'extension pour le faire et obtenir le bon type de réponse. Cet exemple suppose également que vous avez enregistré une ILoggerFactory.
_container = new UnityContainer(); _container.RegisterInstance<ILoggerFactory>(new LoggerFactory().AddLog4Net(), new ContainerControlledLifetimeManager()); _container.RegisterFactory(typeof(ILogger<>), null, (c, t, n) => { var factory = c.Resolve<ILoggerFactory>(); var genericType = t.GetGenericArguments().First(); var mi = typeof(Microsoft.Extensions.Logging.LoggerFactoryExtensions).GetMethods().Single(m => m.Name == "CreateLogger" && m.IsGenericMethodDefinition); var gi = mi.MakeGenericMethod(t.GetGenericArguments().First()); return gi.Invoke(null, new[] { factory }); });
Comme il existe déjà une implémentation de Logger container.RegisterType<ILoggerFactory, MyLoggerFactory>();
container.RegisterType(typeof(ILogger<>), typeof(Logger<>));
container.Resolve<ILogger<MyClass>>();
container.RegisterType ();
ne devrait pas être quelque chose comme container.RegisterTypecontainer.RegisterType ()
est pour la démo, le problème est la résolution deILogger
.L'avez-vous essayé avec une
interface
enregistrée dans uneclasse
? La résolution pose peut-être un problème, car elle n'a pas d'interface.Essayez à la place
private readonly Microsoft.Extensions.Logging.ILogger _logger;
etpublic MyClass (Microsoft.Extensions.Logging.ILogger logger)
. Vous créez un logger non spécialisé dans votre configuration d'injection, donc cela ne sera bien sûr pas assignable à un logger spécialisé.@kara oui, le même problème est là avec une interface (IMyClass par exemple)
@ErikFunkenbusch le but est ici de créer le Logger générique. Non générique fonctionne (mais nécessite un autre enregistrement). Veuillez noter que les enregistreurs génériques sont conseillés par MS. Voir docs.microsoft.com/en-us/aspnet/core/ principes de base / journalisation (notez que ce cas n'est pas ASP.NET Core)
CreateLogger ne crée pas de logger générique cependant ...
@ErikFunkenbusch vrai, mais la chose amusante est que cela fonctionne un peu avec ASP.NET Core (en utilisant loggingProvider et loggingFactory). Voir usage / source github.com/serilog/serilog-extensions-logging . Il existe des ILoggers génériques résolus avec le même SerilogLoggerProvider
Non, pas pareil. Ils créent un fournisseur de serilog en utilisant le type de logger, vous créez un fournisseur de logger sans type.