Skip to content
Blazor — Full-Stack Web UI with .NET Explained

Blazor — Full-Stack Web UI with .NET Explained

DodaTech Updated Jun 15, 2026 5 min read

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

AspectBlazor ServerBlazor WebAssembly
Runtime locationServer (ASP.NET Core)Browser (WebAssembly)
UI updatesSignalR WebSocketDOM manipulation
NetworkAlways connectedWorks offline
ScalabilityServer memory per connectionScales horizontally
StartupFast (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:

BindingSyntaxDirection
One-way@variableC# → 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:

  1. Register services in Program.cs:
builder.Services.AddScoped<ITodoService, TodoService>();
  1. Inject in components with @inject:
@inject ITodoService TodoService
@inject ILogger<TodoList> Logger

Scoped 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:

  1. Displays a list of cities with current temperatures
  2. Uses a WeatherService injected via DI
  3. Has a search input with @bind for filtering cities
  4. Navigates to a detail page (/weather/{city}) on click
  5. Shows a loading spinner with @if (isLoading)

FAQ

Can Blazor replace JavaScript entirely?
For most business apps, yes. For heavy DOM manipulation or WebGL, you may still need JavaScript interop.
Does Blazor WebAssembly work offline?
Yes, with ASP.NET Core hosted WASM and PWA support. The app can run fully offline after initial load.
Is Blazor production-ready?
Yes. Blazor has been production-ready since .NET 5 and is used by Microsoft, Stack Overflow, and enterprise companies.

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