Updated: August 13, 2024
Developing Cross-Platform Apps Faster and on Any Platform
At the end of the last century, Microsoft, one of the most successful software development corporations, faced the problem of a huge number of incompatible languages, environments and programming technologies. At the same time, the development process was rigidly focused on a specific programming language. Also, across different languages, there was a different set of incompatible technologies. Above all, these technologies were gradually becoming obsolete.
There was a need to implement new programming tools that would fully support the object-oriented approach, exceptions handling and garbage collection. The growing popularity of the new Java software platform by Sun Microsystems surely added some fuel to the fire.
What was there before .NET Core?
In 1999, Microsoft began the development of a new unified platform, NWGS, later called the .NET Framework. This software platform, despite all the weaknesses and inoperability of the first versions, has become a unique product, combining many benefits. The main advantages of the platform:
- Hardware-independent execution environment with the ability to compile just-in-time (JIT). This means that an application written in languages that support .NET can be run on processors of different architectures, in case there is a translator from the .NET MSIL language into the command codes of this processor.
- Support for compatibility of program fragments written in different languages. For example, in C#, you can create your own class, inherited from a class written in Visual Basic, and call a method written in Managed C++. This all works without error.
As the .NET Framework evolved, it acquired new technologies and development capabilities. In version 2.0 there were WinForms and ASP.NET, in the 3.0 version there were WPF and WCF, the 3.5 version gave us LInQ, in version 4.0 TPL and PLInQ saw the light, and in version 4.5 API for Windows Store applications was added.
In 2002, the first version of the .NET Compact Framework was released. It was intended for mobile devices run by Windows Mobile. The .NET Compact Framework is formally a subset of the .NET Framework, but it actually contains its own application model, framework, and runtime environment, that is significantly different from the similar .NET Framework model.
Subsequently, all new “subsets” of the .NET Framework were born. They were architecturally and functionally different from the desktop .NET version. These subsets are familiar to all .NET developers. They are: Silverlight, Windows Phone, Windows Store, .NET Micro Framework, and ASP.NET. The situation is even stranger for the last one: ASP.NET of version 4 and ASP.NET of version 5 are two different platforms, each with its own application model, framework, and execution environment (Figure 1).
Figure 1. Example of the different .NET verticals
Of course, all the platforms mentioned have a number of common APIs because they all once were separated from the desktop version of the .NET Framework. But their evolution caused the growth of differences between them, and Microsoft had to come up with increasingly sophisticated “crutches” to ensure compatibility and uniformity of their APIs. The compatibility problem arises when you need a software product that can work on several platforms. This raises the question of the availability and compatibility of the API in each of these platforms.
In addition to the mentioned “subsets” of .NET that run exclusively on Windows, there are also implementations of the .NET Framework for Linux systems, the most famous of which are Mono and DotGNU. These are created by communities of enthusiasts; Microsoft did not participate in their development in any way. Each of these implementations also represents a “subset” of .NET, with its own application model, framework, and runtime. Porting applications from the Windows version of the .NET Framework to Mono or DotGNU is as difficult as the development of an ASP.NET application version based on its desktop implementation.
It turned out that Microsoft eventually gave birth to a whole “zoo” of similar, but at the same time different, platforms with different APIs, application models, and execution environments in order to create a single software platform with full language and technology compatibilities. The .NET Framework, which Microsoft considered a salvation from the “zoo” of incompatible languages and technologies, eventually itself became the “zoo” of APIs and implementations. Microsoft again faced the challenge of creating a single software platform for all development methods that exist in the .NET Framework. This platform is .NET Core.
What is .NET Core?
.NET Core is a modular cross-platform version of .NET Framework with the ability to port applications to other platforms and operating systems. In this case, the already created code is used to the maximum during the porting process, while the use of APIs specified for a particular platform is minimized. However, .NET Core does not replace the .NET Framework, but is just a version of it (a subset). Also, .NET Core does not replace Mono on Linux-like operating systems – both projects are developing in parallel.
This is achieved by using portable class libraries (PCL) with the most common form of API for all target platforms. At the same time, implementations of the application, including the framework itself and the execution environment, remain different, although they are subsets of .NET. Appeals to the API are particular for a specific platform (in the case of designing a cross-platform project) and are separated by special preprocessor directives:
#if WINDOWS_PHONE_APP
Windows.Phone.UI.Input.HardwareButtons.BackPressed
+= HardwareButtons_BackPressed;
#elif WINDOWS_APP
// Ignore. Windows Store doesn't have support for this.
#else
#error Unknown platform
#endif
where WINDOWS_PHONE_APP is the preprocessor symbol declared in the project. It can be found in the project properties (the Build section).
Beginning with 2013 Update 2 version in Visual Studio, it became possible to create universal applications for Windows that can be run on several platforms, due to PCL.
.NET Core is creating by the .NET Foundation community, which, in addition to Microsoft programmers, includes many independent developers, including the Mono Community developers.
Everyone can participate in the creation of .NET Core. The participation rules are published on GitHub. The project with open source is published on GitHub as well. .NET Core is a free software under the licenses of MIT, Apache 2.0 and Creative Attribution 4.0 (for some modules).
Portable Class Libraries (PCL)
In the .NET Framework, the core of the system is the extensive mscorlib library. It contains a lot of APIs and their implementations, some of which are not required in other target platforms (which differ from the desktop version) and others are not supported by these platforms. It turns out that on another target platform (for example, in Silverlight) there is a completely different mscorlib library. The situation is the same for other .NET libraries. Unlike the .NET Framework, the .NET Core has a flexible architecture of PCL, designed with significant code decomposition. At the same time, the dependencies between the libraries are clearly monitored by the .NET Core itself.
Each PCL is responsible for a specific .NET module and no more than that. Each PCL has its own independent assembly version, and new APIs are available only in new PCL versions.
This allows the target platform to choose the PCL modules independently. It is also important to note that the platform cannot support any PCL partially – it either supports it or it does not.
Also, the main principle of .NET Core is based on PCL, and there are uniform APIs for various .NET implementations. However the .NET implementations have not disappeared. They continue to exist and they are as different as before, but access to them can be done through APIs which are common to all of these implementations.
PCL allows you to implement the same code in several target .NET Core platforms.
If you’re interested in more, read How an IT Pro Makes His Life Easier Using TFS 2015
Unified BCL is the Cross-platform Kernel for .NET Core
BCL contains an API that is uniform for the entire .NET Core and for all its implementations. For example, most of the .NET Native API used to create applications for mobile devices and ASP.NET 5, on which the server side of web applications is written, contains BCL, and it is the same for both technologies.
BCL is an intermediate layer of assemblies on MSIL, common for all .NET implementations. Above BCL, there are APIs specific for each particular platform (so-called “application models”), for example, WinRT interop for .NET Native and MVC for ASP.NET 5.
Below BCL there is a layer of adaptation to various .NET implementations to the performing environments, for example, CLR (CoreCLR) or .NET Native. The CLR compiles the MSIL code into the target platform command system during the execution of the application (JIT compilation).
Unlike the CLR, .NET Native compiles the MSIL code, together with the .NET libraries, into the target platform command system, even before it reaches this platform, and launches on it. As you can see from the description above, CoreCLR and .NET Native are two completely different .NET execution environments, but the BCL is the same for both and interacts with them only through the adaptation layer.
Currently, .NET Core BCL is being developed under the name of .NET Standard.
Compatibility Issues in the .NET Framework
The traditional .NET Framework is distributed as a single, indivisible software product. It is installed on the device entirely and it is removed from the device entirely. The new version replaces the previous one, with all the ensuing consequences. However, the new version of the .NET Framework can disrupt the normal operation of the application written in an older version. For example:
- If a new interface is added in the new version to the existing type of the .NET Framework, there may be problems with the serializing of this type;
- If an additional overload has been added to the existing method in the new version of the .NET Framework, then there may be a problem with the reflection of this method;
- In the case of renaming an internal type to the .NET Framework, the application’s performance may also be compromised if the type name is determined by the toString() method.
Since the release of the new version of the .NET Framework, Microsoft has been trying to make it compatible with the previous version. But even if the probability of failure is extremely low (less than 0.1%), then there may be millions of such failures, because the .NET Framework is currently used on billions of devices.
NuGet – Distribution Mechanism and Modularization Basis of .NET Core
Unlike .NET Framework, .NET Core is presented as small NuGet packages, and each of them, as a rule, is responsible for any library or namespace. For example, if in .NET Framework the System.Colections.Generic namespace was a part of a large mscorlib library, then in .NET Core it is a certain NuGet package.
- Every NuGet package has its own name and version.
- Every NuGet package can be updated to a new version without updating other .NET Core components.
- NuGet packages can be downloaded and installed individually from the website nuget.org without installation of a new .NET Core version.
Currently the nuget.org web page contains more than 800,000 .NET Core libraries. But this doesn’t mean that you would have to download .NET Core components from the website and install them separately every time a new application on .NET Core needs to be developed. All the NuGet packages included in .NET Core are installed alongside the installation of .NET Core and have the same version as the current version of .NET Core. Additional packages or packages of a newer version are downloaded and installed separately from the installation of .NET Core.
Additional NuGet packages that are not included in the current .NET Core version are circulated with the application after downloading. There is no need for NuGet to download its packages from the Internet. There is an autonomous installer for NuGet that is included in Visual Studio. Any plug-in in .NET Core can be replaced by a newer one without the installation of a new version of the framework. If a .NET Core plug-in works insecurely, NuGet can roll it back to an older version without disrupting the work of other .NET Core components.
Thus, .NET Core is a framework adjusted for every application. Every .NET application uses only these .NET Core libraries, which are required. The libraries that are common for all .NET applications are presented as NuGet packages within .NET Core. Additional .NET Core libraries are circulated together with applications.
Integration with Other .NET Platforms
.NET Core is a subset of .NET Framework and must be compatible with its other subsettings. The .NET platform is fully compatible with .NET Framework 4.6 and fully realizes its function. In time, .NET Core will develop faster than .NET Framework, but both projects will develop simultaneously. All the new technologies will be tested on .NET Core, and only then will they be adapted to .NET Framework.
Mono is a subset of .NET Framework released in Linux and MacOS. The Mono community is building up support for .Net Core release on these operating systems, at most, integrated with Mono.
Windows Store and Windows Phone are subsets of .NET Core as well, and contain their own models of applications over BCL and their own runtime (.NET Native).
Other .NET platforms can be compatible with .NET Core as well. It is achieved either by the usage of PCL or by the creation of a common project and the adaptation of code with the help of #if directives.
.NET Compiler Roslyn as a .NET Core Part
Particularly in .NET Core, a new compiler, Roslyn, is used, written for usage in .NET Core. Roslyn allows the connecting of each stage of code compilation and .NET application building through API.
The possibilities of Roslyn are described in more detail in the article Microsoft Roslyn – using the compiler as a service.
Among the most interesting Roslyn possibilities we can point out are the building and reprogramming of a syntactic tree, the generation of source code by this tree and the possibility of using C# and Visual Basic as script languages (with the use of REPL).
.NET Core gave Roslyn its own namespace of Microsoft.Net.Compilers and its own NuGet package, which corresponds to this namespace. On the basis of Roslyn, a freely distributable cross-platform IDE with Visual Studio Code open source code was developed.
ASP.NET Core – a New Framework for Web Applications
Despite its crudity, the ASP.NET becomes a prospective platform for web service development. This is facilitated by more compact code, better scalability and the very high efficiency of a new platform. Along with that, Microsoft has refused many technologies in ASP.NET Core which were used in ASP.NET. These are System.Web namespace, Web Forms, Transaction Scope, WPF, and WinForms. Instead, .NET Framework provides a flexible web application model, with the use of MVC and WebAPI subsystems.
If the earlier ASP.NET, based on System.Web.dll, ran only on Windows and IIS, then at present, relying on benchmarks, it ranks among the top Linux web frameworks in terms of efficiency.
Microsoft’s aspiration to make ASP.NET Core cross-platform led to ASP.NET Core depending on neither the operating system nor the web server which it will run on. ASP .Net Core will run equally well on either Windows, Mac, or Linux, and its projects will be able to run both in Windows Azure Web App or in Docker on Linux, and everything will work correctly in both cases.
Further .NET Core (Roadmap) Development
Nowadays .NET Core is developing actively. .NET Core is adopting more and more common APIs from .NET Framework and Xamarin to make an application portable to all .NET platforms. Microsoft and .NET Foundation are pursuing the following aims in developing upgrades for the framework:
- To make .NET appropriate for most of the current development tasks;
- To develop high-quality .NET Core versions for Windows, Linux, and MacOS operating systems;
- To create high-quality .NET Core versions for processor architectures: x86, x64 arm32, and arm64;
- To perform releases of new .NET Core versions at least several times per year;
- To allow developers to develop applications as quickly as possible, using intuitive .NET Core tools;
- To improve application building productivity in .NET Core to make the development cycle (making changes in code and subsequent code execution on a compiler) as quick as possible;
- To improve the work of .NET applications in the cloud – to improve logging algorithms, tracings, and error diagnosis;
- To allow the user to assemble .NET Core from source code files independently, including those modified by the user.
The release of the 2.0 version of .NET Core is expected in 3Q 2017. The next version of cross-platform framework by Microsoft is expected to have many improvements. The utility of the second .NET Core version has been proclaimed for the following operating systems:
- Windows (starting from 7 SP1);
- Windows Server (starting from 2008 R2 SP1);
- Red Hat Enterprise Linux (from version 7.3);
- Fedora (from version 25);
- Debian (from version 8.7);
- Ubuntu (from version 14.04);
- OpenSuse (starting from version 42.2);
- Tizen (from version 4);
- MacOs X (from version 10.12).
Microsoft continues to develop other .NET tools, together with .NET Core. These are: ASP.NET, .NET Framework, programming languages for .NET, and others. The project .NET Standard, developed from Unified BCL, is developing actively. .NET Standard is a set of common specifications for all .NET platforms: .NET Core, .NET Framework, Mono, Xamarin, and others. .NET Standard guarantees the usage of its libraries in all .NET runtime environments.
Summary
The contribution of Microsoft to the progress of development tools is, of course, wonderful, but at the same time, the progress of these tools was ambiguous. The tendency to use a huge number of different technologies and approaches to software development resulted in many incompatible languages and development tools. This led to the problem of unification and compatibility of all languages, development tools and technologies ever developed by Microsoft.
Microsoft, having resolved this issue once and having created .NET Framework, faced the problem again. Now this issue presents as different verticals of .NET subsettings, which have originated from one framework but are different, and have become more and more distant from each other as they developed. The colossal effort of developers was needed to create a single software platform. The result of such work was .NET Core – one framework for all .NET verticals.
.NET Core is not just another .NET Framework. As opposed to .NET Framework, it is an absolutely new .NET platform with technologies and work principles entirely different from .NET. Absolutely everything has changed in .NET Core: the framework and its core building principles, the distribution and upgrade scheme (NuGet), development frameworks (Visual Studio 2015/2017 and Visual Studio Code), web development platforms (Asp.NET Core), and even the compiler *(Roslyn). However, Microsoft and .NET Foundation have not hurried to switch fully to .NET Core; they are developing it along with other .NET platforms.