Blazor — Full-Stack Web UI with .NET Explained
Blazor is a .NET framework for building interactive web UIs using C# instead of JavaScript. You write Razor components that run either on the server (Blazor Server) or directly in the browser via WebAssembly (Blazor WebAssembly).
What You’ll Learn
You’ll master Blazor’s two hosting models, component architecture, data binding, dependency injection, and routing. You’ll build a fully functional todo list component.
Why Blazor Matters
Blazor lets C# developers build full-stack web apps without learning JavaScript frameworks. It shares code between server and client, has full access to the .NET ecosystem, and runs at near-native speed via WebAssembly. At DodaTech, we use Blazor for internal dashboards that integrate with DodaZIP analytics.
Blazor Learning Path
flowchart LR
A[.NET Overview] --> B[ASP.NET Core]
B --> C[Blazor]
C --> D{You Are Here}
D --> E[.NET MAUI]
D --> F[Entity Framework]
style D fill:#f90,color:#fff
Blazor Server vs Blazor WebAssembly
| Aspect | Blazor Server | Blazor WebAssembly |
|---|---|---|
| Runtime location | Server (ASP.NET Core) | Browser (WebAssembly) |
| UI updates | SignalR WebSocket | DOM manipulation |
| Network | Always connected | Works offline |
| Scalability | Server memory per connection | Scales horizontally |
| Startup | Fast (small download) | Slower (download .NET runtime) |
When to use: Blazor Server for intranet apps with low latency. Blazor WebAssembly for public-facing apps where server cost matters.
Component Architecture
A Blazor component is a .razor file combining HTML and C#:
@* TodoList.razor *@
@using BlazorApp.Data
@inject ITodoService TodoService
<h3>Todo List (@todos.Count(t => !t.IsDone) remaining)</h3>
<ul>
@foreach (var todo in todos)
{
<li>
<input type="checkbox" @bind="todo.IsDone" />
<input @bind="todo.Title" />
<button @onclick="() => DeleteTodo(todo)">Delete</button>
</li>
}
</ul>
<input @bind="newTitle" placeholder="Add a new todo..." />
<button @onclick="AddTodo">Add</button>
@code {
private List<TodoItem> todos = new();
private string? newTitle;
protected override async Task OnInitializedAsync()
{
todos = await TodoService.GetAllAsync();
}
private async Task AddTodo()
{
if (string.IsNullOrWhiteSpace(newTitle)) return;
var item = new TodoItem { Title = newTitle, IsDone = false };
await TodoService.AddAsync(item);
todos.Add(item);
newTitle = string.Empty;
}
private async Task DeleteTodo(TodoItem item)
{
await TodoService.DeleteAsync(item.Id);
todos.Remove(item);
}
}Data Binding
Blazor supports three binding directions:
| Binding | Syntax | Direction |
|---|---|---|
| One-way | @variable | C# → HTML |
| Two-way | @bind="variable" | C# ↔ HTML |
| Event | @onclick="Method" | HTML → C# |
<p>You typed: @userInput</p>
<input @bind="userInput" />
<button @onclick="ShowAlert">Submit</button>
@code {
string userInput = "Hello";
void ShowAlert() => Console.WriteLine(userInput);
}Dependency Injection
Blazor uses built-in DI from ASP.NET Core:
- Register services in
Program.cs:
builder.Services.AddScoped<ITodoService, TodoService>();- Inject in components with
@inject:
@inject ITodoService TodoService
@inject ILogger<TodoList> LoggerScoped services in Blazor Server are per-circuit (per-connection). In Blazor WebAssembly, scoped behaves like singleton.
Routing
Blazor routing is file-based. Pages/Index.razor maps to /. Pages/Counter.razor maps to /counter.
Route parameters:
@page "/todo/{Id:int}"
<h3>Todo Details: @Id</h3>
@code {
[Parameter]
public int Id { get; set; }
}Use NavigationManager for programmatic navigation:
@inject NavigationManager Nav
<button @onclick="() => Nav.NavigateTo("/counter")">Go to Counter</button>Common Mistakes Beginners Make
1. Forgetting @page Directive
Without @page "/route", the component is not routable. It only works as a child component.
2. Modifying @ref Objects Outside the Render Tree
Storing a component reference with @ref is fine, but don’t call methods on it that modify state — Blazor won’t detect the change. Use StateHasChanged().
3. Blocking the UI Thread in Blazor Server
Long-running synchronous operations block the SignalR connection. Always use async/await and Task.Run for heavy work.
4. Not Handling OnInitializedAsync Errors
Unhandled exceptions crash the component. Wrap initialization in try-catch and show a friendly error message.
5. Overusing StateHasChanged()
Blazor calls StateHasChanged() automatically after event handlers. Manual calls can cause unnecessary re-renders.
6. Ignoring RenderFragment for Templates
For reusable components with custom content, use RenderFragment parameters instead of duplicating HTML.
7. Forgetting @key in Loops
When rendering lists that may reorder, add @key="item.Id" to each element. This helps Blazor’s diffing algorithm avoid unnecessary DOM updates.
Practice Questions
1. What is the difference between Blazor Server and Blazor WebAssembly?
Server runs C# on the server and updates UI via SignalR. WASM runs compiled .NET in the browser via WebAssembly.
2. What does @bind do in Blazor?
Creates two-way data binding between a C# variable and an HTML element’s value.
3. How do you inject a service into a Blazor component?
Use @inject IServiceName PropertyName or inject via [Inject] in the @code block.
4. What is OnInitializedAsync used for?
It’s a lifecycle method for async initialization logic, such as loading data from an API.
5. Challenge: Add edit-in-place for todo items.
When double-clicking a todo title, replace the span with an input field pre-filled with the current title. Save on Enter or blur.
Mini Project: Blazor Weather Dashboard
Build a dashboard that:
- Displays a list of cities with current temperatures
- Uses a
WeatherServiceinjected via DI - Has a search input with
@bindfor filtering cities - Navigates to a detail page (
/weather/{city}) on click - Shows a loading spinner with
@if (isLoading)
FAQ
What’s Next
Congratulations on completing this Blazor tutorial! Here’s where to go from here:
- Practice daily — Build one component per day
- Build a project — Create a CRUD app with Blazor WASM
- Explore related topics — Blazor with Entity Framework, authentication
- Join the community — Share your Blazor projects and get feedback
Remember: every expert was once a beginner. Keep building!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro