There has been continuous transformation since the last few years to bring .NET to platforms other than Windows. .NET Core 3.0 released in September 2019 with primary focus on adding Windows specific features.
.NET Core 3.0 supports side-by-side and app-local deployments, a fast JSON reader, serial port access and other PIN access for Internet of Things ( IoT) solutions, and tiered compilation on by default. In this article we will explore the .Net Core components of its new 3.0 release.
Pieces of .NET Core components
These are pieces that play an important role in the development of the .NET Core:
- Language compilers: These turn your source code written with languages such as C#, F#, and Visual Basic into intermediate language (IL) code stored in assemblies. With C# 6.0 and later, Microsoft switched to an open source rewritten compiler known as Roslyn that is also used by Visual Basic.
- Common Language Runtime (CoreCLR): This runtime loads assemblies, compiles the IL code stored in them into native code instructions for your computer’s CPU, and executes the code within an environment that manages resources such as threads and memory.
- Base Class Libraries (BCL) of assemblies in NuGet packages (CoreFX): These are prebuilt assemblies of types packaged and distributed using NuGet for performing common tasks when building applications. You can use them to quickly build anything you want rather combining LEGO™ pieces. .NET Core 2.0 implemented .NET Standard 2.0, which is a superset of all previous versions of .NET Standard, and lifted .NET Core up to parity with .NET Framework and Xamarin. .NET Core 3.0 implements .NET Standard 2.1, which adds new capabilities and enables performance improvements beyond those available in .NET Framework.
Understanding assemblies, packages, and namespaces
An assembly is where a type is stored in the filesystem. Assemblies are a mechanism for deploying code. For example, the System.Data.dll assembly contains types for managing data. To use types in other assemblies, they must be referenced.
Assemblies are often distributed as NuGet packages, which can contain multiple assemblies and other resources. You will also hear about metapackages and platforms, which are combinations of NuGet packages.
A namespace is the address of a type. Namespaces are a mechanism to uniquely identify a type by requiring a full address rather than just a short name. In the real world, Bob of 34 Sycamore Street is different from Bob of 12 Willow Drive.
In .NET, the IActionFilter interface of the System.Web.Mvc namespace is different from the IActionFilter interface of the System.Web.Http.Filters namespace.
Understanding dependent assemblies
If an assembly is compiled as a class library and provides types for other assemblies to use, then it has the file extension .dll (dynamic link library), and it cannot be executed standalone.
Likewise, if an assembly is compiled as an application, then it has the file extension .exe (executable) and can be executed standalone. Before .NET Core 3.0, console apps were compiled to .dll files and had to be executed by the dotnet run command or a host executable.
Any assembly can reference one or more class library assemblies as dependencies, but you cannot have circular references. So, assembly B cannot reference assembly A, if assembly A already references assembly B. The compiler will warn you if you attempt to add a dependency reference that would cause a circular reference.
Understanding the Microsoft .NET Core App platform
By default, console applications have a dependency reference on the Microsoft .NET Core App platform. This platform contains thousands of types in NuGet packages that almost all applications would need, such as the int and string types.
When using .NET Core, you reference the dependency assemblies, NuGet packages, and platforms that your application needs in a project file.
Let’s explore the relationship between assemblies and namespaces.
- In Visual Studio Code, create a folder named test01 with a subfolder named AssembliesAndNamespaces, and enter dotnet new console to create a console application.
- Save the current workspace as test01 in the test01 folder and add the AssembliesAndNamespaces folder to the workspace.
- Open AssembliesAndNamespaces.csproj, and note that it is a typical project file for a .NET Core application, as shown in the following markup:
Check out this code on GitHub.
Although it is possible to include the assemblies that your application uses with its deployment package, by default the project will probe for shared assemblies installed in well-known paths.
First, it will look for the specified version of .NET Core in the current user’s .dotnet/store and .nuget folders, and then it looks in a fallback folder that depends on your OS, as shown in the following root paths:
- Windows: C:\Program Files\dotnet\sdk
- macOS: /usr/local/share/dotnet/sdk
Most common .NET Core types are in the System.Runtime.dll assembly. You can see the relationship between some assemblies and the namespaces that they supply types for, and note that there is not always a one-to-one mapping between assemblies and namespaces, as shown in the following table:
System, System.Collections, System.Collections.Generic
Int32, String, IEnumerable
Interlocked, Monitor, Mutex
XDocument, XElement, XNode
Understanding NuGet packages
.NET Core is split into a set of packages, distributed using a Microsoft-supported package management technology named NuGet. Each of these packages represents a single assembly of the same name. For example, the System.Collections package contains the System.Collections.dll assembly.
The following are the benefits of packages:
- Packages can ship on their own schedule.
- Packages can be tested independently of other packages.
- Packages can support different OSes and CPUs by including multiple versions of the same assembly built for different OSes and CPUs.
- Packages can have dependencies specific to only one library.
- Apps are smaller because unreferenced packages aren’t part of the distribution.
The following table lists some of the more important packages and their important types:
Object, String, Int32, Array
Assembly, TypeInfo, MethodInfo
There is a two-way relationship between frameworks and packages. Packages define the APIs, while frameworks group packages. A framework without any packages would not define any APIs.
.NET packages each support a set of frameworks. For example, the System.IO.FileSystem package version 4.3.0 supports the following frameworks:
- .NET Standard, version 1.3 or later.
- .NET Framework, version 4.6 or later.
- Six Mono and Xamarin platforms (for example, Xamarin. iOS 1.0).
Understanding dotnet commands
When you install .NET Core SDK, it includes the command-line interface (CLI) named dotnet.
Creating new projects
The dotnet command-line interface has commands that work on the current folder to create a new project using templates.
- In Visual Studio Code, navigate to Terminal.
- Enter the dotnet new -l command to list your currently installed templates, as shown in the following screenshot:
The dotnet CLI has the following commands that work on the project in the current folder, to manage the project:
- dotnet restore: This downloads dependencies for the project.
- dotnet build: This compiles the project.
- dotnet test: This runs unit tests on the project.
- dotnet run: This runs the project.
- dotnet pack: This creates a NuGet package for the project.
- dotnet publish: This compiles and then publishes the project, either with dependencies or as a self-contained application.
- add: This adds a reference to a package or class library to the project.
- remove: This removes a reference to a package or class library from the project.
- list: This lists the package or class library references for the project.