So, I’ve spent quite a bit of time reading everything I can find on .NET Core. I want to share with you what I’ve been reading and key quotes from key articles.
How I Learn New Stuff
When I start learning something, I start with the documentation from Microsoft. I don’t rush the process. I schedule time to read, re-read, copy notes, right-click on hyperlinks and “Open in New Tab” and only close the tab once I’m satisfied I understand what it’s saying. I keep Notepad open and I copy paragraphs (and the URLs) of key ideas.
So, I started here:
… and worked my way through that entire section. Sometimes I skimmed. Sometimes I re-read a paragraph a dozen times.
I also keep a list of acronyms and definitions as I find them. This helps me get everything straight in my mind.
I also make simplifying statements condensing paragraphs into one or two sentences for clarity and concision … then I test those statements as I continue reading to make sure those statements are still accurate. As my understanding evolves, I continue tweaking those sentences.
It’s a very messy process. It’s very organic. No one taught me how to do it … it just comes out of me. I’m sure you have a similar approach.
Why Does .NET Core Exist?
Before I share my notes, I wanted to share my overall conclusion about .NET Core and what I feel its motivations were. I don’t have any special insight. In fact, after reading this, you might think I’m a bit of a conspiracy theorist, but I remember the original conversations / rationale about .NET Core two years ago and its funny to see how — whether intentionally or because everyone got buried in the details and forgot why they’re doing this — the messaging has changed.
.NET Core is all about anticipating war with other cloud vendors. In these early years of innovation and competition and pricing wars, the fastest, leanest cloud vendor will win. The winning strategy: keep your costs down (maximize your existing investments in hardware and facilities) and increase functionality agility (reduce the time it takes to get an idea from whiteboard into NuGet) and re-engage developers on other platforms with best of breed platform and tooling.
More specifically, there’s two parts to this:
First, .NET Core will allow Microsoft to host more applications without purchasing/managing more physical hardware. Have you seen pictures inside of a Microsoft Azure data center (Bing it!)? It’s mind-blowingly cool. I can’t even begin to imagine how much one of those things cost to build and operate. At some point, the bean counters will ask the engineers to squeeze out more performance from each data center to maximize profit. The .NET Framework wasn’t originally built with the cloud in mind and it organically grew as customers demanded more features. By re-writing the platform to require less bits on hard drives and in memory, you have an opportunity to re-write the bottom line costs of Azure.
Second, .NET Core allows greater access to Azure regardless of your chosen client or server OS. Why did Microsoft finally embrace Linux? Because they figured out how to monetize it! Microsoft has become a fancy web host. As a web host, they can host Windows machines or Linux machines — whatever the customer prefers. Furthermore, many web developers have purchased Macs. If you’re Microsoft, do you just write off all of those developers forever? No, you offer them tools for their platforms. You offer them environments they’re comfortable in. Because you want them to host their apps on Azure.
There may be other tangential benefits for developers and Microsoft (although at the moment, the state of affairs is rather confusing … I’ll have more to say about that later) what with all the versions, new acronyms, tooling, etc. But .NET Core is fundamentally a business investment in a Microsoft driven by profits from cloud based computing.
The Focus of .NET Core
I was reading through all the materials, I kept seeing several ideas keep popping up. I would suggest these are the technical philosophies that helped them achieve those business goals:
– .NET Core supports a “pay to play model” – Instead of one monolothic framework with a bunch of interdependencies that require you have a bunch of massive DLLs loaded into memory even when you need to do something simple, you now have hundreds of tiny NuGet packages each with a tiny API that can be updated independently of each other, where interdependencies have been intentionally minimized. Fortunately, this is somewhat simplified through the definition of meta-packages and frameworks, which you can think of as “families” of packages that work together (but still maintain their autonomy) for the sake of your sanity — so you don’t have to go to NuGet every 10 seconds.
– .NET Core is written with a focus on “portability” between operating systems – There’s a huge effort to keep everything “operating system agnostic”. To that end, there’s a thin execution layer for each operating system written in C++ or C, but then everything else in the execution and library stack is written in C# and works cross platform. Your code is compiled into IL on your dev machine (just like before) and it’s JIT compiled when executed the first time on the production machine (just like before). You can also pre-compile targeting a specific operating system, but you must compile on a build box running that specific operating system.
You see “portability” at a versioning level, too. You can choose to deploy your package as a “portable app” — essentially a .DLL, like myApp.dll — which relies on the version of the .NET Core Framework already running on the target deployment system. Or, you can create a “self-contained application” which packages up the .NET Core runtime itself, an executable context (on Windows, myApp.exe) and your app (myApp.dll).
Furthermore, you see “portability” with regards to the portability of custom class libraries across .NET platforms. I’ve been learning about the “.NET Standard” — I guess it’s been around a while, although frankly it’s really just come into my consciousness recently. Hey, I’m still learning all of this stuff, too! Similar to how C# and .NET were ECMA standards (thus Mono was able to implement them cross platform), “.NET Standard” standardizes which APIs (types and functionality) must be present in a platform’s class library to conform to a given version of the standard. Check this out:
** Scroll down to: “.NET Platforms Support”.
There’s A LOT of effort syncing up .NET Standard version to the various versions of the .NET Framework’s Base Class Library, UWP, Mono/Xamarin, Windows, Windows Phone, Silverlight, etc. Of course, the main point of this is the focus on .NET Core’s library known as “CoreFX”. This standardization essentially allows you to create a class library and target a particular .NET Standard Version. This allows you to build your class library making it portable across different application types. In other words, .NET Standard is the new “Portable Class Libraries”.
.NET Core Under the Hood
The architecture / internals of .NET Core is pretty amazing. If you have 20 minutes, read this:
** Don’t space out … stick with it until you hit the section “Architecture”.
Next, read this … it’s the best I’ve read:
Finally, My Notes
Admittedly, these may seem random … these quotes were collected because I found them to contain important ideas or key distinctions I was unaware of up until I took the time to read more closely. I hope they benefit you, but moreover, the links should provide a good jumping off point for further exploration.
“CoreFX” – .NET Core foundational libraries. Classes for collections, file systems, console. XML, async, etc.
CLI = Command Line Interface
On Targetting Versions of .NET
See that table beneath text “How to target the .NET Standard”
You can deploy your .NET Core app in either of two ways:+
As a portable app. A portable app relies on a shared system-wide version of the .NET Core framework that is present on a system. Portable applications are .dll files that can be launched by using the dotnet utility from the command line. For example, dotnet app.dll runs a portable application named app.
As a self-contained application. All components, including .NET Core itself, are included with the application and are isolated from other .NET Core applications. Self-contained applications include an executable (such as app.exe on Windows platforms for a self-contained application named app), which is a renamed version of the platform-specific .NET Core host, and a .dll file (such as app.dll), which is the actual application.
On Creating NuGet Packages
transitive dependencies; that is, a project which depends on another project, you’ll need to make sure to restore packages for your entire solution with the dotnet restore command before creating a NuGet package. Failing to do so will result in the dotnet pack command to not work properly.
On the RID (Runtime IDentifier) Catalog
RID is short for Runtime IDentifier. RIDs are used to identify target operating systems where an application or asset (that is, assembly) will run. They look like this: “ubuntu.14.04-x64”, “win7-x64”, “osx.10.11-x64”. For the packages with native dependencies, it will designate on which platforms the package can be restored.
On the .NET Core Tools
The .NET Core CLI is a new foundational cross-platform toolchain for developing .NET Core applications. It is “foundational” because it is the primary layer on which other, higher-level tools, such as Integrated Development Environments (IDEs), editors and build orchestrators can build on.
It is also cross-platform by default and has the same surface area on each of the supported platforms. This means that when you learn how to use the tooling, you can use it the same way from any of the supported platforms.
On the 1.1 Roadmap
Planned 1.1 Features
Broader API support, bringing parity with .NET Framework and Mono at the BCL level.
Transition to MSBuild and csproj as the default build system and project model for all versions of .NET.
The 1.0 release is accompanied with a preview version of the Visual Studio and command-line tooling. The tooling should reach RTM quality with version 1.1 of the .NET Core runtime in Fall 2016.
.NET Core is split into a set of packages, which provide primitives, higher-level data types, app composition types and common utilities. Each of these packages represent a single assembly of the same name. For example, System.Runtime contains System.Runtime.dll.
There are advantages to defining packages in a fine-grained manner:
Fine-grained packages can ship on their own schedule with relatively limited testing of other packages.
Fine-grained packages can provide differing OS and CPU support.
Fine-grained packages can have dependencies specific to only one library.
Apps are smaller because unreferenced packages don’t become part of the app distribution.
Some of these benefits are only used in certain circumstances. For example, NET Core packages will typically ship on the same schedule with the same platform support. In the case of servicing, fixes can be distributed and installed as small single package updates. Due to the narrow scope of change, the validation and time to make a fix available is limited to what is needed for a single library.
The following is a list of the key NuGet packages for .NET Core:
System.Runtime – The most fundamental .NET Core package, including Object, String, Array, Action and IList.
System.Collections – A set of (primarily) generic collections, including List and Dictionary<K,V>.
System.Net.Http – A set of types for HTTP network communication, including HttpClient and HttpResponseMessage.
System.IO.FileSystem – A set of types for reading and writing to local or networked disk-based storage, including File and Directory.
System.Linq – A set of types for querying objects, including Enumerable and ILookup<TKey, TElement>;.
System.Reflection – A set of types for loading, inspecting and activating types, including Assembly, TypeInfo and MethodInfo.
Packages are referenced in project.json. In the example below, the System.Runtime package is referenced.
In most cases, you will not reference the lower-level .NET Core packages directly since you’ll end up with too many packages to manage. Instead, you’ll reference a metapackage.
Metapackages are a NuGet package convention for describing a set of packages that are meaningful together. They represent this set of packages by making them dependencies. They can optionally establish a framework for this set of packages by specifying a framework.
There antages to using metapackages:
Provides a convenient user experience to reference a large set of fine-grained packages.
Defines a set of packages (including specific versions) that are tested and work well together.
On Changes to Project.json
We plan to enhance .csproj to support the missing functionality:
No listing of files in the project system
CLI tool for doing any operations on the project file, for most scenarios you would not edit the file
Build packages directly from the project
And because all of .NET uses the same tooling, we can then look at enhancing MSBuild.
On the .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 .NET Standard Library enables the following key scenarios:
Defines uniform set of BCL APIs for all .NET platforms to implement, independent of workload.
Enables developers to produce portable libraries that are usable across .NET runtimes, using this same set of APIs.
Reduces and hopefully eliminates conditional compilation of shared source due to .NET APIs, only for OS APIs.
Comparison to Portable Class Libraries
.NET Standard Library can be thought of as the next generation of Portable Class Libraries (PCL). The .NET Standard Library improves on 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”.
The .NET Standard Library and PCL profiles were created for similar purposes but also differ in key ways.
Defines APIs that can be used for binary code sharing.
The .NET Standard Library is a curated set of APIs, while PCL profiles are defined by intersections of existing platforms.
The .NET Standard Library linearly versions, while PCL profiles do not.
PCL profiles represents Microsoft platforms while the .NET Standard Library is agnostic to platform.
The spec is not singular, but an incrementally growing and linearly versioned set of APIs. The first version of the standard establishes a baseline set of APIs. Subsequent versions add APIs and inherit APIs defined by previous versions. There is no established provision for removing APIs from the standard.
The .NET Standard Library is not specific to any one .NET runtime, nor does it match the versioning scheme of any of those runtimes.
APIs added to any of the runtimes (such as, .NET Framework, .NET Core and Mono) can be considered as candidates to add to the specification, particularly if they are thought to be fundamental in nature. New versions of the .NET Standard Library are created based on .NET runtime releases, enabling you to target new APIs from a .NET Standard PCL. The versioning mechanics are described in more detail in .NET Core Versioning.