.NET Core is new big thing in .NET universe, no question. However, there many .NET streams out there and it is not easy to make right decisions, which will hold for years or decades. This post describes few basic, but very important steps when developing applications with .NET Core. I will show how to create an application and a library. Then I will target different frameworks and finally build some unit tests in the way which is not very common in .NET community as probably many other things, which you will read here.
How to create application in Visual Studio?
Easiest way to create an application in .NET Core is using Visual Studio.
That creates common application with a new artifact ‘project.json’ file, which describes the project. Please remember, innovation of project.json is not in moving from XML to JSON. Old XML project file was tightly coupled to visual studio. new project.json file is decoupled from Visual Studio and it is a consisted part of .NET Framework.
Choosing JSON instead of XML has no any value added. It is just influenced by coolness factor of JSON (at least in theses years).
How to Create and reference a library in Visual Studio?
To create a library we use Class-Library template, as usual.
Let’s add now a reference to new library from our executable Sample01.
By default .NET core use NUGET to reference packages from external projects. By adding a reference to project ClasLibrary1, VS will add reference to the project, but project.json will try to resolve it as a NUGET package. Because we didn’t create a package we will get error shown at the picture above (NU1001).
To fix it, open the project.json file of the project which is referencing the library (In my case ‘Sample01’) and lookup following entry:
We need to tell VS ,that we want to reference the library as a project and not as NUGET package.
After that build will still report the same error. To make it finally working we have to restore NUGET packages:
While restoring VS will show on top-right restoring indication.
If you don’t like this, you can switch it of in VS .NET Core settings:
This was easy going, because both Sample01 and ClassLibrary1 was created from set of new .NET Core templates. This is lucky case. In the real life we will have to deal with dependencies, which targets different versions of .NET framework.
.NET Core Application Types
One more important note. project.json file specifies a dependency to “Microsoft.NETCore.App” nuget package.
This is a set of .NET API's that are included in the default .NET Core application model. The type: platform
property on dependency above means that tooling, at publish time, have to skip publishing the assemblies for that dependency to the published output. You don't need them if you expect they will be installed with .NET Core on the targeted machine.
Applications that require .NET Core to be installed on the targeted machine in order to run are called Portable Applications.
Another type of .NET core application is Self Contained Application. These applications have to specify exact runtime, which they will use. To do that you have to specify a runtime in project.json file:
{ "version": "1.0.0-*", "buildOptions": { "emitEntryPoint": true }, "testRunner": "xunit", "dependencies": { "ClassLibrary1": { "target": "project", "version": "1.0.0-*" }, "dotnet-test-xunit": "2.2.0-preview2-build1029", "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.0" }, "xunit": "2.2.0-beta2-build3300" }, "frameworks": { "netcoreapp1.0": { "imports": [ "dnxcore50", "portable-net45+win8" ] } }, "runtimes": { "win10-x64": {}, "osx.10.11-x64": {} } } |
I added two runtimes, which are on next restore installed on your development machine (see next topic for more information about install location).
To publish your self-contained application execute following command:
dotnet publish --runtime win10-x64
Last, but not least self-contained applications are independent, but occupies more space. For example one runtime occupies approximately 1-5 MB (at the moment – not optimized).
How about different Runtimes?
In the previous topic we have described different standards and different versions of .NET Framework. But we should not forget runtimes. Runtime is smallest subset of functionalities and type system, required to run on a specific operative system. Frameworks are built on top of runtimes. An example of runtime is “win7-x64” “win7-x32”, "osx.10.11-x64” etc. To specify a correct runtime, .NET framework use following notation:
[os].[version]-[arch]
That string defines an identifier called RID (Runtime IDentifier). It represents the concrete operating system. The list of all supported runtimes can be found
https://github.com/dotnet/corefx/blob/master/pkg/Microsoft.NETCore.Platforms/runtime.json
Interestingly, in project.json created by VS templates, does not contain any runtime reference. This is because VS targets by default portable .net core application type. It means application requires correct runtime to be installed on the machine independent on application.
Once you reference some runtime in your projec.json file and do restore of packages, dotnet tool will install them under user hive as shown at following picture:
Working with different standards and versions of .NET framework
Once the library is created, open project.json of the ClassLibrary1 and look for
"dependencies": { "NETStandard.Library": "1.6.0" },
But, what NETStandard.Library does mean? That name is so called Target Framework Moniker or shortly TFM. It is always followed by some version number.
The .NET Standard Library is a formal specification of .NET APIs that are intended to be available on all .NET runtimes.
Standard library:
- Defines uniform set of BCL APIs for all .NET platforms.
- Enables developers to produce portable libraries that are usable across .NET runtimes, using this same set of APIs.
- Reduces conditional compilation of shared source due to .NET APIs, only for OS APIs.
.NET Standard Library is versioned set of reference assemblies that ALL .NET Platforms must support as defined. This library is defined in the CoreFX repository. In the new world of .NET universe, we can think about it as Portable Class Library vNext.
To get a better feeling about relations between different version, take a look on following table.
As you see .NET Core 1.0 and .NET 4.6.3 implements same set of libraries in .NET Standard Library 1.6. This is a huge step forward. Unfortunately, big disadvantage is that UWP targets .NET Standard v1.4 only, which might make some difficulties to target Windows 10 devices on UWP.
Another important fact, you have to be aware of is that .NET cannot be ported to any of .NET standards. That means, if you have PCL build with profile portable-net40+sl5+wp80+win8+wpa81, that one cannot be retargeted to .NET standard. But if you would have a PCL portable-net45+wp80+win8+wpa81+dnxcore50, we could retarget it to .NET Standard1.0.
In other words, every assembly built with 4.5 or older version (as mono) cannot be retargeted to any .NET standard.
To get a bit better feeling how all this behaves, let’s build a Win32 (Desktop) console application, which will reference ClassLibrary1. Create a new project and be sure that you chose Windows/Console Application. Do not chose .NET Core/Console Application as in previous example.
As next, let’s reference the ClassLibrary1 from new Console Application. Some of you might be suppressed, because this will not work.
You will get following error:
That means, VS still does not recognize template of the .NET Core project. But this will be fixed soon, I guess.
We have two choices at the moment to reference the library from Win32 (Desktop) application:
- Add reference directly to assembly
- Add reference to package. (At the end of this article I will show how to create NUGET package.
I will add a reference directly to assembly, but before I do that I have to be sure which version of .NET Framework uses my Desktop Console Application.
If my application uses .NET 4.6.1 then I can only reference assemblies, which uses .NET Standard Library 1.4. I know this, if I take a look in a table shown above.
However, our ClassLibrary1 is build with support to v1.6.0. (take a look in project.json)
"dependencies": { "NETStandard.Library": "1.6.0" },
The table below shows that 4.61 of .NET Framework is not compatible with .NET Platform Standard 1.6
If we try to do that, following exception will be thrown (at least):
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 workaround this, there must be a build of a ClassLibrary1, which supports standard 1.4. To achieve this we need to extend project.json as shown below:
{ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.6.0" }, "frameworks": { "netstandard1.4": { "imports": "dnxcore50" }, "netstandard1.6": { "imports": "dnxcore50" } } } |
After this change, we need to add a reference to DLL v1.4 from Console Application.
How to create a Unit Test project?
As unit test engine, I will use XUNIT. Let’s add XUnitTesting packages ‘xunit’ and ‘dotnet-test-xunit’ to project ‘Sample01’. After adding a NUGET package you will have to change reference.
Lookup dnxcore50 in project.json (belov on left and replace it with import shown below on right.
Note, xunit libraries have been compiled as portable library with a profile that includes "portable-net45+win8". At the moment of creating of that library .NET Core in this version was not existing. If you have been working with .NET core previously, you will probably need to change import directive too the same way as I shown it here.
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.
Sample01 project looks like shown at following picture:
Here is my test sample:
Tests can be started as usual by using Visual Studio, but we can also use DOTNET-core tooling. To execute tests, navigate to project folder, which contains project.json and implementation of tests. Then execute
dotnet test
Following is the result. If there is at least one failed test, you will get result as shown below:
Ho to create a NUGET package
One of helpful features of .NET core is creation of NUGET packages. It is simply a part of dot net core toolset. To create a package simply use following command:
dotnet pack
Command will produce following output:
Package can be found in debug output folder:
Useful 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:
https://docs.microsoft.com/en-us/dotnet/articles/standard/library - Getting started:
https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/using-on-windows
Posted
Jul 26 2016, 10:49 PM
by
Damir Dobric