| name | maui-blazor-development |
| description | Expert guidance for .NET MAUI Blazor Hybrid development combining native mobile/desktop apps with Blazor web UI.
Use when working with: (1) .NET MAUI Blazor Hybrid apps, (2) BlazorWebView components, (3) Cross-platform apps sharing Blazor UI,
(4) Platform integration in Blazor Hybrid, (5) MVVM with Blazor components, (6) Navigation between MAUI pages and Razor components,
(7) Shared Razor Class Libraries (RCL) for MAUI and Web. Applies to any .NET MAUI project using Blazor for UI.
|
.NET MAUI Blazor Hybrid Development
Expert guidance for building cross-platform apps with .NET MAUI and Blazor.
Implementation Workflow
1. Analysis Phase (Required)
Before implementation, determine:
- App type: Pure MAUI Blazor or MAUI + Blazor Web App (shared UI)
- Platform targets: Android, iOS, Windows, macOS
- Native features needed: Sensors, camera, file system, notifications
- State management: Component state, MVVM, or hybrid approach
- Navigation pattern: Blazor-only, Shell, or mixed navigation
2. Architecture Decision
| Scenario | Recommended Approach |
|---|
| Mobile-first with some web | maui-blazor template |
| Shared UI across mobile + web | maui-blazor-web template with RCL |
| Complex native integration | MVVM with platform services |
| Simple data-driven UI | Component state with DI services |
3. Project Setup
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
builder.Services.AddMauiBlazorWebView();
#if DEBUG
builder.Services.AddBlazorWebViewDeveloperTools();
#endif
builder.Services.AddSingleton<IDeviceService, DeviceService>();
builder.Services.AddScoped<IDataService, DataService>();
return builder.Build();
}
4. BlazorWebView Configuration
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:b="clr-namespace:Microsoft.AspNetCore.Components.WebView.Maui;assembly=Microsoft.AspNetCore.Components.WebView.Maui">
<b:BlazorWebView HostPage="wwwroot/index.html">
<b:BlazorWebView.RootComponents>
<b:RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
</b:BlazorWebView.RootComponents>
</b:BlazorWebView>
</ContentPage>
Core Patterns
Dependency Injection
| Lifetime | Use Case |
|---|
AddSingleton<T> | App-wide state, device services, settings |
AddScoped<T> | Per-BlazorWebView instance state |
AddTransient<T> | Stateless utilities, factories |
public interface IDeviceService
{
string GetDeviceModel();
Task<bool> HasPermissionAsync(string permission);
}
builder.Services.AddSingleton<IDeviceService, DeviceService>();
Component Lifecycle
@code {
[Parameter] public string Id { get; set; } = "";
protected override async Task OnInitializedAsync()
{
await LoadDataAsync();
}
protected override void OnParametersSet()
{
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
}
}
}
Platform Feature Access
@inject IDeviceService DeviceService
@if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
<AndroidSpecificComponent />
}
@code {
private async Task AccessCameraAsync()
{
var status = await Permissions.CheckStatusAsync<Permissions.Camera>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<Permissions.Camera>();
}
if (status == PermissionStatus.Granted)
{
}
}
}
State Updates from External Events
@implements IDisposable
@inject IDataService DataService
<p>@message</p>
@code {
private string message = "";
protected override void OnInitialized()
{
DataService.OnDataChanged += HandleDataChanged;
}
private async void HandleDataChanged(object? sender, EventArgs e)
{
message = "Data updated!";
await InvokeAsync(StateHasChanged);
}
public void Dispose()
{
DataService.OnDataChanged -= HandleDataChanged;
}
}
Reference Documentation
For detailed patterns and examples, see:
- Project Structure: Solution templates, RCL setup, multi-targeting
- Blazor Components: Lifecycle, RenderFragment, EventCallback, data binding
- Platform Integration: Device APIs, permissions, platform-specific code
- Navigation & Routing: Blazor routing, Shell, deep linking
- State Management: MVVM, DI patterns, CommunityToolkit.Mvvm
Quick Reference
Common Service Registration
builder.Services.AddSingleton<ISettingsService, SettingsService>();
builder.Services.AddSingleton<IConnectivity>(Connectivity.Current);
builder.Services.AddSingleton<IGeolocation>(Geolocation.Default);
builder.Services.AddTransient<MainViewModel>();
builder.Services.AddTransient<SettingsViewModel>();
builder.Services.AddTransient<MainPage>();
Platform Checks
if (DeviceInfo.Current.Platform == DevicePlatform.iOS) { }
if (DeviceInfo.Current.Platform == DevicePlatform.Android) { }
if (DeviceInfo.Current.Platform == DevicePlatform.WinUI) { }
if (DeviceInfo.Current.Platform == DevicePlatform.macOS) { }
#if ANDROID
#elif IOS
#elif WINDOWS
#endif
Navigation Patterns
@inject NavigationManager Navigation
Navigation.NavigateTo("/details/123");
await Navigation.PushAsync(new SettingsPage());
await Shell.Current.GoToAsync("//settings");