Application upgrade
.NET Core C# Entity Framework Core OData OpenAPI Visual Studio Web API

How to Migrate from a .NET Core 2.0 Web API to .NET Core 3.1 (Part 2)

Welcome to today’s post.

Today I will be continuing with the second part of my series on showing how we can migrate from an existing ASP.NET Core 2.0 Web API application to an ASP.NET Core 3.1 Web API application.

In my previous post, I showed how to apply the following migrations:

  1. Migrating of ASP.NET Core packages.
  2. Updating Entity Framework Core packages.
  3. Updating JSON Token security packages.
  4. Updating Entity Framework Core for SQL Server.
  5. Updating MVC Endpoint Routing.
  6. Endpoint Routing for Controllers with Attribute Routing.
  7. Update to JSON Formatting
  8. Discussion of the HTTP 500 error.

Some of the upgrades are due to simply requiring an upgrade of the NuGet package. Others are due to the following reasons:

  1. Library packages contain breaking changes that will no longer work with the code you have written for the previous version.
  2. Changes to the libraries are new features or deprecated features.
  3. Changes to types declared within the libraries prevent code containing variable declarations and parameters from being compiled and/or executable without errors.

In this post I will be discussing how to upgrade packages for the following features of .NET Core 3.1:

  1. Updating OData packages.
  2. Swagger (Open API) packages.

Also, the upgrades I have been explaining from the previous post and from this post can also be applied to upgrade an ASP.NET Core web application.

OData Support for .NET Core

The next package we will upgrade is OData support for .NET Core 3.1.

The previous version 2.2 of .NET Core was the last working version to support OData, however it is not supported in .NET Core 3.0. The OData package for .NET Core 3.1 support (preview) needs installation before it can be used with endpoint routing.

There are numerous discussions on the availability of support for OData in .NET Core 3.1 since the last known version where it received support and updates was for .NET Core 2.2.

The most common error we get when running our upgraded Web API application that has OData is:

System.TypeLoadException: 'Could not load type 'Microsoft.AspNetCore.Mvc.Internal.ActionConstraintCache' from assembly 'Microsoft.AspNetCore.Mvc.Core, Version=3.1.10.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.'

The above error will occur when you attempt to setup OData service routing using MVC, which does not allow endpoint routing in .NET Core 3.1. Below will trigger the above exception:

app.UseMvc(o =>
{
o.Select().Expand().Filter().OrderBy().Count();
       o.MapODataServiceRoute("odata", "odata", EdmHelpers.GetEdmModel(),
       	ODataHelper.CreateDefaultODataBatchHander(2, 5, 100));
});

Recommended update: Install OData 7.4.1 preview for .NET Core 3.1 NuGet package Microsoft.AspNetCore.OData version 7.4.1. A useful article on endpoint routing for the OData preview for .NET Core 3.1 is here.

To fix this issue we make the following amendments within Startup.cs:

Replace

public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    app.UseMvc(o =>
    {
       	o.Select().Expand().Filter().OrderBy().Count();
              o.MapODataServiceRoute("odata", "odata", EdmHelpers.GetEdmModel(),
              	ODataHelper.CreateDefaultODataBatchHander(2, 5, 100));
    });
    ...

With

public void ConfigureServices(IServiceCollection services)
{
	...
    services.AddControllers();
    ...

and

public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    app.UseRouting();
    …
    app.UseEndpoints(endpoints =>
    {
        endpoints.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
        endpoints.MapODataRoute("odata", "api", EdmHelpers.GetEdmModel(),             
            ODataHelper.CreateDefaultODataBatchHander(2, 5, 100));
        });
        ...

In the next section, I will show how to upgrade a Swagger interface.

Updating Swagger UI (Open API)

For Swagger UI to function in .NET Core 3.1, it requires an update from NuGet package Swashbuckle.AspNetCore.Swagger* versions 4.x, that are compatible with .NET Core 2.0 to a minimum version of 5.0.0, that is .NET Core 3.1 compatible. I recommend reviewing this tutorial on how to configure Swagger as it can vary for each version of .NET Core.

Recommended update: From the package manager, apply the suggested update below:

Update the following NuGet packages from 4.x to 5.0.0

Swashbuckle.AspNetCore.Swagger
Swashbuckle.AspNetCore.SwaggerGen
Swashbuckle.AspNetCore.SwaggerUI

Following the update, the following additional library will be added to our project:

Microsoft.OpenApi 1.1.4.

Now rebuild the application. I will go through the common build errors occurring for Swagger related configuration and how to resolve each.

The first error is:

Error CS0234 The type or namespace name 'Info' does not exist in the namespace 
'Swashbuckle.AspNetCore.Swagger' (are you missing an assembly reference?)	

Change

public void ConfigureServices(IServiceCollection services)
{
    …
    services.AddSwaggerGen(c =>
    {
  	    c.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { 
  		    Title = "BookLoan Catalog API", Version = "v1" 
  	    });
        …

to

using Microsoft.OpenApi.Models;

..

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", 
  		    new OpenApiInfo { 
  			    Title = "BookLoan Catalog API", 
                Version = "v1" 
  	    });
    ...

The next error that occurs is shown:

Error CS0246 The type or namespace name 'ApiKeyScheme' could not be found 
(are you missing a using directive or an assembly reference?)	

Change

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSwaggerGen(c =>
    {
        c.AddSecurityDefinition("Bearer", new ApiKeyScheme()
        {
            In = “header”,
            Type = “apiKey”,
            Description = "Please enter into field the word 'Bearer' following by space and JWT",
            Name = "Authorization"
        });
        c.AddSecurityRequirement(
  		    new Dictionary<string, IEnumerable<string>> 
            {
                { 
                    "Bearer", 
                    Enumerable.Empty<string>() 
                },
            });
        ...

To

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSwaggerGen(c =>
   	{
        c.AddSecurityDefinition("Bearer", new ApiKeyScheme()
        {
            In = ParameterLocation.Header, 
            Description = "Please enter into field the word 'Bearer' following 
by space and JWT",
            Name = "Authorization",
            Type = SecuritySchemeType.ApiKey
        });

        c.AddSecurityRequirement(new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                    }
                },
                new string[] { }
            }
        });
        ...

After we have applied all the above updates to our project, they should look as follows:

After running the application, with no errors the Swagger UI should look like the screen below:

I will finalize this series on upgrading .NET Core from 2.0 to 3.1 in the next post.

That’s all for today’s post.

I hope you found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial