Blazor Simple CQRS with MediatR

Strong Recommendation

I strongly recommend you take the time to watch NDC 2018 session entitled Vertical Slice Architecture – Jimmy Bogard at the bottom of this blog post.

Unless you give yourself a chance to understand MediatR and the motivations for using it, you won’t get much out of the blog post. After this one hour video, come back and read this blog post.

This blog post examines using MediatR in Blazor applications.

Introduction

I’m a pragmatic software architect and developer. I try to write the most straightforward code that can easily be understood and maintained over time. When learning and adopting a new UI stack or platform, I spin up spikes to learn the API’s, figure out cross-cutting concerns, and discover patterns that are a natural fit. Individual spikes allow me to explore and learn concepts and patterns without the noise of an entire application.

In 2004-2008, I wrote a good number of ASP.NET Web Forms applications for customers around the United States. These were e-commerce, online bill pay, tax assessment, customer portal, and property tax applications. Many of the forms required dropdowns and other data that was directly related to performing an insert or update. In other words, the shape of the data to load the form was different than the shape of the data to perform the user action. All of my forms hit the database once during load and returned the data for the form (dropdown data was cached). I wrote a two-way data binder control that automatically performed the insert, updates, or deletes. I was doing an elementary form of Command query responsibility segregation (CQRS) without knowing it.

The pattern of querying data and getting a different shape than the shape of the data to update, delete or insert, was as natural, simple, performant, and easy to understand and maintain. I didn’t need a masters degree in software design to write the code this way, it just made sense.

This blog post covers my first spike for the Blazor Moo2U application I’m writing. The goal of this blog post is to discover if the CQRS pattern is a good fit and if the MediatR library can help implement the pattern.

In this blog post, we will be looking into a server-side Blazor app. In server-side Blazor apps, UI logic can be located in either the @code block in the .razor file, in a code-behind C# file, or view model file.

I’ve grown attached to the code-behind file pattern. It fits Blazor very well as the UI binds to properties, events, methods, and cascading parameters quite nicely. I like the tooling for C# files and it feels better than in a @code block. Although, @code blocks do make it easier when presenting since the HTML markup and code can be easily seen together.

Client-side Blazor is scheduled to ship in May 2020. For now, I’ll be sticking to server-side Blazor until Steve Sanderson declares there should be more breaking changes in future client-side releases. I fully expect to easily refactor any applications I’ve written using the server-side model to the client-side model when appropriate.

Source

https://github.com/Oceanware/BlazorMediatr

Goals

  • Author a testable, understandable, and maintainable application.
  • Execute code to get the required data for forms and execute a method to persist changes based on user action in the UI.
  • Enable cross-cutting concerns such as logging, auditing, validation, enabling retries, etc.
  • Use an application structure that supports medium to large size developer teams and embraces change.
  • Use patterns that empower developers to write code quicker with no or fewer defects.

Blazor CQRS with MediatR Library Video

Video walkthrough of the project.

CQS & CQRS Patterns

The command–query separation (CQS) and command-query-responsibility-segregation (CQRS) patterns have been written about for years. There are many books, blog posts, and YouTube videos covering these subjects.

Almost without exception, all of my web, desktop, and mobile applications load their UI with data that is shaped differently than the data used to persist the insert, update, or delete operations.

The CQRS pattern defines a query for getting data, and a command to perform actions such as saving the form data.

We use this pattern at work on a very large Angular – Web API project with great success with developers of all skill levels and experience.

Is CQRS For Me?

If you read the below links, you can see that CQRS is more than queries and commands. Some of the links provide advice to not use CQRS if your app is simple and CRUD patterns would suffice. Obviously, the app presented here is a straightforward app that doesn’t require CQRS.

I would recommend you not base your decision solely on one metric, instead base your decision on how well this or any pattern, framework, or tool enables you to meet your GOALS and fulfill your requirements. Base your decision on the long-term impact and advantages your code and team receive.

CQRS Links
Microsoft Command and Query Responsibility Segregation (CQRS) pattern
Martin Fowler CQRS
Eleven labs CQRS Pattern
Google Search for CQRS

MediatR

What is, and what does MediatR provide?

From the MediatR GitHub ReadMe

Supports request/response, commands, queries, notifications, and events, synchronous and async with intelligent dispatching via C# generic variance.

From the MediatR Wiki

A low-ambition library trying to solve a simple problem – decoupling the in-proc sending of messages from handling messages.

The desire to write decoupled code does not have to come with a big price tag or bloated infrastructure. MediatR has no dependencies, is cross-platform, supporting all of .NET. MediatR is a library that helps implement the CQRS pattern in .NET applications.

The Pattern

MediatR usage is predictable and straightforward. A request is made, the handler handles the request and returns T. You’re an expert now.

The below code is from the SelfContainedExampleBase class. Mediator is injected into the class. To make a request use the Send method and pass the IRequest or IRequest argument. Mediator will invoke the appropriate handler. The handler will return the requested T object.

The below ViewModel is the EditForm Model for the SelfContainedExampleBase.razor page.

The SelectionsDto is returned by the handler and the ViewModel is populated. Roles and Names are the values that are displayed in the two InputSelect controls in the UI. The two InputSelect controls bind their values to the SelectedRole and SelectedName properties respectively. I’m showing only the Roles InputSelect for brevity.

protected override async Task OnInitializedAsync() {
    var selections = await this.Mediator.Send(new GetSelectionsQuery());
    this.Model = new ViewModel(selections.Roles, selections.Names);
}

public class GetSelectionsQuery : IRequest {
}

public class ViewModel {

    public IList Names { get; }
    public IList Roles { get; }
    public String SelectedName { get; set; }
    public String SelectedRole { get; set; }

    public ViewModel(IList roles, IList names) {
        this.Roles = roles;
        this.Names = names;
    }
}

<p>
    <label for="role">Role: </label>
    <InputSelect id="role" @bind-Value="Model.SelectedRole">
        <option value="">Select role ...</option>
        @foreach (var role in Model.Roles) {
            <option value=@role>@role</option>
        }
    </InputSelect>
</p>

The above has a simple implementation and comes at very little cost. The query requests all data required by the form; that data is used to populate a class that acts as the EditForm's Model, in our case a ViewModel instance. Remember, a view model is just a model class that provides data that is shaped specifically for its view.

Below, when the button is clicked the VerifySelections method is invoked. The VerifyAnswerCommand is processed the same as the above query. Like most commands, the VerifyAnswerCommand has a few properties that will be used by the handler. The handler returns a Boolean result and we update the UI accordingly.

<button class="btn btn-primary" @onclick="@VerifySelections">Verify Selections</button>

public async Task VerifySelections() {
    var result = await this.Mediator.Send(new VerifyAnswerCommand { 
        Name = this.Model.SelectedName, Role = this.Model.SelectedRole 
    });
    if (result) {
        this.Result = $"Outstanding, {this.Model.SelectedName}'s role is {this.Model.SelectedRole}";
    } else {
        this.Result = "Sorry give it another try.";
    }
}

The Two MediatR Implementations

I’ve provided two implementations of using MediatR so that you can compare them and if desired, adopt the one that fits your application, team, and requirements.

Self Contained SelfContainedExample
In Jimmy’s video, he showed the Self Contained version in his MVC Razor page app. All the required classes (less repository) are in the one file. Blazor server-side Razor pages can also be authored using this approach. Client-side apps will need to use the below Web API Style approach since the MediatR code will be in the controller route handlers.

This approach isolates the code from the rest of the application, making it almost impossible to introduce a bug in other unrelated code when making changes in the future to this code or any other code in the application.

Web API Style WebApiStyleExample
This approach places the queries, commands, handlers, and models in a familiar separate folder structure. You can see the green highlighted classes and their locations. The above self-contained version, highlighted in orange is a single file.

This is the approach you’ll use in Web API apps like a Blazor API for client-side apps. The Web API controllers will be very thin, each route handler containing the Mediator.Send call.

I have been considering the Web API Style approach for Blazor Moo2U because while the initial release will be Blazor server-side, I know that I will eventually refactor to the Web API / Blazor client-side app. Of course, refactoring a single file class to separate files is easy too. Got to love choices.

Pro’s and Con’s

Cons

  • More classes, more files.  Yes, we essentially took service methods and make each of them a handler class.

Pros

I’ve written some of the below Pro’s using different wording to hopefully enable the reader to see the valuer from multiple perspectives.

  • Mitigate service layer class bloat as features are added to the app over time since they are all handlers now instead of service methods.
  • Team development has way less merge conflicts when modifying a feature.
  • Team development has no merge conflicts when adding a feature since we are only adding code, no need to modify anything to add a feature.
  • Much easier to add a feature or modify one, since each feature is its own vertical slice of code.
  • MediatR has a built-in pipeline that effortlessly enables decorating handlers, resulting in effortless cross-cutting concern implementation.
  • Query responses provide everything a form requires to function.
  • Using this approach, to add a feature, you’re adding code, not changing existing code.
  • Imagine working on a large open source app like Moo2U, where multiple developers could be adding features simultaneously. This app structure easily supports this scenario without conflicts between developers.

Pipelines & Decorators

The MediatR library enables implementing cross-cutting concerns such as validation, logging, auditing, etc., by configuring the DI container. The developer does not have to deal with any of the code to handle these because MediatR organically supports a pipeline approach to processing messages and returning responses.

Blazor Moo2U will have all cross-cutting concerns handled by the MediatR pipeline.

Note: There is a difference between Blazor server-side application and a Web API application with respect to cross-cutting concerns. This is because Web API has its own pipeline to handle things like validating the model passed to the route handler and for catching exceptions and returning to the client caller the correct HTTP Status Code.

Pipeline Links
Mediatr Pipeline Examples
MediatR Behaviors
Tackling Cross-Cutting Concerns With A Mediator Pipeline
Add Validation To A Mediatr Behavior Pipeline
Defining Cross-Cutting Concerns Using The MediatR Library

MediatR Links

MediatR Wiki Docs
CQRS Using MediatR ASP .NET Core
A Non Trivial Example of MediatR Usage
MediatR YouTube Videos

Vertical Slice Architecture – Jimmy Bogard

Highly recommend you watch this video, you’ll learn a lot that can help you decide if this is for you and your team.

Close

There are no silver bullets in our profession. We look at the available information, compare with our requirements, and make the best decision.

Give, my stated goals, I think the CQRS pattern and MediatR Library will provide significant value to the Blazor Moo2U application.

I hope you find this information helpful. Enjoy authoring your Blazor applications!

Just a grain of sand on the world’s beaches.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s