Chapter 3: Customizing Dependency Injection

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:

  • Using a different DI container
  • Exploring the ConfigureServices method
  • Using a different ServiceProvider
  • Introducing Scrutor

The topics in this chapter refer to the hosting layer of the ASP.NET Core architecture:

Figure 3.1 – ASP.NET Core architecture

Figure 3.1 – ASP.NET Core architecture

Technical requirements

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.

Using a different DI container

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:

  • Create an application that supports modules as lightweight dependencies using Ninject, for example, modules you might want to put into a specific directory and have them be automatically registered in your application.
  • Configure the services in a configuration file outside the application, in an XML or JSON file instead of in C# only. This is a common feature in various DI containers, but not yet supported in ASP.NET Core.
  • Add services at runtime, probably because you don't want to have an immutable DI container. This is also a common feature in some DI containers.

Let's now see how the ConfigureServices method enables you to use alternative DI containers.

Exploring the ConfigureServices method

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.

Using a different ServiceProvider

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:

  1. Let's start by using Autofac as a third-party container. Type the following command into your command line to load the NuGet package:

    dotnet add package Autofac.Extensions.DependencyInjection

    Autofac is good for this because you are easily able to see what is happening here.

  2. To register a custom IoC container, you need to register a different IServiceProviderFactory. In that case, you'll want to use AutofacServiceProviderFactory if you use Autofac. IServiceProviderFactory will create a ServiceProvider instance. The third-party container should provide one, if it supports ASP.NET Core.

    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.

  3. To use this extension method, you can use AutofacServiceProvider in Program.cs:

    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.

Introducing Scrutor

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/.

Summary

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.66.106