The .NET Stacks #52: 🎂 Happy birthday to us
In this extended issue, we're recapping Build and walking through the release of .NET 6 Preview 4.
As if the completely ridiculous banner image didn't tip it off, it's true: today is the 1st birthday of The .NET Stacks! I'd like to thank our friend Isaac Levin—our first interview guest—for being such a good sport. If you haven't seen the wonderful "Application Development" keynote from Build, you should (and the picture will all make sense).
But most of all, I'd like to thank all of you for your support. Honestly, this little project started as a way to keep my mind busy during a pandemic lockdown and I really wasn't sure how things would go. (Looking back at the first issue ... that was very evident.) I'm thrilled it's been able to have the impact it has, and I'm grateful to all of you for that.
With all that out of the way, what are we talking about this week? In this extended issue, there's a lot here:
- Build 2021 recap
- .NET 6 Preview 4 has arrived
- Visual Studio updates
- System.Console in .NET 7
Build 2021 recap
Last week, Microsoft rolled out Build 2021. You can check out the 330 sessions at the Build website, and there's a YouTube playlist at the Microsoft Developer YouTube channel. It's no secret that these days Build is heavy on promoting Azure services, but .NET got a lot of love last week, too.
Your mileage may vary, but my favorite sessions included the application development keynote, a .NET "Ask the Experts" session, increasing productivity with Visual Studio, microservices with Dapr, modern app development with .NET, and a .NET 6 deep-dive session with Scott Hunter. (Hunter is Microsoft's CSO—the Chief Scott Officer. He also runs .NET.)
I want to call out a few interesting details from that session: updates on C# 10 and a new Blazor FluentUI component library that's taking shape. (There were other nice updates on .NET MAUI and Minimal APIs that we'll surely address in depth in later issues.)
C# 10 updates
In Scott Hunter's talk, Mads Torgersen and Dustin Campbell walked through some updates coming to C# 10. C# 10 looks to be focused on productivity and simplicity features. I want to show off record structs, required object initializers, auto-implemented property improvements, null parameter checking, global usings, and file-scoped namespaces.
Record structs
C# 9 brought us records, which gives you the ability to enforce immutability with the benefits of "value-like" behavior. While the C# 9 records are really just a class under the covers and accessed by reference, the "value-like" behaviors ensure that default equality checking works with your object's data (as opposed to reference equality). A good use case is with DTOs and other objects that benefit from immutability.
With all reference types, though, passing around a lot of records can create a lot of pressure on the garbage collector. If you couple that with using
with expressions, copying and GC pressure can become an issue if you go crazy with records. Can we use structs with records? With C# 10, you can with the
record struct syntax. It'll behave similarly, with the only key difference being that record structs aren't heap-allocated. This will also work with tuples, expressions, or any other struct types.
Let's look at some code, shall we? Let's say you have a
Person record in C# 9:
record Person { public string FirstName { get; init; } public string LastName { get; init; } }
To use a record struct, change it to this:
record struct Person { public string FirstName { get; init; } public string LastName { get; init; } }
The default
record declaration will still be a reference type. If you want to make that explicit, you can use the new
class struct syntax. They are the same.
Required object initializers
I enjoy the flexibility of object initializers. You can use them to initialize objects however you want: you can initialize just a few properties, in whatever order you want, or none at all! Unfortunately, this flexibility can also bite you in the rear end if you aren't careful.
With C# 10, you can set fields to be required when performing object initialization, like this:
record struct Person { public required string FirstName { get; init; } public required string LastName { get; init; } }
Its early days on this feature, but it might also help to enforce whether types can be instantiated by positional syntax (constructors) or object initialization.
Auto-implemented property improvements
In the Build talk, Dustin and Mads talked about the cliff: let's say you want to change one little thing about an auto-implemented property. The next thing you know, you're creating a backing field, adding bodies for your getters and setters, and you're left wondering why it takes so much work to change one little thing.
With C# 10, you can refer to the auto-generated backing field without all that nonsense. You'll be able to work with a
field keyword in your getters, setters, or even both.
record struct Person { public string FirstName { get; init => field = value.Trim(); } public string LastName { get; init; } }
This change provides better encapsulation and fewer lines of boilerplate code.
Null parameter checks
We've seen many nullability improvements over the last few C# releases, but null parameter checking can still be a manual chore—even with null reference types, you have to depend on the caller to do null checks.
With C# 10, this is taken care of with the
!! keyword:
public void DoAThing(string text!!) { Console.WriteLine(text); }
Don't worry, you aren't seeing double—this doesn't mean you're super excited about the
text argument. Personally, I'm not a fan of the
!!—at this rate, the C# team will need to start inventing new characters—but I am a fan of removing a bunch of this boilerplate nonsense.
Global usings and file-based namespaces
Lastly, the team introduced a few enhancements to help simplify your C# codebase.
With global usings, you can use the
global using keywords to signify usings should be accessible throughout every .cs file in your project.
Here's a typical example of using statements you might want to use in your global using file:
global using System; global using System.Collections.Generic; global using System.Linq; global using System.Threading.Tasks; global using static System.Console;
I wonder if we could use Roslyn analyzers to shake out unused global usings for individual files. Anyway, I think this is a feature I will originally hate, then learn to love. It's nice to see what is being used, but after a while, it's a maintenance headache. This will be nice. (Not to mention ASP.NET Core developers are familiar with a similar approach with Razor files.) In any case, in many files, you might wind up with a global usings file, then individual usings for references that aren't scattered across your projects.
Lastly, the team introduced file-scoped namespaces. It allows you to go from this:
namespace MyNamespace { record Person { public string FirstName { get; init; } public string LastName { get; init; } } }
To this:
namespace MyNamespace; record Person { public string FirstName { get; init; } public string LastName { get; init; } }
Of course, you could use top-level statements to remove namespaces completely—however, there are plenty of reasons why you don't want to abstract away your namespace declarations. In those cases, it's a nice, clean approach.
New Blazor component library
So here's something interesting that isn't getting a lot of attention: Microsoft is working on a component library for Blazor. Technically, these are wrappers around Microsoft's existing FluentUI Web Components and are built on FAST. You can fork the repository and browse to the examples app for a test page:
This is early, but I'd recommend taking a look—while it comes with the Blazor name, these are technically Razor components. This means you use them in other ASP.NET Core web apps, such as Razor Pages and MVC.
Microsoft customers have been asking for an in-house, free component library for a while—this will fill the need. While Microsoft will eventually introduce this as yet another tool at your disposal, they'll need to be careful here: the .NET community has a rich community of open-source and third-party component libraries (both free and paid), and they'll need to avoid the perception they're trying to replace these options. (To be abundantly clear, they definitely are not.)
.NET 6 Preview 4 has arrived
Just minutes into Build, Microsoft announced the official release of .NET 6 Preview 4. We've teased a few features in the last month or so, but it's nice to see the official news. Richard Lander wrote up the blog post. As a reminder, .NET 6 will be an LTS release.
.NET Hot Reload is a big .NET 6 feature (as is improving the developer inner loop in general). I've written about how you can use it by running
dotnet watch with ASP.NET Core web apps (that is, Blazor, Razor Pages, and MVC). With Preview 4, you can also use it with other project types like WPF, Windows Forms, WinUI, console apps and "other frameworks that are running on top of the CoreCLR runtime." It's now integrated with the Visual Studio debugger as well—to do this, you need to download VS 2019 16.11 Preview 1.
In Lander's post, we also see much of what we've discussed previously: check out the official details on
System.Text.Json improvements, LINQ enhancements, FileStream performance improvements on Windows, and new
DateOnly and
TimeOnly structs.
What about ASP.NET Core? ASP.NET Core is bringing it in this release—there's Minimal APIs, async streaming, HTTP logging middleware, improved SPA templates, Blazor error boundaries, and ... drum roll ... Blazor WebAssembly ahead-of-time (AOT) compilation! You can also start building .NET MAUI client-side apps with Blazor. Speaking of MAUI, there's a separate post outlining its Preview 4 updates. If you're using Entity Framework, make sure to check out that team's Preview 4 post to see all the wonderful perf improvements.
Preview 4 is a big one. Even with a little under six months to go, we'll only have a few previews to go until the focus turns to bug fixes. .NET 6 is coming along nicely.
Visual Studio updates
Last week, Microsoft also released Visual Studio 2019 v16.10 and v16.11 Preview 1.
With 16.10, we're seeing some more Git workflow improvements. The initial improvements to Git workflow in Visual Studio 2019 were a little rough, if we're being honest. It's nice to see the Visual Studio team listening to customer feedback and making it better. You can also now remove unused references—a long-adored ReSharper feature. In other news, there's improvements to Docker container tooling, IntelliSense completion improvements, Test Explorer improvements, and more. If F# is your jam, Phillip Carter announced some tooling updates for 16.10.
Also, if you're developing Azure Functions with the isolated worker in .NET 5, Azure Functions PM Anthony Chu has an update for you:
If you're building .NET 5 isolated @AzureFunctions apps and want to use @VisualStudio, update to VS 2019 v16.10 for full support for templates, local debug, and deployment.— Anthony Chu (@nthonyChu) May 26, 2021
We'll be updating our tutorial and docs shortly. pic.twitter.com/eaGjTdr9mp
With 16.11 Preview 1, the big news is supporting hot reload in Visual Studio. We're also seeing .NET MAUI support.
On the topic of IDEs, JetBrains released its roadmaps for ReSharper 2021.2 and Rider 2021.2.
Rethinking System.Console in .NET 7
With .NET 7—yes, .NET 7!—Microsoft is taking a look at redesigning
System.Console.
As Adam Sitnik describes it, the initial design was driven by Windows OS capabilities and APIs. With .NET going cross-platform, it introduced a number of issues since there wasn't a good way to map Windows concepts to Unix. You're encouraged to follow the discussion and provide feedback.
We've seen a lot of community innovation in this space. For example, Patrik Svensson's Spectre.Console library shows us that the developer console experience can be productive and beautiful. This isn't lost and I'm interested to see how this work evolves.
🌎 Last week in the .NET world
Welcome to Build week, where announcements are everywhere.
🔥 The Top 3
- Microsoft Build 2021 came and went—Amanda Silver and Scott Guthrie welcome you, and Microsoft provides the Build 2021 Book of News.
- Richard Lander announces .NET 6 Preview 4, Dan Roth announces ASP.NET Core updates, Shay Rojansky does the same for EF Core, and David Ortinau announces .NET MAUI Preview 4.
- Khalid Abuhakmeh announces the roadmap for ReSharper 2021.2 and also for Rider 2021.2.
📢 Announcements
- Microsoft releases Visual Studio 2019 v16.10 and v16.11 Preview 1, and Phillip Carter announces F# and F# tools updates.
- Dmitry Lyalin introduces the .NET Hot Reload experience for editing code at runtime.
- The Windows Package Manager goes 1.0, and Kayla Cinnamon releases Windows Terminal Preview 1.9.
- Troy Hunt announces that Have I Been Pwned is part of the .NET Foundation and a partnership with the FBI.
- Sam Basu announces Telerik UI for MAUI.
📅 Community and events
- David Ramel writes about the Visual Studio 2022 roadmap.
- The .NET Docs Show talks to Christos Matskas about Microsoft Identity.
- Wolfgang Hennerbichler writes about how GitHub is adopting OpenTelemetry.
- Because of Build, no community standups.
🌎 Web development
- The Code Maze blog uses Serilog with ASP.NET Core.
- Cody Merritt Anhorn uses Blazor with SignalR.
- Matthew Groves compares SQL and NoSQL in ASP.NET.
- Jeremy Likness writes about 10 Blazor features you might not know about.
- Jay Krishna Reddy writes about using OData in .NET 5.
- Mark Downie disables FLoC in ASP.NET.
- Joydip Kanjilal implements nanoservices in ASP.NET Core.
- Adam Storr calls a REST API with HttpClient in .NET 5.0.
- David McCarter processes data with microservices.
🥅 The .NET platform
- Patrick Smacchia migrates Delegate.BeginInvoke Calls to .NET Core, .NET 5 and .NET 6.
- Maarten Balliauw runs a .NET application as a service on Linux with Systemd.
- Steve Gordon uses DateOnly and TimeOnly in .NET 6.
- David Ramel provides updates on Project Reunion.
- Khalid Abuhakmeh explains the difference between HTML and URL Encode in .NET.
- Paula Fahmy begins a series on async C#.
- Jonathan Allen builds a source generator in C#.
⛅ The cloud
- Daniel Krzyczkowski uses Auth0 Actions with Azure Functions.
- Aaron Powell works with the Azure Static Web Apps CLI.
🔧 Tools
- Andrew Lock stops Visual Studio from creating launchsettings.json.
- Steve Smith disables logging loading symbols in VS Code.
📱 Xamarin
- Mark Allibone uses the OIDC client in Xamarin Forms to refresh an access token.
- Sam Basu provides his weekly MAUI update.
🎤 Podcasts
- The .NET Rocks podcast talks to Scott Hunter about Build 2021 announcements.
- The Adventures in .NET podcast talks to Chris Sainty about Blazor.
- The Azure DevOps Podcast talks to David Ortinau about MAUI.
- The Coding Blocks Podcast talks through some fun APIs.
- The 6-Figure Developer podcast talks about .NET Data with Jeremy Likness.
🎥 Videos
- Azure Friday provides an update on Azure Cosmos DB.
- The On .NET Show talks about clustering in Orleans and also C# exception filters.
- One Dev Question asks: who at Microsoft is using WinUI?
- The Xamarin Show improves accessibility with the Xamarin Community Toolkit.