It's been a long journey, but ASP.NET Core and .NET Core were v1.0 releases in June of 2016. A lot's changed since I wrote my first articles for ASP.NET vNext in CODE Magazine (Jan/Feb 2015). In this article, I'm going to revisit the high-level architecture of .NET Core and ASP.NET Core to help you understand how the main architectural pieces fit together. I'll also demonstrate how to get started, purposefully using lower-level command line tools to create a simple application from scratch and add framework features one at a time in order to demonstrate how the framework is put together.
Version 1.0 of .NET Core and ASP.NET Core will very much be a 1.0 product. The platform will grow and improve from there.
ASP.NET and .NET Core Today
After a lot of anticipation and delays, ASP.NET Core and .NET Core 1.0 have finally been released. The last couple of years have been tough if you've been keeping up with Microsoft's ever-changing architectures for the new .NET platform. The .NET Core platform has gone through three major platform updates since this journey to reboot .NET started nearly three years ago, but now it finally seems that all of this churn is coming together in a much clearer vision of where .NET is headed. Even so, not all of this unification and integration has come to fruition with the RTM release because more post-RTM changes have already been announced.
This initial release is about drawing a line in the sand and having a stable base on top of which, additional frameworks, components and updated features can be built. It's also a stake in the ground to let people start using an officially released version of these new tools. Microsoft is quite adamant in saying that although a lot more changes are coming in the future both for .NET Core and ASP.NET Core, these changes are not going to be as drastic as some of the changes that we can see in the latest release. Instead, future changes are supposed to light up new functionality that won't break backward compatibility.
Version 1.0 was released with a solid tooling infrastructure, a solid but “snapshot in time” version of the .NET Core framework and a fully functional ASP.NET application layer. Of these major components, the one most in flux is .NET Core, which is going to gain additional features to bring it closer to the full .NET Framework. The v1.0 release is meant to bring a production-ready and fully supported release of the .NET Core and ASP.NET Core systems so that early adopters have a solid, base-production framework that's officially supported by Microsoft to deploy on.
With .NET Core and ASP.NET Core, Microsoft is on a mission to build a unified .NET base library that provides a common .NET baseline that all platforms running .NET can take advantage of.
Microsoft proposes to create a new .NET Standard, which defines a common base layer that a platform should support. They plan to implement this new .NET Standard across the runtimes that Microsoft itself publishes. It's very likely that ultimately, .NET Core, which is an implementation of .NET Standard, will figure heavily in this vision, with .NET Core providing a single implementation that can run on many platforms. We're already seeing that with support for .NET Core on Windows, Mac, and Linux for the server version. But there are more OSs to worry about - Xamarin's mobile platforms running Mono, UWP Windows application, game development platforms and the desktop OS implementations that are currently served by Mono. As of the RTM release, the landscape is starting to come together with the common infrastructure layer shown in Figure 1.
The .NET Common Infrastructure
On the bottom of the stack, you have the common infrastructure and tools that provide the base rock of the platform: The Roslyn Compiler platform, C#, VB.NET, F#, and the runtime loaders and the new dotnet.exe-based command line tools. The important thing about this base is that it provides a single set of tools to get started with .NET. In this scenario, .NET is installed from a single .NET SDK. Once the SDK is installed. you can create a new project from the command line, compile it, and run it, all with a few very simple steps. As part of configuration, you can specify which version of the .NET platform you want to target and the compilers will figure out how to build and run the proper version(s) using the correct runtimes. You don't need Visual Studio or to install a host of other .NET SDKs - all that's needed is the single .NET SDK that gets you everything you need to do it all. This common set of tools can be used to build, package, and deploy applications, as I'll show later in this article.
This may not seem very significant at first glance, but if you compare this to the process of getting started with .NET today, it's a big step forward. Rather than installing the huge monster that is Visual Studio and that gives you everything under the sun, or installing a host of disparate SDKs and support tools, a single reasonably sized SDK install gets you everything you need to build and run any kind of .NET application. You can get started with .NET after a few minutes of download and a short install.
To be clear: We're not there yet, as support for .NET Standard currently is limited to .NET Core applications at the moment, but if you're building apps with ASP.NET Core or .NET Core, you can see and try out how this process works and I'll show you how in this article.
The dotnet command line tools combine compiler, runtime loaders, package management, and deployment into a single, easy-to-use environment.
An important component of the new .NET infrastructure is the dotnet
command line interface (CLI) that lets you do all build- and run-related tasks via command line tooling. When you install the SDK (see the Getting .NET sidebar), the dotnet
command line tool is referenced in your path. You can say dotnet new
to scaffold a simple HelloWorld console project that you can modify and edit in a plain text editor. You can then do dotnet restore
to restore missing NuGet packages, including runtimes, followed by dotnet run
to execute the application. Both dotnet build
and dotnet pack
can build and package your application and component packages, and dotnet publish
can deploy an application to a server or other packing location. This simple command line front-end interface wraps up a ton of disparate tooling under a single installable package, which makes it much easier and quicker to get started with .NET. And to top it off, these tools work the same on all of the operating systems that .NET now supports: Windows, Mac, and Linux. This tooling significantly lowers the barrier of entry to starting with .NET regardless of the platform you're using.
Base Class Libraries
In the current state of .NET, there are a lot of different yet similar .NET runtimes. There's the full framework .NET library, the .NET Core library and there's Mono that's used for mobile and Mac development with Xamarin. Then there are various older libraries like Silverlight, Windows Phone 8 and 8.1, etc. There are tons of libraries, all similar and providing common .NET functionality, but all with different levels of feature support. For developers and especially component developers, it hasn't been a major headache to support so many variations of .NET.
Today, .NET Core is the key for Microsoft's journey to moving to a single .NET Standard Library, which is meant to provide a core base line for the .NET Framework across all platforms, which is shown in Figure 2. We're not yet there obviously, but a .NET Core stack with ASP.NET gives you a good glimpse of what development will look like for all platforms using .NET Standard. There's a lot of discussion around this today and even though .NET Core is currently in v1.0, there's already talk that .NET Core will continue to gain a lot more full framework .NET features in the future.
The .NET Standard Library will eventually replace the multitude of .NET runtime implementations with a common baseline implementation.
Application Libraries
The push for a standard .NET library makes it much clearer where the boundaries are between the base library and the application layer. Because the standard library has to be able to run cross-platform, a lot of feature functionality, like OS-specific library features, have to move higher up the stack into the application frameworks. To be clear, what the .NET Standard Library addresses is akin to what was called the BCL (Base Class Library: the stuff in mscorlib.dll) of old. Additional services that traditionally were services of the FCL (Function Class Library) have to move to the specific framework/application layer.
For the full .NET Framework, this includes common application frameworks that we use to build desktop and server applications. WPF, WinForms, Console apps, Services, and ASP.NET apps of all stripes. Note that the full framework doesn't go away. It will continue to be delivered and improved on with its Windows-centric focus and support of all the Windows-specific and rich application features that you're using today. This means that you're not required to move to .NET Core or ASP.NET Core; your existing applications and new applications built with ASP.NET MVC 5 using the System.Web-based ASP.NET stack will continue to work and are still viable for new projects going forward.
It's clear that .NET Core is where most of the excitement is because that's where most of the new features of .NET are being tried out and implemented from the Microsoft side. ASP.NET Core is the application framework that's getting a lot of attention because it's one of the first big frameworks built on top of the .NET Core framework using the current .NET Standard Library implementation.
Although Figure 2 doesn't describe this use case well, ASP.NET Core can also use the full .NET Framework to run ASP.NET Core applications. But even if it's possible to do, I think that this is not the optimal use case for ASP.NET Core. If you're considering ASP.NET Core, most likely you're considering it for its new features, like reduced footprint, high performance infrastructure, and the cross-platform capabilities that aren't directly available to full framework ASP.NET Core applications. To take full advantage of all that ASP.NET Core has to offer, you really have to use .NET Core.
Finally, on the right, we have Xamarin and the various client and mobile platforms which, to date, are based on Mono. Mono is a port of the full .NET Framework that runs on Mac, Linux, Android, and iOS. Because Microsoft has acquired Xamarin recently, Mono and .NET Core are starting to converge and it's expected that eventually Xamarin -based tools will use .NET Standard as well. The idea is to bring all platforms together under a single standard library so you can get the consistency of a single implementation.
The take-away from all of this is that the .NET platform on various devices and operating systems is becoming much more unified. As we now know, this hasn't all happened with the .NET Core and ASP.NET 1.0 releases this summer. There will be additional, hopefully, incremental and non-breaking improvements that bring .NET Core closer to what's in the current full framework BCL. What all this means is that you can build on .NET Core today, and expect more features to light up in the future, so things will get easier as time goes on. Whether you want to be an early adopter with the less featured framework now, or jump in later is going to be a decision that you have to make on your own.
Now that you have an idea of the overall architecture that you end up using with ASP.NET Core, let's jump in and do something practical.
Getting Started with .NET Core
To demonstrate the new command-line tooling, let's quickly demonstrate how to create a new .NET application using the command line tooling. I'll use Windows here, but note that you can also do the same thing on a Mac or Linux computer if the .NET SDK is installed. The steps are the same, so you can follow along on a Mac or Linux.
Start by downloading the .NET SDK from http://dot.net. Click on the .NET Core link and follow the installation instructions for your platform. To create a new project, you can follow the directions from that page. Figure 3 shows the command line output as you create the new project.
The steps are:
- Create a new folder.
- Change path to the folder.
- Run dotnet new to create a new project.
- Run dotnet restore to bring down NuGet packages required.
- Run dotnet run to run the application.
As you can see in Figure 3, the output of this console application is dumped to the console. You've just created and run a .NET application in three simple commands.
You can create and run a boilerplate .NET application with three simple commands from the command line.
You can now open the program.cs
file that was generated and change the code. For example, change the Console.WriteLine()
to add a date and time:
Console.WriteLine("Hello World! Time is: " +
DateTime.Now);
Back at the command line, now run dotnet run and you should see the updated message, including the time, displayed.
The cool thing about this isn't so much that you can do this from the command line, but the fact that it's very easy to get started. Download a relatively small SDK, install it, scaffold a base project, and then use a text editor to make a change to your code and run.
That isn't to say that you're going to have to build your application from the command line now (see the Command Line versus Visual Studio sidebar). In fact, if you install the Visual Studio tooling for ASP.NET Core, you get Visual Studio integration like you'd expect, so you can use the rich Visual Studio editor and your favorite tools and extensions to build your applications. But behind the scenes, Visual Studio calls into these same command line tools to compile your project. This opens up the build process to tooling or your own build process management, because you have easy access to the same tools that Visual Studio uses to build your project.
What about ASP.NET?
Okay, so far, I've talked about a lot of general .NET stuff, but what does all of that have to do with ASP.NET? Well, ASP.NET Core projects are console applications that launch a Web server execution environment and use this very same infrastructure that I've talked about in the last example.
Let's turn the lowly HelloWorld application into a much more desirable HelloWorld Web application. Change out the Main()
method with the code shown in Listing 1.
Listing 1: A HelloWorld ASP.NET Core Application
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync(
"Hello World. The Time is: " +
DateTime.Now);
});
}
}
You'll also need to make a small change in project.json
to add references for a couple of dependencies that pull in the Kestrel Web server and HTTP extensions:
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
},
Now, go back to the command line and run the application again and you'll get a prompt that states that the Web server has been started on port 5000. Navigate to http://localhost:5000
and...voila: HelloWorld from ASP.NET Core. You'll get a plain text string:
Hello World. The Time is: 6/3/2016 2:32:20 PM
This is super trivial, but it highlights the basic process of how an ASP.NET Core application bootstraps on top of the .NET Core runtime. You can see that the same Console application structure is used for ASP.NET. There's no magic; you have full control all the way from the initial bootstrapping of the application, through startup configuration, and into the full ASP.NET pipeline.
ASP.NET Core applications are self-contained Console applications that self-host the Kestrel Web server.
Middleware
To make ASP.NET do something useful, you need to use middleware. Middleware is essentially what we thought of as HttpHandlers and HttpModules in older versions of ASP.NET; it's the stuff that makes things happen in an ASP.NET Core Web application.
The code in the Startup
class above uses the App.Run()
middleware handler, which is roughly the equivalent of an HttpHandler in classic ASP.NET. When App.Run()
gets fired, it's expected to handle the inbound request completely and return a result. You can think of App.Run()
as a last-resort handler that's fired when nothing else has handled the request. In the example above, there's nothing else handling requests, so the App.Run()
handler is fired and you see the HelloWorld message.
If App.Run()
is like an HTTP handler, App.Use()
is like an HttpModule
. App.Use()
handlers can be chained together and are fired in the order that they're assigned. Unlike HttpModules, they can handle before- and after-request processing operations. Let's modify the HelloWorld sample with an App.Use()
handler that hooks in pre- and post-processing for each request on the server.
Add the following to the Configure
method just before the App.Run()
implementation:
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("PreProcessing");
await next();
await context.Response.WriteAsync("PostProcessing");
});
If you stop the server with Ctrl-C and rerun it with dotnet run, you should now get:
Pre Processing...Hello World.
The Time is: 6/3/2016 3:10:19 PM Post Processing...
As you can see, the App.Use()
middleware has wrapped itself around the App.Run()
call. The middleware pipeline strings together all pieces of middleware one after the other, and each piece of middleware calls the next in the chain. The middleware handlers are executed in order going in, and then in reverse order going out. Again, if you think of the analogy with older ASP.NET versions, you can think of it as pre- and post-request handler processing. All of the pre-handlers fire until the pipeline has no more middleware or an operation doesn't call next()
(like our App.Run()
handler), and then it reverses and walks the chain the other way. Note that middleware can handle both the inbound and outbound processing with a single middleware implementation. It's a simple and elegant, but very low-level concept.
Hooking up ASP.NET MVC
App.Use()
and App.Run()
are very low-level, akin to creating HttpHandlers and HttpModules and generally not the level at which you build applications. App.Use()
is typically implemented by application frameworks like ASP.NET MVC or utility features like Authentication modules, state managers, or loggers hook into.
When you build a Web application, you tend to use much higher abstractions, such as ASP.NET MVC. Rather than implementing middleware yourself, ASP.NET MVC provides middleware integration with a configuration link that hooks up the MVC framework you then use to build your application. Once configured, building a typical ASP.NET Core MVC application is fairly similar to the way you built older ASP.NET MVC applications.
To demonstrate, let's add ASP.NET MVC to the startup sample and create a simple API endpoint that returns some JSON data to show that it works.
The first step is to get the right packages loaded. Add the following to your dependencies in project.json
:
"Microsoft.AspNetCore.Mvc": "1.0.0",
Next, add the following configuration code to the Startup
class:
public class Startup
{
public void ConfigureServices(
IServiceCollection services)
{
services.AddMvc();
}
public void Configure(
IApplicationBuilder app)
{
app.UseMvc();
}
}
This code sets up the required dependency injection in ConfigureServices()
and then enables MVC for the application in Configure()
. This is a common pattern: ConfigureServers
() initializes dependency injection services, typically with configuration settings that are set up so that dependency injection creates types with the right configuration settings when injected. Configure()
then adjusts the behavior of the middleware, which is usually a more specific wrapper around App.Use()
. Methods like app.AddMvc()
and app.UseMvc()
are extension methods that are provided by the specific implementation; in this case, provided by the Microsoft.AspNetCore.Mvc
package.
In the case of MVC, there's no explicit configuration required, but other providers like EntityFramework or a logging provider require that you set up a connection string and data provider, for example.
All that's left now is to create a controller. I'm going to start with an API request and I'll create a good old HelloWorld API request. To do this, create a class like this in the same program.cs
file you used earlier:
public class HelloWorldController
{
[HttpGet("api/helloworld")]
public object HelloWorld()
{
return new
{
message = "Hello World", time = DateTime.Now
};
}
}
Now go back to the command line and again do dotnet run. Then navigate to http://localhost:5000/api/helloworld
. You should now get:
{
message: "Hello World",
time: "2016-06-03T15:39:18.339626-07:00"
}
Note that the controller implementation doesn't derive from Controller. It's a POCO object and ASP.NET Core can figure out to call the controller's method based on the name of the class by the Controller postfix convention. Unless you need specific features of the Controller base class, you don't have to inherit from it.
The MVC engine in ASP.NET Core combines MVC and WebAPI in a single framework.
Adding MVC and Razor Views
Finally, let's add another method to the controller and render a Helloworld View page. To do this, you need to make a configuration change. Set the UseContentRoot()
in the Main()
startup to provide a root path for the application:
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseContentRoot(
Directory.GetCurrentDirectory())
.UseKestrel()
.UseStartup<Startup>()
.Build();
host.Run();
}
Without this configuration step, MVC can't find Views referenced from your Controller code.
Now you can add a Controller
method to the existing Helloworld
controller. Note that ASP.NET Core's MVC version supports both API and MVC endpoints in the same controller, so you don't need to create a separate controller class (although generally, it's a good idea to separate API and UI endpoints):
[HttpGet("helloworld")]
public ActionResult HelloworldMvc()
{
ViewBag.Message = "Hello world!";
ViewBag.Time = DateTime.Now;
return View("helloworld");
//return View("~/helloworld.cshtml");
}
There's one more change required on this controller: When I showed the API request, the controller didn't inherit from Controller
and was a POCO object. For running the above example, you're relying on some controller features like ViewBag
and the View()
method, so you have to inherit from Controller
to get access to these features. Change the Controller
class definition to:
public class HelloworldController : Controller
Now, all you need is a View. ASP.NET Core MVC uses standard View discovery logic by default, so it's looking in the /Views/Helloworld
folder for a HelloworldMvc.cshtml
view. Instead, create a helloworld.cshtml
view, which is reflected by explicitly specifying the requested view in the View(“helloworld”) call.
The view is ultra simple and just used to demonstrate that it works:
Message:
@ViewBag.Message
<hr/>
Time:
@ViewBag.Time
This simply echoes out the Viewbag values you passed from the controller as Razor expressions. Views work as you would expect, supporting the full Razor/C# syntax. I'm only setting and accessing ViewBag values here, but of course you can also pass a full-blown model object into the View just as you could in earlier versions of MVC.
When you run the application now again with dotnet run you should see:
Message: Hello world!
---
Time: 6/3/2016 9:29:12 PM
At this point, you started with a plain Console application, then added a low-level ASP.NET Core handler implementation, followed by an MVC API implementation, and finally an MVC View-based implementation. All of the code required to do this is in a single small code file of about 60 lines of code, as shown in Listing 2 (also see the Samples on GitHub sidebar).
Listing 2: Complete ASP.NET Sample discussed in this Article
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseKestrel()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
public class Startup
{
public Startup(IHostingEnvironment env)
{
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseMvc();
// this becomes the last handler in the chain
app.Run(async (context) =>
{
await context.Response.WriteAsync(
"Hello World. The Time is: " +
DateTime.Now +
" (App.Run() fallback handler)");
});
}
}
public class HelloworldController : Controller
{
private IHostingEnvironment Environment;
public HelloworldController(IHostingEnvironment env)
{
Environment = env;
}
[HttpGet("api/helloworld")]
public object Helloworld()
{
return new
{
message = "Hello World",
time = DateTime.Now
};
}
[HttpGet("helloworld")]
public ActionResult HelloworldMvc()
{
ViewBag.Message = "Hello world!";
ViewBag.Time = DateTime.Now;
return View("helloworld");
//return View("~/helloworld.cshtml");
}
}
Where's IIS?
You may have noticed that I just ran a console application on Windows. There's no IIS or other external Web server hosting the application. What's happening is that ASP.NET Core uses a self-hosted Web Server (Kestrel, which is ASP.NET's high-performance built-in Web Server) in a console application. The application is self-contained, running with its own private copy of .NET and its own Web server, which makes the application very portable. It's portable in terms of deployment, but also portable in terms of platform; you can host this application on multiple operating systems and, assuming that you didn't use any platform-specific features, the application will run on both using the same Kestrel Web server.
The application is self-hosted and doesn't directly need a Web server to run. However, it's not recommended to run Kestrel directly over the Internet. Instead, it's recommended to use a front-end reverse proxy, like IIS on Windows or nginx or similar on Linux, to front the IIS Web server. The reverse proxy provides multiple bindings to the open HTTP (80) and SSL (443) ports as well as potential load balancing and other request routing logic.
On Windows, IIS additionally provides process management, which can ensure that your application always stays running. If your application crashes, it's automatically restarted, much in the same way that the Windows Activation Service (WAS) does today with IIS Application Pools. Figure 4 shows the interaction between IIS and your ASP.NET Core application.
There's a native AspNetCoreModule
that's installed in IIS and handles ASP.NET Core routing and process management. This native module is lightweight and still requires an Application Pool but no .NET runtime, because IIS doesn't do any direct request processing, but rather acts as a proxy to forward requests to your application.
Another benefit with this set up is that you can more easily set up load balancing and you can have a single server that requires an SSL certificate while the backplane runs over plain HTTP. You can also hide your application Web server from the Internet because only the IIS server needs to be publicly exposed.
When running ASP.NET Core on Windows, IIS is relegated to the job of reverse proxying and process management.
Running on a Mac
So far, I've run this little walk-through exclusively on the Windows computer, but I can take this entire application and now move it over and run it on the Mac without any changes to the code!
To make this happen, I'm pushing the project to source control on GitHub at https://github.com/RickStrahl/AspNetCoreFromScratchSample.
The first thing that has to happen on the Mac side is to make sure that the .NET SDK is installed. If you haven't installed it yet, you can find it at http://dot.net. Follow the simple and quick instructions there for installation and after a few minutes, you should have a full install of .NET with the same feature functionality that I've discussed so far in this article. In fact, all of the steps I've run through so far (except for the section on IIS) apply just the same on the Mac - or on Linux, for that matter.
Once the SDK is installed, you can clone the repository from GitHub into any folder on your Mac or Linux computer. Once you've done that, you can issue the following commands:
git clone https://github.com/RickStrahl/AspNetCoreFromScratchSample.git
dotnet restore
dotnet run
You can see the results in Figure 5, which shows the packages being downloaded and installed, the compiler building the application, and then running the Web server on port 5000. You can then navigate to http://localhost:5000/api/helloworld
, http://localhost/helloworld
, and http://localhost/`` to see the API, MVC, and raw
App.Run()` endpoints.
Although it's not super practical or even realistic to have applications that run on multiple platforms, it's pretty cool to see this work without any special effort or any code or configuration changes. You're no longer limited to just running on Windows, which is exciting, as it opens many new opportunities for .NET code.
Granted, the examples are just about the most basic thing you can build, so it's not too surprising that the code works across platforms. But I've also taken a few more involved data-centric applications and moved them over to the Mac. I was surprised to find them working just as well. As long as you can stay away or isolate platform-specific features in your application, .NET Core code just runs on multiple platforms now.
You can take a .NET Core application developed on Windows, restore it on a Mac or Linux, and it just runs.
Core Analysis
It's been a long journey for .NET Core and ASP.NET Core, with a lot of false starts and a few tribulations along the way. But with the v1.0 release, the platform has finally found its stride in delivering on the promise of providing a more unified, more lightweight, and truly cross-platform .NET Framework.
Without a doubt, the new .NET Core platform will grow and continue to get richer. Version 1.0 is very much a 1.0 product with all of the warts and missing features that you'd expect from a 1.0 product. But now, there's at least a common vision of where .NET is headed going forward, which up until very recently, was sadly missing. There'll be changes going forward, but those changes are going to be primarily enhancements to existing functionality and features, rather than the groundbreaking, change-everything upheavals that have occurred several times during this long pre-release cycle. It's taken Microsoft some time to find the right direction, but personally, I prefer that this process takes time, rather than rushing and ending up with an incomplete or difficult-to-use framework. From what I see today in v1.0, Microsoft is on the right path with the direction of .NET. You can get done what needs to get done to build applications with the feature set available.
All that said, adoption of ASP.NET Core right at the v1.0 release is not a slam dunk. There are a lot of decisions to be made by developers like you and me to decide whether .NET Core and ASP.NET Core are the right choice for applications initially. There are still a lot of missing features in the framework, especially when it comes to support of third-party libraries. If you need a particular library that hasn't been ported, it might be very difficult to work around that library. It's going to take time to get parity in this space, especially given the recent announcements that the post RTM .NET Standard enhancements will bring more features back that will make porting full .NET Framework code easier. Nobody wants to do a difficult port now, if an easier port based on a richer feature set in a few months will be available to make the process much smoother.
In the end, it all depends on the type of application you're building and what dependencies your application has. For example, if you plan to host your application on Linux and you're building small micro services that have small footprint and basic integration needs, ASP.NET Core is going to be a great choice. If you're building a Web application that relies on a ton of Windows platform features, such as COM Interop, Active Directory, WMI etc., or uses a specific library that hasn't been ported to .NET Core yet, it might not be such a great idea to jump right away. Either way, it's a good idea to review carefully what your application requirements are, and whether all of the external dependencies and integrations you need to make your application work are available in .NET Core and ASP.NET Core initially.
Summing up
I've tackled an overview of the .NET Core and ASP.NET Core platforms that should give you a good idea of how the pieces fit together. The new dotnet tooling and single-point SDK installation go a long way toward making .NET more accessible not only to .NET developers but also those who are going to try .NET for the first time. Already, .NET Core provides impressive cross-platform functionality and the feature set is reasonably complete, with more features that bring it closer to full framework BCL functionality coming soon. I didn't spend a lot of time on ASP.NET Core, but it currently feels very stable and there are many new features that make building MVC and API applications easier. I'll talk more about these aspects in my next article in CODE Magazine.
In this article, I've purposefully stuck to the low-level aspects of creating an application using only the command line tooling. This isn't because I love command line tools, or because I plan on building everything using just this low-level tooling. I'm quite happy using Visual Studio and the rich tooling and developer support it provides in the IDE, thank you very much. I wanted to use this lower-level approach because it demonstrates so well how an application is put together. I hope you found this as useful as I found it when I worked through my exploration of .NET Core and ASP.NET Core.
In the next article, I'll pick up where I left off this time, by creating a more realistic sample application to demonstrate what you can expect when creating a more realistic ASP.NET Core application with data access and some non-Helloworld UI. Until then, give ASP.NET Core a try and see what you think.