0

I have written a plugin architecture in .net core 3.1. The main program loads the plugins and establishes DI bindings for code within those plugins. The main program will obtain a plugin object reference, with DI, and then execute a method on that object. When it fetches that plugin object via DI, I want the ILogger which has been injected into that object reference (and sub-dependencies) to already have the name of the plugin configured (i.e. the assembly name of the plugin).

So for example, I want code within the plugin to do this:

// Assume Serilog injection provided by SimpleInjector
ILogger logger; 
// No need to specify the parameter value for 'Plugin', if this is done correctly!
logger.Information("This is the plugin called {Plugin}");

The normal way to configure an ILogger instance for the above behavior, is with code like this:

logger = log.ForContext("Plugin", "CoolPlugin.DLL");

It is possible to create a factory-like binding in SimpleInjector, but unfortunately that factory has no knowledge of the type into which the new dependency is being injected:

container.Register<ILogger>(() => log);

I've also looked at Serilog enrichers, but they likewise do not have access to the type information from the class from which they were called. Finally, the using-context construct of Serilog only works at the precise moment of construction, and is thereafter unavailable. At least this is true for me, wherein all my code is async.

At this point I don't think this is an achievable goal using my two chosen technologies (Serilog and SimpleInjector). I'd like to know if anyone has a potential solution.

Steven
  • 166,672
  • 24
  • 332
  • 435
Brent Arias
  • 29,277
  • 40
  • 133
  • 234
  • I don't know if SimpleInjector has the capabilities do to that, but you can definitely do it with Autofac: https://github.com/nblumhardt/autofac-serilog-integration – C. Augusto Proiete Dec 10 '20 at 03:47
  • 1
    Hi Brent, does this question answer the question: https://stackoverflow.com/q/37620823/264697? If not, can you specify why not? – Steven Dec 10 '20 at 08:30
  • @Steven I think that works. My understanding is that SimpleInjector will cache the closed-generic type that is created, in relation to the target type, which means the type-generation lambda will only execute a finite number of times and still achieve my goal. Yes? Still, this just leads to another question, which is why not just have a SimpleInjector conditional registration signature overload that returns instances rather than type objects? It would make for less coding, at the cost of a bit less performance. – Brent Arias Dec 10 '20 at 17:56
  • "which means the type-generation lambda will only execute a finite number of times and still achieve my goal. Yes?" The type-generation lambda will be invoked once for every consumer, but for there will only be a single registration per returned type. In other words, if multiple consumers get the same (closed) type, one single registration is used. – Steven Dec 10 '20 at 18:08
  • @Steven What I really want is the native Serilog ILogger interface, which has over 70 signatures. I could just derive directly from it, to achieve this trick, except it is a sealed type. So I need to "PIMPL" idiom author all 70 signatures. What a pain, which takes me back to the question about simply having an additional SimpleInjector conditional registration overload. – Brent Arias Dec 10 '20 at 18:10
  • "why not just have a SimpleInjector conditional registration signature overload that returns instances rather than type objects? It would make for less coding, at the cost of a bit less performance." This is actually supported by overriding the `IDependencyInjectionBehavior`. Simple Injector, however, tries to push its users into creating a set of registrations that can be fully verified. Lambda expressions often lead to callbacks into the Container (e.g. `container.GetInstance`) and this blinds SIs ability to analyse an application's object graphs. – Steven Dec 10 '20 at 18:10
  • "I could just derive directly from it, to achieve this trick, except it is a sealed type." This is a design flaw in Serilog that still hasn't been fixed. I communicated with Nick Blumhardt [about this more than 4 years ago](https://github.com/serilog/serilog/issues/861). – Steven Dec 10 '20 at 18:13
  • As long as there is no solution from Serilog, you might want to try [this approach](https://github.com/simpleinjector/SimpleInjector/issues/295#issuecomment-318740952). – Steven Dec 10 '20 at 18:14
  • @Steven I LOVE that you have a solution for Serilog. I gave it a try...but it does not work if I do not also have an explicit registration in place (e.g. `c.RegisterInstance(Log.Logger)`). Otherwise it reports "No registration for type ILogger could be found" even though I have also set `c.Options.ResolveUnregisteredConcreteTypes = true` prior to setting `DependencyInjectionBehavior`. With the seemingly vestigial explicit registration in place, then it all works. – Brent Arias Dec 10 '20 at 19:51
  • Oops. Good catch. That answer seems outdated and needs to be updated. I'll take care of that – Steven Dec 10 '20 at 21:14
  • Hi @BrentArias, I [updated the implementation](https://github.com/simpleinjector/SimpleInjector/issues/295#issuecomment-318740952) to v5 compatible. Unfortunately, I'm unable to reproduce the issue you are describing? Would you mind posting an repro on [GitHub](https://github.com/simpleinjector/SimpleInjector/issues/new?assignees=&labels=question&template=bug_report.md&title=)? – Steven Dec 11 '20 at 09:40

0 Answers0