Upgrading an ASP.NET Core 2.0 application to ASP.NET Core 2.1 (preview 1)

The first official preview of ASP.NET Core 2.1 was released yesterday. I’ve been playing around with the nightly builds for various parts of ASP.NET Core 2.1 for the last few months and finally I was able to move to the official preview 1 packages on NuGet rather than the MyGet feeds.

I wanted to test things out by upgrading the Humanitarian Toolbox allReady project from ASP.NET Core 2.0 to ASP.NET Core 2.1. This is a minor release of the framework so it shouldn’t require too many complex changes.

I made most of these changes prior to the official blog post being released and having now read that I’m pleased to see that I covered the right update steps.

Upgrading the Project

The first set of changes to be made are in the project file for the main web application. I decided to do these manually so that I had full control over the versions.

First I changed the TargetFramework from 2.0 to 2.1 at the top of the project file.

The relevant line of code in 2.0 was

<TargetFramework>netcoreapp2.0</TargetFramework>

and became

<TargetFramework>netcoreapp2.1</TargetFramework>

The next step was to pull in the ASP.NET Core 2.1 packages. In 2.0, this was accomplished with the Microsoft.AspNetCore.All meta-package. In 2.1 a new meta package called Microsoft.AspNetCore.App is available. This reduces the number of 3rd party (and some 1st party) dependencies which are pulled into your application by default. You can read more about this change in the announcement issue.

<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />

became

<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0-preview1-final" />

Our project includes BrowserLink and as a result of the change to the App meta-package this is no longer included for us by default. To fix this I added an explicit package reference for it.

<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="2.1.0-preview1-final" />

Finally I updated the CLI tooling references. These allow you to bring in and use command line tools against your project. In 2.1, some of these will move over to global tools, a new feature which will allow these to be installed on your device once, and then used by any project that needs them. You can read more about Global Tools in the .NET Core 2.1 preview 1 announcement post. This will avoid the need to reference and maintain the versions of them.

Global tools are likely to get more stable in the preview 2 timeframe and so for now I simply updated the version numbers where necessary.

<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />

changes to

<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.1.0-preview1-final" />
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.1.0-preview1-final" />

This completed the changes that were needed in the main project file for the 2.1 upgrade.

Upgrading the Unit Test Project

Similar changes were needed in our unit test project too. I updated to target netcoreapp2.1 and were we reference specific AspNetCore packages, I updated those to point to the preview1 packages. For example

<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" />

Became…

<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0-preview1-final" />

Other Changes

At this point, for a basic upgrade I was actually almost done with the required changes. My code was restoring and compiling correctly. I did hit one issue at runtime that I’ll briefly touch on.

ModelBinderProvider Issue

Our code includes and adds a custom IModelBinderProvider After the upgrade, some requests began throwing NullReferenceExceptions. Tracking down the issue was actually quite interesting, since the exception occurred for me after the page had started to render in the browser. At first I couldn’t work out why. It was actually the result of a missing JavaScript file that was causing a 404 error. We have an error handling flow that re-executes the request to a custom error Action and View.

It was actually this flow that was highlighting the model binding issue. That error action includes a route parameter and after the 2.1 upgrade I noticed that when running through the IModelBinderProvider, a change in the 2.1 code was causing our existing code to break.

I put together a small solution that reproduced and confirmed the behaviour changes. I was then able to raise an issue with the ASP.NET team to highlight this. To their credit, they got onto it very quickly and provided a workaround for our code and confirmation that they would aim to fix the behavior in preview 2.

You can read more about that in the issue on GitHub.

As per the suggestion from Doug in the issue, I updated our code, from…

if (!context.Metadata.IsComplexType && !string.IsNullOrEmpty(context.Metadata.PropertyName) && context.Metadata.ContainerType != null)

to this…

if (!context.Metadata.IsComplexType && context.Metadata.MetadataKind == ModelMetadataKind.Property)

At this point, the site functioned as expected during my basic testing. As per the issue, this change should hopefully not be required in 2.1 preview 2.

Further Enhancements

At this stage, all I’ve done here is to re-target the application to .NET Core 2.1 and update it to point at the relevant ASP.NET Core 2.1 packages. To take advantage of some of the new features in ASP.NET Core 2.1, some areas of our code could be updated to make use of those features. For example, I didn’t add in the new middleware for the HttpsRedirection features. New ASP.NET Core 2.1 projects will use SSL by default and redirect to HTTPS. Making such a change in the allReady project would require additional consideration as it could impact how we build, deploy and run the application.

There are other things such as the new IHttpClientFactory feature which I’ve blogged about already that we could look to utilise in the project. I consider those enhancements, beyond a basic upgrade and so each change would first be assessed and then implemented where necessary.

Summary

That concludes the upgrade process of a real application from ASP.NET Core 2.0 to ASP.NET Core 2.1 preview 1. Note that we don’t intend to move to 2.1 for allReady just yet. At this point it’s not go-live ready and is for preview purposes only. I’m pleased that for the most part, upgrading was pretty painless. Hopefully the breaking issue I did run into will be fixed or improved by the time preview 2 is released.

If you care strongly about the direction of ASP.NET Core it’s well worth you testing this upgrade on your own applications to see if you run into any issues. By testing preview 1 early it’s possible to give feedback that as in my example, will be raised early enough for inclusion in the next preview. Preview 2 is anticipated in around 4 to 5 weeks’ time.