88008

Resolve generic Microsoft.Extensions.Logging.ILogger with Unity - get InvalidCastException

<h3>Question</h3>

I am trying to register a generic ILogger (from Microsoft.Extensions.Logging, not from Serilog) in Unity (version 4).

I've got the following class:

<pre class="lang-cs prettyprint-override">public class MyClass { private readonly Microsoft.Extensions.Logging.ILogger<MyClass> _logger; public MyClass(Microsoft.Extensions.Logging.ILogger<MyClass> logger) { _logger = logger; } }

And the following Unity registrations and test:

<pre class="lang-cs prettyprint-override">// 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>();

This seems OK to me, too bad I am having the following error when resolving:

<blockquote>

Exception is: InvalidCastException - Unable to cast object of type 'Serilog.Extensions.Logging.SerilogLogger' to type 'Microsoft.Extensions.Logging.ILogger`1[MyNamespace.MyClass]'.

</blockquote>

How to fix this issue?

Full exception:

<blockquote>

Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, type = "MyNamespace.MyClass", name = "(none)". Exception occurred while: Resolving parameter "logger" of constructor MyNamespace.MyClass(Microsoft.Extensions.Logging.ILogger1[[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.ILogger1[MyNamespace.MyClass]'.

</blockquote> <h2>Update</h2>

when using Microsoft.Extensions.DependencyInjection, this works:

<pre class="lang-cs prettyprint-override">// Arrange var serviceCollection = new Microsoft.Extensions.DependencyInjection.ServiceCollection() .AddLogging(builder => builder.AddSerilog()) .AddTransient<MyClass, MyClass>(); var serviceProvider = serviceCollection.BuildServiceProvider(); // Assert serviceProvider.GetService<MyClass>();

So I try to get this working with Unity instead of Microsoft.Extensions.DependencyInjection

Unfortunately there is no AddSerilog for Unity and I'm bound to Unity


<h3>Answer1:</h3>

The easiest way I have found is to register a factory and reflect their extension method to do it and get the right response type. This example also expects that you have registered an 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 }); });
<h3>Answer2:</h3>

I resolved this with the help of MakeGenericMethod and a helper method:

<pre class="lang-cs prettyprint-override">private static ILogger<T> CreateLogger<T>(ILoggerFactory factory) { return new Logger<T>(factory); }

And the final code (without reflection caching etc):

<pre class="lang-cs prettyprint-override">// 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>();

来源:https://stackoverflow.com/questions/55573065/resolve-generic-microsoft-extensions-logging-iloggert-with-unity-get-invalid

Recommend

  • Not able to sort array of objects after adding values [closed]
  • VSTS Build : Git submodule automatization
  • React/Redux dispatch not triggering reducer
  • coding++:解决Not allowed to load local resource错误-SpringBoot配置虚拟路径
  • Inheritance: Internal Class vs. Internal Interface
  • Change Locale not work after migrate to Androidx
  • GnuWin32 or Cygwin - from a programmers point of view
  • Python: override len
  • Get the textbox Text using ajax on button click
  • UIViewControllerAnimatedTransitioning: Black screen fragments after rotation change
  • openTSDB REST API is not storing data
  • Use of x`apply` to speed up loops
  • Change the font based on language CSS
  • Automate editable PDF
  • Error with custom SVM model for tuning in caret
  • Need to pass object and operation in a function that executes it
  • Get Element By Classname Script Not Working
  • How do I detect if an email client is configured on an Android device?
  • build an API for streaming audio/video from GridFS mongodb
  • Using VCL Styles gives a exception / crash in TOpenDialog
  • in Gwt, there are 2 different packages (or 2 options) for doing drag n Drop? Which one is better?
  • What is the diff. between default.properties and project.properties?
  • async GET request with body from browser
  • can you use embedded ruby in custom javascript files in rails?
  • didSelectItemAtIndexPath of UICollectionView inside of a UIScrollView is not getting called
  • How to process remote XML files with XSLT
  • Firestore: Version history of documents
  • How can I filter an array of dictionaries in 'updateSearchResultsForSearchController' to s
  • Find all parks for a given zipcode with google maps
  • Adding horizontal slider to QTableWidget
  • How to control xtics in gnuplot
  • Run a form (insert/update/delete) from within a div using jquery
  • How to use AJAX to upload large CSV file? [closed]
  • How to resolve this in PHPUnit where it is asking me to set KERNEL_DIR in my phpunit.xml?
  • Multiplying polynomials/simplifying like terms
  • How to define something in JavaScript [closed]
  • VS2010 RDLC C#. How can I set a LocalReport object to a ReportViewer?
  • Amazon Elastick BeanStalk error: Failed to create the AWS Elastic Beanstalk application version
  • How to decleare char *const argv[] in swift [duplicate]
  • Grails - How to implement a foreign key relationship not using an id column?