Cannot resolve ILogger Simple Injector ASP.NET

2020-07-09 07:09发布

问题:

We use Simple Injector in ASP.NET Core application. Recently we've decided to use Serilog for logging purposes.

Configuration was done in Program.cs as stated in their documentation. Then, in order to make Simple Injector able to resolve ILoggerFactory I did something like this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseMvc();

    // As per my understanding, we force SimpleInjector to use 
    // ILoggerFactory registration from IApplicationBuilder
    container.CrossWire<ILoggerFactory>(app)
}

After that ILoggerFactory can be injected wherever we use it. And it works fine (creates new instances ILogger<T>).

But this is annoying, to create instance from factory every time we need. It would be better to get ILogger<T> directly in dependent class, instead of ILoggerFactory.

So, how can I register ILogger<T> to get instance in case like below?

public class HelloWorldController : Controller
{
    public HelloWorldController(ILogger<HelloWorldController> logger)
    {
         // ...
    }
}

回答1:

Although Alsami's answer would work, use the following registration instead:

container.RegisterConditional(
    typeof(ILogger),
    c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType),
    Lifestyle.Singleton,
    c => true);

// This next call is not required if you are already calling AutoCrossWireAspNetComponents
container.CrossWire<ILoggerFactory>(app);

This exact example is shown in the documentation.

This registration allows injecting the Logger<T> into a non-generic ILogger constructor argument, where the T of Logger<T> becomes the type the logger is injected into. In other words, when HelloWorldController depends on ILogger, it will get injected with a Logger<HelloWorldController>. This means you can simplify your HelloWorldController to the following:

public class HelloWorldController : Controller
{
    public HelloWorldController(ILogger logger)
    {
         // ...
    }
}

By letting your application components depend on ILogger rather than ILogger<T> you:

  • Simplify your application code
  • Simplify your unit tests
  • Remove the possibility of making accidental errors, because it becomes impossible to inject the wrong logger.


回答2:

You also have to register the logger iteself as a generic type. I don't know simple injector but this should be the correct syntax.

container.Register(typeof(ILogger<>), typeof(Logger<>), Lifestyle.Singleton);