0% found this document useful (0 votes)
288 views

Blazor Boilerplate: Release 2.0.0

The document discusses the Blazor Boilerplate starter template for building Blazor web apps. It provides an overview of the pros and cons of the two Blazor hosting models: Blazor Server and Blazor WebAssembly. It also describes the architecture of projects in the boilerplate, including dependencies between projects, and discusses how features like Breeze Sharp, Entity Framework Core, localization, and IdentityServer4 are implemented in the boilerplate.

Uploaded by

ddoru
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
288 views

Blazor Boilerplate: Release 2.0.0

The document discusses the Blazor Boilerplate starter template for building Blazor web apps. It provides an overview of the pros and cons of the two Blazor hosting models: Blazor Server and Blazor WebAssembly. It also describes the architecture of projects in the boilerplate, including dependencies between projects, and discusses how features like Breeze Sharp, Entity Framework Core, localization, and IdentityServer4 are implemented in the boilerplate.

Uploaded by

ddoru
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Blazor Boilerplate

Release 2.0.0

13.03.2021
Introduction

1 Blazor Server 3
1.1 Pros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Cons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Blazor WebAssembly 5
2.1 Pros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Cons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.1 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2.2 Breeze Sharp with Blazor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2.3 Entity Framework Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2.4 Localization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2.5 Deploy with Terraform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.6 Dual mode Blazor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.7 MultiTenancy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.8 IdentityServer4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

i
ii
Blazor Boilerplate, Release 2.0.0

Blazor Boilerplate is a starter template for Blazor web apps.


With Blazor Boilerplate you can easily switch between the two modes of Blazor.
From Microsoft documentation ASP.NET Core Blazor hosting models.

Introduction 1
Blazor Boilerplate, Release 2.0.0

2 Introduction
KAPITEL 1

Blazor Server

1.1 Pros

• Download size is significantly smaller than a Blazor WebAssembly app, and the app loads much faster.
• The app takes full advantage of server capabilities, including use of any .NET Core compatible APIs.
• .NET Core on the server is used to run the app, so existing .NET tooling, such as debugging, works as expected.
• Thin clients are supported. For example, Blazor Server apps work with browsers that don’t support WebAssem-
bly and on resource-constrained devices.
• The app’s .NET/C# code base, including the app’s component code, isn’t served to clients.

1.2 Cons

• Higher latency usually exists. Every user interaction involves a network hop.
• There’s no offline support. If the client connection fails, the app stops working.
• Scalability is challenging for apps with many users. The server must manage multiple client connections and
handle client state.
• An ASP.NET Core server is required to serve the app. Serverless deployment scenarios aren’t possible (for
example, serving the app from a CDN).

3
Blazor Boilerplate, Release 2.0.0

4 Kapitel 1. Blazor Server


KAPITEL 2

Blazor WebAssembly

2.1 Pros

• There’s no .NET server-side dependency. The app is fully functioning after it’s downloaded to the client.
• Client resources and capabilities are fully leveraged.
• Work is offloaded from the server to the client.
• An ASP.NET Core web server isn’t required to host the app. Serverless deployment scenarios are possible (for
example, serving the app from a CDN).

2.2 Cons

• The app is restricted to the capabilities of the browser.


• Capable client hardware and software (for example, WebAssembly support) is required.
• Download size is larger, and apps take longer to load.
• .NET runtime and tooling support is less mature. For example, limitations exist in .NET Standard support and
debugging.

5
Blazor Boilerplate, Release 2.0.0

6 Kapitel 2. Blazor WebAssembly


Blazor Boilerplate, Release 2.0.0

2.2.1 Architecture

The diagram shows the dependencies of the main projects. Every project with text to localize depends on Localization
project.
Client project is used only with Blazor WebAssembly, so it runs on the browser. It initializes the WebAssembly startup.
Server project manages the main services: authentication, authorization, API, etc.
Storage project manages the persistence of models in a database with Entity Framework Core.
Infrastructure project contains interfaces and models in common among projects running on server.
Shared project contains base interfaces and models in common among projects running on server or client.
Module projects contains UI, services, etc. that define your web application.

2.2.2 Breeze Sharp with Blazor

Bemerkung: What you will read here are my personal opinions. I have been using Breeze from years for both web
and desktop applications and I have no connection with Breeze team.
Giovanni Quarella

Recommended CRUD API design is too verborse and boring.


For each CRUD action Create, Read, Update and Delete you have to add a method to your API controller. Also you
have to repeat the same pattern for every entity of your application domain.
In real use cases you cannot perform also single actions on entities, because changes have to happen at the same time
in a transaction. So you have to write other code. . .

2.2. Cons 7
Blazor Boilerplate, Release 2.0.0

Do you know good coders are lazy? Do you know the DRY principle?
The solution is a Breeze Controller.
As you can read in the official documentation: “One controller to rule them all . . . ”.

Breeze Server

In this project the Breeze Controller is ApplicationController and the EFPersistenceManager is ApplicationPersis-
tenceManager.
The ApplicationController has no Authorize attribute, because to keep policy management with Breeze, I implemented
a simple custom policy management in ApplicationPersistenceManager.
First of all you can mark the EF entities with Permissions attribute which takes CRUD Actions flag enum as parameter.
Examples:

[Permissions(Actions.Delete)]
public partial class Todo
{
...
}

[Permissions(Actions.Create | Actions.Update)]
public partial class Todo
{
...
}

[Permissions(Actions.CRUD)]
public partial class Todo
{
...
}

In BeforeSaveEntities method of ApplicationPersistenceManager the actions of the entities to be saved are compared
with the claims of permission type of the current user. If a policy is violated an EntityErrorsException is thrown.
To check Actions.Read in ApplicationController you have to access EF DbSet with GetEntities method of Applica-
tionPersistenceManager.

Breeze.Sharp (Breeze C# client)

To access Breeze Controller you have to use Breeze.Sharp. In Blazor BlazorBoilerplate ApiClient is what you need to
query ApplicationController. You can inject IApiClient in every Razor page where entities are requested.
The Breeze.Sharp entities are the so called DTO and you have create one for every entities of your Entity Framework
context. In this project they are in BlazorBoilerplate.Shared.Dto.Db.

Notes

At the moment Todo is the only entity used to demonstrate Breeze.Sharp capabilities. In fact you can extend the use
to all other entities, but administrative entities (users, roles, etc.) are managed by others libraries like ASP.NET Core
Identity and IdentityServer4, so I preferred to keep the dedicated AdminController.
If you think that is all wonderful, here it comes the drawback.

8 Kapitel 2. Blazor WebAssembly


Blazor Boilerplate, Release 2.0.0

The used of C# as a replacement of javascript is something very new: it is the Blazor revolution. So till now Bree-
ze.Sharp has been used a little only on desktop application. In fact the most used Breeze client is the javascript client
BreezeJS and Breeze itself is not .NET centric.
For this reason breeze.sharp library is rarely updated, so to make BlazorBoilerplate working with Breeze I used my
fork GioviQ/breeze.sharp where I fixed some issues. You can find the package in folder nupkg and nuget.config tells
Visual Studio to use this folder as a package source.

2.2.3 Entity Framework Core

Migrations

You can perform Entity Framework Core migrations directly from Visual Studio with Package Manager Console or
with command-line interface.
Here some tips to manage migrations in Blazor Boilerplate with command-line interface (CLI).
1. Make sure you have installed CLI; from the command line execute:

dotnet tool install --global dotnet-ef

or to update

dotnet tool update --global dotnet-ef

2. Keep in mind that every DbContext has its own migrations.


The main DbContext is ApplicationDbContext. PersistedGrantDbContext and ConfigurationDbContext
depend on IdentityServer4; if new versions have changed one or both db contexts, you have to add migrations.
The migrations are in BlazorBoilerplate.Storage, so you have to open your shell in this path. Then you have to
specify the project where the db contexts are added to the services, because dotnet ef has to know how to find
and instantiate them. In our case the so called startup project is BlazorBoilerplate.Server. So the commands
are:

dotnet ef --startup-project ../BlazorBoilerplate.Server/ migrations add 4Preview3 -c


˓→PersistedGrantDbContext --verbose --no-build --configuration Debug

dotnet ef --startup-project ../BlazorBoilerplate.Server/ migrations add 4Preview3 -c


˓→ConfigurationDbContext --verbose --no-build --configuration Debug

Without the –no-build parameter, dotnet rebuilds the startup project, but if you have just built it with Visual Studio, it
is just a waste of time. Also the dotnet build is not the Visual Studio build, so to avoid issue, use this procedure.
The name of migration, in this case 4Preview3, is only descriptive and it does not need to be unique, because automa-
tically the name is prepended with date time.
If the command is successful, [datetime]_[migration-name].cs is added to the solution. Also the [db-context-
name]ModelSnapshot.cs is updated to reflect the db changes in case a new db has to be created.
When you run the project, the migrations are applied to the database (in our case we have only one db). The db table
__EFMigrationsHistory keeps track of applied migrations without information about the related db context. To get
this information use the following command; for example for ConfigurationDbContext:

dotnet ef --startup-project ../BlazorBoilerplate.Server/ migrations list -c


˓→ConfigurationDbContext --verbose --no-build --configuration Debug

You can also update the database, without running the project with the following command:

2.2. Cons 9
Blazor Boilerplate, Release 2.0.0

dotnet ef --startup-project ../BlazorBoilerplate.Server/ database update 4Preview3 -c


˓→ConfigurationDbContext --verbose --no-build --configuration Debug

If you specify a previous migration, you can revert the db changes to that migration.
Warning
The migrations are not smart, when you have an existing db with populated tables. If migrations add keys and/or
unique indexes or something else violating referential integrity, you have to manually modify [datetime]_[migration-
name].cs for example to add some SQL to fix the errors. E.g. migrationBuilder.Sql(„UPDATE AspNetUserLogins
SET Id=NEWID() WHERE Id=““); to add unique values to a new field before setting as a new primary key.

Shadow Properties vs Source Generator

Always keeping in mind the DRY principle, it is boring implementing audit information and adding the same properties
CreatedOn, ModifiedOn, CreatedBy and ModifiedBy to all entities.
Some articles teach you to use Shadow Properties to add audit information, but this is not the right solution, if you
want expose these properties on the mapped entity types and use them e.g. in UI.
A solution is using Source Generator. AuditableGenerator generates for every class implementing IAuditable the
above properties. Remember all classes implementing IAuditable have to be partial.

2.2.4 Localization

Localization has moved from Resource based localization to Database based localization, so translation are no more
in dll satellite libraries, but in table LocalizationRecords. Look at LocalizationDbContext.
The localization code is in BlazorBoilerplate.Shared.Localizer project. The supported cultures are defined in Set-
tings.cs.
At this time Data Annotations do not support IStringLocalizer<>, so to localize validation error messages, we have
to use Blazored.FluentValidation.

Po files

This project adopts the PO file format as standard translations files. In the admin section you can edit translations and
import and export PO files. There are a lot of free and paid tools and online services to manage these files. E.g.:
Poedit
Eazy Po
Crowdin (PO file format support)
To manage PO files BlazorBoilerplate uses Karambolo.PO library. So to handle plurals the Karambolo.PO syntax is
used like in the example below.
Everywhere you need localized text, inject IStringLocalizer<Global> and look how it is used throughout the code.

L["MsgId usually in english"]

L["Email {0} is not valid", email]

L["One item found", Plural.From("{0} items found", totalItemsCount)]

10 Kapitel 2. Blazor WebAssembly


Blazor Boilerplate, Release 2.0.0

2.2.5 Deploy with Terraform

Terraform Overview
• Use terraform to deploy to nearly any hosting environment
• Terraform is open source https://github.com/hashicorp/terraform
• For more information go to https://www.terraform.io/

Pass

1. Install and initialize pass.


• pass makes managing these deployment parameters extremely easy
• For instructions to install and initialize go to: https://www.passwordstore.org/
• When you export your environment variables via export TF_VAR_variable_name, the variables get pulled in
during terraform plan and terraform apply

Terraform for AWS

1. Once pass is installed and initialized do the following to store the environment variables in pass

pass insert access_key


pass insert secret_key
pass insert aws_key_name
pass insert docker_blazorboilerplate_image
pass insert docker_sqlserver_image
pass insert sa_password
pass insert cert_password
pass insert ASPNETCORE_ENVIRONMENT
pass insert Serilog__MinimumLevel__Default

2. Set terraform deployment environment variables for use in terraform:

export TF_VAR_access_key=$(pass access_key)


export TF_VAR_secret_key=$(pass secret_key)
export TF_VAR_aws_key_name=$(pass aws_key_name)
export TF_VAR_docker_blazorboilerplate_image=$(pass docker_blazorboilerplate_image)
export TF_VAR_docker_sqlserver_image=$(pass docker_sqlserver_image)
export TF_VAR_sa_password=$(pass sa_password)
export TF_VAR_cert_password=$(pass cert_password)
export TF_VAR_ASPNETCORE_ENVIRONMENT=$(pass ASPNETCORE_ENVIRONMENT)
export TF_VAR_Serilog__MinimumLevel__Default=$(pass Serilog__MinimumLevel__Default)

In Windows use setx instead. e.g.


setx TF_VAR_access_key=$(pass access_key)

3. Install Terraform at https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/aws-get-started

- follow instructions on page

4. Deploy using Terraform

2.2. Cons 11
Blazor Boilerplate, Release 2.0.0

cd ./src/Utils/Terraform/AWS
terraform init
terraform plan
terraform apply

Terraform for Azure (Todo)

1. Once pass is installed and initialized do the following to store the environment variables in pass

todo:
pass insert param1
pass insert param2

2. Set terraform deployment environment variables for use in terraform:

todo:
export TF_VAR_param1=$(pass param1)
export TF_VAR_param2=$(pass param2)

In Windows use setx instead. e.g.


setx TF_VAR_param1=$(pass param1)

3. Install Terraform at https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/azure-get-started

- follow instructions on page

4. Deploy using Terraform (Todo)

cd ./src/Utils/Terraform/Azure
terraform init
terraform plan
terraform apply

2.2.6 Dual mode Blazor

As stated in doc home Blazor has two hosting models: WebAssembly or Server. Each hosting model has pros and
cons, so you have to decide which is better for your web application.
With Blazor Boilerplate you can switch at runtime between WebAssembly or Server in the Settings of Admin.

12 Kapitel 2. Blazor WebAssembly


Blazor Boilerplate, Release 2.0.0

Choose the desiderd runtime in the dropdown list and then click on Save button. The application is then reloaded.

2.2.7 MultiTenancy

The implementation of multitenancy is based on Finbuckle.MultiTenant.


The host strategy is used:

services.AddMultiTenant()
.WithHostStrategy("__tenant__")
.WithEFCoreStore<TenantStoreDbContext>()
.WithFallbackStrategy(Settings.DefaultTenantId);

Setup Visual Studio and Windows for multiple bindinds

Open \src.vs\BlazorBoilerplateconfig\applicationhost.config and add these bindings:

<site name="BlazorBoilerplate.Server" id="...">


<application path="/" applicationPool="BlazorBoilerplate.Server AppPool">
<virtualDirectory path="/" physicalPath="...\src\Server\BlazorBoilerplate.Server"
˓→/>

</application>
<bindings>
<binding protocol="http" bindingInformation="*:53414:localhost" />
<binding protocol="http" bindingInformation="*:53414:tenant1.local" />
<binding protocol="http" bindingInformation="*:53414:tenant2.local" />
</bindings>
</site>

2.2. Cons 13
Blazor Boilerplate, Release 2.0.0

Run as administrator \src\Utils\Scripts\addTenantBindings.cmd to enable access in Windows to the above bindings.


It contains commands like

netsh http add urlacl url=http://tenant1.local:53414/ user=everyone

Open as administrator C:\Windows\System32\drivers\etc\hosts and add the following line:

127.0.0.1 tenant1.local tenant2.local

Delete the previous database if any, because DatabaseInitializer inits TenantInfo for the two tenants.
Run debug and in Admin UI you will find a MultiTenancy section with links to the two demo tenants.
In the following screenshot you see the configuration with the two online demo tenants.

2.2.8 IdentityServer4

IdentityServer4 has detailed documentation to read first.


IdentityServer4 authentication is used with ApplicationController:

[Route("api/data/[action]")]
[Authorize(AuthenticationSchemes = AuthSchemes)]
[BreezeQueryFilter]
public class ApplicationController : Controller
{
private const string AuthSchemes =
"Identity.Application" + "," + IdentityServerAuthenticationDefaults.
˓→AuthenticationScheme; //Cookie + Token authentication

In fact as you can see ApplicationController uses both cookie and bearer token authentication scheme.
Currently ApiClient uses cookie authentication to access ApplicationController. To see an example of external access
with ApiClient and bearer authentication, you have to look at BlazorBoilerplate.Server.Tests project.

14 Kapitel 2. Blazor WebAssembly

You might also like