Front
Mateusz Turzyński / Michał Michalczuk

What's Blazor?





Michał
Michalczuk
Mateusz
Turzyński




@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">
Click me
</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}







?

App.dll
.NET
(mscorlib.dll, System.core.dll etc)
WebAssembly
(dotnet.wasm)

.cs

.razor
Compilation



What can Blazor do?

@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<InputNumber @bind="@currentCount" />
<button class="btn btn-primary" @onclick="IncrementCount">
Click me
</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
A day in the life of a software developer
let's create a form :)
public class PersonModel
{
[Required]
[Range(18, 60,
ErrorMessage = "Either too old or too young :(")]
public int Age { get; set; }
[Required]
[MinLength(5)]
[MaxLength(15)]
public string FullName { get; set; }
public string Password { get; set; }
[Compare(nameof(Password))]
public string RepeatPassword { get; set; }
}
@inject HttpClient Http
@code {
private PersonModel person = new PersonModel();
private async Task HandleValidSubmit()
{
await Http.PostJsonAsync("/api", person);
}
private void HandleInvalidSubmit()
{
Console.WriteLine("The form is not valid :(");
}
}
<EditForm Model="person"
OnValidSubmit="@HandleValidSubmit"
OnInvalidSubmit="@HandleInvalidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<h1>Personal form</h1>
<p>
<label>Enter your age:</label>
<InputNumber @bind-Value="person.Age" />
</p>
<p>
<label>Enter your name:</label>
<InputText @bind-Value="@person.FullName" />
<ValidationMessage For="@(() => person.FullName)" />
</p>
(...)
<p>
<button type="submit">Submit</button>
</p>
</EditForm>

Style




// MyComponent.razor
<h1>My Component</h1>
// MyComponent.razor.css
h1 {
color: red;
}
// generated code in scoped.styles.css
[b-dew6pvofzw] h1 {
color: red;
}

<Styled @bind-Classname="@styledClass">
color: red;
background: @color;
</Styled>
<h1 class="@styledClass">Hello!</h1>
@code {
private string color = "pink";
private string styledClass;
}
// result in browser
<h1 class="epav-hwc">Hello!</h1>
👍
Routing
@page "/simple-routing/{text}"
@page "/advanced-routing/{counter:int}"
<p>Text from parameter: @Text</p>
@if (Counter.HasValue)
{
<p>Counter: @Counter</p>
}
@code {
[Parameter]
public string Text { get; set; }
[Parameter]
public int? Counter { get; set; }
}
<NavLink href="simple-form"
Match="NavLinkMatch.All"
class="nav-link">
Simple form
</NavLink>
<NavLink href="simple-routing/test"
Match="NavLinkMatch.Prefix"
class="nav-link" >
Simple routing
</NavLink>
Components
<div>
<p>Hello @FullName</p>
<button @onclick="OnDeleteAccount">
Delete my account
</button>
</div>
@code {
[Parameter]
public string FullName { get; set; }
[Parameter]
public EventCallback OnDeleteAccount { get; set; }
}
@page "/person"
@if (accountDeleted)
{
<p>Account deleted</p>
}
else
{
<PersonDetails FullName="John Rambo"
OnDeleteAccount="() => AccountDeleted()" />
}
@code {
private bool accountDeleted;
private void AccountDeleted()
{
accountDeleted = true;
}
}
How to talk with JavaScript?
JavaScript interop

// index.html
<script>
window.getElementDimensions = selector => {
try {
const element = document.querySelector(selector);
if (!element) {
return null;
}
return {
height: element.scrollHeight,
width: element.scrollWidth
};
} catch (ex) {
return null;
}
};
</script>
// UseJavaScript.razor
@inject IJSRuntime JSRuntime;
...
@code {
class BrowserSize {
public int Height { get; set; }
public int Width { get; set; }
}
private string Selector { get; set; } = "body";
private BrowserSize ClientSize { get; set; } = new BrowserSize();
private async Task UpdateSize()
{
var jsResult = await JSRuntime.InvokeAsync<BrowserSize>(
"getElementDimensions",
Selector
);
ClientSize = jsResult != null ? jsResult : new BrowserSize();
StateHasChanged();
}
}
3rd party JS

// index.js
import { Chart } from 'chart.js';
import 'chartjs-plugin-labels';
export const charts = {
drawChart: (canvasSelector, type, { data = [], labels = [] }) => {
const canvas = document.querySelector(canvasSelector).getContext('2d');
new Chart(canvas, {
....
});
}
};


const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
},
output: {
path: path.resolve(__dirname, '../wwwroot/js'),
filename: 'js-lib.js',
library: 'FrontNetJS'
}
};


// index.html
<script src="js/js-lib.js"></script>
@inject IJSRuntime JSRuntime;
<canvas @ref="charCanvas"></canvas>
@code {
private ElementReference charCanvas;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await InitializeChart();
}
}
private async Task InitializeChart()
{
await JSRuntime.InvokeVoidAsync("FrontNetJS.charts.drawChart",
charCanvas,
"pie",
new {
Data = new List<int> { 100, 200, 300, 400},
Labels = new List<string> { "A", "B", "C", "D" }
}
);
StateHasChanged();
}
}

Browser
UI Thread
Blazor
Blazor is single thread
What's more?
Lazy loading

<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="GrantImaharaRobotControls" />
</ItemGroup>
----
@inject LazyAssemblyLoader assemblyLoader
<Router AppAssembly="@typeof(Program).Assembly"
AdditionalAssemblies="@lazyLoadedAssemblies"
OnNavigateAsync="@OnNavigateAsync"
>
<Navigating>...</Navigating>
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>...</NotFound>
</Router>
@code {
private List<Assembly> lazyLoadedAssemblies = new List<Assembly>();
private async Task OnNavigateAsync(NavigationContext args)
{
if (args.Path.EndsWith("/robot"))
{
var assemblies = await assemblyLoader.LoadAssembliesAsync(
new List<string>() { "GrantImaharaRobotControls.dll" });
lazyLoadedAssemblies.AddRange(assemblies);
}
}
}
Progressive Web Apps


Blazor ❤ Xamarin

<StackLayout>
<Label FontSize="30"Text="Hello!"/>
<Button Text="+1"OnClick="@HandleClick" />
</StackLayout>
@code {
int count;
void HandleClick()
{
count++;
}
}

<StackLayout>
<StackLayout Margin="new Thickness(20)">
<Label
Text="Hello!"
FontSize="30" />
<Button
Text="Increment from native"
OnClick="@CounterState.IncrementCount"
Padding="10" />
</StackLayout>
<BlazorWebView
ContentRoot="WebUI/wwwroot"
VerticalOptions="
LayoutOptions.FillAndExpand
"
>
<FirstBlazorHybridApp.WebUI.App />
</BlazorWebView>
</StackLayout>
What's Blazor?
it's a .NET runtime
it's a SPA framework



Blazor Web Assembly is finally production ready...

...so is Blazor Server

Blazor Server - How it works


JavaScript interop
Blazor WASM
- runs client-side
- heavy assets
- no communication overhead
- requires server-based API
- doesn't require much server infrastructure
- supports lazy loading
Blazor Server
- runs server-side
- light assets
- generates heavy WS traffic
- can act as an API server
- doesn't scale well
- no need for lazy loading
vs


Where to use Blazor Web Assembly
Nowadays: corporate systems, PWA
Future: performance-sensitive apps (see AoT)
Where to use Blazor Server
Nowadays: intranet, dashboards
Future: since Blazor WASM is released we don't really see room for Blazor Server

Back in 2019
Final thoughts
- Common code base
- Vendor lock
- Strong, static typing
- There is no runaway from JS
- Rich JS ecosystem is available
- Super easy for backend developers
- Young community
- Ready to use in no time
- Microsoft is heavily investing in Blazor
Thank you
Survey


[EN] What is Blazor? - Front.net
By Mateusz Turzyński