0

I've found the documentation on this topic very lacking and I'm in too much of a time squeeze to read a book on the topic. Is this a correct understanding of how to use Microsoft.Extensions.DependencyInjection?

My understanding is that DI frameworks cut down boilerplate. Imagine you have 30 different classes that your need to dependency inject has convinced you all want a SqlConnection Conn argument. You know that there's a sensible default SqlConnection that you will want to use all of the time except when doing unit tests. Furthermore, imagine that all of these classes take genuine parameters in their constructors that have nothing to do with dependency injection (e.g. the first parameter in SqlClass1(string UserName, SqlConnection Conn) or SqlClass2(string UserID, SqlConnectionConn)). You could write an extra constructor for each of them that lets you leave the SqlConnection unspecified and defaults to your sensible default, but this is way too much work. Instead, a DI framework lets you write code like this and put it in the same class as Main().

using Microsoft.Extensions.DependencyInjection;
static class Program
{
    public static IServiceProvider ServiceProvider { get; private set; }
    static IHostBuilder CreateHostBuilder()
    {
        return Host.CreateDefaultBuilder().ConfigureServices((context, services)=>{
            // Tells callers to replace any requests for `SqlConnection` types with my sensible default.                
            services.AddTransient<SqlConnection, MySensibleDefaultSqlConnection()>();
            // Tells callers that SqlClass1 is one of the callers that should replace its `SqlConnection`.
            services.AddTransient<SqlClass1>();
            // The same for SqlClass2.      
            services.AddTransient<SqlClass2>();
            // [...]
            services.AddTransient<SqlClass30>();
        });
    }
    static void Main()
    {
        var host = CreateHostBuilder().Build();
        ServiceProvider = host.Services;

        // When we actually want to use one of the classes that use our sensible default, we do
        var x = ServiceProvider.GetRequiredService<SqlClass1>("foo");
        // rather than...
        // var x = SqlClass1("foo", MySensibleDefaultSqlConnection());
    }
}
J. Mini
  • 1,868
  • 1
  • 9
  • 38
  • *"DI frameworks cut down boilerplate"* - No. They decouple components from their dependencies, by providing dependencies to the components (injecting them) instead of having the components create the dependencies themselves. This isn't unique to M.E.DI, this is dependency injection, period. Don't focus on M.E.DI to learn about the concept of dependency injection because they (MS) assume you know it (well enough, anyway) and only document how to do it specifically with M.E.DI. – madreflection May 19 '23 at 00:03
  • `SqlConnection` generally isn't a dependency that's good to inject. Either inject a factory that creates the connection (allowing you to specify the parameters you need), or just don't inject it at all and admit that you're going to be tightly coupled to that dependency. – madreflection May 19 '23 at 00:23
  • 1
    There is no `ServiceProvider.GetRequiredService` overload takes allows you to supply a runtime argument, such as `ServiceProvider.GetRequiredService("foo")` in your code example. That's because [runtime data should not be injected into components during their construction](https://blogs.cuttingedge.it/steven/p/runtime-data/). – Steven May 19 '23 at 08:16
  • I'd say the statement "DI frameworks cut down boilerplate" is pretty accurate, but I'll like to refer to this q&a for a more precise answer: [What's the purpose of the "container" in an "IoC container"?](https://stackoverflow.com/a/8549096/264697). In short: "the sole purpose of a DI container is to make the composition root maintainable." – Steven May 19 '23 at 08:24
  • @madreflection Yeah, I'd use a factory in real applications but I get it as just `SqlConnection` here to keep the code simple. – J. Mini May 19 '23 at 13:40

0 Answers0