Blazor Basics & Components in C# – The Ultimate Guide
1. Introduction to Blazor
1.1 What is Blazor?
Blazor is a revolutionary web framework from Microsoft that lets you build rich, interactive web apps using C# instead of JavaScript. By compiling C# into WebAssembly or running it on the server, Blazor enables full-stack development with a single language. This means you can share libraries and models between client and server—simplifying your codebase and developer experience.
Blazor offers a component‑based architecture, routing, dependency injection, forms, and more. And because it leverages modern browser standards, your users enjoy a fast, responsive experience without relying on traditional JavaScript frameworks.
1.2 Blazor Hosting Models: Server vs WebAssembly
There are two main ways to host Blazor apps:
- Blazor Server: Your C# component logic runs on the server. The UI updates are sent via SignalR. This model uses minimal client resources and works well for intranet apps.
- Blazor WebAssembly: The entire app, including the .NET runtime, runs in the browser as WebAssembly. Offers offline support and full client‑side rendering.
Select the model that best suits your needs and constraints—though most concepts, including components, apply to both.
1.3 Why Use Blazor for Modern Web Apps
Blazor brings many benefits:
- Full .NET ecosystem: Use C#, EF Core, Identity, and your favorite libraries.
- Single-language code: No more back-and-forth between C# and JavaScript.
- Reusability: Components can be shared across pages and other apps.
- Strong typing: Enjoy compile-time safety and IntelliSense.
Whether you're a .NET web developer or a full-stack engineer, Blazor lets you write cleaner, more maintainable code and ship faster by avoiding language context switching.
2. Setting Up a Blazor Project
2.1 Prerequisites and Tooling
To get started with Blazor, you need:
- .NET 7 (or latest SDK)
- Visual Studio 2022/2023, Visual Studio Code, or JetBrains Rider
- Basic familiarity with C#, ASP.NET, and HTML
Install .NET SDK:
dotnet --version
Look for version 7.0+ to ensure full support for the latest Blazor features.
2.2 Creating Your First Blazor App
Create a new Blazor WebAssembly app using the CLI:
dotnet new blazorwasm -n BlazorBasicsApp
Or create a Blazor Server app:
dotnet new blazorserver -n BlazorBasicsApp
Open the generated project folder in your IDE and run:
dotnet run
Navigate to https://localhost:5001
and you’ll see the default Blazor template in action.
2.3 Project Structure and Folders Overview
Blazor projects follow a logical structure:
Pages/
: Razor components representing pages (with routing)Shared/
: Reusable componentswwwroot/
: Static assets (CSS, images)Program.cs
: Startup logic and DI registration
Understanding this structure helps you maintain organized code as your app grows.
3. Blazor Components Fundamentals
3.1 What Are Components?
Components are the basic building blocks in Blazor. Each component encapsulates UI (HTML), behavior (C#), and rendering logic. You define them using Razor syntax in .razor
files.
Think of them as reusable functions—every page you see is just a combination of components.
3.2 Anatomy of a Razor Component
A Razor component has three main parts:
- Markup: HTML UI
- @code block: C# logic and properties
- Parameters: External input via
[Parameter]
attributes
Example:
@* HelloWorld.razor *@
Hello, @Name!
@code {
[Parameter] public string Name { get; set; } = "World";
}
3.3 First Hello World Component
Add a new file Pages/Hello.razor
with:
@page "/hello"
Hello, @Name!
@code {
private string Name { get; set; } = "Blazor";
}
Navigate to /hello
and type in the textbox to see real-time updates—no JavaScript needed!
4. Understanding Component Parameters
4.1 Passing Data into Components
Blazor components can accept data from their parent components using parameters. You declare parameters in the @code
block using the [Parameter]
attribute.
@* Greeting.razor *@
Hello, @Name!
@code {
[Parameter]
public string Name { get; set; }
}
You can now use this component and pass in a value like this:
<Greeting Name="Alice" />
4.2 Optional Parameters and Defaults
You can assign default values to parameters to make them optional:
[Parameter]
public string Color { get; set; } = "blue";
If the parent doesn’t supply a value, Blazor will use the default.
4.3 Two-Way Binding with Parameters
You can use two-way binding for parameters by adding the [Parameter]
and [EditorRequired]
attribute combination (or manually raise events):
[Parameter]
public string Title { get; set; }
[Parameter]
public EventCallback<string> TitleChanged { get; set; }
private async Task UpdateTitle(string value) {
Title = value;
await TitleChanged.InvokeAsync(value);
}
---
5. Event Handling in Blazor
5.1 Handling Button Clicks
Handling events in Blazor is as easy as adding a method and calling it via @onclick
:
<button @onclick="ShowMessage">Click Me</button>
@code {
private void ShowMessage() {
Console.WriteLine("Button clicked!");
}
}
This is similar to JavaScript but written in C# and compiled to WebAssembly or executed on the server.
5.2 Passing Parameters to Events
You can pass arguments to event handlers using lambda expressions:
<button @onclick="() => ShowAlert(5)">Show 5</button>
@code {
private void ShowAlert(int value) {
Console.WriteLine($"You clicked: {value}");
}
}
5.3 Preventing Default and StopPropagation
Use @onclick:preventDefault
and @onclick:stopPropagation
for fine-grained control:
<a href="https://example.com" @onclick:preventDefault @onclick="OpenModal">Open Modal</a>
This allows you to control behavior just like JavaScript, but within your C# component.
---6. Data Binding in Blazor
6.1 One-Way Binding
Use curly braces @{ }
or simply @variable
to bind a variable’s value into the DOM:
<p>Hello, @username</p>
@code {
string username = "Blazor Dev";
}
6.2 Two-Way Binding with @bind
Use @bind
to bind an input’s value to a field or property. Changes in the UI update the variable, and vice versa:
<input @bind="username" />
<p>You typed: @username</p>
@code {
private string username = "";
}
6.3 @bind-Value:event and Custom Events
You can specify the binding event (e.g., oninput
) like this:
<input @bind-value="username" @bind-value:event="oninput" />
This enables instant feedback on every keystroke.
---7. Component Lifecycle
7.1 Lifecycle Overview
Blazor components go through a series of lifecycle stages. You can hook into these using lifecycle methods like:
OnInitialized()
– Called after parameters are set (sync)OnInitializedAsync()
– Async versionOnParametersSet()
– When parameter values changeOnAfterRender()
– After rendering is done
7.2 Using OnInitializedAsync
@code {
protected override async Task OnInitializedAsync() {
products = await ProductService.GetAllAsync();
}
private List<Product> products;
}
This is perfect for making API calls during component initialization.
7.3 Dispose and Cleanup
Implement IDisposable
to clean up resources like timers or subscriptions:
@implements IDisposable
@code {
private Timer _timer;
protected override void OnInitialized() {
_timer = new Timer(UpdateTime, null, 0, 1000);
}
public void Dispose() {
_timer?.Dispose();
}
private void UpdateTime(object state) {
// Refresh UI or perform action
}
}
This ensures your components don’t cause memory leaks or performance issues—key for Google AdSense compliance and SEO reliability.
8. Routing in Blazor
8.1 Defining Routes with @page
Routing in Blazor is simple. You define routes directly in Razor components using the @page
directive:
@page "/about"
<h2>About Us</h2>
This component will now respond to /about
in the browser.
8.2 Route Parameters
You can accept values from the URL using parameters:
@page "/user/{id:int}"
<h3>User ID: @Id</h3>
@code {
[Parameter]
public int Id { get; set; }
}
You can also support optional parameters and constraints like {name:alpha}
.
8.3 NavigationManager and Navigation
Inject NavigationManager
to programmatically change routes:
@inject NavigationManager Nav
<button @onclick="GoToHome">Go Home</button>
@code {
void GoToHome() => Nav.NavigateTo("/");
}
---
9. Forms and Validation
9.1 Using EditForm
EditForm
is a special Blazor component that binds to a model and supports validation:
<EditForm Model="@formModel" OnValidSubmit="HandleSubmit">
<InputText @bind-Value="formModel.Name" />
<ValidationMessage For="() => formModel.Name" />
<button type="submit">Submit</button>
</EditForm>
@code {
private FormModel formModel = new();
private void HandleSubmit() {
Console.WriteLine($"Submitted: {formModel.Name}");
}
public class FormModel {
[Required] public string Name { get; set; }
}
}
9.2 Custom Validation
Implement IValidatableObject
for model-level rules:
public class FormModel : IValidatableObject {
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context) {
if (Name?.ToLower() == "admin")
yield return new ValidationResult("Admin is not allowed.", new[] { nameof(Name) });
}
}
9.3 Input Components
Use Blazor’s built-in input controls:
InputText
InputTextArea
InputCheckbox
InputSelect
These support full validation and binding out-of-the-box.
---10. Dependency Injection (DI)
10.1 Injecting Services
Blazor supports DI via @inject
or constructor injection:
@inject IWeatherService WeatherService
<p>@WeatherService.GetForecast()</p>
10.2 Registering Services
Register services in Program.cs
:
builder.Services.AddScoped<IWeatherService, WeatherService>();
10.3 Scoped, Singleton, Transient
Blazor supports these lifetimes:
- Scoped: One instance per user session
- Singleton: One instance for the app’s lifetime
- Transient: New instance each time
Use scoped for most web apps to match user sessions cleanly.
---11. JavaScript Interop
11.1 Calling JS from Blazor
Sometimes, C# can't do everything alone. Call JS like this:
@inject IJSRuntime JS
<button @onclick="CallJS">Alert</button>
@code {
async Task CallJS() {
await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
}
}
11.2 Calling C# from JS
Define a C# method as static and JS invokable:
[JSInvokable]
public static void FromJS(string message) {
Console.WriteLine($"JS says: {message}");
}
Call from JS:
DotNet.invokeMethodAsync("MyApp", "FromJS", "Hi!");
11.3 When to Use JSInterop
Use JSInterop for things like:
- Working with browser APIs
- Calling third-party JS libraries
- DOM manipulation not possible in C#
12. Component Communication
12.1 Parent to Child
Use parameters to pass data:
<ChildComponent Message="Hello from parent!" />
@code {
public string Message { get; set; } = "Hello from parent!";
}
12.2 Child to Parent
Use EventCallback
to notify parent:
<ChildComponent OnClick="ParentHandler" />
@code {
void ParentHandler() => Console.WriteLine("Child clicked");
}
12.3 Cascading Parameters
Pass data to deeply nested components using CascadingValue
:
<CascadingValue Value="Theme">
<Child />
</CascadingValue>
@code {
string Theme = "dark";
}
Then inject with:
[CascadingParameter]
public string Theme { get; set; }
13. Layouts and Reusability
13.1 Creating Layouts
Layouts let you define a common structure for pages. You define them using LayoutComponentBase
or Razor syntax:
@inherits LayoutComponentBase
<div class="main-layout">
<header>Blazor App Header</header>
<div class="content">
@Body
</div>
</div>
13.2 Applying Layouts to Pages
Use the @layout
directive at the top of your page to apply a layout:
@layout MainLayout
Or set it globally in App.razor
:
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
</Router>
13.3 Reusable Components and Templates
You can create your own reusable input, layout, or control components. Use generics for templates:
@typeparam TItem
<div>@Item</div>
@code {
[Parameter]
public TItem Item { get; set; }
}
---
14. Hosting & Deployment
14.1 Publishing Blazor WASM
dotnet publish -c Release -o ./publish
This creates static files you can host on:
- GitHub Pages
- Azure Static Web Apps
- Firebase Hosting
- Cloudflare Pages
14.2 Hosting Blazor Server
Blazor Server runs on ASP.NET Core with SignalR, so you can deploy to:
- Azure App Service
- Docker containers
- Self-hosted Linux/Windows servers
14.3 Deploying to GitHub Pages
For Blazor WASM:
dotnet publish -c Release
# Copy wwwroot to gh-pages branch and push
---
15. Best Practices
- Use component libraries: Like MudBlazor, Radzen, or Telerik for rich UI
- Keep components small: One feature or purpose per component
- Use partial classes: Keep UI and logic separated for maintainability
- Avoid tight coupling: Prefer interfaces and services for DI
- Organize with folders: Group related components for clarity
16. Frequently Asked Questions (FAQs)
1. Is Blazor production ready?
Absolutely. Blazor WASM and Server are stable and used in real-world enterprise apps.
2. Can I use JavaScript in Blazor?
Yes. Blazor supports full JavaScript interop for calling JS from C# and vice versa.
3. Does Blazor work with .NET MAUI?
Yes. Blazor Hybrid lets you build native apps using Razor components inside .NET MAUI.
4. What's the difference between Blazor Server and WASM?
Blazor Server executes on the server with SignalR UI sync. WASM runs entirely in the browser.
5. Can Blazor apps be indexed by search engines?
Blazor Server apps are fully indexable. Blazor WASM needs pre-rendering for SEO bots.
---17. Conclusion
Blazor empowers you to build fast, modern, and interactive web apps using just C#. By mastering components, routing, forms, data binding, DI, and interop, you can create rich UIs with ease and elegance—without ever writing a single line of JavaScript if you don’t want to.
Whether you choose Blazor Server for enterprise dashboards or Blazor WebAssembly for client-side apps, the possibilities are endless. This guide has covered everything you need to start building powerful, production-ready Blazor applications with confidence.
---Please don’t forget to leave a review.
Post a Comment