Adding Superpowers to your Blazor WebAssembly App with Project Fugu APIs

Blazor WebAssembly is a powerful framework for building web applications that run on the client-side. With Project Fugu APIs, you can extend the capabilities of these apps to access new device features and provide an enhanced user experience. In this article, learn about the benefits of using Project Fugu APIs, the wrapper packages that are available for Blazor WebAssembly, and how to use them in your application.

Whether you're a seasoned Blazor developer or just getting started, this article will help you add superpowers to your Blazor WebAssembly app.

In diesem Artikel:

cl-neu
Christian Liebel ist Consultant bei Thinktecture. Sein Fokus liegt auf Webstandards und Progressive Web Apps. Er vertritt Thinktecture beim W3C.

Blazor WebAssembly is Microsoft’s framework for building single-page apps (SPAs) with C# and Razor. You can use Blazor to build more or less the same experiences as with other SPA frameworks such as React or Angular. This includes Progressive Web Apps (PWA)—web-based applications that work offline and can be installed on the user’s system.

Project Fugu, a joint venture between Microsoft, Google, Intel, and others, wants to bring more capabilities to the web to make PWAs and other web-based applications even more powerful. This includes accessing the file system, displaying app badges, or registering a web app as a handler for specific file extensions. As web platform APIs are for everyone, they can also be used within Blazor WebAssembly applications.

A diagram showing four Fugu APIs, with hte
The Fugu is the mascot of the Project Fugu initiative.

However, those APIs are typically JavaScript-based. To access them within Blazor WebAssembly apps, they must be wrapped for .NET. Some ready-to-use open-source NuGet packages exist, but my Thinktecture colleague Patrick Jahr and I missed some APIs. So, over the last couple of weeks, we implemented several missing Fugu wrappers for Blazor WebAssembly. You can find the source code and all samples on GitHub: https://github.com/thinktecture/Thinktecture.Blazor

This blog post will introduce some of the new web platform APIs, including their browser and platform support, and explains how to use the Blazor WebAssembly wrapper packages provided by the community and us. Please note that our packages are technical showcases and not official Thinktecture products.

Stay backwards compatible with Progressive Enhancement

Before using any of the following APIs, you should always check if it is available on the target system, as the platform support varies. Calling a non-existing API will lead to an error during runtime, and the application may crash. To avoid this, all wrapper packages discussed in this blog post offer a method called IsSupportedAsync() returning a boolean value whether the API is available:

				
					var isSupported = await badgingService.IsSupportedAsync();
if (isSupported)
{
    // enable badging feature
}
else
{
    // use fallback mechanism or hide/disable feature
}
				
			

In case the API is not available on the user’s system, you should hide or disable the feature. In some cases, alternative implementations are available to achieve similar behavior.

Share content to other apps with the Web Share API

The Web Share API allows you to share a title, URL, text, or files with another application installed on the user’s system via the share functionality provided by the operating system.

The image shows the platform-specific share dialog on top of a Blazor WebAssembly application.
Thanks to the Web Share API, Blazor WebAssembly apps can share data using the platform-specific share sheet

To use this API from your Blazor WebAssembly application, install the wrapper NuGet package for the Web Share API by using the following command:

				
					dotnet add package Thinktecture.Blazor.WebShare
				
			

Before using the API, you have to add the WebShareService to the IServiceCollection in Program.cs as follows:

				
					builder.Services.AddWebShareService();
				
			

Now, you can inject the WebShareService into your Blazor component. By calling its ShareAsync() method and passing a WebShareDataModel object to it, the device’s share sheet will open. The user can select an already installed application to share the content with or send it to another device via nearby sharing or AirDrop.

				
					try
{
    var data = new WebShareDataModel
    {
        Title = "Test 1",
        Text = "Lorem ipsum dolor...",
        Url = "https://thinktecture.com"
    };
    await webShareService.ShareAsync(data);
}
catch (Exception ex)
{
    // data not shareable or user denied sharing
}
				
			

Please note that the API is only exposed on secure contexts (sites transferred via HTTPS and localhost) and can only be invoked due to user interaction (i.e., a keypress or click). This also applies to most other APIs in this article. If the data cannot be shared or the user has dismissed the share sheet, an exception will be thrown.

Details about sharing files can be found in the readme file of the Web Share API wrapper package.

The Web Share API is supported by Chrome 89, Edge 81, and Safari 12.1. Mozilla Firefox also supports the API, but only on Android. For more details, see the browser support table for the Web Share API on caniuse.com.

Access the clipboard via the Async Clipboard API

The Async Clipboard API allows you to read and write text, images, and other data from or to the system’s clipboard. The supported data formats depend on the target platform. For instance, WebKit currently only supports plain text, HTML, URI lists, and PNG images.

You can install this wrapper package by using the following command:

				
					dotnet add package Thinktecture.Blazor.AsyncClipboard
				
			

Before using the API, you have to add the service to your service collection:

				
					builder.Services.AddAsyncClipboardService();
				
			

Afterward, you can inject the service into your Blazor component. It offers two shorthand methods for writing and reading plain text to or from the clipboard:

				
					// Write plain text to the clipboard
await asyncClipboardService.WriteTextAsync("Hello world");

// Read plain text from the clipboard
var text = await asyncClipboardService.ReadTextAsync();
				
			

The service also offers WriteAsync() and ReadAsync() methods for dealing with arbitrary data, if supported by the target platform. The readme file of the Async Clipboard API wrapper package explains those two methods in more detail.

Depending on the platform and action, permission or confirm prompts may open.

The browser shows a permission prompt after the application has attempted to access the clipboard
Due to security and privacy considerations, Chrome shows a permission prompt before giving the web application read access to the Clipboard.

The Async Clipboard API is supported since Microsoft Edge 79, Google Chrome 62, and Apple Safari 13.1. Mozilla Firefox only supports writing plain text, since version 63. For more details, see the browser support table for the Async Clipboard API on caniuse.com).

Opening and saving files with the File System Access API

The File System Access API allows your app to open, modify, and save local files and directories. It is based on the more general File System API and specifically deals with the local file system. This allows developers to finally bring traditional productivity apps to the web, such as image editors, word processors, or IDEs. For instance, the web-based version of Visual Studio Code uses this API to access local code workspaces.

Kristoffer Strube maintains wrappers for both the File System API and the File System Access API. His implementations inspired all our wrappers, and some rely on his packages. We want to take this opportunity to thank Kristoffer for the great collaboration so far.

To install this wrapper, run the following command:

				
					dotnet add package KristofferStrube.Blazor.FileSystemAccess
				
			

Next, the File System Access API service needs to be added to your service collection:

				
					builder.Services.AddFileSystemAccessService();
				
			

Now you can inject the IFileSystemAccessService into your Blazor component or service. To get a file handle, call the ShowOpenFilePickerAsync() method. If the user selects a file via the file picker, it will then be passed to the application, where you can access its contents:

				
					try
{
    var fileHandles = await _fas.ShowOpenFilePickerAsync();
    var fileHandle = fileHandles.Single();
    var file = await fileHandle.GetFileAsync();
    var text = await file.TextAsync();
    Console.WriteLine(text);
}
catch (Exception ex)
{
    // API not available, user denied request or file could not be opened/read
    Console.WriteLine(ex);
}
				
			

With the help of the file handle, you can also modify its contents. Additional usages of this API and package are shown in the readme file of the File System Access API wrapper package.

A screenshot showing a file open dialog box on top of a Blazor WebAssembly application.
Thanks

The File System Access API is supported by Chromium-based browsers only: Microsoft Edge and Google Chrome since version 86. Browser vendors can decide to disable the API, though. For example, Brave chose not to support the API, although this browser is also Chromium-based. Apple Safari only supports the File System API with the Origin Private File System (OPFS), an isolated file system that isn’t mapped to the local one. Mozilla Firefox supports neither of them. For more details, see the browser support table for the File System Access API on caniuse.com. If you need to support all browsers, refer to fallback approaches.

Registering your app as a file editor via File Handling

The File Handling API is built on top of the File System API. It allows your PWA to register as a file handler for specific file types. This requires your app to be installed on the user’s system, as the app has to register its name and icon with the operating system. On desktop systems, installation is currently only supported by Chromium-based browsers.

To use the File Handling API in your Blazor WebAssembly app, install the following NuGet package:

				
					dotnet add package Thinktecture.Blazor.FileHandling
				
			

Next, you need to add the file handling service to the service collection:

				
					builder.Services.AddFileHandlingService();
				
			

In contrast to all other APIs, the File Handling API has an imperative and a declarative part. To be registered as a file handler on installation, you must declare the file_handlers property in your application’s Web Application Manifest:

				
					{
  "file_handlers": [{
    "action": "./",
    "accept": {
      "text/plain": [".txt"]
    }
  }]
}
				
			

This property takes an array of file handlers which must include an action (the URL that should be called if the application is invoked as a file handler) and an accept object. This object maps the list of file extensions to a media type. A handler can deal with more than one media type and file extension. Optionally, you can also specify an icon for this file type.

A screenshot showing a Windows Explorer window with a context menu for a text file. A Blazor WebAssembly app appears as a compatible program.
The Blazor WebAssembly app appears in the list of compatible editing programs.

The second part involves adding code to your application: This code is executed when your application is launched as a file handler. Therefore, we are exposing the method SetConsumerAsync() on the FileHandlingService. This method takes a callback with launch parameters. The callback is invoked if the application was launched as a file handler. It will then expose the file handles on the Files property. The type is fully compatible with the File System Access API types.

				
					await _fileHandlingService.SetConsumerAsync(async (launchParams) =>
{
    foreach (var fileSystemHandle in launchParams.Files)
    {
        if (fileSystemHandle is FileSystemFileHandle fileSystemFileHandle)
        {
            var file = await fileSystemFileHandle.GetFileAsync();
            var text = await file.TextAsync();
            Console.WriteLine(text);
        }
    }
});
				
			

Using the file handles, the application can access the files’ contents and display them during runtime.

A screenshot of a Blazor WebAssembly application displaying text from a local file.
The Blazor WebAssembly app has gained access to the content of a file it was opened with.

The File Handling API is only supported by Chromium-based browsers since version 102 (see Chrome 102 release notes).

Communicate unfinished tasks via the Badging API

The Badging API allows you to display a badge on the installed application’s icon as a less obtrusive alternative to notification banners. The badges are well known from applications like email clients, instant messengers, or to-do apps. This also requires your application to be installed so it has an icon in the taskbar or dock.

To use this API, install the following wrapper package:

				
					dotnet add package Thinktecture.Blazor.Badging
				
			

As always, the services needs to be added to the service collection:

				
					builder.Services.AddBadgingService();
				
			
To set a badge on the application’s icon, call the SetAppBadgeAsync() method. This method takes a number that will be shown on the badge. You can also set it to null. In this case, a generic badge will be shown (without a number).
				
					await badgingService.SetAppBadgeAsync(3);
				
			
A screenshot showing a Blazor WebAssembly application and the Windows task bar. The application's icon has a little badge with the number 3 on it.
Thanks to the Badging API, Blazor WebAssembly applications can display badges on their app icons.

To remove the badge again, for example, when all email messages are read, all instant messages are answered, or all todo items are done, simply call the ClearAppBadgeAsync() method:

				
					await badgingService.ClearAppBadgeAsync();
				
			

The Badging API is currently only supported by Chromium-based browsers since version 81 on macOS and Windows, and by Apple Safari on iOS and iPadOS starting from version 16.4 Beta 1 (as long as the application has been added to the home screen and has permission for receiving push notifications). For more details, see the browser support table for the setAppBadge() method on caniuse.com.

Powerful APIs for a more capable web

The new web platform APIs introduced by Project Fugu make web applications significantly more powerful, including your Blazor WebAssembly apps. Using the wrapper packages provided by the community and us, you can genuinely add superpowers to your Blazor-based web apps. We look forward to your feedback and are eager to see where our packages will be used. Keep an eye on our blog for more wrapper packages and updates on Progressive Web Apps. So let’s go and make the web a more powerful place!

Kostenloser
Newsletter

Aktuelle Artikel, Screencasts, Webinare und Interviews unserer Experten für Sie

Verpassen Sie keine Inhalte zu Angular, .NET Core, Blazor, Azure und Kubernetes und melden Sie sich zu unserem kostenlosen monatlichen Dev-Newsletter an.

Newsletter Anmeldung
Diese Artikel könnten Sie interessieren
Low-angle photography of metal structure
AI
cl-neu

AI-Funktionen zu Angular-Apps hinzufügen: lokal und offlinefähig

Künstliche Intelligenz (KI) ist spätestens seit der Veröffentlichung von ChatGPT in aller Munde. Wit WebLLM können Sie einen KI-Chatbot in Ihre eigenen Angular-Anwendungen integrieren. Wie das funktioniert und welche Vor- und Nachteile WebLLM hat, lesen Sie hier.
26.02.2024
Database Access with Sessions
.NET
kp_300x300

Data Access in .NET Native AOT with Sessions

.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.
15.11.2023
Old computer with native code
.NET
kp_300x300

Native AOT with ASP.NET Core – Overview

Originally introduced in .NET 7, Native AOT can be used with ASP.NET Core in the upcoming .NET 8 release. In this post, we look at the benefits and drawbacks from a general perspective and perform measurements to quantify the improvements on different platforms.
02.11.2023
.NET
kp_300x300

Optimize ASP.NET Core memory with DATAS

.NET 8 introduces a new Garbage Collector feature called DATAS for Server GC mode - let's make some benchmarks and check how it fits into the big picture.
09.10.2023
.NET CORE
pg

Incremental Roslyn Source Generators: High-Level API – ForAttributeWithMetadataName – Part 8

With the version 4.3.1 of Microsoft.CodeAnalysis.* Roslyn provides a new high-level API - the method "ForAttributeWithMetadataName". Although it is just 1 method, still, it addresses one of the biggest performance issue with Source Generators.
16.05.2023
AI
favicon

Integrating AI Power into Your .NET Applications with the Semantic Kernel Toolkit – an Early View

With the rise of powerful AI models and services, questions come up on how to integrate those into our applications and make reasonable use of them. While other languages like Python already have popular and feature-rich libraries like LangChain, we are missing these in .NET and C#. But there is a new kid on the block that might change this situation. Welcome Semantic Kernel by Microsoft!
03.05.2023