ASP.NET Core: A More Realistic Starter Kit

ASP.NET Core is a fascinating platform with many good ideas, but in its present form (RC1)there is a culture shock for experienced ASP.NET developers to experience the effort involved in porting a realistic application. There is an obvious advantage in being able to host an application on any web server, but is this enough to compensate for losing the convenience of an integrated pipeline?

The web is suddenly awash with articles and blog posts that show how to create your first ASP.NET Core application. There is a lot of content that aims to show how the latest tooling running in Visual Studio 2015 creates for you a brand new app in a matter of seconds. The vast majority of these “getting-started” articles and posts seem very similar, and tend to emphasize how cool it is to use Bower and the command line from a Mac computer.

This article intends to talk primarily to existing ASP.NET developers, those who are used to work with Visual Studio and more familiar (or just more accustomed) to the comfort of the mouse rather than the frugality of the keyboard. The article starts with an empty ASP.NET Core project and adds, step by step, all the bells and whistles required to display a HTML page. It may be shocking at first, but in the end the overall effort required to port even a realistic ‘toy’ application is in the order of hours, assuming only a superficial familiarity with the new platform. Porting a full application is a different story and I’m not even sure that, at this time, somebody somewhere really knows how long it may take.

Let’s start by creating a brand new ASP.NET Core project in Visual Studio 2015 equipped with the RC1 bits of ASP.NET Core.

Configuring the Empty Project

An empty ASP.NET Core project is really empty, and devoid of any source file but one: startup.cs. Nicely enough, though, if you build and run it right away you get a valid response in the form of a “hello, world!” message. The startup.cs file contains a Startup class defined as below:

As you can guess, the entry point in the web application is the Main method. This method triggers a workflow that uses the information contained in the startup class to launch the web application. UseIISPlatformHandler sets the URL to listen to. The name of the startup class is passed as a type argument to the Run method but it doesn’t mean you can change it at your leisure. If you rename the class to something like Startup1, and pass the Run method the same name Startup1, you get an internal error as in the figure below.

2402-71bf5ffc-0cfe-41bc-9f0d-6507d3d20f3

Therefore, the first lesson we’ve learned is that the class Startup can only be renamed to StartupDevelopment. Well, there’s actually a little bit more to it. The name Startup is a fallback name that you can optionally replace with a custom StartupXXX class name where XXX indicates a working environment such “development”, “production”, “staging” or whatever else you like. Changing the name of the startup class, however, is not simply a refactoring action. You also have to set the name as the current environment for the application. You do that through the Properties window of the project in Visual Studio.

2402-ba8cb657-7d7c-4199-adec-15bc2b769ca

So the method Main in the startup class is the entry point in the web application, but who calls the Main method?

The Visual Studio project contains another relevant file-the project.json file. In the beginning it looks like below:

The crucial part of it is the commands section. The Kestrel name refers to a cross-platform executable that keeps the ASP.NET application hosted outside the IIS environment. ASP.NET Core is designed to be web server-agnostic, therefore the application host needs be distinct from a specific web server product. When the Kestrel application host is fired up, it looks for a startup class to configure the environment and launch the actual application.

The startup class is required to have at least one method named after the ConfigureXXX convention. Also in this case, XXX identifies the environment. A class named Startup can only have a Configure method; a class named StartupWhatever can only have a ConfigureWhatever method as long as “whatever” is set as the current environment in the properties of the project.

The signature of the class in extensible with any number of injectable objects that the dependency injection infrastructure of ASP.NET runtime can resolve. In the Configure method, you are expected to configure all the default services and the additional services you may add through the ConfigureServices method.

Minimal Configuration for a True ASP.NET MVC Application

Even though the freshly created ‘ hello-world application gives signs of life, it is far from being an ASP.NET MVC application. You must first add the MVC service and then enable and configure it. This step requires changes to the both the ConfigureServices and Configure method. Here’s what you need to have in ConfigureServices.

When you do so, a balloon pops up and suggests that you should add the latest Microsoft.AspNet.Mvc package. You click and the project.jso n file changes too. The “dependencies” section now looks as below:

It’s not enough yet to have the ASP.NET MVC fully configured. If you add a controller class at this point it will be blithely ignored. Here’s the additional code you need to have in Configure.

As you can guess, the UseMvc method enables the MVC machinery and registers routes. The UseStaticFiles method instead enables your app to serve static files such as images, stylesheets and scripts. Note that static files are the ones that are available under the project folder wwwroot. Under that folder, however, you can have your own hierarchy of folders. Note also that the wwwroot folder is only a project folder and disappears once the application is deployed to a web server.

If you look back at the code that was originally created for the Configure method, you notice the following call:

This call enables interaction between the application and the IIS environment. The interaction takes place through a component-the IIS HttpPlatformHandler-that you need to have installed on your IIS when you deploy the application.

Finally, note that in order to see error pages during the development phase you need to enable it explicitly. As a general rule, keep in mind that nothing, repeat nothing, is by default in ASP.NET Core. For a legacy ASP.NET developer this is probably the hardest thing to learn. To enable developer error pages, you add the following to method Configure.

Support for the error pages is baked into yet another package to reference. ASP.NET Core is presented as a lean and composable framework slated to allow much better performance than the current ASP.NET. It achieves that by removing every single piece of functionality and requesting you add every little bit you need explicitly.

I see the point of building a “lean and composable” framework but I expect that at some point in the future facilities and templates will be added to preserve the ease-of-use that always characterized web development under Visual Studio and ASP.NET.

Controllers and Views

At this point, the ASP.NET MVC application is ready to work as expected. You can add controller classes and views following the same rules of classic ASP.NET MVC programming. Note that, in ASP.NET Core, a controller method may optionally return an IActionResult type instead of a well-defined ActionResult type. It’s not a breaking change, though, and it works either way.

ASP.NET Core doesn’t support Web Forms and provides an ASP.NET MVC programing experience that is just the same you may know plus a few tweaks and some new programming goodies such as tag helpers and some minor facilities such as view imports. The structure of the Views folder is the same and the Razor language is the same plus some extra keywords such as @inject.

The @inject keyword connects the Razor view with the list of services that the built-in dependency injection infrastructure deals with. To pass data to the view, you typically fill the view model with all the data and references you need. As an alternative, for some ad hoc references, you can inject them directly into the view care of the dependency injection framework.

The view imports instead is a nice piece of syntactic sugar that allows to group in a file all using statements you might be using from multiple views always the same way. View imports come in the form of a ViewImports.cshtml file populated with @using and other @xxx declarations that would go at the top of Razor views.

Adding Bootstrap and Other Libraries

ASP.NET Core, in combination with Visual Studio, promotes the use of Nuget packages for every library reference, but Nuget packages are considered incompatible with client-side references. You should use Bower for installing Bootstrap, jQuery or any other client-side package, most typically Bootstrap and jQuery plugins and other third-party JavaScript libraries. Using Bower is no big deal in Visual Studio. You just have a new window to deal with similar to Add Packages window you use for Nuget class libraries. Under the hood of the Bower configuration, though, lies a JSON file you can even edit manually if you wish. In this case, all you do is to add a new Bower configuration file and edit its JSON content manually in the text editor. (Editing JSON manually seems to be the new trend, at this time in history!) Thankfully, the Visual Studio JSON editor offers some IntelliSense support when it comes to editing Bower files. So here’s the content of the newly added bower.json file once you told it to download and install Bootstrap.

As you save the content of the bower.json file, Visual Studio attempts to download packages and updates your project. By default, all Bower-controlled resources are placed under wwwroot in the aptly created lib folder.

In alternative to using Bower, whether manually or through the Visual Studio user interface, the old approach of just downloading files and adding them manually to the project still works. Especially if you have a common collection of client resources that you use over and over again, you’d probably better off copy-pasting folders than configuring each package again according to the new Bower rules. At the end of the day, Bower is there to try to make the developer’s life easier but it has no impact on the way that resources are actually linked to HTML views. As long as you point browsers to a valid server path to download CSS and JavaScript resources, you won’t have bad surprises.

Choosing the .NET Framework

ASP.NET Core may work on top of several flavors of the .NET Framework. One of these is the fully-fledged .NET Framework 4.5.x and another is the newest and more compact .NET Core which will also be available at some point on non-Windows platforms. The .NET Core eliminates some of the classes and namespaces you may be using in existing ASP.NET code. There are no reliable statistics yet about the percentage of code you may be able to bring as-is to .NET Core, but presumably Microsoft did a lot of work to keep the percentage as high as possible to minimize the amount of work it takes to existing ASP.NET code over.

For what it’s worth, I run a small experiment recently and took one of the examples from my latest ASP.NET book ( Modern Web Development: Understanding domains, technologies, and user experience, Microsoft Press, 2016) and ported it to ASP.NET Core. The example is six read-only views, a couple of controllers and a dozen views and partial views. It took me a couple of intense hours the first time, but I’m fairly confident that if I take another example it’ll take much less.

What’s ASP.NET Core for?

ASP.NET Core is designed from the grounds up to work, whatever is used as the web server. This is a complete turnaround from the vision of the “integrated pipeline” that was pushed as the panacea of web evil a few years ago. The challenge will be making ASP.NET Core independent from the host web server while keeping it super-easy to use and faster than today when hosted on a classic and fully-fledged web server like IIS. Around the time that the RC1 of the platform was released (November 2015), a significant change occurred in the hosting model: the tooling that is used to back it up is being redesigned in the transition to RC2, still to come at some point in the future.

As you can see, there’s a lot in the works regardless of the release-candidate label that was hastily put on it. A sure thing is that ASP.NET Core will not be integrated with IIS as was the case with past versions. The primary reason for this is to make the programming platform available also on non-Windows systems. ASP.NET Core doesn’t bring cool new programming features so I wouldn’t say it’s been created to empower developers. As I see it, it’s there to serve Microsoft’s overall strategy in the web space. For ASP.NET people used to the classic IIS-ASP.NET stack, it’s still a matter of writing ASP.NET MVC applications and hosting on IIS using a different bunch of settings and possibly experiencing more gaps than you’re used to with the current experience.

It’s a long and winding road and I believe we’ve barely reached the first milestone.