How to get correct IServiceProvider instance in my extension method

53 Views Asked by At

I am writing extension methods for my api to be used in host builder and I need to get an instance of IServiceProvider in it.

I saw that builder.Services.AddDbContext<T>()

has a parameter

(IServiceProvider, DbContextOptionsBuilder)

, so i tought to just add it to my extension method but how?

Lets say I have this extension method:

public static class MyExtensions
{
    public static IServiceCollection AddMyServices(this IServiceCollection services, Action<IServiceProvider, MyServicesOptionBuilder> overrides)
    {
        ...
        return services;
    }
}

and the expected usage is this:


var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMyServices((serviceProvider, config)=>
{
    var serviceconfiguration = serviceProvider.GetRequiredService<SomeServiceConfiguration>();
    cfg.ConfigureService1(serviceconfiguration);
    cfg.ConfigureService2(serviceconfiguration);

    ....
});

What I don't understand is, who or how is IServiceProvider passed into the Action parameter?

1

There are 1 best solutions below

2
quyentho On BEST ANSWER

Here is an example I created:

public record MyServicesOptionBuilder 
{
    public string DependencyName { get; set; }
};
public record MyDependency(string DependencyName);

public static class MyExtensions
{
    public static void AddMyServices(this IServiceCollection services, Action<IServiceProvider, MyServicesOptionBuilder> overrides)
    {
        // get IServiceProvider from IServiceCollection
        IServiceProvider serviceProvider = services.BuildServiceProvider();

        // create MyServicesOptionBuilder instance
        var options = new MyServicesOptionBuilder();

        // Let the client set option's value
        overrides.Invoke(serviceProvider, options);

        // create MyDependency instance using the option value that was set by the client
        var dependency = new MyDependency(options.DependencyName);

        services.AddKeyedSingleton("Second", dependency);

        serviceProvider.GetKeyedServices<MyDependency>("Second");

        Debug.Assert(dependency.DependencyName == "This is a different dependency");
        Console.WriteLine(dependency.DependencyName);
    }
}

Program.cs:

// Add services to the container.
builder.Services.AddKeyedSingleton("First" ,new MyDependency("This is a dependency"));

builder.Services.AddMyServices((services, options) =>
{
    var firstDependency = services.GetRequiredKeyedService<MyDependency>("First");

    Debug.Assert(firstDependency.DependencyName == "This is a dependency");
    Console.WriteLine(firstDependency.DependencyName);

    options.DependencyName = "This is a different dependency";
});

What I don't understand is, who or how is IServiceProvider passed into the Action parameter?

As you can see, you are the one who will create the IServiceProvider.