Having the following service constructor
public class Service : IService
{
public Service(IOtherService service1, IAnotherOne service2, string arg)
{
}
}
What are the choices of passing the parameters using .NET Core IOC mechanism
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService>(x=>new Service( _serviceCollection.BuildServiceProvider().GetService<IOtherService>(), _serviceCollection.BuildServiceProvider().GetService<IAnotherOne >(), "" ));
Is there any other way ?
The expression parameter (x in this case), of the factory delegate is a
IServiceProvider
.Use that to resolve the dependencies,
The factory delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
It should be noted that the recommended way is to use the Options Pattern. But there are use cases where its unpractical (when parameters are only know at runtime, not at startup/compile time) or you need to dynamically replace a dependency.
Its very useful when you need to replace a single dependency (be it a string, integer or another type of dependency) or when using a 3rd party library which accepts only string/integer parameters and you require runtime parameter.
You could try CreateInstance(IServiceProvider, Object[]) as a shortcut hand
(not sure it works with string parameters/value types/primitives (int, float, string), untested)(Just tried it out and confirmed its working, even with multiple string parameters) rather than resolving every single dependency by hand:The parameters (last parameter of
CreateInstance<T>
/CreateInstance
) define the parameters which should be replaced (not resolved from the provider). They are applied from left to right as they appear (i.e. first string will be replaced with the first string-typed parameter of the type to be instantiated).ActivatorUtilities.CreateInstance<Service>
is used on many places to resolve a service and replace one of the default registrations for this single activation.For example if you have a class named
MyService
, and it hasIOtherService
,ILogger<MyService>
as dependencies and you want to resolve the service but replace the default service ofIOtherService
(say itsOtherServiceA
) withOtherServiceB
, you could do something like:Then the first parameter of
IOtherService
will getOtherServiceB
injected, rather thanOtherServiceA
but the remaining parameters will come from the container.This is helpful when you have a lot dependencies and want just to specially treat a single one (i.e. replace a database specific provider with a value configured during the request or for a specific user, something you only know at run time and during a request and not when the application is built/started).
You could also use ActivatorUtilities.CreateFactory(Type, Type[]) Method to create factory method instead, since it offers better performance GitHub Reference and Benchmark.
Later one is useful when the type is resolved very frequently (such as in SignalR and other high request scenarios). Basically you'd create a
ObjectFactory
viathen cache it (as a variable etc) and call it where needed
Update:
Just tried it myself to confirm its also working with strings and integers, and it does indeed work. Here the concrete example I tested with:
Prints
If you fell uncomfortable with newing the service, you could use the
Parameter Object
pattern.So extract the string parameter into its own type
And the constructor now it will look like
And the setup
The first benefit is if you need to change the Service constructor and add new services to it, then you don't have to change the
new Service(...
calls. Another benefit is the setup is a bit cleaner.For a constructor with a single parameter or two this might be too much though.