Dependency Injection with .NET Core

Configuring Startup Services and in .NET Core Web APIs

Updated: 03 September 2023

You can think of a service simply as a reusable class instance that can be reused in different controllers. This can be injected via dependency injection where it is needed

Define a Service

To create a new service, you will first need to define a class that provides the relevant functionality. We can define a simple class for a service as follows:

1
public class MyCat {
2
public string Name { get; set; }
3
4
public MyCat(string name)
5
{
6
Name = name;
7
}
8
9
public string SayHi ()
10
{
11
return "Hello, from " + Name;
12
}
13
}

Add Service

You can the define this as a service in your startup.cs file’s ConfigureServices method with the services<T>.AddScoped function to create a service that can be used by your controllers

1
services.AddScoped<MyCat>(serviceProvider => new MyCat("Bob"));

Additionally if you would like your service to be able to make use of other services, or do any more complex things, you can access the different parts of the lambda, such as reading from the application config the Name value

1
services.AddScoped<MyCat>(serviceProvider => {
2
var config = serviceProvider.GetRequiredService<IConfiguration>();
3
var name = config.GetValue<string>("Name");
4
5
return new MyCat(name);
6
});

Using the same pattern as above, we can define an SMTP Client with preconfigured information with the following:

1
services.AddScoped<SmtpClient>(serviceProvider => {
2
var config = serviceProvider.GetRequiredService<IConfiguration>();
3
return new SmtpClient()
4
{
5
UseDefaultCredentials = false,
6
EnableSsl = true,
7
Host = config.GetValue<string>("Host"),
8
Port = config.GetValue<int>("Port"),
9
Credentials = new NetworkCredential(
10
config.GetValue<string>("Username"),
11
config.GetValue<string>("Password"),
12
config.GetValue<string>("Domain")
13
)
14
};
15
});

The service can then be used by a controller by including a reference based on the service type in the controller’s constructor and its functionality can be used by the controller like with the example below:

1
public class CatController : Controller
2
{
3
4
private MyCat _cat;
5
6
public CatController(MyCat cat)
7
{
8
_cat = cat;
9
}
10
11
public ActionResult Index()
12
{
13
return _cat.SayHi();
14
}
15
}

Note that the MyCat service is injected into our controller simply by us defining it in the constructor as a dependency

Different ConnectedServices by Environment

Using the above approach combined with the Visual Studio Connected Services / svcutil functionality you can set up a different service instance based on your environment configuration with something like this:

1
services.AddScoped(serviceProvider => {
2
var endpoint = serviceProvider
3
.GetRequiredService<Iconfiguration>()
4
.GetValue<string>("WSDLEndpoint");
5
6
var endpointConfig = ServiceName.ClientName.EndpointConfig.ConfigValue;
7
8
var myClient = new ServiceName.ClientName(endpointConfig, endpoint);
9
10
reutrn myClient
11
});