So, What is Microsoft.NETCore.App anyways?

Getting my head clear on the new ASP.NET Core platform is taking a lot longer than I anticipated. A lot has to do with dotnet core going cross platform and having to support many different eco systems. Key to this understanding is getting the model right on how dependencies are evaluated based on how you target your application.

I have tried in the post to capture some of the paths I have discovered myself, but frankly, it has left me open to more questions than answers. So, I'll leave this here for now, but a much better discussion of this model can be found here and also in Damian and David's talk on Channel9 before the package renaming exercise.

Here is my summary:

When you create a new dotnet app with dotnet new, you create an app that depends on Microsoft.NETCore.App. Have a look at the newly creates project.json file:

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },
  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.0-rc2-3002702"
    }
  },
  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}

This is everything that you need to build a basic cross platform dot net application that could possible run on the dotnet run time on Windows, Mac or Linux, and it could also run on the Microsoft Full fat existing .NET Framework.

I say possibly, because it depends on what frameworks you actually target when you build. In the example above we are only targeting netcoreapp1.0.

Now, unfortunately, not all the third part libraries understand netcoreapp1.0 yet, so the import section is a workaround until we do.

So, what is the netcoreapp1.0 suppose to give you? It's a meta package that bundles up other packages that makde up the cross platform dot net core application model. Browse to the dotnet MyGet feed and you'll find it:

Looking at the description we see that it's :

A set of .NET API's that are included in the default .NET Core application model.

If we look inside, we find that it's got a bunch of other dependencies. I guess it's the modern day equivalent of an assembly that bundles up a bunch of dlls, but it's a meta package, because it doesn't contain any code, just references to another 40 packages. Have a look for yourself (here is just a sample):

 <dependencies>
      <group targetFramework=".NETCoreApp1.0">
        <dependency id="Libuv" ..." />
        <dependency id="Microsoft.CodeAnalysis.CSharp" ... />
        <dependency id="Microsoft.CodeAnalysis.VisualBasic"... />
        <dependency id="Microsoft.CSharp".. />
        <dependency id="Microsoft.NETCore.DotNetHostPolicy" ... />
        <dependency id="Microsoft.NETCore.Runtime.CoreCLR" ... />
        <dependency id="Microsoft.VisualBasic" ... />
        <dependency id="NETStandard.Library" ... />
          ... other dependencies

      </group>
    </dependencies>

So, to me it looks like a way to define the standard set of references that are added to a project. For example in the old .net4 framework model of the world, you might see something like this if you look at the References that are automatically added to a Visual Studio Project when you "new up" a project from a template such as an MVC Web App or an Console App.

but what's this NETStandard.Library ?

        <dependency id="NETStandard.Library" ... />

It's another meta-package. Let's have a look at the description of the NETStandard.Library:

A set of standard .NET APIs that are prescribed to be used and supported together. This includes all of the APIs in the NETStandard.Platform package plus additional libraries that are core to .NET but built on top of NETStandard.Platform.

So, I'm guessing this is anothe meta-package with a bunch of dependencies? Let's have a look:

Turns out it's a bit more. It defines several groups of dependencies, namely NETStandard1.0, NETStandard1.1, NETStandard1.2 and NETStandard1.3

 <dependencies>
      <group targetFramework=".NETStandard1.0">
        <dependency id="Microsoft.NETCore.Platforms"  ...   />
        <dependency id="System.Collections" ... />
        ... other dependencies

      </group>
      <group targetFramework=".NETStandard1.1">
        <dependency id="Microsoft.NETCore.Platforms" ..    />
        <dependency id="System.Collections" ... />
        ... other dependencies

      </group>
      <group targetFramework=".NETStandard1.2">
        <dependency id="Microsoft.NETCore.Platforms"  ..   />
        <dependency id="System.Collections" ... />
        ... other dependencies

      </group>
      <group targetFramework=".NETStandard1.3">
        <dependency id="Microsoft.NETCore.Platforms" .. />
        <dependency id="Microsoft.Win32.Primitives" ... />
        <dependency id="System.AppContext"  ... />
        <dependency id="System.Collections"  ... />
        ... other dependencies

      </group>
    </dependencies>

So, when you indicate a targetFramework with a Target Framework Moniker (TFM) such as netstandard13, nugets know what packages to include.

For those that are interested, here is the Issue raised on GitHub to create the "netcoreapp1.0" TFM

Interesting that it only goes up as far as netstandard13 at the moment. Strange.

The Microsoft.TargetingPack.NETFramework.v4.6.2.1.0.1.nupkg package on the other hand contains real libraries. If you rename the nupkg extension to a .zip and unzip it, in the lib\net462 folder you will see 185 libraries, such as System.dll, System.Web.dll etc.

If we look at the NuGet GitHub repository and browse to NuGet.Client /src/NuGet.Core/NuGet.Frameworks/NuGetFrameworkFactory.cs we can see where these strings in the project.json are mapped to an actual framework:

  case "netcoreapp1.0":
  case "netcoreapp10":
      framework = FrameworkConstants.CommonFrameworks.NetCoreApp10;
      break;

Going back to the NETStandard.Library package, all the groups depend on Microsoft.NETCore.Platforms so let's have a quick look at the description.

Provides runtime information required to resolve target framework, platform, and runtime specific implementations of .NETCore packages.

Again, no dlls in the lib folder, so it's another meta-package, also doesn't refefence other dependences, but it's got a runtime.json file:

        "win7": {
            "#import": [ "win" ]
        },
        "win7-x86": {
            "#import": [ "win7", "win-x86" ]
        },
        "win7-x64": {
            "#import": [ "win7", "win-x64" ]
        },

        ... lots more stuff

        "unix": {
            "#import": [ "any" ]
        },
        "unix-x64": {
            "#import": [ "unix" ]
        },

        "osx": {
            "#import": [ "unix" ]
        },
        "osx-x64": {
            "#import": [ "osx", "unix-x64" ]
        },

        "osx.10.10": {
            "#import": [ "osx" ]
        },
        "osx.10.10-x64": {
            "#import": [ "osx.10.10", "osx-x64" ]
        },

... lots more stuff

So, what have we learned?

We started out looking at NETCore.App but there is really nothing to see there. The real interesting info is in the NetStandard library.

The .NET Platform Standard target framework is an abstract target framework that represents API surface of many frameworks and platforms.

As such .NETStandard assemblies can run on any platform that supports the .NETStandard targeted by that assembly, for example: .NET Desktop, Windows Phone, Universal Windows Platform applications, .NET Core applications. Think of it as a interface that needs to be implemented by the framework you choose to deploy your app to.

It's purpose is to provide a more concrete guarantee of binary portability to future .NET-capable platforms with an easier-to-understand platform versioning plan.
It is a replacement for the portable class library Profiles.

Prior to asp.net core RC1, you would specify what surface area API your app needs to support by adding a list of monikers for each framework version you need your app to support. e.g. portable-net40+win8+sl4+wp7

You can now specify a netstandard moniker such as netstandard1.3.

Mapping the .NET Platform Standard to platforms

In general, class libraries which target a lower .NET Platform Standard version, like 1.0, can be loaded by the largest number of existing platforms, but will have access to a smaller set of APIs. On the other hand, class libraries which target a higher .NET Platform Standard version, like 1.3, can be loaded by a smaller number of newer platforms, but will have access to a larger, more recent set of APIs.