What is a service collection?

Service collections are a way of registering and resolving dependencies in C# applications using the built-in dependency injection (DI) system. Blazor Server is a web framework that allows you to run C# code on the server and interact with the user interface through a SignalR connection. To use service collections in Blazor Server, you need to register your services in the Program class, which is executed when the application starts.

How to register a service that implements an interface

Program.cs

				
					var builder = WebApplication.CreateBuilder(args);

builder.Services.AddServerSideBlazor();
//ILogService is a service we created that we want available throughout the application
builder.Services.AddScoped<ILogService, LogService>();
.
.
var app = builder.Build();
app.Run();
				
			

This means that whenever a component or a class needs an instance of ILogService, it will get an instance of LogService that is scoped to the current connection. You can also use other lifetimes, such as Singleton or Transient, depending on your needs.

How to resolve a service in a Razor component

CoolComponent.razor

				
					@inject ILogService logService

@code
{
    protected override async Task OnInitializedAsync()
    {
        await logService.WriteLogAsync(Level.Info, "Cool Component Loaded");
    }
}
				
			

This will inject an instance of ILogService into the CoolComponent and make it available as a property named service. You can then use this property to access the methods and properties of the service such as WriteLogAsync()

What happens when you have a lot of dependencies?

Sometimes Program.cs ends up getting large and unwieldly as an applications evolves and matures. Luckily the solution to this is the service collection extension pattern.

The solution: Service Extension Collection Pattern

The service collection extension pattern is a way of organizing the dependency injection configuration for ASP.NET Core applications. It allows you to create extension methods on the IServiceCollection interface that register your services in a modular and reusable way. For example, you can create a method like builder.Services.AddOrderManagementServices() that registers all the services from your class library project .

This pattern can be useful for Blazor Server applications, which use ASP.NET Core as the host environment. Blazor Server applications are stateful and maintain a circuit between the server and the client. This means that you need to be careful about how you use singleton/scoped and transient services, as they may have a longer lifetime than expected. By using the service collection extension pattern, you can encapsulate the logic of registering your services with the appropriate lifetime and options.

One benefit of this pattern is that it can make your Blazor components more flexible and adaptable to different hosting models. For example, you can create a service that abstracts the data access logic for your components, and then register it with different implementations depending on whether you are using Blazor Server or Blazor WebAssembly. This way, you can reuse your components without changing their code. Another benefit is that it can make your Program.cs more concise and readable, as you can group related services into one extension method.

How to implement a service collection extension

AddOrderManagementServices.cs

				
					public static class OrderManagementServiceExtensions
    {
        public static IServiceCollection AddOrderManagementServices(this IServiceCollection services)
        {
            services.AddScoped<IOmsHeaderService, OmsHeaderService>();
            services.AddScoped<IOmsDetailService, OmsDetailService>();
            services.AddScoped<IChargesService, ChargesService>();
            services.AddScoped<ILoadService, LoadSerivce>();
            services.AddScoped<ITransportationService, TransportationService>();
            services.AddScoped<IChargesService, ChargesService>();
            services.AddScoped<IUserRepository, UserRepository>();
            services.AddScoped<IUserRoleService, UserRoleService>();
            services.AddScoped<IEdiService, EdiService>();
            services.AddScoped<ILogService, LogService>();
            services.AddScoped<IFreightRateService, FreightRateService>();
            services.AddScoped<IReportService, ReportService>();
            services.AddScoped<IRpcService, RpcService>();
            services.AddScoped<IContactService, ContactService>();
            services.AddScoped<ISupplierWorkFlowService, SupplierWorkFlowService>();
            services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
            services.AddScoped<DateFilterStateContainer>();
            services.AddScoped<LayoutStateContainer>();

            return services;
        }
    }
				
			

Then, in your Blazor Server app’s Program.cs class, you can call the extension method

Program.cs

				
					builder.Services.AddOrderManagementServices();
.
.
.
var app = builder.Build();
.
.
app.Run();
				
			

A lot more concise, huh?

Program.cs

By using this pattern, you can simplify and organize your service registration code, and enjoy the benefits of dependency injection in your Blazor Server applications.

Want to learn more?

IHttpClientFactory vs. HttpClient

Why should you use IHttpClientFactory The main reason to use IHttpClientFactoryinstead of HttpClient directly is to manage the life cycle of HttpClient instances. HttpClient was designed to be instantiated once and reused throughout the application…

Read more