1

I am trying to get access to an instance of a custom class during the ConfigureServices method.

I have read that I can build an intermediate service provider to do this:

public void ConfigureServices(IServiceCollection services)
{
    // .... Other Stuff ....
    services.AddSingleton<Wso2Actions>();
    var serviceProvider = services.BuildServiceProvider();
    var wso2Actions = serviceProvider.GetService<Wso2Actions>();
    // .... Other stuff ....

I have 3 questions regarding this technique:

  1. What are the drawbacks to making this "Intermediate Service Provider"?
  2. Will my wso2Actions object still be managed by the dependency injection framework? (As if it had been injected later on?)
  3. Would I be better off just "newing" up the object myself?
    • var wso2Actions = new Wso2Actions(); services.AddSingleton<Wso2Actions>(wso2Actions);
    • I seem to recall reading that passing an instance into the DI engine results in poorer lifetime management.
Vaccano
  • 78,325
  • 149
  • 468
  • 850
  • 1
    Does this answer your question? [What are the costs and possible side effects of calling BuildServiceProvider() in ConfigureServices()](https://stackoverflow.com/questions/56042989/what-are-the-costs-and-possible-side-effects-of-calling-buildserviceprovider-i) – devNull Apr 27 '20 at 22:58

1 Answers1

1

What are the drawbacks to making this "Intermediate Service Provider"?

You could end up with having multiple containers in your application. One of the main drawbacks here is your singleton services can exist in multiple containers. i.e. multiple instances of a singleton service.

Since ASP.NET Core 3.0, if you call BuildServiceProvider in configure methods, you see warning:

Calling 'BuildServiceProvider' from application code results in an additional copy of
singleton services being created. Consider alternatives such as dependency injecting 
services as parameters to 'Configure'.

Comment from @devNull gives more details if you also want to read.

Will my wso2Actions object still be managed by the dependency injection framework?

Yes.

(As if it had been injected later on?)

No. If you inject wso2Actions later on, for example, into your controller, the container used to resolve the instance is the container used by ASP.NET Core. Whereas in your ConfigureServices, the instance is resolved using a transient container built by your code.

Note that both containers are independent and may contain different service registrations.

Would I be better off just "newing" up the object myself?

If you are willing to use new, then why not.

If you are willing to use dependency injection, there are multiple choices depending on what wso2Actions is for:

Move your code to Configure

Obviously you could move your code to Configure which is invoked after the container is built:

var wso2Actions = app.ApplicationServices.GetService<Wso2Actions>();

Use options pattern

Read this.

services.AddOptions<MyOptions>("optionalName")
    .Configure<Service1, Service2, Service3, Service4, Service5>(
        (o, s, s2, s3, s4, s5) => 
            o.Property = DoSomethingWith(s, s2, s3, s4, s5));
weichch
  • 9,306
  • 1
  • 13
  • 25
  • Good answer! However I need to call Wso2Actions to get the `TokenValidationParameters` for the `services.AddAuthentication().AddJwtBeaerer` lambda. (But I need to make the call at startup so I don't have to wait for the call during the first call to my service, which is when the lambda for `AddJwtBearer` is called.) I can't move that to the `Configure` method. Aso, I don't how `AddOptions` can help get that done at startup and give it to the lambda... I think I will go with the `new Wso2Actions` option. Just need to figure out how that will affect DI (to use and instance of the object). – Vaccano Apr 28 '20 at 18:01
  • You can implement `IConfigureNamedOptions` and register it using `services.ConfigureOptions`. Then you could inject `Wso2Actions` to the configure type. However, the configure type is invoked while instantiating JWT authentication handler, which is likely on the first call requires JWT. So yeah, if you don't mind using `new`, then there is no better solution than `new` I guess. – weichch Apr 28 '20 at 22:06