0

Consider the following:

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSingleton<ILogger, Logger>();
        ...
    }

So I obviously want a logging class within my controller methods, as shown, but I also have many other components that will be common to them - and all of those components will want to have references to my logger. It is a singleton after all (which might be an anti-pattern here, I guess, but anyway).

How should I properly be passing "dependencies within dependencies" within a ConfigureServices method? I could do something like this, I guess:

    public void ConfigureServices(IServiceCollection services)
    {
        Logger l = new Logger();
        services.AddSingleton<ILogger, Logger>((provider) =>
        {
            return l;
        });
        services.AddScoped<IFoo, Foo>((provider) =>
        {
            return new Foo(l);
        });
        ...
    }

I could do something like that! But it looks and feels like a hack. I'm certain I shouldn't be resolving / making actual concrete constructions in my ConfigureServices method like this, but I don't know of a way to tell my Foo constructor to (like my controller methods) be dependent on ILogger.

What is the intended mechanism for doing this -- or is there a completely different pattern I should consider following?

  • 2
    Why exactly are you thinking of doing that? Can you share the definition of `Foo`? – Camilo Terevinto Sep 04 '18 at 12:40
  • 2
    You know core can successfully resolve them without any action. E.g : `public Foo(ILogger logger) => _logger = logger;` this will be resolved to singleton Logger when Used its contract anywhere. – ilkerkaran Sep 04 '18 at 12:43
  • 2
    You can just do `.AddScoped()` and the IoC framework should automatically resolve the dependency – Kevin Gosse Sep 04 '18 at 12:44
  • You don't need to add a Func in `AddSingleton`, should be like that `services.AddSingleton()` and as said above, let .Net Core handle the injection (In a controller) – Zysce Sep 04 '18 at 12:44

1 Answers1

1

From what i can tell there are no dependencies inside your dependencies in any kind of "weird" way...

All you need to do is register the implementation for each service like so:

services.AddSingleton<ILogger, Logger>();

When this lines executes you can "request" an ILogger in the definition of a constructor and the framework will handle instantiating (or not,depending on service scope etc) and passing the reference to your calls.

This means that if your IFoo "requests" an ILogger in one of its constructors you dont need to do anything tricky to resolve it, as long as you register IFoo service provider after your ILogger provider. Below is a simple example on the fly, where Foo implementations requests an ILogger in the constructor

public class Foo : IFoo
{
    private readonly ILogger<Foo> _logger;

    public Foo(ILogger<Foo> logger)
    {
        _logger = logger;
    }

    public Task WriteMessage(string message)
    {
        _logger.LogInformation("Foo.WriteMessage called. Message:{MESSAGE}", message);

        return Task.FromResult(0);
    }
}
MKougiouris
  • 2,821
  • 1
  • 16
  • 19
  • What about `private ILogger Logger { get; }` instead of the `readonly` field? It produces the same code and you still use properties. – Matías Fidemraizer Sep 04 '18 at 13:03
  • 1
    @MatíasFidemraizer you would only use this `_logger` inside this class, you don't want to expose it to the outside. So a field would be enough – Hans Kesting Sep 04 '18 at 13:04
  • Sure thing, the above is just a quick-sample to explain how Dep Injection works. Keep in mind thought that by making the logger of the class private you ensure that nobody is going to get a reference to it outside your Foo class. You dont want anything getting logged from your Foo logger by calls made to it outside of Foo class. But this is all a matter of "taste" sometimes – MKougiouris Sep 04 '18 at 13:05
  • @HansKesting I've edited the comment... I wanted to point to a `private` property – Matías Fidemraizer Sep 04 '18 at 13:05
  • @MKougiouris I know that. I've edited the comment, for who knows why my mind thought `private` and my fingers typed `public` ;P – Matías Fidemraizer Sep 04 '18 at 13:06
  • Yup, in the general use case you are just fine with it. But for a bit more reading i will redirect you to this https://stackoverflow.com/questions/37496738/c-sharp-readonly-vs-get , check out Rob's answer on the matter. It all comes down to how "proper" things are and how "proper" things need to be. IE for your own project you are just fine with a getter only. If you were to create a package for others to use as a 3rd party package you are better off with the readonly declaration to avoid missunderstangins – MKougiouris Sep 04 '18 at 13:12