Volume 31 Number 4
.NET Goes Cross-Platform with .NET Core
By Phillip Carter | April 2016
At Microsoft, we’re buildinga new implementation of .NET, called .NET Core, to let you write cross-platform code for cloud-optimized workloads. Many are excited about this open source development, but what does it actually mean? This article should help clarify what .NET Core is today and what its goals are, how it relates to the Microsoft .NET Framework and the fundamentals of the command-line tooling that you can use to get started with .NET Core.
What’s .NET Core?
To understand what .NET Core is, it’s helpful to understand .NET itself. Many people mean “.NET Framework” when they say “.NET,” but there’s more to it than that. .NET is an ECMA standard that has different implementations—.NET Framework, Mono, Unity and, now, .NET Core. This means that many of the experiences are shared between the .NET Framework and .NET Core. However, .NET Core is new, with some different principles in mind.
First, .NET Core is cross-platform. It runs on Windows, OS X and multiple distributions of Linux. It also supports different CPU architectures. We’re adding more Linux distribution and CPU architecture support with the eventual goal of .NET Core running in as many places as possible.
At the same time, .NET Core is fundamentally modular in its design and architecture. The runtime, library and compiler components are all separate entities that communicate through well-designed interfaces. This allows you to “swap” components in and out for your particular needs. The libraries themselves are also modular and distributed via NuGet, letting you use only what you need so that you can fine-tune the footprint of .NET Core on any given system.
In addition, code written for .NET Core is portable, and can be tuned to run across different supported platforms. Depending on how you target your projects, it’s possible to have .NET Core code run on the .NET Framework, Mono and Xamarin platforms, on Windows 8 and Windows Phone, and on the Universal Windows Platform (UWP). To learn more, check out the .NET Platform Standard (bit.ly/1Of6W1r).
Finally, .NET Core will be “pay-for-play” and performant. One goal of the .NET Core effort is to make the cost of abstraction clear to developers, by implementing a pay-for-play model that makes obvious the costs that come from employing a higher-level abstraction to solve a problem. Abstractions don’t come for free, and that truth should never be hidden from developers. Additionally, .NET Core will favor performance with a standard library that minimizes allocations and the overall memory footprint of your system.
Scenarios for .NET Core
Today, four scenarios exist in which you can write code for .NET Core: cross-platform ASP.NET Web apps, cross-platform console apps, cross-platform libraries and frameworks, and UWP apps
Built for speed, ASP.NET Core 1.0 is the cross-platform Web stack for .NET Core. If you’ve ever wanted to do something like deploy your ASP.NET Web app to a container on Linux, you can now do that. To learn more about the breadth of functionality ASP.NET Core offers, check out the documentation at bit.ly/1TqPcIo.
The scope of cross-platform console apps is actually quite larger than many developers might expect. For example, an ASP.NET Core Web app is, at its core, a console app that reads and writes information to ports—it just so happens to do a lot of other things. A suite of microservices that form the back end of an entire system could each be written as console apps.
The distinction between cross-platform libraries and frameworks is one of scale. Libraries are one of the most natural candidates on which to build things on .NET Core. But at a much larger scale, things like frameworks for distributed computing are good candidates, as well.
Finally, UWP apps that target the family of Windows 10 devices run on .NET Core. You can build a fully featured UWP app that incorporates .NET Core libraries to help build rich Windows 10 apps.
In other words, there are a lot of things you can write for .NET Core today. As the tooling matures and expands, there’ll be even more things you can build in the future.
If you have .NET Framework assets that fall into one of these four scenarios, or want to cut your teeth on some new technology, go to bit.ly/1Q1Q18q so you can begin writing some .NET Core code.
How .NET Core Compares with the .NET Framework
The .NET most of you have come to know and love is known as the .NET Framework. So how does .NET Core compare with the .NET Framework? The first thing to keep in mind is that you still use the same languages—C#, F#, Visual Basic—to write all your code. Your experience writing code should look and feel very familiar. However, .NET Core is a new stack—not a subset of .NET Framework. It’s best to think of .NET Core and the .NET Framework as two stacks that coincide and co-evolve.
The .NET Framework is and will continue to be the stack to use when writing desktop applications for Windows 7 through Windows 10. In fact, you can have .NET Framework and .NET Core code live harmoniously together in the same solution. For example, consider a scenario where a .NET Framework GUI (like Windows Forms) consumes services written on .NET Core.
It’s helpful to think about the similarities and differences of .NET Core and the .NET Framework from two perspectives: API Surface area and runtime capabilities. Figure 1 helps illustrate the overlap of APIs between the two platforms.
Figure 1 The .NET Framework and .NET Core Share a Subset of APIs
There are .NET APIs implemented on both .NET Core and the .NET Framework (although sometimes with different underlying implementations). At the same time, .NET Core and .NET Framework both have APIs and capabilities that the other does not. For example, the .NET Framework has multiple GUI frameworks and Windows-specific APIs that aren’t present in .NET Core. Likewise, .NET Core has cross-platform capabilities and APIs that the .NET Framework lacks.
Additionally, the .NET Framework is a Windows component that’s serviced through Windows Updates. .NET Core employs a completely different model for where it lives and how it’s serviced. .NET Core is composed of NuGet packages, with the runtime installed App-Local. This means that applications can “carry” .NET Core with them, enabling them to exist side-by-side with other .NET Core instances on a machine or device. Servicing can then be done per-application and through a package manager, rather than globally through OS updates.
A practical question is this: If you write something on one stack, will it run on the other? Like most answers in life, it depends. If the APIs you use are implemented on both platforms, then you should be able to run your code on .NET Core and the .NET Framework with relatively little work on your part. However, if you assume dependencies on the running environment or use APIs not available on one stack (such as a library for working with XAML-based UIs), your code won’t run across both stacks. The .NET Portability Analyzer—available as a command-line tool (bit.ly/1Sd8oIK) or Visual Studio extension (bit.ly/1LqX0aF)—is a tool that will analyze your .dll files and generate a report on how portable your code is from the .NET Framework to .NET Core. We’ll be releasing more tools to help with porting in the future.
The Command Line: Your Entry Point for .NET Core
.NET Core comes with a new and revamped foundational toolset that’ll be used to develop applications. That toolset is called .NET Core CLI, which is short for .NET Core Command-Line Interface. As with other parts of .NET Core, it’s also open source (see GitHub.com/dotnet/cli) and has a vibrant open source community that’s intimately involved with its development.
There are several reasons for introducing a new toolset to the world. First, we have the need to support core development scenarios on all of the platforms that .NET Core supports. Given the diverse set of the platforms, a good command-line experience is a great foundation that we can build on; after all, the command line is what each of these platforms comes with by default.
As a logical extension, we wanted to support the same UX across the supported platforms. You’ll be able to move between Linux, Windows, and OS X and not have to re-learn the tools, their syntax, or semantics. They’re the same on all platforms. The usage patterns are the same and even the syntaxes are the same.
This idea that there’s one toolset you use across the platforms also extends to higher-level tooling, namely Visual Studio Code and Visual Studio. These higher-level tools will be layered upon the .NET CLI and will use them to support .NET Core projects moving forward. This means that when you build your .NET Core application from Visual Studio, .NET CLI tools will be invoked to perform the build.
Trying the .NET Core Command-Line Interface
The easiest way to get started with the .NET Core CLI is to follow the Getting Started guide (aka.ms/dotnetcoregs). The short of it is that you download an installer for your platform (or register a new apt-get feed in the case of Ubuntu), install the tools and you’re ready to go. The installers will take care of setting the installation folder on your system PATH in all supported OSes, as well as any other environment variables the CLI needs.
After this, you can start by invoking the driver “dotnet” and passing a command (what we also call a “verb”). The driver is in charge of running the command and passing any arguments to it. At the time of this writing, the CLI package comes with the commands in Figure 2. Of course, by the time you read this we’ll probably add more commands that will increase your productivity.
Figure 2 Some Common .NET CLI Commands You Can Use Today
|dotnet new||Initialize a valid project for either a class library or a console application using C# as a language.|
|dotnet restore||Restore dependencies that are defined in the project.json file for a given project. Dependencies are usually NuGet packages you use in your application.|
|dotnet build||Build your code! This command will produce an Intermediate Language (IL) binary for your project. If the project is a console application, the produced output will be an executable that you can immediately run. By default, the build command will output the built assemblies and executables (if applicable) to the bin directory in the directory where it’s invoked.|
|dotnet test||No good tooling should come without support for running tests. This command allows you to run a suite of tests using a runner that you can specify in the project.json file. Currently supported are xUnit and NUnit test runners.|
|dotnet publish||Publish your application for running on the targeted machine.|
|dotnet pack||The pack command will package your project as a NuGet package. The output is a set of nupkg files that you can then upload to your feeds or use in the restore operation by using the local folder override.|
|dotnet run||The run command will compile and run your application. You can think of this as a Ctrl+F5 analogue, just without Visual Studio.|
In addition to any commands that come with the package, you’ll also have an option to add additional commands as tools in your project.json and then restore them. They’re packaged as a NuGet package, which provides a nice and easy-to-use and understand extensibility model.
We hope you learned about .NET Core and are excited about writing .NET code that can run cross-platform. As a new stack, it provides some exciting capabilities that weren’t possible with the .NET Framework before. The .NET CLI also introduces a great command-line experience that will be the foundation of the developer experience and integrated into other tools such as Visual Studio and Visual Studio Code.
Finally, we know that you have a lot of assets written for the .NET Framework, and we’d love to see those assets continue to grow as the .NET Framework evolves. We imagine a world where the .NET Framework and .NET Core are used together in systems that take advantage of the strengths of both stacks.
If you’d like to learn more and perhaps get involved, here are a few places to get started:
- .NET Core Runtime: GitHub.com/dotnet/coreclr
- The .NET libraries: GitHub.com/dotnet/corefx
- The command-line interface and tooling: GitHub.com/dotnet/cli
- The Roslyn compiler (C# and Visual Basic) and language tooling for Visual Studio: GitHub.com/dotnet/roslyn
- Our documentation for .NET Core: GitHub.com/dotnet/core-docs
We have many more .NET open source projects that are being worked on. If you’re interested in seeing more of them, check out the .NET Foundation, an independent organization that fosters open development and collaboration around .NET. Microsoft has contributed several projects to the .NET Foundation, as well as other companies like Xamarin, Umbraco, Salesforce and the .NET community. Learn more about them and contribute at DotNetFoundation.org/projects.
Phillip Carter is a program manager on the .NET Team at Microsoft. A lover of systems and programming language theory, Carter can be found staying up late at night arguing over concurrency models with friends. He hopes one day that the runtime behavior of all systems can be expressed in type systems, thereby allowing the human race to ascend to a state of higher reasoning. He can be reached at firstname.lastname@example.org.
Zlatko Knezevic is a program manager (PM) on the .NET Team at Microsoft. In 2005, he joined Microsoft, first working in CEE as a developer evangelist, then moving on to become a PM in SQL Server. There he worked on a range of things, from adding new indices in the core engine to building butt services that deal with Big Data, data discovery and so on. In 2015, he joined the .NET team as a PM and has since been working on .NET Core cross-platform experiences. He can be reached at Zlatko.Knezevic@microsoft.com.
Thanks to the following Microsoft technical experts for reviewing this article: Immo Landwerth and the .NET Core and Framework Program Management Team