X

Dependency injection in Blazor

In one of my previous Blazor post Separating code and presentation of Blazor pages I briefly covered dependency injection in Blazor views and components. This posting makes step further and based on my Blazor demo solution it shows how to inject custom instances to Blazor pages using built-in dependency injection.

Source code! This blog post is based on my Blazor demo application. It is simple application for books database with server back-end that demonstrates Blazor features and gives some guidance about how to things on Blazor. Demo application is available in my GitHub repository gpeipman/BlazorDemo.

Before this post my sample application used direct calls to server API through built-in HTTP client. To demonstrate how dependency injection works we will replace HTTP client in components with special books database client that hides calls to server API from Blazor views.

Defining books client

We start by defining interface for books API client and this interface goes to shared project.

public interface IBooksClient
{
    Task<PagedResult<Book>> ListBooks(int page);
    Task<Book> GetBook(int id);
    Task SaveBook(Book book);
    Task DeleteBook(Book book);
    Task DeleteBook(int id);
}

To stay safe and avoid using HttpClient methods that may not be allowed in browser I define implementation in Blazor UI project to use safe JSON extensions that are convenient too.

public class BooksClient : IBooksClient
{
    private readonly HttpClient _httpClient;

    public BooksClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task DeleteBook(Book book)
    {
        await DeleteBook(book.Id);
    }

    public async Task DeleteBook(int id)
    {
        await _httpClient.PostAsync("/Books/Delete/" + id, null);
    }

    public async Task<PagedResult<Book>> ListBooks(int page)
    {
        return await _httpClient.GetJsonAsync<PagedResult<Book>>("/Books/Index/page/" + page);
    }

    public async Task<Book> GetBook(int id)
    {
        return await _httpClient.GetJsonAsync<Book>("/Books/Get/" + id);
    }

    public async Task SaveBook(Book book)
    {
        await _httpClient.PostJsonAsync("/Books/Save", book);
    }
}

Now we have all dirty details of communicating with server API hidden to BooksClient class and it’s time to register it for dependency injection.

Introducing books client to Blazor dependency injection

Introducing new books service to built-in dependency injection is actually easy. It is very similar to how we do it in ASP.NET Core. Just open Program.cs in Blazor UI project and make Program class look like shown here.

public class Program
{
    static void Main(string[] args)
    {
        var serviceProvider = new BrowserServiceProvider(services =>
        {
            services.AddSingleton<IBooksClient, BooksClient>();
        });

        new BrowserRenderer(serviceProvider).AddComponent<App>("app");
    }
}

We don’t have here Startup class we know from ASP.NET Core but it’s still easy to introduce our custom services to built-in dependency injection.

Injection books client to Blazor views

In my solution I have base class for Blazor pages and components that need routing and access to server API. As we have now BooksClient class available we have to introduce it to pages where something is done with books. This is the new version of BaseComponent class I created to Blazor UI project.

public abstract class BaseComponent : BlazorComponent
{
    [Inject]
    protected IUriHelper UriHelper { get; set; }

    [Inject]
    protected IBooksClient BooksClient { get; set; }
}

Notice how dependency injection is done here. I define protected members and decorate them with InjectAttribute.

This is how book editing and adding page uses BooksClient class.

protected async Task LoadBook(int id)
{
    CurrentBook = await BooksClient.GetBook(id);
}

protected async Task Save()
{
    await BooksClient.SaveBook(CurrentBook);

    UriHelper.NavigateTo("/");
}

Not much different from using direct calls to server API but still better because it is always possible to change APi end-point addresses easily and add some additional logic to client if needed.

Wrapping up

Dependency injection in Blazor is similar to what we have in ASP.NET Core and using this mechanism we can inject correct instances of services to Blazor components. To get dependencies injected to views we are using InjectAttribute or view injection similar to what we have in Razor views with ASP.NET Core.

Liked this post? Empower your friends by sharing it!
Categories: ASP.NET Blazor

View Comments (3)

  • Have you done much with the Flux/Redux pattern? I've used it for about the past year in angular (ngrx/store) and quite looked it (except for their choice of rxjs).

    First thing I did with Blazor was to write my own library. It's so much easier in C#!

    Take a look and please let me know if you have any suggestions for improvements. The docs have links to running demos on Azure.

    https://mrpmorris.github.io/blazor-fluxor/

Related Post