| name | maui-blazor-hybrid |
| description | Build and debug .NET MAUI Blazor Hybrid features with BlazorWebView, HybridWebView, Razor components, static assets, JS/.NET interop, trimming/NativeAOT concerns, and DevFlow CDP route inspection. USE FOR: MAUI apps hosting Razor UI, embedded HTML/JS, choosing BlazorWebView vs HybridWebView, AddMauiBlazorWebView, RootComponent, SendRawMessage/RawMessageReceived, JSON DTO contracts, JsonSerializerContext, wwwroot assets, hybrid auth/data handoff, stale DOM/Razor route debugging, and maui_cdp_webviews/source/evaluate/screenshot/logs. DO NOT USE FOR: pure XAML UI or browser-only apps. |
MAUI Blazor Hybrid
Use this skill when a MAUI app hosts Razor components or an embedded web surface
inside a native app.
Workflow
- Inspect
MauiProgram.cs, .razor files, wwwroot, and XAML pages that host
BlazorWebView or HybridWebView.
- Choose the right host:
BlazorWebView for Razor components rendered inside MAUI.
HybridWebView for HTML/JavaScript content that exchanges messages with
.NET without using the Blazor component model.
- Register Blazor Hybrid services in
MauiProgram.cs.
- Keep native services in MAUI DI and consume them from Razor through DI.
- Put static web assets under
wwwroot or referenced Razor class libraries.
- Use JS/.NET interop through documented APIs, not platform WebView internals.
For
HybridWebView raw messaging, always show SendRawMessage,
RawMessageReceived, a JSON DTO contract, and a source-generated
JsonSerializerContext/System.Text.Json path when trimming, NativeAOT,
Release trimming, or trimming-safe messaging is part of the request. Do not
answer with only raw strings or DynamicDependency.
- Review trimming and NativeAOT risks for reflection, serialization, and JS
interop payloads.
- Use DevFlow CDP tools to inspect WebView DOM, console logs, CDP screenshots,
and route state when debugging. For Blazor Hybrid stale route/DOM answers,
explicitly name
maui_cdp_webviews, maui_cdp_source or
maui_cdp_evaluate, and at least one evidence tool: maui_cdp_screenshot
or maui_logs.
BlazorWebView Pattern
builder.Services.AddMauiBlazorWebView();
<BlazorWebView HostPage="wwwroot/index.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app" ComponentType="{x:Type local:Routes}" />
</BlazorWebView.RootComponents>
</BlazorWebView>
Razor components can inject MAUI services registered in the same DI container.
Keep platform work behind interfaces so components remain testable. The root
component type depends on the template; newer templates often use Routes,
while older templates may use Main.
HybridWebView Pattern
Use HybridWebView when the app owns an HTML/JS surface and needs message
exchange. For raw JS/.NET messaging answers, include both the raw message APIs
and a typed JSON DTO/source-generated serialization boundary:
hybridWebView.SendRawMessage("refresh");
hybridWebView.RawMessageReceived += OnRawMessageReceived;
For non-trivial or trimming-sensitive payloads, keep messages typed at the .NET
boundary instead of switching on ad-hoc strings. Use a DTO plus System.Text.Json
source generation ([JsonSerializable] and JsonSerializerContext) so
serialization stays trimming/NativeAOT friendly:
public sealed record HybridMessage(string Action, string? Id);
[JsonSerializable(typeof(HybridMessage))]
internal sealed partial class HybridJsonContext : JsonSerializerContext
{
}
void OnRawMessageReceived(object? sender, HybridWebViewRawMessageReceivedEventArgs e)
{
var message = JsonSerializer.Deserialize(
e.Message,
HybridJsonContext.Default.HybridMessage);
if (message is null)
throw new JsonException("Malformed HybridWebView message.");
}
hybridWebView.SendRawMessage(JsonSerializer.Serialize(
new HybridMessage("refresh", null),
HybridJsonContext.Default.HybridMessage));
window.HybridWebView.SendRawMessage(JSON.stringify({
action: "save",
id: "42"
}));
Static Assets
- Put app-owned web files under
wwwroot.
- Use
_content/{PackageId}/... for static web assets from Razor class
libraries.
- Avoid file-system paths that only work on one platform.
- Ensure CSP, local scripts, and asset paths work from the packaged app origin,
not just from a development server.
Interop and State
- Use
IJSRuntime from Razor components for Blazor JS interop.
- Use
HybridWebView messaging APIs for non-Blazor HTML/JS content.
- Dispose
DotNetObjectReference instances when Razor components are disposed
to avoid leaking component instances through JavaScript references.
- Keep auth/session/data services native-side and expose only the minimal state
needed by Razor or JavaScript.
- Do not put long-lived secrets in browser local storage.
- Validate
RawMessageReceived payloads against an expected schema before
dispatching to .NET logic. Do not let raw messages trigger sensitive
operations without authorization checks at the .NET receiver.
Trimming and NativeAOT Guardrails
- Prefer
System.Text.Json source-generated contexts for interop DTOs.
- Avoid reflection-based component discovery or dynamic serialization unless
annotations/preservation are added.
- Test release builds because debug WebView behavior can hide trimming issues.
- Check third-party JS/.NET interop packages for trimming support.
DevFlow CDP Debugging
When DevFlow is enabled, use WebView CDP tools to debug cross-route behavior:
maui devflow mcp
Blazor WebView developer tools and platform WebView debugging must be enabled
only in debug builds:
#if DEBUG
builder.Services.AddBlazorWebViewDeveloperTools();
#endif
Relevant MCP tools include maui_cdp_webviews, maui_cdp_source,
maui_cdp_evaluate, maui_cdp_screenshot, and maui_logs. Inspect the active
WebView before evaluating route-specific DOM or JavaScript. When the issue is
stale Blazor route state or DOM, include maui_cdp_screenshot for WebView
visual evidence and/or maui_logs for Blazor rendering or WebView console
errors; do not substitute only the generic app-level maui_screenshot for CDP
WebView evidence. Do not ship release builds with WebView devtools or CDP access
enabled.
Validation Checklist
AddMauiBlazorWebView is registered for Blazor Hybrid apps.
- Static assets resolve from packaged
wwwroot or RCL _content paths.
- JS/.NET interop uses Blazor or HybridWebView APIs intentionally.
- HybridWebView raw messages use JSON DTOs plus
JsonSerializerContext or
another explicit System.Text.Json source-generated path when trimming-safe
serialization matters.
- Release/trimming-sensitive code avoids unpreserved reflection.
- DevFlow CDP inspection targets the correct WebView and route, and route/DOM
debugging guidance names
maui_cdp_screenshot or maui_logs for evidence.