This is Part 2 in the multi-part series of .NET MAUI – Blazor articles.
In Part 1, we’ve seen an introduction on how to make use of BlazorWebView in the .NET MAUI app.
Part 3 of this series is on the streamlined process of registering the dependencies for BlazorWebView from .NET MAUI RC1 release.
Since it is implemented as a View, it’s possible to share data between .NET MAUI and Blazor and that’s the takeaway of this article. Along with that, the core logic is now abstracted as Razor Class Library (RCL), Dependency Injection, and Component routing for Navigation.
RCL is a library project targeting the Microsoft.NET.Sdk.Razor
SDK type. Allows sharing Razor components with other projects to maximize code reuse. Not only Razor components, but it’s also possible to share static assets (like CSS, JS) from these libraries.


In the sample described in the previous article, all the components were in the same project as the UI, but now apart from Gateway.razor, all the other components have been abstracted as RCL. It’s possible to have this Gateway.razor in the RCL itself, but to illustrate how to refer to components from external assemblies, have left it in the MAUI project itself. And to add to this, have created a new CSS in the RCL, that would be referred to in the index.html
file, the host page in BlazorWebView.

The AdditionalAssemblies
attribute on the Router
component holds the list of all other assemblies to scan for the components that are to be loaded during runtime. This can be multiple.
The Router
component maintains a list of routes that are defined in all the components and redirects the incoming request to the right component for servicing it or if none of the routes match displays the view defined in the NotFound
section.
Now the sample is updated with a different layout for Found
and NotFound
scenario. Check out the sample in the GitHub repo for details.
As mentioned earlier, the resources from the folder name starting with _
are from external assemblies. Now, the CSS from this RCL gets referenced in index.html
as depicted in the below image. _content
for user-defined resources and _framework
for base libraries.
Ensure this NuGet package is referenced in the .NET MAUI project to serve the static assets from the referenced assemblies: Microsoft.Extensions.FileProviders.Embedded
The default convention is _content/<assemblyName>/<resourcePath>
. The resources need to be made available in the wwwroot
folder in the RCL for this to work. There is yet another approach for serving static resources with Razor components known as Scoped CSS/JS. More on that in another article.

Component routing can be handled with NavigationManager
or HTML anchor element (<a href="" />
). The difference is in the outcome of the requested route not matching any of the available route addresses. While using NavigationManager, it shows the NotFound view whereas when using the anchor element, it shows the platform-specific Invalid address page (404 – Not Found). The reason is, that if none of the routes match, the Router
passes on the anchor’s request to the platform handler considering it as an external resource (broader scope).
NavigationManager
can be injected into the component using @inject
directive, capture the injected instance into a variable, and with that call the NavigateTo
method with the route address to navigate to another component.



Note: The component directives can also be used as attributes while using code-behind. Define a partial class in the name of the component, define public properties, and decorate them with appropriate attributes. For example, @page
will become [Route]
(to be applied to the component class itself) and @inject
will become [Inject]
. @using
and @implements
are exceptions.
using Microsoft.AspNetCore.Components;
namespace RazorLib
{
[Route("/")]
public partial class Index
{
[Inject]
public NavigationManager? Navigator { get; set; }
}
}
Route addresses won’t be powerful without parameters in them. Yes, they do support passing parameters (both URL as well as Query type parameters), can be marked as optional if necessary and components can have more than one route defined on them. Query type parameters can only be used during routing and not while nesting in other components.
The routing address of the Counter component has been updated to accept a parameter named StartWith (case-insensitive) with an added constraint that the incoming value should be of type integer.

For example, a route with an address /counter/7
would match whereas /counter/foo
won’t match as the parameter is not of type integer in the latter.
In the sample, the Counter component is used in two ways: Nested, in the Index itself, and Standalone with routing. From Index, on Navigate with Random value button click, a random integer is passed as a parameter to set as an initial value for the counter.
Now on to the most exciting part of this article, sharing the state between .NET MAUI and Blazor. Yes, both native MAUI controls and Blazor web components gonna work in tandem on the same counter value. Actioning on either of the controls will increment the counter and refresh the value in the UI. For this to work, we need a shared AppState to hold the counter value and we use a DI container to hold the same.

The shared AppState has a public property to read the current counter value and public methods to initialize and increment the counter. Whenever the value of the counter changes, a state change notification is raised so that the interested components can subscribe to the notification and respond to that.

Now in the App Startup, this AppState is registered in the DI container as Singleton so that the same instance is returned to all the parties requesting it. And the other registrations are for the .NET MAUI startup page (defined in XAML and C# respectively) and this AppState is injected in the constructor of those pages so that it is resolved automatically as their dependency.
public partial class App : Application
{
public App()
{
InitializeComponent();
// C# definition
MainPage = AppService.GetService<BlazorPage>();
// XAML definition
//MainPage = AppService.GetService<WebPage>();
}
}
User action on the MAUI button or Blazor button would increment the counter value and UI is updated to reflect the state change.
On navigation, a random value would be passed as input and the counter would start from that.
Finally, upon clicking the Back to Home link, the counter value would reset to zero and start again.




Happy coding. Stay connected as we continue to learn and share the experiences from this exciting journey of being a software developer.
4 replies on “.NET MAUI – Blazor – Interop”
[…] And Part 2 on abstracting core logic as Razor Class Library (RCL), Component Navigation, and Sharing AppState between .NET MAUI and Blazor is now available to read. Click here to read the article. […]
LikeLike
[…] .NET MAUI – Blazor – Interop (Vijay Anand E G) […]
LikeLiked by 1 person
[…] .NET MAUI – Blazor – Interop (Vijay Anand E G) […]
LikeLike
[…] for .NET MAUI – Preview (Daniel Hindrikes) .NET MAUI – Blazor – Interop (Vijay Anand E G) Stable channel release notes for the Windows App SDK 1.0 (Windows App Development […]
LikeLike