Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add scoped service when creating a new scope

Tags:

Is it possible to add a service to an IServiceProvider when creating a new scope?

E.g. a scope is created like this:

using (var scope = Services.CreateScope())
{
    // Register some service using "AddScoped"
    scope.??.AddScoped<IOrganizationIdProvider, OrganizationIdProvider>((x) => { return new OrganizationIdProvider("dynamic-parameter")});

    // Resolve service
    scope.ServiceProvider.GetService<IOrganizationIdProvider>();

}

The service should be resolved when creating new instances in the scope.

like image 355
BendEg Avatar asked Apr 10 '20 22:04

BendEg


1 Answers

@Nkosi already mentioned that you can't make new registrations in MS.DI once the container has been created. But even if you could, changing the container in-flight is a bad idea, which is why most DI Container do not support such feature. The newest versions of Autofac and Ninject, for instance, recently removed such feature, and the Simple Injector documentation explains why it never had this feature.

But you can achieve what you want by making small changes to your code. Probably the easiest way to implement this is by making changing injecting the dynamic parameter through property injection instead of constructor injection. For instance:

Changes in application code:

public class OrganizationIdProvider : IOrganizationIdProvider
{
    // Only required code change (notice that the interface doesn't change, this
    // property is an implementation detail)
    public string DynamicParameter { get; set; }
}

Configuration of the container:

// Register the implementation by itself to allow it to be requested by your infrastructure
services.AddScoped<OrganizationIdProvider>();

// Register the provider by its interface so it can be injected into application components
services.AddScoped<IOrganizationIdProvider>(c => c.GetService<OrganizationIdProvider>());

Usage:

using (var scope = Services.CreateScope())
{
    // Here we resolve the OrganizationIdProvider *implementation*
    var provider = scope.ServiceProvider.GetRequiredService<OrganizationIdProvider>();

    // Set the runtime parameter
    provider.DynamicParameter = "dynamic-parameter";

    // Resolve service that might have a dependency on IOrganizationIdProvider.
    var handler =
        scope.ServiceProvider.GetRequiredService(typeof(IMessageHandler<DoSomething>));

    // Use the service
    handler.Handle(new DoSomething());
}

There are certainly more options when it comes to dealing with runtime data, but for that I would recommend you to read this series on DI Composition Models.

like image 192
Steven Avatar answered Sep 19 '22 22:09

Steven