In this third chapter, we'll take a look at ASP.NET Core dependency injection (DI) and how to customize it to use a different DI container, if needed.
In this chapter, we will be covering the following topics:
The topics in this chapter refer to the hosting layer of the ASP.NET Core architecture:
To follow the descriptions in this chapter, you will need to create an ASP.NET Core MVC application. Open your console, shell, or Bash terminal and change to your working directory. Use the following command to create a new MVC application:
dotnet new mvc -n DiSample -o DiSample
Now, open the project in Visual Studio by double-clicking the project file, or in Visual Studio Code by typing the following command in the already-open console:
cd DiSample
code .
All of the code samples in this chapter can be found in the GitHub repository for this book at https://github.com/PacktPublishing/Customizing-ASP.NET-Core-6.0-Second-Edition/tree/main/Chapter03.
In most projects, you don't really need to use a different DI container. The existing DI implementation in ASP.NET Core supports the main basic features and works both effectively and quickly. However, some other DI containers support a number of interesting features you might want to use in your application:
Let's now see how the ConfigureServices method enables you to use alternative DI containers.
Let's compare the current ConfigureServices method with a previous long-term support version to see what has changed. If you created a new ASP.NET Core project using version 3.1 and open Startup.cs, you will find the method to configure the services, which looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user
// consent for non-essential cookies is
// needed for a given request.
options.CheckConsentNeeded = context => true;
});
services.AddControllersWithViews();
services.AddRazorPages();
}
In contrast, in ASP.NET Core 6.0, there is no Startup.cs anymore, and the configuring of the services is done in Program.cs, which looks like this:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// The rest of the file isn't relevant for this chapter
In both cases, the method gets IServiceCollection, which is already filled with a bunch of services that are required by ASP.NET Core. This service was added by the hosting services and parts of ASP.NET Core that are executed before the ConfigureServices method was called.
Inside the method, some more services are added. First, a configuration class that contains cookie policy options is added to ServiceCollection. After that, the AddMvc() method adds another bunch of services required by the MVC framework. So far, we have around 140 services registered to IServiceCollection. However, the service collection isn't the actual DI container.
The actual DI container is wrapped in the so-called service provider, which will be created out of the service collection. IServiceCollection has an extension method registered to create an IServiceProvider out of the service collection, which you can see in the following code snippet:
IServiceProvider provider = services.BuildServiceProvider()
ServiceProvider contains the immutable container that cannot be changed at runtime. With the default ConfigureServices method, IServiceProvider is created in the background after this method is called.
Next, we'll learn more about applying an alternative ServiceProvider as part of the DI customization process.
Changing to a different or custom DI container is relatively easy if the other container already supports ASP.NET Core. Usually, the other container will use IServiceCollection to feed its own container. The third-party DI containers move the already-registered services to the other container by looping over the collection:
dotnet add package Autofac.Extensions.DependencyInjection
Autofac is good for this because you are easily able to see what is happening here.
You should place this small extension method in Program.cs to register AutofacServiceProviderFactory with IHostBuilder:
using Autofac;
using Autofac.Extensions.DependencyInjection;
namespace DiSample;
public static class IHostBuilderExtension
{
public static IHostBuilder
UseAutofacServiceProviderFactory(
this IHostBuilder hostbuilder)
{
hostbuilder.UseServiceProviderFactory
<ContainerBuilder>(
new AutofacServiceProviderFactory());
return hostbuilder;
}
}
Don't forget to add using statements to Autofac and Autofac.Extensions.DependencyInjection.
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseAutofacServiceProviderFactory();
// Add services to the container.
builder.Services.AddControllersWithViews();
This adds the AutofacServiceProviderFactory function to IHostBuilder and enables the Autofac IoC container. If you have this in place, you will use Autofac if you add services to IServiceCollection using the default way.
You don't always need to replace the existing .NET Core DI container to get and use some cool features. At the beginning of this chapter, I mentioned the autoregistration of services, which can be done with other DI containers. This can also be done with a nice NuGet package called Scrutor (https://github.com/khellang/Scrutor) by Kristian Hellang (https://kristian.hellang.com). Scrutor extends IServiceCollection to automatically register services with the .NET Core DI container.
Note
Andrew Lock has published a pretty detailed blog post relating to Scrutor. Rather than just repeating what he said, I suggest that you just go ahead and read that post to learn more about it: Using Scrutor to automatically register your services with the ASP.NET Core DI container, available at https://andrewlock.net/using-scrutor-to-automatically-register-your-services-with-the-asp-net-core-di-container/.
Using the approaches we have demonstrated in this chapter, you will be able to use any .NET Standard-compatible DI container to replace the existing one. If the container of your choice doesn't include ServiceProvider, create your own that implements IServiceProvider and uses the DI container inside. If the container of your choice doesn't provide a method to populate the registered services in the container, create your own method. Loop over the registered services and add them to the other container.
Actually, the last step sounds easy but can be a hard task, because you need to translate all the possible IServiceCollection registrations into registrations of the other container. The complexity of that task depends on the implementation details of the other DI container.
Anyway, you have the choice to use any DI container that is compatible with .NET Standard. You can change a lot of the default implementations in ASP.NET Core.
This is also something you can do with the default HTTPS behavior on Windows, which we will learn more about in the next chapter.
3.17.66.106