How to port from .net framework to .net standard

The last days I spent some time to port my NuGet packages (AzureBillingApi and FeedReader) to .net standard. As it was not so straight forward, I want to share what I did. The migration is certainly more complicated the larger the project is, but this post will hopefully give you some basic insights on how to migrate. The most time-consuming part will be to change the existing code so that it works with .net standard. In this blog post, I’ll focus on how to change the project to use .net standard and .net framework. In this case, I’ll port the AzureBillingApi to .net standard 1.4, but it will still support .net framework 4.5.2.

Prerequisites

Before migrating the project, you should at first check if the NuGet packages that you use in your project are already compatible to .net standard. There are different ways how to check it. You can create a new .net standard project and manually add all NuGet packages to it – then try to build it. This will immediately show you if these packages support .net standard or not.
Another way is to go to nuget.org or use the NuGet Package Explorer and check the dependencies (Dependencies section) for all your packages.

If one of your packages is not yet migrated, you can check if there is already a migration from another user available. You can also check, if the source is public available (e.g. on GitHub) and if try to contact the owners. You can also migrate the source on your own.

Another thing you should do before you start with the migration is to check how much work the migration will be. You can use the .net Portability Analyzer tool. It allows you to analyze your assemblies and it will create a report which contains information about portability, how to change code parts so that they work with .net core and other useful information.

Step 1: Change Project to .net standard

If all packages are available, you can start to migrate the project. The first step is to change the C# project file (.csproj) to use .net standard. Open the .csproj in an editor of your choice and replace the whole content of the project by:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFrameworks>netstandard1.4;net452</TargetFrameworks>
    </PropertyGroup>
</Project>

Replace the values in TargetFrameworks by the frameworks that you use. I wanted that my library works with .net standard 1.4, but that it still supports .net framework 4.5.2, so I added both frameworks. .net standard 1.4 is not compatible to .net framework 4.5.2, that’s why I added both. The following table shows, the framework versions and their compatibility:

(Source: .NET Standard)

If you have a lot of NuGet packages, then you could copy all NuGet packages from the old project file to the new one, but I think it’s easier to add them manually (via the NuGet package manager). Adding them via the NuGet package manager will also give you the latest version and it will show you, if the package is already available for .net standard. If you want to add them directly in the project xml, extend it to e.g.:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFrameworks>netstandard1.4;net452</TargetFrameworks>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
    </ItemGroup>
</Project>

Attention! As mentioned in Prerequisites, there are still some NuGet packages that are not yet migrated to .net standard/.net core.

Reload the project in Visual Studio and try to build it – you will now get a lot of errors. Those errors occur because a lot of types/classes/methods/… are not available or must be used in another way in .netstandard/.net core.

Step 2: Replace AssemblyInfo.cs

The AssemblyInfo.cs file is no longer required. Go to the properties of your project, select package and copy the values from the AssemblyInfo file to it. If you have a NuGet package for your library, you can also remove the .nuspec file and copy the values of the .nuspec file to the package tab.
The package tab does not contain a Title value which is available in the .nuspec file. That’s not a problem because you can add it manually in the .csproj file:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFrameworks>netstandard1.4;net452</TargetFrameworks>
        <SignAssembly>True</SignAssembly>
        <AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
        <Title>AzureBillingApi</Title>
        <Version>1.1.0.3</Version>
        <Copyright>Copyright 2017 codehollow.com</Copyright>
        <Description>.net library that reads data from the azure rest billing (ratecard and usage) apis and calculates the costs.</Description>
        <Authors>Armin Reiter</Authors>
        <Company>Armin Reiter</Company>
        <PackageLicenseUrl>https://github.com/codehollow/AzureBillingApi/blob/master/LICENSE</PackageLicenseUrl>
        <PackageProjectUrl>https://github.com/codehollow/AzureBillingApi/</PackageProjectUrl>
        <RepositoryUrl>https://github.com/codehollow/AzureBillingApi/</RepositoryUrl>
        <PackageTags>azure billing billingapi windowsazure microsoftazure managementapi azuremanagementapi</PackageTags>
        <PackageReleaseNotes>migrated azurebillingapi to .netstandard 1.4</PackageReleaseNotes>
        <AssemblyVersion>1.1.0.3</AssemblyVersion>
        <FileVersion>1.1.0.3</FileVersion>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
      <PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="3.13.9" />
    </ItemGroup>
     
    <ItemGroup Condition="'$(TargetFramework)' == 'net452'">
        <Reference Include="System.Net.Http" />
  </ItemGroup>
</Project>

Step 3: Migrate the code to .net core

This step is the most time consuming one as you must replace all code that does no longer work in .net standard. In addition, Visual Studio will sometimes show you errors that are no “real errors”. These errors are only shown in the IntelliSense, but the build will work. To make the migration easier, I recommend to:

  • Show issues from Build only: The default setting of the error list (which contains all build errors) is Build + IntelliSense. IntelliSense does sometimes show errors that do not exist. Switch to Build only and try to build your solution. This will show the “real” errors
  • Create a new .net standard project with the same version as the project you want to port: IntelliSense will sometimes show you the .net framework (not .net standard) “stuff” (method signatures etc.) in your migrated project. The code migration will be easier if you have another project that you can just use to check the code with the correct IntelliSense.

You will probably also need to work with compiler switches. If there are statements that are different in .net standard than in .net framework, then you can work with #if statements as I did in the AzureAuthenticationHelper.cs:

private static AuthenticationResult GetOAuthTokenForUser(string url, string tenant, string resource, string redirectUrl, string clientId)
{
    var authenticationContext = new AuthenticationContext(CombineUrl(url, tenant));
 
#if NET452
    PlatformParameters p = new PlatformParameters(PromptBehavior.Auto);
#else
    PlatformParameters p = new PlatformParameters();
#endif
 
    var authTask = authenticationContext.AcquireTokenAsync(resource, clientId, new Uri(redirectUrl), p);
    authTask.Wait();
    return authTask.Result;
}

You will probably also face the issue, that you must reference assemblies that are available in .net standard but must be manually referenced in .net framework. That’s for example if you use the HttpClient in System.Net.Http. You can add a reference only for the .net framework build. I already added such a statement in my project file. The important statement is:

<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
  <Reference Include="System.Net.Http" />
</ItemGroup>

Those were the steps that I had to do for both of my projects. After that, I was able to build it and to create the NuGet packages. If you check the AzureBillingApi NuGet package, then you can see that there is a dependency to .net framework 4.5.2 and .net standard 1.4:

Additional information

Developing Libraries with Cross Platform Tools: https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/libraries
.NET Standard: https://docs.microsoft.com/en-us/dotnet/articles/standard/library
Porting to .NET Core from .NET Framework: https://docs.microsoft.com/en-us/dotnet/articles/core/porting/

Categories:

6 Responses

  1. Thanks Armin! Thanks to this post I was able to migrate my libraries to .NET Standard in less than 2 hours after I received a request!

  2. It was a really nice experience to read about How to port from .net framework to .net standard. provided information very useful for Students. You have explained all the information in a very structured manner. Thanks for sharing this informative article.

Leave a Reply

Your email address will not be published. Required fields are marked *

About
about armin

Armin Reiter
Azure, Blockchain & IT-Security
Vienna, Austria

Reiter ITS Logo

Cryptix Logo

Legal information