The .NET Stacks #57: ๐ง Taking a look at Blazor Error Boundaries
Good morning, everybody. I hope everyone has had a good last couple of weeks, as I took last week off to celebrate Independence Day here in the United States.
Here's what we have this week:
- The big thing: Taking a look at Blazor Error Boundaries
- The little things: .NET Foundation elections, Minimal API improvements, pining to help with OSS?
- Last week in the .NET world
The big thing: Taking a look at Blazor Error Boundaries
This weekend, I finished writing a piece on Blazor error boundaries. It'll be published in a week or two, so here's a preview for you.
Looking at Blazor Server apps: when an unhandled exception occurs, Blazor Server treats it as a fatal error because the circuit hangs in an undefined state, which can potentially lead to usability or security problems. As a result, your app is as good as dead, loses its state, and your users are met with an undesirable An unhandled error has occurred message, with a link to reload the page.
This begs the question: if I get an unhandled exception from a single component, why should my entire app die? As a Blazor developer, you're left spending a lot of time hacking around this by putting try
and catch
blocks around every single method of your app, leading to performance issuesโespecially when thinking about cascading parameters. Blazor developers look longingly at React's Error Boundaries and wonder when we get to have nice things.
With .NET 6 Preview 4, you can. Inspired by Error Boundaries in React, it attempts to catch recoverable errors that can't permanently corrupt stateโand like the React feature, it also renders a fallback UI. This capability won't catch all possible exceptions but most common scenarios such as the various lifecycle methods (like OnInitializedAsync
, OnParametersSetAsync
, and OnAfterRenderAsync
, ย and rendering use cases with BuildRenderTree
.
The new ErrorBoundary
component provides a ChildContent
fragment (what to display when all goes well), an ErrorContent
fragment (what to display when it doesn't), and a CurrentException
property so you can capture exception details.
Most importantly, the ErrorBoundary
component allows you to call a Recover
method, which resets the error boundary to a "non-errored state." By default, the component handles up to 100 errors through its MaximumErrorCount
property. The Recover
method does three things for you: it resets the component's error count to 0
, clears the CurrentException
and calls StateHasChanged
. The StateHasChanged
call notifies components that the state has changed and typically causes your component to be rerendered.
Here's an example:
@code {
ErrorBoundary errorBoundary;
protected override void OnParametersSet()
{
errorBoundary?.Recover();
}
}
For another example, let's say you have a component that calls off to an API. Here, I'm getting a list of surfboards. I can wrap the data fetching in an ErrorBoundary
.
<tbody>
@foreach (var board in ShirtProductsList)
{
<ErrorBoundary @key="@board">
<ChildContent>
<tr>
<td>@board.Id</td>
<td>@board.Name</td>
<td>@board.Color</td>
<td>@board.Price</td>
</tr>
</ChildContent>
<ErrorContent>
Sorry, I can't show @board.Id because of an internal error.
</ErrorContent>
</ErrorBoundary>
}
</tbody>
Blazor Error Boundaries is not meant to be a global exception handling mechanism for any and all unhandled errors you encounter in your apps. You should be able to log all uncaught exceptions using the ILogger
interface.
While you can mark all your components with error boundaries and ignore exceptions, you should take a more nuanced approach to your application's error handling. Error Boundaries are meant for control over your specific component's unhandled exceptions and not a quick way to manage failures throughout your entire application. What do you think?
The little things: .NET Foundation elections, Minimal API improvements, pining to help with a project?
The .NET Foundation will be holding elections next month for two upcoming Board seats. If you've made it to the Elections page, you'll see my face as I'm on the Election Committee.
The .NET Foundation serves the general .NET community by promoting .NET in general, advocating .NET OSS, promoting .NET across a wider community of developers, supporting .NET community events, and offering administrative support to member projects. This is an organization that runs separately from Microsoft.
As a Board member, you'd help to run the .NET Foundation by deciding how the money is spent, decide which projects join the foundation, and much more. If you're interested in running for a seat, let me know and I'll get you started.
We've covered Minimal APIs in .NET 6 a time or two. Prioritizing functions over classes, it's a route to simple APIs that many call ".NET Express"โI like the name because it describes getting right to the point and one of the inspirations.
The examples have mostly been a little "Hello World"-ish. ASP.NET Core architect David Fowler shows that it's coming along:
This Results
class looks nice, especially if you aren't a fan of attributes for MVC controllers. I'm interested to see if it can be extended further, and the team is looking into it.
If you're looking to extend model binding by using a single request object, you'll have to wait as it won't make it into .NET 6 (but maybe .NET 7). You can bind directly from the JSON object, but manually dealing with route and query parameters might get a tad unwieldy.
If you're looking to help with some open-source, David Pine could use some help. David has a project called the Azure Cosmos DB Repository .NET SDK, which allows you to use the repository pattern to work with your Cosmos DB instances. It really helps to simplify working with CRUD behavior in Cosmos, especially if you're familiar with the
interface. I find it quite nice, and use it for one of my projects (and have written about it as well).IRepository
<T>
David is working on a Blazor book for O'Reillyโif you've ever written a book or know someone who has, you won't be surprised to hear he'll need some help with the project. If you're interested in helping out, let him know.
๐ Last week in the .NET world
๐ฅ The Top 3
- Claudio Bernasconi works on end-to-end UI testing using SpecFlow.
- Steve Gordon writes about the StringBuilder in two posts.
- Sam Walpole writes about higher-order functions in C#.
- Leomaris Reyes explores automation properties in Xamarin.
๐ Community and events
- Colin Eberhardt writes about GitHub Copilot, and so does Renato Losio.
- Matthew MacDonald asks: is Windows 11 a Better OS for developers?
- In community standups, we have Machine Learning talking about model explainability and Languages & Runtime talks about what's coming up with the next .NET 6 previews.
๐ Web development
- Matthew Jones continues building a Solitaire game in Blazor.
- Andrew Lock adds authentication to a Blazor Server app using Auth0.
- Vladimir Pecanac writes about things to avoid in your ASP.NET Core controllers.
- Khalid Abuhakmeh decrypts secrets into ASP.NET Core MVC action arguments using action filters.
๐ฅ The .NET platform
- Jason Bock works on anagrams and prime numbers in .NET.
- Nick Randolph writes about what it means to be a Windows app developer.
- Patrick Smacchia writes about some .NET 6 API updates and improvements.
- Niels Swimberghe creates a Discord Bot using the .NET worker template.
โ The cloud
- Aaron Powell continues his series of GraphQL on Azure, creates Azure Static Web Apps with F# and Fable, and also controls the serialization of CosmosDB bindings for Azure Functions.
- Mark Heath writes about dependency injection in Azure Durable Functions.
- Yohan Lasorsa builds a shopping app with Azure Static Web Apps.
๐ Languages
- Davide Bellone compares String.IsNullOrEmpty and String.IsNullOrWhiteSpace.
- Ken Bonny rediscovers implicit casting in C#.
- Nikola M. Zivkovic writes about upcoming C# 10 features.
- Jason Roberts writes about C# 9 foreach support.
- Sanjay Modi writes about SOLID principles in C#.
๐ง Tools
- Mark Downie uses Visual Studio to search objects in a memory dump.
- Raymond Chen asks: what happens if I use a squash instead of a true merge?
- Joe Guadagno tests Web APIs or services with JetBrains Rider.
- Scott Hanselman adds predictive IntelliSense to Windows Terminal.
- Alex Russell writes about Git worktrees.
- Nick Randolph converts an app from .NET MAUI to Uno.
๐ Design, testing, and best practices
- Sarah Drasner writes about running good meetings.
- Peter Vogel writes about best practices when mocking objects.
- Sean Killeen uses custom comparers in NUnit.
- The Overflow writes about the unexpected benefits of mentoring others.
- Derek Comartin talks through a Clean Code architecture example.
๐ค Podcasts
- The Coding Blocks Podcast continues talking about the DDIA book.
- The .NET Rocks Podcast talks to Jeff Richter about Azure APIs.
- Richard Lander talks to the Azure DevOps Podcast.
๐ฅ Videos
- Shawn Wildermuth explains dependency injection.
- The On .NET Show diagnoses thread pool exhaustion issues in .NET Core apps, discusses Azure Functions with F#, and also talks about the null-coalescing assignment operator in C#.