Scarlet.AspNetCore.Components.WebView.WindowsForms
1.2.1
Prefix Reserved
dotnet add package Scarlet.AspNetCore.Components.WebView.WindowsForms --version 1.2.1
NuGet\Install-Package Scarlet.AspNetCore.Components.WebView.WindowsForms -Version 1.2.1
<PackageReference Include="Scarlet.AspNetCore.Components.WebView.WindowsForms" Version="1.2.1" />
<PackageVersion Include="Scarlet.AspNetCore.Components.WebView.WindowsForms" Version="1.2.1" />
<PackageReference Include="Scarlet.AspNetCore.Components.WebView.WindowsForms" />
paket add Scarlet.AspNetCore.Components.WebView.WindowsForms --version 1.2.1
#r "nuget: Scarlet.AspNetCore.Components.WebView.WindowsForms, 1.2.1"
#:package Scarlet.AspNetCore.Components.WebView.WindowsForms@1.2.1
#addin nuget:?package=Scarlet.AspNetCore.Components.WebView.WindowsForms&version=1.2.1
#tool nuget:?package=Scarlet.AspNetCore.Components.WebView.WindowsForms&version=1.2.1
Scarlet.AspNetCore.Components.WebView.WindowsForms
Host Blazor (Razor components) inside a Windows Forms application with WebView2. Your UI is written in Razor and C#; it runs locally in-process (no web server), and calls into .NET and Windows APIs directly.
This package is a drop-in replacement for Microsoft's Microsoft.AspNetCore.Components.WebView.WindowsForms. It
keeps the same namespaces and types (BlazorWebView, RootComponent, AddWindowsFormsBlazorWebView()), and adds fixes
and features that are not available in the official package.
Why use it instead of the official package?
Microsoft's Windows Forms BlazorWebView ships as part of .NET MAUI and is only updated on MAUI's release schedule.
This package is a fork of that code, released independently, with these changes:
- Safer teardown when a form closes while components are still working. Background work that calls
InvokeAsync(StateHasChanged)orDispatchExceptionAsyncafter its form was closed (dotnet/maui#34855) no longer reaches a disposed WebView: navigation and messages after disposal are dropped, and the disposed-renderer race ("The renderer does not have a component with ID ...") is not rethrown on the UI thread. - Shared WebView2 environment. Several
BlazorWebViews can reuse oneCoreWebView2Environmentinstead of each creating its own, which saves that work for every view after the first (see Sharing a WebView2 environment).
The lifetime scenarios from dotnet/maui#34855 run in CI against real forms: closing, disposing, modal forms that are never disposed, and rapid open/close.
Getting started
Requirements: .NET 9 or later on Windows, and the WebView2 Runtime (preinstalled on Windows 11).
Use the Razor SDK and reference the package:
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net9.0-windows</TargetFramework> <UseWindowsForms>true</UseWindowsForms> </PropertyGroup> <ItemGroup> <PackageReference Include="Scarlet.AspNetCore.Components.WebView.WindowsForms" Version="x.y.z" /> </ItemGroup> </Project>Add
wwwroot/index.htmlwith a<div id="app">and<script src="_framework/blazor.webview.js"></script>, and your Razor components (for example aRoutes.razorwith aRouter).Register the services and add a
BlazorWebViewto a form:var services = new ServiceCollection(); services.AddWindowsFormsBlazorWebView(); #if DEBUG services.AddBlazorWebViewDeveloperTools(); #endif var blazorWebView = new BlazorWebView { Dock = DockStyle.Fill, HostPage = @"wwwroot\index.html", Services = services.BuildServiceProvider(), }; blazorWebView.RootComponents.Add<Routes>("#app"); form.Controls.Add(blazorWebView);
A form shown with Show() is disposed when it closes, and disposes the BlazorWebView and its Razor components with
it. A form shown with ShowDialog() is only hidden when it closes; dispose it yourself.
Migrating from Microsoft.AspNetCore.Components.WebView.WindowsForms
Replace the package reference. No code changes are needed. Don't reference both packages: they define the same types.
Sharing a WebView2 environment
By default every BlazorWebView creates its own CoreWebView2Environment. Creating one is asynchronous and part of
the time before a view shows anything. If your app opens several views, or opens and closes them often, create the
environment once and share it: later views only create their WebView2 controller, and every view uses the same user
data folder and options.
The short form takes a factory, which runs once:
services.AddWindowsFormsBlazorWebView()
.UseSharedCoreWebView2Environment((sp, _) => new ValueTask<CoreWebView2Environment>(
CoreWebView2Environment.CreateAsync(userDataFolder: @"C:\MyApp\WebView2")));
For full control, implement ICoreWebView2EnvironmentProvider:
public sealed class SharedWebView2Environment : ICoreWebView2EnvironmentProvider
{
// Created on first use. Concurrent first callers share the same task, and a failure is cached for all of them.
private readonly Lazy<Task<CoreWebView2Environment>> _environment = new(CreateAsync);
public ValueTask<CoreWebView2Environment> GetEnvironmentAsync(CancellationToken cancellationToken = default)
=> new(_environment.Value);
private static Task<CoreWebView2Environment> CreateAsync()
{
// A persistent user data folder keeps the HTTP cache and WebView2 state across app restarts.
var userDataFolder = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MyApp", "WebView2");
Directory.CreateDirectory(userDataFolder);
return CoreWebView2Environment.CreateAsync(
browserExecutableFolder: null,
userDataFolder: userDataFolder,
options: new CoreWebView2EnvironmentOptions("--no-proxy-server")
{
AreBrowserExtensionsEnabled = false,
ExclusiveUserDataFolderAccess = true,
});
}
}
services.AddWindowsFormsBlazorWebView()
.UseSharedCoreWebView2Environment<SharedWebView2Environment>();
The options are only an example: --no-proxy-server makes WebView2 connect directly instead of resolving the system
proxy, which suits an app that loads only its own local content, and ExclusiveUserDataFolderAccess keeps other
processes out of the folder. There is also an overload that takes an already-created environment. You own the
environment's lifetime; the views never dispose a shared environment. A single view can still use its own environment
through BlazorWebViewInitializingEventArgs.CoreWebView2Environment, which takes precedence.
More
- Example app: examples/WindowsForms.BlazorApp
- Other hosts: Scarlet.AspNetCore.Components.WebView.Wpf and the NativeAOT-friendly Scarlet.AspNetCore.Components.WebView.Win32Aot
- Source and issues: https://github.com/ScarletKuro/Scarlet.AspNetCore.Components.WebView
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0-windows7.0 is compatible. net10.0-windows was computed. |
-
net9.0-windows7.0
- Microsoft.AspNetCore.Components.WebView (>= 9.0.21)
- Microsoft.Web.WebView2 (>= 1.0.4258.31)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.