This is the fourth article in the .NET MAUI – Blazor series and have provided links for the other 3 articles previously published.
- .NET MAUI – Blazor – Getting Started
- .NET MAUI – Blazor – Interop
- .NET MAUI – RC1 – BlazorWebView – Streamlined
This article primarily focuses on the Blazor Hybrid scenarios.
The reason is the potential of Blazor, the modern web UI stack based on Razor SDK and allows to work with C# language constructs which can be used across multiple frameworks with the introduction of BlazorWebView, now officially supported on .NET MAUI, classic Windows desktop application frameworks such as Windows Forms (WinForms) and WPF.
Supporting WinForms and WPF paves the way to modernize the existing applications by adding BlazorWebView on even a single page and then gradually rolling out to other pages.
And of course, the Web frameworks such as Blazor Server and Blazor WebAssembly (WASM) are supported by default.
Thus by creating a Blazor Hybrid application one can target the below platforms/frameworks. And by abstracting the common items such as Razor components, C# types, etc … in a Razor Class Library (RCL), the code can be shared across all the mentioned targets. In the below list, items #1 through #5 are supported via .NET MAUI
- macOS (via Mac Catalyst)
- Windows (via WinUI3 aka Windows AppSDK)
- Windows Forms
- Blazor Server
- Blazor WebAssembly (WASM) – Can also be published as PWA (Progressive Web App)
To get started with the BlazorWebView, refer to my earlier articles #1 and #3 (which cover the final changes), and their links provided in the intro.
Before moving on to the details, the BlazorWebView runs natively on the same process as that of the application and there’s no Web Server (or) WebAssembly involved and hence no-sandbox concerns and it can harness the full power of the underlying platform.
For classic WinForms and WPF applications, it has to target .NET 6 and can run on Windows 7 or later OS versions. So the TFM would be
net6.0-windows7.0. Most importantly, this technology is built on top of WebView2, the modern web browser implementation so the WebView2 Runtime needs to be installed in the client machine where the app is going to be deployed. Which can be downloaded from here or installed via the maui-check tool.
For client applications such as .NET MAUI, WinForms, and WPF, the app has to be compiled against the
Microsoft.NET.Sdk.Razor SDK. And for all these three UI frameworks, a separate NuGet package for each of them. They are:
For a .NET MAUI app, when the
<UseMaui>true</UseMaui> tag is defined and the project target Razor SDK, the corresponding NuGet package is implicitly referenced. No need to define again.
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <UseMaui>true</UseMaui> <!-- Any other relevant definition --> </PropertyGroup> </Project>
Whereas for the other 2 classic frameworks, the corresponding package needs to be added explicitly.
Project definition for Windows Forms:
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net6.0-windows7.0</TargetFramework> <UseWindowsForms>true</UseWindowsForms> <!-- Any other relevant definitions --> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Components.WebView.WindowsForms" Version="6.0.312"/> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1"/> </ItemGroup> </Project>
Project definition for WPF:
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net6.0-windows7.0</TargetFramework> <UseWPF>true</UseWPF> <!-- Any other relevant definitions --> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Components.WebView.Wpf" Version="6.0.312"/> <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1"/> </ItemGroup> </Project>
App startup and adding a BlazorWebView to a Form/Window is covered in detail in article #3, link in the intro.
Project definition for Blazor Server and WebAssembly, both a superset of the Razor SDK.
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <!-- Any other relevant definitions --> </PropertyGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <!-- Any other relevant definitions --> </PropertyGroup> </Project>
A Razor Class Library (RCL) is a class library that is compiled against the Razor SDK and targets .NET 6.0. Hence it can contain Razor components and can be referenced in any of the Blazor-supported projects provided it contains only the items and references that are not specific to a particular target. Since it’s a class library, C# types and business logic can also be defined here. If they’re to be shared with other projects such as Web API, then they can be defined in a regular class library project and referenced to the RCL.
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <!-- Any other relevant definitions --> </PropertyGroup> </Project>
Now we’re going to walk through a real multi-targeted solution that runs on all supported frameworks. The source for this sample is hosted on the GitHub repository here. It’s a good starter application with fair enough concepts to implement. And it’s a newsletter published every week and is popular among the developers of Xamarin and now .NET MAUI named WeeklyXamarin.
This has 4 main UIs laid out as Tabs and a detailed UI to list down the articles for each edition and can be navigated from the main UI. Since this Blazor application can run on a variety of platforms and devices, I chose Bootstrap to design the UI so that it adapts to them and is responsive. Next, the Services are carefully abstracted so that they can reside in the shared code without any platform dependency and yet uses the platform-specific navigation and dialogs.
On .NET MAUI, it uses Shell as the navigation paradigm and uses platform native dialogs. And on Blazor Server and WebAssembly, it uses the Bootstrap dialogs to show messages.
Glad to introduce the NuGet packages – VijayAnand.MauiToolkit.Core and VijayAnand.MauiToolkit. The Core package targets .NET 6 and it contains the abstractions needed to work with Blazor Hybrid and the latter MauiToolkit package implements those abstractions specific to the .NET MAUI UI stack and provides extension methods to register them in the startup pipeline (MauiProgram.cs). Feedback is welcome on improving this toolkit so that it can cater to a broader set of Blazor hybrid scenarios, which can be logged as issues in the GitHub repository where it is actively worked upon.
The Core package is referenced in all the projects in the solution and the MauiToolkit package (which depends on the Core package) will be referenced on the .NET MAUI project alone. On the other framework projects, the implementations of those abstracted interfaces would have been defined, if necessary, and registered in the App startup.
UI is developed as Razor components and some of them are templated pages providing a common definition for the UI, like the Back Navigation and Bottom Tab. And it all depends on the project’s needs.
Since BlazorWebView works on top of the underlying platform’s native WebView, any of the supported Web APIs such as connectivity, localStorage, notifications, web share, etc … can be made use of.
In fact, this BlazorApp makes use of localStorage to store data locally and allows the solution to work offline to a certain extent such as browse editions, bookmark, and search. But to view an article, an Internet connection is required.
Thus with a Razor Class Library and thoughtfully created NuGet package, maximizing the code sharing with the framework projects and unleashing the full potential of Blazor.
Happy coding. Stay connected as we continue to learn and share the experiences from this exciting journey of being a .NET developer.