Partager via


From the MVPs: Key Steps in Developing .NET Core Applications

This is the 58th in our series of guest posts by Microsoft Most Valued Professionals (MVPs). You can click here to see all past MVP articles.

Since the early 1990s, Microsoft has recognized technology champions around the world with the MVP Award . MVPs freely share their knowledge, real-world experience, and impartial and objective feedback to help people enhance the way they use technology. Of the millions of individuals who participate in technology communities, around 4,000 are recognized as Microsoft MVPs. You can read more original MVP-authored content on the Microsoft MVP Award Program Blog .

This post is by Microsoft Azure MVP Damir Dobric with support from his technical editor, Windows Development MVP Andreas Erben. Thanks Damir and Andreas!


.NET Core is the new big thing in the .NET universe, no question. However, there are many differences in the .NET framework, which possibly target different devices and which are not necessarily compatible to each other. This post describes some very important steps in development of applications with the new .NET Core platform. I will show how to create an application and a library by focusing on the most important features of .NET Core, which every .NET developer should be aware of. At the end I will also demonstrate how to deal with different frameworks and how to build unit tests for this purpose, which is not very common in the .NET developer community.

How to create a .NET Core application in Visual Studio

As you probably expect, the easiest way to create an application in .NET Core is using Visual Studio project template:

This creates a common .NET Core application with the new artifact ‘project.json’ file, which fully describes your project. Please take notice, the innovation behind ‘project.json’ is not to simply move from the old XML format to JSON. The old XML project file was tightly coupled with Visual Studio. Here Microsoft wants to keep all important features inside of .NET Core and not couple them to any IDE. The new ‘project.json’ file is decoupled from Visual Studio and it is a part of the .NET Framework.  This is a great idea, which keeps .NET independent on other tools and products. However, already existing projects in context of Visual Studio, Xamarin, Unity etc. will and should probably not be easily migrated to the new project format. Most of such solutions have features which are very specific in their context and have nothing to do with .NET. Migration of such features to project.json would mean that .NET should support no .NET features. Because of this, Microsoft is working on a new strategy around ‘project.json’. How the final strategy will look is not clear at the moment. But it is certain that the original strategy ‘project.json – only’ will not work.

Choosing JSON instead of XML has no specific value in this case. It is just influenced by the coolness factor of JSON in this decade. Later in this article, I will dig deeper into the structure of a project file. The following picture shows the complete solution, which was created by utilizing the Console Application (.NET Core) project template.

How to create and reference a library in Visual Studio

One of the important common tasks is obviously creating a reusable functionality, which can be shared as a library (assembly). To create a library, we use the Class-Library (.NET Core) template. Note this is a new .NET CORE project template:

As the next step, let’s add a reference to the new library from our executable Sample01. The following picture shows both projects in a single solution and the referencing of a library as a project:

By default, .NET core uses NUGET to import reference packages from external projects. For example, by adding a reference to project ClasLibrary1, Visual Studio will add a reference to the project, but according to ‘project.json’, it will try to resolve it as a NUGET package. This is not explicitly specified. It is a default action, which probably indicates that in the future referencing of libraries will primarily work by using NUGET. Because we didn’t create a package reference for ClassLibrary1, we will get an error as shown in the picture below (NU1001):

To fix it, please open the ‘project.json’ file of the project which is referencing the library (in this case ‘Sample01’) and look up the entry marked in red, which specifies the reference to the library added in the previous step:

Because we want an explicit reference to a project, we have to additionally define the type of target, as shown in the following picture, by setting it to the value “project”:

After that change, Visual Studio might still report the same error. To make it finally work we have to restore NUGET packages (right-mouse click on References | Restore Packages):

You typically will have to do a package restore every time, when ‘project.json’ is changed. Note, during restoring, Visual Studio will show an indication about restoring the packages in the top area of Solution Explorer:

If you don’t like this, you can disable in the Visual Studio settings for .NET Core Projects:

Now, you know how to create an application and a library. This was easy going and straightforward, because both Sample01 and ClassLibrary1 were created from a set of the new .NET Core templates. In the real life we will have to deal with dependencies, which target different versions and types of the .NET framework and require different types of deployment.
In the rest of this article, I will describe how to do that.

There are two types of .NET Core Applications

If we take a deeper look at the ‘project.json’ file of the Sample01 project, you will notice an entry, which indicates a dependency on the “Microsoft.NETCore.Appnuget package.

Microsoft.NETCore.App is a set of .NET APIs that are included in the default .NET Core application model. The property type: platform indicates that the tooling, at publishing time, has to skip publishing of assemblies defined under specified dependency to the published output. In this case you don’t need to include them in the deployment process. It is expected that all dependencies are installed with .NET Core on the targeted machine, before your application is installed. Remember, this is nothing new for .NET developers. We have been deploying applications this way for 16 years now. Applications that require .NET Core to be installed on the targeted machine in order to run are called Portable Applications. This is nothing new, but this approach has a name now, because there is another, new kind of .NET application introduced with .NET core.

The new type of .NET core application is called Self Contained Application. In contrast to a portable application, this type of application has to specify the exact runtime, which will be used. The runtime can be specified in ‘project.json’ file:

As an example, I added two runtimes (see the part highlighted in yellow). If the specified runtimes are not installed on your machine, they will be installed during the next package restore. In the next topic we will provide more information about that.

To publish your self-contained application, execute the following command:

dotnet publish –runtime win10-x64

This command will produce the following output:

After a successful build, the application will be published in the folder shown in the picture above. The published folder will also include a full set of required runtimes:

Last but not least, self-contained applications are independent, but they occupy more space, because the full runtime is installed with the application. Right now, one runtime occupies approximately 1-5 MB (at the moment – not optimized).

Working with different runtimes

In the previous topic we have described different standards and different versions of the .NET Framework. But we should not forget the importance of runtimes. A runtime is the smallest subset of functionalities, type system etc., required to run on a specific operating system. Frameworks are typically built on top of runtimes and represent their superset. Some examples of runtimes are “win7-x64”, “win7-x32”, “osx.10.11-x64” etc. To specify a required runtime, .NET framework uses the following notation:

15

This string defines an identifier called RID (Runtime IDentifier). It represents the specific operating system. The list of all supported runtimes can be found here:

https://github.com/dotnet/corefx/blob/master/pkg/Microsoft.NETCore.Platforms/runtime.json

Interestingly, ‘project.json’, when created by Visual Studio templates, does not contain any runtime reference. This is because Visual Studio targets the portable .NET CoreNET Core application type by default. However, when linking a runtime to an application, we have to specify the exact runtime through providing the appropriate RID.

Once one runtime is referenced in the project.json file, the dotnet tool will install them under the user hive as shown in the following picture. Please do not forget to do a package restore when trying.

Working with different standards and versions of .NET framework

As the next step, go to the ‘project.json’ file from the ClassLibrary1 project and look for:

“dependencies”: { “NETStandard.Library”: “1.6.0” },

.NETStandard.Library is a so called Target Framework Moniker or TFM. It must always be followed by some version number and specify a standardized set of APIs, which your application depends on.

In other words, the .NET Standard Library is a formal specification of .NET APIs that are intended to be available on all .NET runtimes.

  • It defines a uniform set of BCL APIs for all .NET platforms.
    Developers can use a set of APIs specified by this standard.• It enables developers to create portable libraries that are compatible across .NET runtimes, using this same set of APIs. An application, which uses this standard set can run on Linux, Mac, Windows, or on some other runtimes.• It reduces conditional compilation for the shared source due to existing .NET APIs, only for OS APIs.

.NET Standard Library is a versioned set of reference assemblies that ALL .NET Platforms MUST support as defined by specification. This so called “foundational library” is defined in the CoreFX repository. In the new world of .NET Core, we can think about it as a new definition of Portable Class Library.

To get a better feeling about the relationships between different versions, take a look at following table.

By following the table above, you see that .NET Core 1.0 and .NET 4.6.3 implement the same set of libraries in .NET Standard Library 1.6. This is a huge step forward. Unfortunately, the big disadvantage is that UWP targets .NET Standard v1.4 only, which might cause some difficulties for developers trying to target Windows 10 devices on UWP. Personally, I do see an increasing number of small issues with the strategy around UWP 10, because it does not converge to the new very promising strategy of .NET Core as quickly as I would expect. A better solution could be to have UWP 10 aligned to .NET Standard 1.6 vNext. This would probably make Windows more attractive to developers.

Another important fact be aware of is that aa .NET library in general doesn’t have to be portable to any of .NET standards. Assume you have a PCL (Portable Class Library) built for example the profile portablenet40+sl5+wp80+win8+wpa81. This PCL cannot be retargeted to any of the specified .NET Platform Standards. But if you have a PCL with profile portable-net45+wp80+win8+wpa81+dnxcore50, we could retarget it to .NET Platform Standard1.0.
In other words: Every assembly built prior to ver. 4.5 (i.e. mono) cannot be retargeted to any .NET Standard.

To get a better feeling of how all this behaves, let’s build a Win32 (Desktop) console application, which will reference ClassLibrary1. When creating a new project, please be sure that you choose Windows/Console Application. At this time dodo not choose .NET Core/Console Application as in the previous example.

Next, let’s reference ClassLibrary1 from the new Console Application. Some of you might be surprised, because this will not work. You will get the following error:

That means, Visual Studio still does not recognize the template of the .NET Core project. But this will be fixed soon, I guess.
At the moment we have two choices to reference the library from a Win32 (Desktop) application:

– Add the reference directly to the assembly.
– Add the reference to a NUGET package. (I will demonstrate at the end of this article how to create a NUGET package.)

Right now, I will add a reference directly to the assembly in my example, but before I do that I have to be sure which version of .NET Framework my Desktop Console Application uses. If my application uses .NET 4.6.1 then I can only reference assemblies, which are compatible .NET Platform Standard 1.4. Check this by using the table shown below. However, our ClassLibrary1 is built with support for v1.6.0. You can find this in the project.json file of the library in following section:

“dependencies”: { “NETStandard.Library”: “1.6.0” },

The table below (an excerpt of the full table from above) shows that the version 4.6.1 of the .NET Framework is not compatible with .NET Platform Standard 1.6.

If we try to add the reference under this condition, the following exception will be thrown, followed by many other exceptions:

An unhandled exception of type ‘System.IO.FileNotFoundException’ occurred in mscorlib.dll
Additional information: Could not load file or assembly ‘System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The system cannot find the file specified.

To work around this, ClassLibrary1 must support standard 1.4. To achieve this, we need to extend project.json as shown below:

After this change, we need to add a reference to the DLL v1.4 from the Console Application. Note that in this example we could simply add support for lower version. Unfortunately, in real life you might have functionalities in your library, which require features unavailable in older versions.

Working with Unit Tests

I will use XUNIT as the unit test engine in my example.
Let’s add the XUnitTesting packages ‘xunit’ and ‘dotnet-test-xunit’ to project ‘Sample01’. After adding the NUGET package you will have to change the reference.
Lookup dnxcore50 in project.json (below on the left and replace it with the import shown below on the right.)

Note, xunit libraries have been compiled as portable library with a profile that includes “portable-net45+win8”.
At the moment of creation of that library .NET Core did not exist in the current version. As already described, a PCL profile can be retargeted to standard 1.4. If you have been working with .NET core previously, you will probably need to change import directive the same way as I have shown here or to retarget your projects to the appropriate standard.
Once all existing libraries are migrated to the new profile set, this will not be required anymore.

Please also activate a testRunner as shown on the picture below:

Finally, you will have to restore the references as already described above.  The Sample01 project looks now as shown in the following picture:


And finally, here is my unit test sample:

Tests can be started as usual by using Visual Studio (Ctrl+R+T or by using Test Explorer), but we can also use DOTNET-core tooling. To execute the tests, navigate to the project folder, which contains project.json and the implementation of our tests and execute
> dotnet test

The result of executing the test should be similar as seen the following picture:

If there is at least one failed test, the result will be marked in red. Note that our Sample1 is used as a test application, but it can also be started as a typical executable. If you want to prevent starting an application as an executable, you have to set the value of property emitEntryPoint to false.

Creating NUGET packages

One of the helpful features of .NET Core is the creation of NUGET packages. This is now a part of the .Net Core toolset. You do not need any PowerShell, additional nuget package or similar external tools. To create a package, simply use the following command:

dotnet pack

The command when applied to our example will produce the following output:

After execution of the dotnet pack command, the packages will be created in the debug output folder:

Recap

When I first saw .NET 16 years ago I had over 10 years of experience in working with C++. I was a big fan of C++ at that time. Interestingly I fell in love with C# and .NET immediately. I just had a feeling that that it would be a new big thing. Now, seeing how .NET is grooving in the Open Source direction with cross-platform support, I feel impressed again and think it is the platform for the next decade. The only concern I still have is the lack of a fast(er) convergence towards a unified framework, which was and is an important core idea. But I hope this will happen soon.

Most of the official information provided in this article can be found shared across the following references:

– .NET Standard Library in depth: https://github.com/dotnet/corefx/blob/master/Documentation/architecture/net-platform-standard.md
– Reference Implementation on GIT: https://github.com/dotnet/corefx
– Overview .NET Standard: /en-us/dotnet/articles/standard/library
– Getting started: /en-us/dotnet/articles/core/tutorials/using-on-windows

About the author

Damir is co-founder, managing director and lead architect of DAENET Corporation, which is a long-time Microsoft Gold Certified Partner and leading technology integrator specializing in Microsoft technologies with a strong focus on Windows, .NET and Web. DAENET was the winner of the worldwide Technology Innovation Award in 2005, German Innovation Award for SOA in 2008 and Microsoft Partner of the year 2010.