ERNI Technology Post No. 57: .NET Core – open for extension, open for modification

Open sourcing Microsoft .NET was definitely the biggest IT news of 2015. And in 2016, the experience of open source .NET became a reality, representing an opportunity for many projects.

.NET Core

.NET Core is a general purpose development platform maintained by Microsoft and the .NET community as an open source project at GitHub. It extends the success of .NET to multiple platforms, including Windows, Linux and macOS, and can be used in devices, cloud, and embedded/IoT scenarios.

.NET Core might seem like a subsequent version of .NET Framework, but this is not completely true. It complies with the .NET standards and provides compatibility on a very high level. And thus, most of your .NET development experience can be used in .NET Core development. However, it has its own runtime, toolset and base class library. These .NET Core specifics are described in this issue of TechLetter.

.NET Standard and Common Language Runtime

When the first version of .NET Framework was designed, one of the goals was to create a single runtime that could be used by many programming languages. At the beginning, it was Visual Basic and C#. Soon many other languages like F#, C++, IronPython, and even PHP followed. This was possible thanks to the Common Language Infrastructure (CLI) that was standardized as ECMA-335 in 2001 and ISO/IEC 23271 in 2003. It helped not only the development of many languages on a single runtime, but also the development of several implementations of CLR on different platforms like Mono, Xamarin and .NET Native.

From this perspective, .NET Core is another CLI implementation. It is not a successor of .NET Framework, but will rather co-exist with it. Furthermore, .NET Core offers a lot of services guaranteed by .NET CLI.

Feature

Description

Language independence .NET Core uses the Roslyn compiler platform. In the current release of .NET Core, only C# is fully supported across all Microsoft tools. F# is supported in the .NET Core SDK, but does not have Visual Studio tooling yet. Visual Basic supports for the SDK and Visual Studio tooling are coming.
Automatic memory management Garbage collection is the most well-known feature of .NET. Developers do not need to actively manage memory, although there are mechanisms to provide more information to the garbage collector (GC). C# includes the new keyword to allocate memory in terms of a particular type, and the using keyword to provide scope for the usage of the object. The GC operates on a lazy approach to memory management, preferring application throughput to the immediate collection of memory.
Type safety Objects are allocated in terms of types. The only operations allowed for a given object, and the memory it consumes, are those of its type. The .NET runtime will only allow object casts and calls that align with the object hierarchy.
Just-in-time compiler JIT compilation converts MSIL to native code on demand at application runtime, when the contents of an assembly are loaded and executed. Because the common language runtime supplies a JIT compiler for each supported CPU architecture, developers can build a set of MSIL assemblies that can be JIT-compiled and run on different computers with different machine architectures. However, your managed code will run only on a specific operating system if it calls platform-specific native APIs or a platform-specific class library.
Native interoperability P/Invoke is a technology that allows you to access structs, callbacks and functions in unmanaged libraries from your managed code.
Exception handling Applications must be able to handle errors that occur during execution in a consistent manner. .NET provides a model for notifying applications of errors in a uniform way: .NET operations indicate failure by throwing exceptions.

In addition to that, it offers the following features compared to the .NET Framework

Feature

Description

Cross-platform support

.NET Core is currently supported on multiple platforms:

  • Windows 7 / Server 2012 R2
  • macOS 10.11
  • RedHat Enterprise Linux 7.1
  • Ubuntu 15.04
  • Ubuntu 16.04
  • Debian 8.2
  • Fedora 23
  • CentOS 7.1
  • openSUSE 13.2
Open source .NET Core is developed as open source project on GitHub with a lot of contribution from the .NET community.
Side-by-side installation Several versions of .NET Core can be installed on a target machine. Additionally, the application can be deployed with the included .NET Core runtime.
Several types of applications

.NET Core can be used to develop several types of applications:

  • Console applications
  • Web applications (console application with in-proc web server)
  • Universal Windows Applications

.NET Standard Library

The .NET Standard Library is a formal specification of .NET APIs that are intended to be available on all .NET runtimes. The motivation behind the Standard Library is establishing greater uniformity in the .NET ecosystem. ECMA 335 continues to establish uniformity for .NET runtime behavior, but there is no similar spec for the .NET Base Class Libraries (BCL) for .NET library implementations.

The various .NET runtimes implement specific versions of the .NET Standard Library. Each .NET runtime version advertises the highest .NET Standard version it supports, a statement that means it also supports previous versions. For example, the .NET Framework 4.6 implements the .NET Standard Library 1.3, which means that it exposes all APIs defined in .NET Standard Library versions 1.0 through 1.3. Similarly, the .NET Framework 4.6.2 implements the .NET Standard Library 1.5, while .NET Core 1.0 implements the .NET Standard Library 1.6.

Recently, no .NET Framework version has supported .NET Standard Library 1.6. This makes it evident that .NET Core is not a subset of .NET Framework, but rather a different framework with additional APIs.

.NET Standard

1.0

1.1

1.2

1.3

1.4

1.5

1.6

2.0

.NET Core

1.0

vNext

.NET Framework

4.5

4.5.1

4.6

4.6.1

4.6.2

vNext

4.6.1

Xamarin Platform

vNext

Universal Windows Platform

10.0

vNext

The .NET Standard Library can be thought of as the next generation of Portable Class Libraries (PCL). The .NET Standard Library improves the experience of creating portable libraries by curating a standard BCL and establishing greater uniformity across .NET runtimes as a result. A library that targets the .NET Standard Library is a PCL or a «.NET Standard-based PCL». Existing PCLs are «profile-based PCLs».

.NET Core Foundation libraries

.NET Core Foundation libraries are equivalent to Base Class Libraries in .NET Framework. It is actually implementation of a specific .NET Standard Library version in .NET Core.

There is a big difference in the distribution of .NET Core Foundation libraries compared to .NET Framework. .NET Framework BCL assemblies are big, monolithic and are stored in Global Assembly Cache. On the other side, .NET Core types are distributed in much smaller assemblies providing very specific functionality. This way it is possible to package only a few small libraries needed by the application instead of a big framework.

.NET Core relies heavily on the NuGet package management system and all assemblies are distributed as NuGet packages. Examples of small NuGet packages:

  • System.IO
  • System.IO.FileSystem
  • System.IO.Compression

Additionally, there are meta-packages containing other packages. For example, the NuGet package NETStandard.Library contains all packages implementing .NET Standard library.

Tools

.NET runtime and API is well standardized, and thus portable to different platforms. On the other hand, tooling is the most different part of .NET Framework. Currently .NET Framework applications are developed in Visual Studio and built using MS Build framework. However, as .NET Core is multiplatform, tooling must also be available on different platforms. Therefore, there is a set of command-line tools for building .NET Core applications.

Command Line Tools

An advantage of command line tools is that they can easily be integrated with other development tools:

The main tool in .NET Core development is dotnet. It supports the following commands:

Command

Description

dotnet new

Initializes a C# or F# console application project

dotnet restore

Restores the dependencies for a given application

dotnet build

Builds a .NET Core application

dotnet publish

Publishes a .NET portable or self-contained application

dotnet run

Runs the application from source

dotnet test

Runs tests using a test runner specified in the project.json

dotnet pack

Creates a NuGet package of your code

Additionally, another command can be added by referencing tooling NuGet packages. For example, Entity Framework Core package adds commands for creating database schema from DbContext.

At first, the dotnet new command will create project.json and Program.cs files, which are source files for the “Hello World!” console program. Project.json is a very important file in .NET Core tooling. It is a counterpart to *.csproj file in MS Build. However, project.json uses JSON format and therefore is easier to maintain in any text editor. Also, it has more predefined variables. For example, by default all *.cs files are included in compilation and there is no need to explicitly list those. Also, Debug and Release configurations are defined by default. Therefore, on average, a project.json file is much smaller than a *.csproj file.

In parallel with adding classes and *.cs files, it is also necessary to specify the dependencies of project. This is done by listing required NuGet packages in the project.json file in the dependencies element. The easiest way is to include full .NET Standard library version 1.6. Also, any other NuGet package targeting .NET Standard can be included. The advantage is that dependent packages don’t need to be listed and are restored automatically.

An example of a project.json file referencing NuGet packages:

  "dependencies": {
    "NETStandard.Library": "1.6.0",
    "NLog": "4.3.10"
  },

When dependencies are listed, the dotnet restore command will download NuGet packages and prepare for compilation.

The next step is to build the project. First, it is necessary to define the .NET frameworks for which the target assembly is targeted. There can be multiple frameworks listed and therefore also multiple output files coming out of a single compilation. Project.json supports the following frameworks:

Framework

Description

.NET Standard

.NET assembly built for a specific version of .NET Standard.

.NET Core Application

Command-line executable application running in .NET Core runtime.

.NET Framework

.NET assembly targeting the full .NET Framework. This is supported only on the Windows platform with .NET Framework installed.

An example of the frameworks element in project.json:

  "frameworks": {
   
"netcoreapp1.0": {
      "dependencies": {
       "Microsoft.NETCore.App": {
         "type": "platform",
         "version": "1.0.1"
       }
      },
      "imports": "dnxcore50"
    }
  }

And now, simply execute the dotnet build command.

In the case of the .NET Core application, this produces DLL that can be executed by a dotnet command. For example: dotnet HelloWorld.dll.

In the case of the library, it is probably desired to create a NuGet package. As mentioned before, .NET Core relies heavily on the NuGet package management system. So it is easy to create a NuGet package from the project. Simply run the dotnet pack command. This will create the package Project.version.nupkg.

Visual Studio

In addition to hardcore command-line developers, there is support for developers using Visual Studio too. In the first step, it is necessary to install the required software.

When all software is installed, you can simply create a new .NET Core project by selecting the Class Library (.NET Core) project type.

This will create the Project.xproj file in addition to the project.json file. The project.json file works exactly the same way as in command-line development and it contains all information about build, dependencies, frameworks, etc.

The *.xproj file is a simple MS Build file that commands MS Build to build project.json using .NET Core tools. Therefore, development using Visual Studio is not much different from development using command-line tools. However, Visual Studio supports IntelliSense in C# and also project.json. It is also possible to use the Visual Studio Package manager to manage dependencies in a project.

Testing

Testing is an integral part of software development. Therefore, it is supported by .NET Core tools. Testing is implemented in the same way as in the .NET Framework, by implementing classes and methods containing testing code.

First it is necessary to include the dependency in the testing framework. For example, Xunit. Then you need to add the dependency on the test runner package that supports .NET Core. For example, xUnit.net [Runner: .NET CLI]. The last step is to specify test runner in project.json.

An example of project.json for a test project using the Xunit testing framework:

{
   "version": "1.0.0-*",
   "buildOptions": {
      "debugType": "portable"
  },
  "dependencies": {
     "System.Runtime.Serialization.Primitives": "4.1.1",
     "xunit": "2.1.0",
     "dotnet-test-xunit": "1.0.0-rc2-192208-24"
  },
  "testRunner": "xunit",
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
        }
      },
      "imports": [
        "dotnet5.4",
        "portable-net451+win8"
      ]
    }
  }
}

Now it is possible to simply run the dotnet test command and all Xunit tests in the project will be executed.

ASP.NET Core

ASP.NET Core is a new framework for the development of web applications. It was designed from the ground up and does not have much in common with ASP.NET 4.6. The biggest change in ASP.NET Core is that it has a much leaner and more modular design. Therefore, it can be very lightweight and loads only needed functionality. For example, in a default configuration, not even the hosting of static web pages is provided.

Additionally, it has the following features:

  • It can run on .NET Framework and .NET Core, and of course it can run on any platform supported by .NET Core.
  • Ships entirely as a NuGet package.
  • Does not rely on IIS and provides its own web server framework.
  • New lightweight and modular HTTP request pipeline.
  • Developed as an open source project on GitHub.

Web server

ASP.NET Core is not hosted in the Internet Information Server, but provides its own web hosting framework. A typical scenario is to run ASP.NET web host in a .NET Core console application using WebHostBuilder class.

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }

The first statement for WebHostBuilder was to use Kestrel. ASP.NET Core decouples web application from an actual web hosting environment. Currently, ASP.NET Core implements 2 HTTP servers and even 3rd party servers might come in the future:

  • Kestrel is a cross-platform web server.
  • WebListener is a Windows-only HTTP server. It runs directly on the http.sys kernel driver and has very little overhead.

It is not recommended to expose these HTTP servers directly to the network, but you should configure IIS (or Apache) as a reverse proxy that redirects HTTP requests to the ASP.NET Core application. The UseIISIntegration statement of WebHostBuilder configures IIS as a reverse proxy for the Kestrel server.

The last important statement is that UseStartup specifies the class that configures ASP.NET Core middleware. Middleware are software components that are assembled into an application pipeline to handle requests and responses. Each component chooses whether to pass the request on to the next component in the pipeline, and can perform certain actions before and after the next component is invoked in the pipeline. Request delegates are used to build the request pipeline. The request delegates handle each HTTP request.

From the picture above, it is evident that the ASP.NET Core HTTP pipeline is much simpler compared to the old ASP.NET pipeline that defined complex application lifecycle.

ASP.NET Core comes with the following middleware:

Middleware

Description

Authentication

Provides authentication support.

COR

Configures Cross-Origin Resource Sharing.

Routing

Defines and constrains request routes.

Session

Provides support for managing user sessions.

Static Files

Provides support for serving static files, and directory browsing.

As mentioned before, middleware is configured in the application’s Startup class. This class must have a Configure method that adds and configures middleware to the HTTP pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseIdentity();

    // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

ASP.NET Core MVC

Probably the most used ASP.NET Core middleware is ASP.NET Core MVC. This framework is not very different from the old ASP.NET MVC and thus all experience from ASP.NET MVC can be reused. The biggest change is the unification of ASP.NET MVC and WebAPI. So ControllerBase, IActionResult and IFilter types are the same for MVC and WebAPI.

ASP.NET Core Extensions

Together with the development of ASP.NET Core, a lot of reusable components have been developed, which can be used not only in web applications. Additionally, these components can be used in both .NET Core and full .NET Framework. These components are known as ASP.NET Core Extensions.

Entity Framework Core

Probably the biggest extension is the Entity Framework Core. This framework provides Object-Relation Mapping functionality. Also, the framework is completely redesigned and does not provide backward compatibility. However, its usage is very similar to the code-first approach of Entity Framework 6. The new design is more lean to provide better extensibility and support for more databases, including SQL and NoSQL databases.

Dependency Injection

ASP.NET Core comes with a simple Dependency Injection container implementation. This is used mostly by MVC framework, when instantiating controllers, filters and other components. It can be used by other middleware too.

The DI container is configured in the ConfigureServices method in the Startup class. Here all services shall be registered in the DI container.

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

Advantage of this extension is that it defines very simple interfaces, so more complex DI frameworks can be used in ASP.NET Core. For example, there is official support from Autofac.

Configuration

The Configuration extension is a completely new application configuration framework. The configuration model is simpler compared to the old .NET configuration framework using *.config files. On the other hand, it provides many more configuration providers:

  • JSON file
  • XML file
  • Environment variables
  • Command-line arguments
  • INI file
  • Memory configuration – useful for default values

Logging

Just like with a DI framework, a logging framework is heavily used in ASP.NET Core to log and trace events in the ASP.NET Core application. Also, this extension provides a set of very simple interfaces, which are implemented by other famous frameworks like NLog.

Follow-ups

.NET Core and ASP.NET Core version 1.0 are here and we can take advantage of the development of multi-platform .NET applications. However, this is not where the development of this product stops. This is only where it begins. A roadmap is already ahead. .NET Standard Library 2.0 is being developed and it will bring a higher API overlap with .NET Framework. ASP.NET Core will offer new middleware features and some better Azure support. The Entity Framework Core will catch up with EF 6 by adding support for complex types and stored procedures.

However, the biggest change in progress is in .NET Core tooling. Now MS Build is open source and becoming cross platform, so it is only natural that it is becoming the primary tool to build .NET Core applications. This way there will be no difference in building .NET Core and .NET Framework applications.

posted on 12.12.2016
Categories: 
by: Rastislav Novotný