Announcing .NET 5.0 RC 2

Rich Lander [MSFT]

Today, we are shipping .NET 5.0 Release Candidate 2 (RC2). It is a near-final release of .NET 5.0, and the last of two RCs before the official release in November. RC2 is a “go live” release; you are supported using it in production. At this point, we’re looking for reports of any remaining critical bugs that should be fixed before the final release.

We also released new versions of ASP.NET Core and EF Core today.

You can download .NET 5.0, for Windows, macOS, and Linux:

You need the latest preview version of Visual Studio (including Visual Studio for Mac) to use .NET 5.0.

.NET 5.0 includes many improvements, notably single file applications, smaller container images, more capable JsonSerializer APIs, a complete set of nullable reference type annotations, new target framework names, and support for Windows ARM64. Performance has been greatly improved, in the NET libraries, in the GC, and the JIT. ARM64 was a key focus for performance investment, resulting in much better throughput and smaller binaries. .NET 5.0 includes new language versions, C# 9 and F# 5.0. Check out some .NET 5.0 examples so you can try these features out for yourself.

Today is an auspicious day because we’re kicking off the 2020 .NET@Microsoft internal conference. There will be many speakers from the .NET team, but also developers and architects from services teams that rely on .NET to power the Microsoft cloud, sharing their victories and also their challenges. I’m presenting (unsurprisingly) “What’s new in .NET 5.0”. My talk will be easy; I’ll just read the .NET 5.0 blog posts, preview by preview! It will be a great talk. More seriously, the conference is our opportunity to make the case why Microsoft teams should adopt .NET 5.0 soon after it is available. At least one large team I know of is running on RC1 in production. The official .NET Microsoft site has been running on .NET 5.0 since Preview 1. It is now running RC2. The case we’ll make to Microsoft teams this week is very similar to the case that I’ve intended to make to you across all of these .NET 5.0 blog posts. .NET 5.0 is a great release and will improve the fundamentals of your app.

Speaking of conferences, please save the date for .NET Conf 2020. This year, .NET 5.0 will launch at .NET Conf 2020! Come celebrate and learn about the new release. We’re also celebrating our 10th anniversary and we’re working on a few more surprises. You won’t want to miss this one.

Just like I did for .NET 5.0 Preview 8 and .NET 5.0 RC1, I’ve chosen a selection of features to look at in more depth and to give you a sense of how you’ll use them in real-world usage. This post is dedicated to C# 9 pattern matching, Windows ARM64, and ClickOnce.

C# 9 Pattern Matching

Pattern matching is a language feature was first added in C# 7.0. It’s best to let Mads reintroduce the concept. This is what he had to say when he originally introduced the feature.

C# 7.0 introduces the notion of patterns, which, abstractly speaking, are syntactic elements that can test that a value has a certain “shape”, and extract information from the value when it does.

That’s a really great description, perfectly worded.

The C# team has added new patterns in each of the C# 7, C# 8, and C# 9 versions. In this post, you’ll see patterns from each of those language versions, but we’ll focus on the new patterns in C# 9.

The three new patterns in C# 9 are:

  • Relational patterns, using relational operators such as < and >=.
  • Logical patterns, using the keywords and, or, and not. The poster child example is foo is not null. This type of pattern is most useful when you want to compare multiple things in one pattern.
  • Simple type patterns, using solely a type and no other syntax for matching.

I’m a big fan of the BBC Sherlock series. I’ve written a small app that determines if a given character should have access to a given piece of content within that series. Easy enough. The app is written with two constraints: stay true to the show timeline and characters, and be a great demonstration of patterns. If anything, I suspect I’ve failed most on the second constraint. You’ll find a broader set of patterns and styles than one would expect in a given app (particularly such a small one).

When I’m using patterns, I sometimes want to do something subtly different than a pattern I’m familiar with achieves and am not sure how to extend that pattern to satisfy my goal. Given this sample, I’m hoping you’ll discover more approaches than perhaps you were aware of before, and can extend your repertoire of familiar patterns.

There are two switch expressions within the app. Let’s start with the smaller of the two.

    public static bool IsAccessOKAskMycroft(Person person) => person switch
        // Type pattern
        OpenCaseFile f when f.Name == "Jim Moriarty"    => true,
        // Simple type pattern
        Mycroft                                         => true,
        _                                               => false,

The first two patterns are type patterns. The first pattern is supported with C# 8. The second one — Mycroft — is an example of the new simple type pattern. With C# 8, this pattern would require an identifier, much like the first pattern, or at the very least a discard such as Mycroft _. In C# 9, the identifier is no longer needed. Yes, Mycroft is a type in the app.

Let’s keep to simple a little longer, before I show you the other switch expression. The following if statement demonstrates a logical pattern, preceded by two instances of a type pattern using is.

        if (user is Mycroft m && m.CaresAbout is not object)
            Console.WriteLine("Mycroft dissapoints us again.");

The type isn’t known, so the user variable is tested for the Mycroft type and is then assigned to m if that test passes. A property on the Mycroft object is tested to be not an object. A test for null would have also worked, but wouldn’t have demonstrated a logical pattern.

The other switch expression is a lot more expansive.

    public static bool IsAccessOkOfficial(Person user, Content content, int season) => (user, content, season) switch 
        // Tuple + property patterns
        ({Type: Child}, {Type: ChildsPlay}, _)          => true,
        ({Type: Child}, _, _)                           => false,
        (_ , {Type: Public}, _)                         => true,
        ({Type: Monarch}, {Type: ForHerEyesOnly}, _)    => true,
        // Tuple + type patterns
        (OpenCaseFile f, {Type: ChildsPlay}, 4) when f.Name == "Sherlock Holmes"  => true,
        // Property and type patterns
        {Item1: OpenCaseFile {Type: var type}, Item2: {Name: var name}} 
            when type == PoorlyDefined && name.Contains("Sherrinford") && season >= 3 => true,
        // Tuple and type patterns
        (OpenCaseFile, var c, 4) when c.Name.Contains("Sherrinford")              => true,
        // Tuple, Type, Property and logical patterns 
        (OpenCaseFile {RiskLevel: >50 and <100 }, {Type: StateSecret}, 3) => true,
        _                                               => false,

The only really interesting pattern is the very last one (before the discard: -), which tests for a Risklevel that is >50 and <100. There are many times I’ve wanted to write an if statement with that form of logical pattern syntax without needing to repeat a variable name. This logical pattern could also have been written in the following way instead and would have more closely matched the syntax demonstrated in the C# 9 blog post. They are equivalent.

        (OpenCaseFile {RiskLevel: var riskLevel}, {Type: StateSecret}, 3) when riskLevel switch
                >50 and <100        => true,
                _                   => false
            }                                           => true,

I’m far from a language expert. Jared Parsons and Andy Gocke gave me a lot of help with this section of the post. Thanks! The key stumbling block I had was with a switch on a tuple. At times, the positional pattern is inconvenient, and you only want to address one part of the tuple. That’s where the property pattern comes in, as you can see in the following code.

{Item1: OpenCaseFile {Type: var type}, Item2: {Name: var name}} 
            when type == PoorlyDefined && name.Contains("Sherrinford") && season >= 3 => true,

There is a fair bit going on there. The key point is that the tuple properties are being tested, as opposed to matching a tuple positionally. That approaches provides a lot more flexibility. You are free to intermix these approaches within a given switch expression. Hopefully that helps someone. It helped me.

If you are curious about what the app does, I’ve saved the output of the program in the app gist. You can also run the app for yourself. I believe it requires .NET 5.0 RC2 to run.

If there has been a pattern with the last three C# (major) versions, it has been patterns. I certainly hope the C# team matches that pattern going forward. I imagine it is the shape of things, and there are certainly more values to extract.


ClickOnce has been a popular .NET deployment option for many years. It’s now supported for .NET Core 3.1 and .NET 5.0 Windows apps. We knew that many people would want to use ClickOnce for application deployment when we added Windows Forms and WPF support to .NET Core 3.0. In the past year, the .NET and Visual Studio teams worked together to enable ClickOnce publishing, both at the command line and in Visual Studio.

We had two goals from the start of the project:

  • Enable a familiar experience for ClickOnce in Visual Studio.
  • Enable a modern CI/CD for ClickOnce publishing with command-line flows, with either MSBuild or the Mage tool.

It’s easiest to show you the experience in pictures.

Let’s start with the Visual Studio experience, which is centered around project publishing. You need to publish to a Folder target.

Folder Targets

The primary deployment model we’re currently supporting is framework dependent apps. It is easy to take a dependency on the .NET Desktop Runtime (that’s the one that contains WPF and Windows Forms). Your ClickOnce installer will install the .NET runtime on user machines if it is needed. We also intend to support self-contained and single file apps.

.NET Prerequisites


You might wonder if you can still be able to take advantage of ClickOnce offline and updating features. Yes, you can.

Publish Settings

The same install locations and manifest signing features are included. If you have strict signing requirements, you will be covered with this new experience.

Now, let’s switch to the command line Mage experience.

The big change with Mage is that it is now a .NET tool, distributed on NuGet. That means you don’t need to install anything special on your machine. You just need the .NET 5.0 SDK and then you can install Mage as a .NET tool. You can use it to publish .NET Framework apps as well, however, SHA1 signing and partial trust support have been removed.

The Mage installation command follows:

dotnet tool install -g Microsoft.DotNet.Mage

The following commands configure and publish a sample application.

Produce First Deployment

The next command launches the ClickOnce application.

Install First Version

And then the familiar ClickOnce installation dialog appears.

Image FirstInstallClickoncePrompt

After installing the application, the app will be launched.

Image FirstVersionAppRuns

After re-building and re-publishing the application, users will see an update dialog.

Update Available

And from there, the updated app will be launched.

Note: The name of the Mage .NET tool will change from to dotnet-mage for the final release. The NuGet package name will remain the same.

This quick lap around ClickOnce publishing and installation should give you a good idea of how you might use ClickOnce. Our intention has been to enable a parity experience with the existing ClickOnce support for .NET Framework. If you find that we haven’t lived up to that goal, please tell us.

ClickOnce browser integration is the same as with .NET Framework, supported in Edge and Internet Explorer. Please tell us how important it is to support the other browsers for your users.

Windows Arm64

MSI installers are now available for Windows Arm64, as you can see in the following image of the .NET 5.0 SDK installer.

.NET 5.0 SDK Arm64 Installer

To further prove the point, I ran the dotnet-runtimeinfo tool on my Arm64 machine to demonstrate the configuration.

C:\Users\rich>dotnet tool install -g dotnet-runtimeinfo
You can invoke the tool using the following command: dotnet-runtimeinfo
Tool 'dotnet-runtimeinfo' (version '1.0.2') was successfully installed.

**.NET information
Version: 5.0.0
FrameworkDescription: .NET 5.0.0-rc.2.20475.5
Libraries version: 5.0.0-rc.2.20475.5
Libraries hash: c5a3f49c88d3d907a56ec8d18f783426de5144e9

**Environment information
OSDescription: Microsoft Windows 10.0.18362
OSVersion: Microsoft Windows NT 10.0.18362.0
OSArchitecture: Arm64
ProcessorCount: 8

The .NET 5.0 SDK does not currently contain the Windows Desktop components — Windows Forms and WPF — on Windows Arm64. This late change was initially shared in the .NET 5.0 Preview 8 post. We are hoping to add the Windows desktop pack for Windows Arm64 in a 5.0 servicing update. We don’t currently have a date to share. For now, the SDK, console and ASP.NET Core applications are supported on Windows Arm64.


We’re now so close to finishing off this release, and sending it out for broad production use. We believe it is ready. The production use that it is already getting at Microsoft brings us a lot of confidence. We’re looking forward to you getting the chance to really take advantage of .NET 5.0 in your own environment.

It’s been a long time since we’ve shared our social media pages. If you are on social media, check out the dotnet pages we maintain:


Discussion is closed. Login to edit/delete existing comments.

  • The Sharp Ninja 0

    This release is very disappointing on a couple of levels.

    1) UWP/XBOX is not yet supported. The latter is especially crucial with the impending launch of Xbox Series X/S. This was supposed to be the unifying release for all .Net and sadly it is not.
    2) WinUI 3 is a mess. They haven’t planned to support having the Desktop SDK and WinUI simultaneously active in the build pipeline. If Microsoft want people to replace legacy apps with WinUI 3, they need to support the basic Windows use cases that require the Desktop SDK.


    Do you know if .NET 5 RC2 is already supported by Azure App Services ?
    The following website doesn’t reference .NET 5 yet : (I didn’t checked all datacenters)

    • Brady GasterMicrosoft employee 0

      .NET 5 RC will not be deployed to App Service, but .NET 5 will be right around the time we GA .NET 5 in November. In the meantime, you can use self-contained publishes, which essentially pin the framework into your app, or you can use App Service on Containers to run .NET 5 apps.

  • Eirik Mangseth 0


    You wrote: “RC2 is a “go live” release; you are supported using it in production.”

    On the RC2 dowload page it says that only Visual Studio 2019 (v16.8, Preview 4) is supported. Opening the download page for Visual Studio 2019 (v16.8, Preview 4) one finds the following comment: “This release is not “go-live” and not intended for use on production computers or for creating production code.”

    So if you are a VS2019 shop you can’t start developing with RC2 (for production use) unless you forget about VS? Or are you secretly driving us towards other dev. tools (dotnet tooling + notepad perhaps)? 😉

    • Richard LanderMicrosoft employee 0

      Ah. That’s a problem. I didn’t realize this.

      The Visual Studio preview statement is a general statement. The .NET statement is more specific. We support RC2 in production, including if Visual Studio Preview was used.

      It’s too late to resolve this issue now. We’re less than month away from both Visual Studio 16.8 and .NET 5.0 being final releases, at which point this issue will be moot. We’ll get this sorted out for .NET 6.0 go-live releases.

      Thanks for reporting this!

      • Eirik Mangseth 0

        No problem. Looking forward to both releases.

      • Kenneth Benson 0

        Excellent! That answers my question from the 23rd. Thank you!

  • Dmitry B 0

    Installer Visual Studio 16.8 Preview 4 squeezes out everything from my i7 laptop. 100% cpu load from BITs and ServiceHub.Host.Clr.
    Have you built a miner there? 0_о

  • Mike Ralston 0

    “foo is not null”–that’s impressive. Maybe someday c# will evolve and look just like visual basic (lighten up on the syntax rules).

  • K E 0

    If you guys end up with critical bugs at launch, I feel that’s more of a failure on your part. I can say pretty confidently that canning a bunch of your tester and relying on customers to test your software was a bad move. Nothing beats in house testing. Hopefully as the new management in MS ages they’ll rediscover the concept of QA.

    • Richard LanderMicrosoft employee 0

      If you guys end up with critical bugs at launch, I feel that’s more of a failure on your part.

      I wasn’t stating otherwise. Instead I was saying “the time for feature requests is over; please prioritize feedback on critical bugs.” That’s a good call to action, right? There is no statement here on what the .NET team is doing to prevent critical bugs from being shipped. We are continuing to test and respond to both internal and external feedback on .NET 5.0 RCx.

  • VB User1 0

    LateBinding error.

            Dim xlApp As Object
            Dim version As String
            xlApp = CreateObject("Excel.Application")
                version = xlApp.Version.ToString
            Catch ex As System.MissingMemberException
            End Try
            version = Microsoft.VisualBasic.CompilerServices.LateBinding.LateGet(xlApp, xlApp.GetType, "Version", Nothing, Nothing, Nothing).ToString
    • Kathleen DollardMicrosoft employee 0

      @VB User1 what framework are you targeting in your project?

      • VB User1 0

        @Kathleen Dollard


        dotnet publish -c Release –self-contained false

        I built and run it on Windows 10 1809.

      • anonymous 0

        this comment has been deleted.

  • julien gourdon 0

    Hello, im really happy to see ClickOnce is back, actually there was no solution for install .net app with automatic update (wsix was not a solution because it targeted only windows10 and i want keep my .net core apps multiplatform)
    I begin to play with ClickOnce, but unfortunately im unable to see the publish.html in the output directory. Am i missing something ?

    • John HartMicrosoft employee 0

      Hi Julien,

      Thanks for trying out the new ClickOnce Experience!

      You’re right this version does not generate the publish.html. Is this something that you found really useful?

  • Andy Patrick 0

    “ClickOnce browser integration is … supported in Edge and Internet Explorer. Please tell us how important it is to support the other browsers”

    Uh… 100% totally and completely necessary, obviously, since 95% of browsers are not Edge or IE (e.g. see Baffling that this is even a question. ClickOnce is utterly, utterly, utterly worthless as long as it doesn’t work for other browsers. It’s not 1998 any more.

    • Basim Kadhim 0

      We are an ISV that makes use of ClickOnce, because it has been such a convenient deployment technology for our corporate users, but the consistent thorn in our side is the lack of good browser integration. Notably, Chromium Edge only supports it when you go to a bunch of flags that are marked “experimental” (it works fine in our experience). Having to tell users about third-party add-ins in order to support other browsers continues to be an unfortunate hurdle.

  • VB User1 0

    To Kathleen Dollard

    I don’t see my comment, so I’ll post it again.
    Please forgive me.

    LateBinding error.

    TargetFramework is net5.0-windows.
    dotnet publish -c Release -self-contained false
    I built and run it on Windows 10 1809.

    Dim xlApp As Object
    Dim version As String
    xlApp = CreateObject("Excel.Application")
        version = xlApp.Version.ToString
    Catch ex As System.MissingMemberException
    End Try
    version = Microsoft.VisualBasic.CompilerServices.LateBinding.LateGet(xlApp, xlApp.GetType, "Version", Nothing, Nothing, Nothing).ToString

Feedback usabilla icon