ASP.NET Core Kestrel @ NDC Oslo

“That’s slow”

On this year’s NDC Olso the guys from ASP.NET team gave a very interesting talk about the challenges and techniques of building a fast and memory efficient HTTP server. They’re aiming at 5M requests/second on plain-text benchmarks, which is very nice. Worth watching!

ASP.NET Core Kestrel: Adventures in building a fast web server

Advertisement

ASP.NET 5 beta 5 and other news

Microsoft recently released beta 5 of ASP.NET 5 and it includes a lot of bug fixes, API reviews and some package refactoring, namely on MVC. It’s nice to see this effort on tidy and coherent APIs. Here are some things I find worth mentioning:

As previously mentioned there’s a visible effort on API/packages organization which is visible if we browse on the change logs for the individual components. Nevertheless, I get the feeling that “it is almost there” for most of the components.

In addition to the beta 5 release, there are some other news worth mentioning:

  • There’s a new Announcements repository where the major changes on ASP.NET 5 are announced. Worth subscribing!
  • Visual Studio 2015 and ASP.NET 4.6 will ship on the July 20! ASP.NET 5 stuff will be beta and updated later.
  • ASP.NET 5 RC is tentative scheduled for late fall 2015. Meanwhile, monthly beta releases should occur.

EDIT: Mid-November is the target date for ASP.NET 5 RC

EDIT: Roadmap is now public.

More info:

An Inside Look at ASP.NET 5 Execution – Setup for Debugging

On the previous post of this series we got to the point where DNX invokes ASP.NET code. While I already had DNX code on VS, I guess from now on it’ll be more important (fun?) to debug and see things happening, so I’ll recap the debug setup before moving further. I’ve cover this on part I and part II of the series but things are a bit fragmented. Also, I was based beta 4 releases of the different components; that was 2 months ago, so I’ll be moving into the latest versions (release branch versions, actually, which seem to be on beta 6 by now). So, here’s what I did:

git clone https://github.com/aspnet/Mvc.git -b release
  • Install DNVM using the command on GitHub or update the existing installation using:
dnvm update-self
  • Install the latest versions of DNX for CLR and CoreCLR (at the time of writing the version is beta6-11944):
dnvm upgrade -r clr -unstable
dnvm upgrade -r coreclr -unstable
  • Create an hello-world folder and add a Startup.cs file with the following content:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using System;

namespace HelloWorld.Web
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(ctx => ctx.Response.WriteAsync("Hello ASP.NET 5 world! Time: " + DateTime.Now));
}
}
}
  • On the same folder add a project.json file with the following content:
{
"webroot": "wwwroot",
"dependencies": {
"Microsoft.AspNet.Hosting": "1.0.0-beta-*",
"Microsoft.AspNet.Mvc": "6.0.0-beta-*",
"Microsoft.AspNet.Server.WebListener": "1.0.0-beta-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-beta-*"
},
"commands": {
"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
}
}
  • Open a command line on the folder and run:
dnu restore
dnx . web

This should launch the server. Try navigating to the URL configured on the project file. Then:

  • Open VS 2015 and create a blank solution.
  • Add the project file above to the solution (Add Existing Project).
  • Replace the global.json file contents with the following (adjust the location of the sources to point to the repos cloned on the first step):
{
"projects": [
"src",
"C:/aspnet-source/hosting/src",
"C:/aspnet-source/mvc/src",
"C:/aspnet-source/http-abstractions/src"
],
"sdk": {
"version":"1.0.0-beta6-11944"
}
}

VS should start restoring dependencies and adding the projects found on the ASP.NET sources to the solution. If not, try closing and reopening the solution.

  • Add a breakpoint on Microsoft.AspNet.Hosting –> Program –> Main.
  • Launch the debugger using the “web” command and wait for it to break on the breakpoint above.

That’s it! You can now debug into ASP.NET code. I’ll go into this code on the following posts.

Hello ASP.NET 5 World – Part III

In the previous post I improved the hello world example to include the static files middleware. In this post I’ll wrap up this series by adding MVC. The first thing is to add the corresponding package. This can be done on the command line:

kpm install Microsoft.AspNet.Mvc 6.0.0-beta3

As the static file middleware, MCV includes a convenience extension method to add itself to the pipeline. We can use that method when configuring the application:

public void Configure(IApplicationBuilder app)
{
app.UseStaticFiles();
app.UseMvc();
}

In addition, since dependency injection is now used throughout the framework, we need to register the services required by MVC on the DI container. I’m not yet familiar with the details of the DI model on ASP.NET 5, but there’s another method (besides Configure) that the framework invokes by convention when starting up an application:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}

Note the usage of AddMvc, an extension method also included in MVC to register its services on the container.

MVC 6 Includes the features that were previously found on both MVC and Web API. Everything should be familiar, having in mind that the base HTTP programming model is a bit different. That said, adding a controller is straightforward. Just add a class whose name has the Controller suffix, define an action and its route and your good to go. You don’t need to extend the base Controller class, even though it has many useful methods and properties (View(), Redirect(), Request, Response).

public class HelloWorldController
{
[Route("Hello")]
public object Index()
{
return new
{
Message = "Hello ASP.NET 5 world!",
Time = DateTime.Now.ToString(),
};
}
}

If we run the app from the console an navigate to http://localhost:5000/hello we’ll get a JSON response returned by the controller. The same controller can also have an action returning an IActionResult which corresponds to a view:

[Route("Hello/Goodbye")]
public IActionResult Goodbye()
{
return View();
}

And that’s it for now!

Hello ASP.NET 5 World – Part II

On my previous post I ended up with a simple Hello World web application. The application configuration simply registered a callback to handle all the requests and write something to the response. I’d like to revisit this in more detail.

public void Configure(IApplicationBuilder app)
{
    app.Run(ctx => ctx.Response.WriteAsync("Hello ASP.NET 5 world! Time: " + DateTime.Now));
}

Let’s start by IApplicationBuilder. This interface – which was IAppBuilder on Katana – is a means of registering components (middlewares) that participate on request processing. You do so by invoking its Use method:

IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);

The method’s signature can be a bit confusing at first. In order to understand it, lets look into RequestDelegate:

public delegate Task RequestDelegate(HttpContext context);

This delegate represents the handling of a request. It’s a function that gets a context and returns a Task that completes when the request has been processed; it corresponds to OWIN’s AppFunc. Did you notice HttpContext? This isn’t System.Web’s infamous class; it’s a new one with the same name and similar function, resulting from Katana’s IOwinContext.

Back to the Use method, we can say that it gets a function that maps one request handler to another. In other words, whatever function that is, it is a means of composing around an existing request handler. This is similar to DelegatingHandlers on ASP.NET Web API and has some similarities with System.Web’s IHttpModule. It’s worth pointing that the Run method on the example above is just an extension method that invokes Use with a constant RequestDelegate. So, let’s do a simple middleware:

public class GotchaMiddleware
{
    public RequestDelegate Process(RequestDelegate next)
    {
        return async httpContext =>
        {
            await next(httpContext);
            await httpContext.Response.WriteAsync("  GOTCHA!");
        };
    }
}

And register it on the pipeline:

public void Configure(IApplicationBuilder app)
{
    app.Use(new GotchaMiddleware().Process);
    app.Run(ctx => ctx.Response.WriteAsync("Hello ASP.NET 5 world! Time: " + DateTime.Now));
}

Note how the middleware has a method that matches the Use method signature. Running the application from the command line again, we get:

Hello ASP.NET 5 world! Time: 07/03/2015 00:26:01  GOTCHA!

ASP.NET includes different middlewares, such as one for serving static files. MVC 6 itself is plugged in as a middleware. Typically, each middleware defines an extension method for IApplicationBuilder to register itself on the pipeline. For instance, we can register the static file handler by adding a dependency on the corresponding NuGet package to the project.json file:

{
    "dependencies": {
        "Microsoft.AspNet.StaticFiles" : "1.0.0-beta3",
        ...
    },
    ...
}

And invoking the UseStaticFiles extensions method:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
    // ...
}

Note the pay-for-play philosophy: we needed to serve static files, so we added a new package.

On the following post I’ll end this Hello World set by adding a simple MVC controller.

Hello ASP.NET 5 World – Part I

First of all, Visual Studio 2015 CTP 6 was released this week and with it the beta 3 of CoreCLR and ASP.NET 5. I’ll be using beta 3 for this post. If you’re not installing VS, make sure you re-install KVM, because there were a few changes (different layout on the file system, new commands on KPM, etc.).

Programming model

In my previous post I wasn’t clear about one thing: ASP.NET’s 5 side-by-side deployment, pay-for-play and multi-host approach also means that the monolithic System.Web is gone. No more IHttpHandler, IHtpModule and co. Of course many of the features on System.Web will have its counterpart on ASP.NET 5 stack.

ASP.NET 5 is OWINish. In fact, the Katana project was integrated into ASP.NET 5, defining the base programming model. This means we’ll deal with middlewares, AppFunc and the enviroment dictionary. Well, actually the ASP.NET 5 HTTP object model has a higher abstraction level rather than exposing the raw OWIN concepts.That’s why I said it is “OWINish”.

Hello World!

So, what does it take to have a simple “Hello World” in ASP.NET 5? It’s actually quite simple. I found this nice tutorial with all the steps to set up from the ground, so I won’t reproduce them here. Just note that the post is based on beta 2 and I’ll be using beta 3.

The bare minimum is to define: a Startup class, where you configure your application. In this case, I’m configuring it to say hello as a response to all the requests.

using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;

namespace HelloWorld.Web
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Run(ctx => ctx.Response.WriteAsync("Hello ASP.NET 5 world! Time: " + DateTime.Now));
}
}
}

And a project.json file with the application dependencies. In this case I’m also configuring a command to be able to run the application from the command line, since I’ll be using a self-host.

{
"dependencies": {
"Microsoft.AspNet.Hosting": "1.0.0-beta3",
"Microsoft.AspNet.Server.WebListener": "1.0.0-beta3"
},
"commands": {
"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
}
}

The bootstrap is convention-based: ASP.NET searches the main assembly of the application for a class named Startup and then for a method named Configure that has the signature above. The app.Run method is used to register code that kicks in when no other component handles the request. Since I have nothing else, it will run for every request. This is somewhat similar to an IHttpHandler on previous versions.

The web command is an easy way to configure the self-hosted server and then start it using k on the command line. So, if you put the two files above on a folder, you can restore dependencies and run the application from the command line by doing:

kpm restore
k web

You should see a “Started” message on the console and then you can access the application on http://localhost:5000. And that’s it!

On the following post I’ll add a few more bits on this example, namely registering a middleware and hosting on IIS express, as well as looking a bit more into the HTTP abstractions and comparing them to the ones previously found on Katana project.