.NET Core DI, ways of passing parameters to constructor
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
add a comment |
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
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
add a comment |
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
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
c# asp.net-core dependency-injection .net-core ioc-container
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
add a comment |
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
add a comment |
3 Answers
3
active
oldest
votes
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.
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 theMicrosoft.Extensions.DependencyInjection.Abstractions
package (so no container specific dependencies)
– Tseng
Dec 21 at 13:20
add a comment |
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
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 theControllerActivatorProvider
withServiceBasedControllerActivator
– Tseng
Dec 21 at 13:40
add a comment |
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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 theMicrosoft.Extensions.DependencyInjection.Abstractions
package (so no container specific dependencies)
– Tseng
Dec 21 at 13:20
add a comment |
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.
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 theMicrosoft.Extensions.DependencyInjection.Abstractions
package (so no container specific dependencies)
– Tseng
Dec 21 at 13:20
add a comment |
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.
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.
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 theMicrosoft.Extensions.DependencyInjection.Abstractions
package (so no container specific dependencies)
– Tseng
Dec 21 at 13:20
add a comment |
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 theMicrosoft.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
add a comment |
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
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 theControllerActivatorProvider
withServiceBasedControllerActivator
– Tseng
Dec 21 at 13:40
add a comment |
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
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 theControllerActivatorProvider
withServiceBasedControllerActivator
– Tseng
Dec 21 at 13:40
add a comment |
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
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
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 theControllerActivatorProvider
withServiceBasedControllerActivator
– Tseng
Dec 21 at 13:40
add a comment |
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 theControllerActivatorProvider
withServiceBasedControllerActivator
– 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
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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