.NET Core DI, ways of passing parameters to constructor












16














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 ?










share|improve this question
























  • Change your design. Extract the arg into a Parameter Object and inject that.
    – Steven
    Dec 22 at 14:50






  • 1




    Does this answer solve your problem?
    – Tseng
    Dec 23 at 18:04










  • yes it works, thanks for the great suggestion
    – MCR
    2 days ago


















16














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 ?










share|improve this question
























  • Change your design. Extract the arg into a Parameter Object and inject that.
    – Steven
    Dec 22 at 14:50






  • 1




    Does this answer solve your problem?
    – Tseng
    Dec 23 at 18:04










  • yes it works, thanks for the great suggestion
    – MCR
    2 days ago
















16












16








16


2





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 ?










share|improve this question















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 ?







c# asp.net-core dependency-injection .net-core ioc-container






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 21 at 12:07









Kirk Larkin

19.5k33756




19.5k33756










asked Dec 21 at 11:57









MCR

517216




517216












  • Change your design. Extract the arg into a Parameter Object and inject that.
    – Steven
    Dec 22 at 14:50






  • 1




    Does this answer solve your problem?
    – Tseng
    Dec 23 at 18:04










  • yes it works, thanks for the great suggestion
    – MCR
    2 days ago




















  • Change your design. Extract the arg into a Parameter Object and inject that.
    – Steven
    Dec 22 at 14:50






  • 1




    Does this answer solve your problem?
    – Tseng
    Dec 23 at 18:04










  • yes it works, thanks for the great suggestion
    – MCR
    2 days ago


















Change your design. Extract the arg into a Parameter Object and inject that.
– Steven
Dec 22 at 14:50




Change your design. Extract the arg into a Parameter Object and inject that.
– Steven
Dec 22 at 14:50




1




1




Does this answer solve your problem?
– Tseng
Dec 23 at 18:04




Does this answer solve your problem?
– Tseng
Dec 23 at 18:04












yes it works, thanks for the great suggestion
– MCR
2 days ago






yes it works, thanks for the great suggestion
– MCR
2 days ago














3 Answers
3






active

oldest

votes


















19














The expression parameter (x in this case), of the factory delegate is a IServiceProvider.



Use that to resolve the dependencies,



_serviceCollection.AddSingleton<IService>(x => 
new Service(x.GetRequiredService<IOtherService>(),
x.GetRequiredService<IAnotherOne>(),
""));


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.






share|improve this answer























  • yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
    – MCR
    Dec 21 at 12:02








  • 1




    No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
    – Nkosi
    Dec 21 at 12:03










  • @MCR that is the default approach with the Core DI out of the box.
    – Nkosi
    Dec 21 at 12:09






  • 2




    @Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
    – Tseng
    Dec 21 at 13:20



















7














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:



_serviceCollection.AddSingleton<IService>(x => 
ActivatorUtilities.CreateInstance<Service>(x, "");
);


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 has IOtherService, ILogger<MyService> as dependencies and you want to resolve the service but replace the default service of IOtherService (say its OtherServiceA) with OtherServiceB, you could do something like:



myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())


Then the first parameter of IOtherService will get OtherServiceB injected, rather than OtherServiceA 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 via



var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new { typeof(IOtherService) });


then cache it (as a variable etc) and call it where needed



MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);


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:



class Program
{
static void Main(string args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));

var provider = services.BuildServiceProvider();

var demoService = provider.GetRequiredService<DemoService>();

Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}

public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;

public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}

public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}

// Just a helper method to shorten code registration code
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}


Prints




Output: Hello Tseng Stackoverflow






share|improve this answer



















  • 3




    This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
    – Tseng
    Dec 21 at 13:40





















5














If you fell uncomfortable with newing the service, you could use the Parameter Object pattern.



So extract the string parameter into its own type



public class ServiceArgs
{
public string Arg1 {get; set;}
}


And the constructor now it will look like



public Service(IOtherService service1, 
IAnotherOne service2,
ServiceArgs args)
{

}


And the setup



_serviceCollection.AddSingleton<ServiceArgs>(_ => new ServiceArgs { Arg1 = ""; });
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService, Service>();


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.






share|improve this answer





















  • It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
    – Tseng
    Dec 22 at 15:22











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53884417%2fnet-core-di-ways-of-passing-parameters-to-constructor%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









19














The expression parameter (x in this case), of the factory delegate is a IServiceProvider.



Use that to resolve the dependencies,



_serviceCollection.AddSingleton<IService>(x => 
new Service(x.GetRequiredService<IOtherService>(),
x.GetRequiredService<IAnotherOne>(),
""));


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.






share|improve this answer























  • yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
    – MCR
    Dec 21 at 12:02








  • 1




    No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
    – Nkosi
    Dec 21 at 12:03










  • @MCR that is the default approach with the Core DI out of the box.
    – Nkosi
    Dec 21 at 12:09






  • 2




    @Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
    – Tseng
    Dec 21 at 13:20
















19














The expression parameter (x in this case), of the factory delegate is a IServiceProvider.



Use that to resolve the dependencies,



_serviceCollection.AddSingleton<IService>(x => 
new Service(x.GetRequiredService<IOtherService>(),
x.GetRequiredService<IAnotherOne>(),
""));


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.






share|improve this answer























  • yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
    – MCR
    Dec 21 at 12:02








  • 1




    No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
    – Nkosi
    Dec 21 at 12:03










  • @MCR that is the default approach with the Core DI out of the box.
    – Nkosi
    Dec 21 at 12:09






  • 2




    @Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
    – Tseng
    Dec 21 at 13:20














19












19








19






The expression parameter (x in this case), of the factory delegate is a IServiceProvider.



Use that to resolve the dependencies,



_serviceCollection.AddSingleton<IService>(x => 
new Service(x.GetRequiredService<IOtherService>(),
x.GetRequiredService<IAnotherOne>(),
""));


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.






share|improve this answer














The expression parameter (x in this case), of the factory delegate is a IServiceProvider.



Use that to resolve the dependencies,



_serviceCollection.AddSingleton<IService>(x => 
new Service(x.GetRequiredService<IOtherService>(),
x.GetRequiredService<IAnotherOne>(),
""));


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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 21 at 14:23









No Refunds No Returns

5,35431936




5,35431936










answered Dec 21 at 11:59









Nkosi

109k16117184




109k16117184












  • yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
    – MCR
    Dec 21 at 12:02








  • 1




    No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
    – Nkosi
    Dec 21 at 12:03










  • @MCR that is the default approach with the Core DI out of the box.
    – Nkosi
    Dec 21 at 12:09






  • 2




    @Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
    – Tseng
    Dec 21 at 13:20


















  • yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
    – MCR
    Dec 21 at 12:02








  • 1




    No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
    – Nkosi
    Dec 21 at 12:03










  • @MCR that is the default approach with the Core DI out of the box.
    – Nkosi
    Dec 21 at 12:09






  • 2




    @Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
    – Tseng
    Dec 21 at 13:20
















yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
– MCR
Dec 21 at 12:02






yes, this is the way I'm doing it right now, but is there any other way ? more elegant maybe ? I mean It would look a little weird to have other parameters that are registered services. I am looking for something more like register the services normally and only pass the non-service arguments, in this case the arg. Something like Autofac does .WithParameter("argument", "");
– MCR
Dec 21 at 12:02






1




1




No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
– Nkosi
Dec 21 at 12:03




No you are building the provider manually, which is bad. The delegate is a delayed invocation. When ever the type is to be resolved it will pass the completed provider as the delegate parameter.
– Nkosi
Dec 21 at 12:03












@MCR that is the default approach with the Core DI out of the box.
– Nkosi
Dec 21 at 12:09




@MCR that is the default approach with the Core DI out of the box.
– Nkosi
Dec 21 at 12:09




2




2




@Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
– Tseng
Dec 21 at 13:20




@Nkosi: Have a look at ActivatorUtilities.CreateInstance, its part of the Microsoft.Extensions.DependencyInjection.Abstractions package (so no container specific dependencies)
– Tseng
Dec 21 at 13:20













7














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:



_serviceCollection.AddSingleton<IService>(x => 
ActivatorUtilities.CreateInstance<Service>(x, "");
);


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 has IOtherService, ILogger<MyService> as dependencies and you want to resolve the service but replace the default service of IOtherService (say its OtherServiceA) with OtherServiceB, you could do something like:



myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())


Then the first parameter of IOtherService will get OtherServiceB injected, rather than OtherServiceA 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 via



var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new { typeof(IOtherService) });


then cache it (as a variable etc) and call it where needed



MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);


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:



class Program
{
static void Main(string args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));

var provider = services.BuildServiceProvider();

var demoService = provider.GetRequiredService<DemoService>();

Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}

public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;

public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}

public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}

// Just a helper method to shorten code registration code
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}


Prints




Output: Hello Tseng Stackoverflow






share|improve this answer



















  • 3




    This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
    – Tseng
    Dec 21 at 13:40


















7














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:



_serviceCollection.AddSingleton<IService>(x => 
ActivatorUtilities.CreateInstance<Service>(x, "");
);


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 has IOtherService, ILogger<MyService> as dependencies and you want to resolve the service but replace the default service of IOtherService (say its OtherServiceA) with OtherServiceB, you could do something like:



myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())


Then the first parameter of IOtherService will get OtherServiceB injected, rather than OtherServiceA 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 via



var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new { typeof(IOtherService) });


then cache it (as a variable etc) and call it where needed



MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);


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:



class Program
{
static void Main(string args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));

var provider = services.BuildServiceProvider();

var demoService = provider.GetRequiredService<DemoService>();

Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}

public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;

public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}

public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}

// Just a helper method to shorten code registration code
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}


Prints




Output: Hello Tseng Stackoverflow






share|improve this answer



















  • 3




    This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
    – Tseng
    Dec 21 at 13:40
















7












7








7






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:



_serviceCollection.AddSingleton<IService>(x => 
ActivatorUtilities.CreateInstance<Service>(x, "");
);


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 has IOtherService, ILogger<MyService> as dependencies and you want to resolve the service but replace the default service of IOtherService (say its OtherServiceA) with OtherServiceB, you could do something like:



myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())


Then the first parameter of IOtherService will get OtherServiceB injected, rather than OtherServiceA 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 via



var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new { typeof(IOtherService) });


then cache it (as a variable etc) and call it where needed



MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);


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:



class Program
{
static void Main(string args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));

var provider = services.BuildServiceProvider();

var demoService = provider.GetRequiredService<DemoService>();

Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}

public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;

public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}

public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}

// Just a helper method to shorten code registration code
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}


Prints




Output: Hello Tseng Stackoverflow






share|improve this answer














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:



_serviceCollection.AddSingleton<IService>(x => 
ActivatorUtilities.CreateInstance<Service>(x, "");
);


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 has IOtherService, ILogger<MyService> as dependencies and you want to resolve the service but replace the default service of IOtherService (say its OtherServiceA) with OtherServiceB, you could do something like:



myService = ActivatorUtilities.CreateInstance<Service>(serviceProvider, new OtherServiceB())


Then the first parameter of IOtherService will get OtherServiceB injected, rather than OtherServiceA 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 via



var myServiceFactory = ActivatorUtilities.CreateFactory(typeof(MyService), new { typeof(IOtherService) });


then cache it (as a variable etc) and call it where needed



MyService myService = myServiceFactory(serviceProvider, myServiceOrParameterTypeToReplace);


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:



class Program
{
static void Main(string args)
{
var services = new ServiceCollection();
services.AddTransient<HelloWorldService>();
services.AddTransient(p => p.ResolveWith<DemoService>("Tseng", "Stackoverflow"));

var provider = services.BuildServiceProvider();

var demoService = provider.GetRequiredService<DemoService>();

Console.WriteLine($"Output: {demoService.HelloWorld()}");
Console.ReadKey();
}
}

public class DemoService
{
private readonly HelloWorldService helloWorldService;
private readonly string firstname;
private readonly string lastname;

public DemoService(HelloWorldService helloWorldService, string firstname, string lastname)
{
this.helloWorldService = helloWorldService ?? throw new ArgumentNullException(nameof(helloWorldService));
this.firstname = firstname ?? throw new ArgumentNullException(nameof(firstname));
this.lastname = lastname ?? throw new ArgumentNullException(nameof(lastname));
}

public class HelloWorldService
{
public string Hello(string name) => $"Hello {name}";
public string Hello(string firstname, string lastname) => $"Hello {firstname} {lastname}";
}

// Just a helper method to shorten code registration code
static class ServiceProviderExtensions
{
public static T ResolveWith<T>(this IServiceProvider provider, params object parameters) where T : class =>
ActivatorUtilities.CreateInstance<T>(provider, parameters);
}


Prints




Output: Hello Tseng Stackoverflow







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 22 at 16:01

























answered Dec 21 at 13:10









Tseng

33k588119




33k588119








  • 3




    This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
    – Tseng
    Dec 21 at 13:40
















  • 3




    This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
    – Tseng
    Dec 21 at 13:40










3




3




This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
– Tseng
Dec 21 at 13:40






This is also how ASP.NET Core instantiates the Controllers by default ControllerActivatorProvider, they are not directly resolved from the IoC (unless .AddControllersAsServices is used, which replaces the ControllerActivatorProvider with ServiceBasedControllerActivator
– Tseng
Dec 21 at 13:40













5














If you fell uncomfortable with newing the service, you could use the Parameter Object pattern.



So extract the string parameter into its own type



public class ServiceArgs
{
public string Arg1 {get; set;}
}


And the constructor now it will look like



public Service(IOtherService service1, 
IAnotherOne service2,
ServiceArgs args)
{

}


And the setup



_serviceCollection.AddSingleton<ServiceArgs>(_ => new ServiceArgs { Arg1 = ""; });
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService, Service>();


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.






share|improve this answer





















  • It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
    – Tseng
    Dec 22 at 15:22
















5














If you fell uncomfortable with newing the service, you could use the Parameter Object pattern.



So extract the string parameter into its own type



public class ServiceArgs
{
public string Arg1 {get; set;}
}


And the constructor now it will look like



public Service(IOtherService service1, 
IAnotherOne service2,
ServiceArgs args)
{

}


And the setup



_serviceCollection.AddSingleton<ServiceArgs>(_ => new ServiceArgs { Arg1 = ""; });
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService, Service>();


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.






share|improve this answer





















  • It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
    – Tseng
    Dec 22 at 15:22














5












5








5






If you fell uncomfortable with newing the service, you could use the Parameter Object pattern.



So extract the string parameter into its own type



public class ServiceArgs
{
public string Arg1 {get; set;}
}


And the constructor now it will look like



public Service(IOtherService service1, 
IAnotherOne service2,
ServiceArgs args)
{

}


And the setup



_serviceCollection.AddSingleton<ServiceArgs>(_ => new ServiceArgs { Arg1 = ""; });
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService, Service>();


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.






share|improve this answer












If you fell uncomfortable with newing the service, you could use the Parameter Object pattern.



So extract the string parameter into its own type



public class ServiceArgs
{
public string Arg1 {get; set;}
}


And the constructor now it will look like



public Service(IOtherService service1, 
IAnotherOne service2,
ServiceArgs args)
{

}


And the setup



_serviceCollection.AddSingleton<ServiceArgs>(_ => new ServiceArgs { Arg1 = ""; });
_serviceCollection.AddSingleton<IOtherService , OtherService>();
_serviceCollection.AddSingleton<IAnotherOne , AnotherOne>();
_serviceCollection.AddSingleton<IService, Service>();


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.







share|improve this answer












share|improve this answer



share|improve this answer










answered Dec 21 at 12:31









Adrian Iftode

13.4k23565




13.4k23565












  • It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
    – Tseng
    Dec 22 at 15:22


















  • It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
    – Tseng
    Dec 22 at 15:22
















It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
– Tseng
Dec 22 at 15:22




It would be more intuitive for complex parameters to use the Options pattern and is the recommended way for options pattern, however is less suitable for parameters only know at runtime (i.e. from a request or a claim)
– Tseng
Dec 22 at 15:22


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53884417%2fnet-core-di-ways-of-passing-parameters-to-constructor%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

數位音樂下載

When can things happen in Etherscan, such as the picture below?

格利澤436b