MS 5 Logo

Microsoft .NET Framework is a well-established mature Framework behind many enterprise applications that we use on a daily basis. With the introduction of Microsoft .NET Core in 2016, have you ever wondered what will happen to applications currently on .NET Framework? This article is exactly what you are looking for.

Microsoft .NET 5.0 (Multi-target approach)

If you are following up lately, Microsoft started the ground work last year and we are on .NET 5 Preview 7 as of writing of this article.

You can download the preview install at : https://dotnet.microsoft.com/download/dotnet/5.0

This move will unify .NET Framework and .Net Core into one single platform targeting Windows, Linux, macOS, Android and much more in the future. Microsoft has promised that the legacy Framework continues to be supported with the focus mainly on .NET 5.0, next version of .Net Core aka vNext.  But if you are ready to start using the newer framework while supporting the legacy system, start with testing multi-targeting the application to get the pulse. This will prepare you to eliminate (and rewrite) features that are no longer going to be supported on future versions.

 

Multi-Targeting

This is not a new concept. Developers have been using this feature to bring common code to a library (mainly for .NET standard libraries) and target multi- framework to avoid duplicated code thereby produce a smaller application footprint. Before we start looking, let me introduce a few tools and links that will benefit during this journey. I will start with some tools that can analyze your code.

 

.NET Portability Analyzer

This Analyzer tool helps to migrate from one Framework to another. It provides detailed information on incompatibilities and provides suggestions to make it compatible on the target Framework.

You can download the tool at : https://marketplace.visualstudio.com/items?itemName=ConnieYau.NETPortabilityAnalyzer

 

.NET API Analyzer

This tool helps to discover compatibility risks on the API that your application is currently using. It is a part of NuGet package, Microsoft.DotNet.Analyzers.Compatibility  which has support for all Visual Studio editions from 2017 and above. You can read more from the MS page at:

https://docs.microsoft.com/en-us/dotnet/standard/analyzers/api-analyzer

For non-compatible areas, consider using Windows Compatibility Pack available at NuGet : https://www.nuget.org/packages/Microsoft.Windows.Compatibility

 

Target Framework Moniker (TFM)

TFM defines unique identity to each supported target framework. Here are the few popular framework monikers

  • 1 (.NET Core)
  • net48 (.NET Framework 4.8)
  • 1 (.NET Standard 2.1)
  • wpa81 (Windows Phone)

 

Sample Application

With a basic knowledge on available tools, let’s start with creating a sample application to learn multi-targeting various Framework & runtime.

I will be using Visual Studio Enterprise 2019 for the demo. However, these steps can be performed on other Visual Studio editions.

Since most of the options we discuss here is not available via IDE at this time, we will be making edits directly on the project file. Editing can be performed inside Visual Studio or you can edit the file on your favorite XML editor or even a simple notepad and the reload the project to take effect.

Editing Project file

On the Visual Studio IDE, right click on project and select “unload project”.  Then select “Edit Project” option to open the contents.

MS 50 1

 

MS 50 2

 

Now, you can edit the contents and save before loading the project again with changes.

MS 50 3

 

I am going to start with creating a console application using legacy .NET Framework.

Open Visual Studio 2019 and pick the “Console App (.NET Framework)” template:

MS 50 4

Keep all defaults and rename the project. Make sure the “.NET Framework 4.8” (preferably 4.7.2 or higher) is selected.

MS 50 5

Added print statements to the class file:

MS 50 6

Compile your project and verify that the application is running. Our next milestone is to convert to .NET Core application. There are multiple ways to approach the conversion. You could convert using “try-convert” which can be found at: https://github.com/dotnet/try-convert

Our demo code is a very simple project, so I go with quick edit to the project file. Unload the project and replace the project file with following contents:

<Project Sdk=”Microsoft.NET.Sdk”>

<PropertyGroup>

<TargetFramework>netcoreapp3.1</TargetFramework>

</PropertyGroup>

<ItemGroup>

</ItemGroup>

</Project>

 

Reload the project and compile, you will see error like below:

MS 50 7

You have two quick options to resolve: Either delete the AssemblyInfo.cs or update the project file to include the following flag:

<PropertyGroup>

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

</PropertyGroup>

 

The project is now ready for .Net Core. If you try to run on a machine with no runtime, you get the following error:

MS 50 9

If the specific .NET Core version is not available on the host, you will get a different error like this one:

MS 50 8

In that case, you can either change the global.json to target a different SDK  version or download and install from https://dotnet.microsoft.com/download

More information on global.json can be found at : https://docs.microsoft.com/en-us/dotnet/core/tools/global-json?tabs=netcore3x#matching-rules

 

Advancing further, lets proceed with publishing the project:

MS 50 10

 

For our demo, let’s pick folder option (of course you can try Azure WebJobs if you have Azure option setup):

MS 50 11

 

Select publish location:

MS 50 12

 

Since it is a .NET Core project, we have couple of options with deployment:

  1. Framework dependent
  2. Self-contained

I generally prefer self-contained option since it builds executable/library that includes everything that is needed to run the application. The application can work without having to install software which is excellent for targeting container based serverless computing.

With self-contained, we also have an option to trim to make a smaller footprint. With trim option, it will include only the libraries/components bare enough to execute the application. We also have an option to make a single EXE instead of a folder with list of dependent assemblies. In that case, please select single EXE option.

 

Here is my setting for the framework dependent option:

MS 50 13

And here is the output:

MS 50 14

 

Now, I am going to explore self-contained option:

MS 50 15

 

Let’s compare the output:

MS 50 16

 

Look at the difference on the published folder: we now have 227 files, about 65 MB in folder size:

MS 50 17

 

Next, I am going to try self-contained option with single EXE flag ON. My new project file will look like below:

MS 50 18

 

Here is my output with single EXE and my corresponding PDB file. The folder size is about the same as before:

MS 50 19

 

MS 50 20

 

Next, enable trim option and perform a comparison:

MS 50 21

 

My single EXE has been reduced to 26 MB ( over 55% decrease).

MS 50 22

 

Now, I wanted to add support for additional .NET Frameworks by adding a few TFM to the project file .VS 2019 will do all the work for you as soon as you make the change to project file. The project dependencies will automatically add necessary additions:

MS 50 23

Upon publish, I have the following folders on the output path:

MS 50 24

 

The same is true for target runtimes. You can target multiple runtimes while publishing. Sometimes you may want to develop code that targets both windows and non-windows systems at the same time. In such cases you can use conditional flags.

MS 50 25

 

Here is the output of each one:

MS 50 26

 

The code is using the API to get runtime information (“System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription”) is supported from .NET Core 3.0 onwards, so you are only getting the friendly display string starting with .NET 3.0 and above.

Here is the class file with runtime prints:

MS 50 27

 

Same logic can be used for adding Framework specific libraries and much more.

MS 50 28

 

Conclusion

I have intentionally picked a console application to walk through the option without complicating the approach. In reality, there will be various dependencies, 3rd party assemblies, legacy and complex code, and will require additional effort and rewrite as you navigate through the migration process. I am going to talk about those details in my future blogs. I hope this blog would help to start preparing towards .NET core and advance congratulations on your first attempt to move to latest Framework.