Make sure version 0.1-alpha-build-0446 of the K Runtime is installed. See the install instructions at https://github.com/aspnet/home.
If you have multiple builds of the runtime installed select version 0.1-alpha-build-0446.
kvm use 0.1-alpha-build-0446
Use the following commands to download the code and run the sample
REM Clone the repository and switch to the project folder
git clone https://github.com/predeekc/aspnet-hello-world.git
cd aspnet-hello-world
REM Download the packages using NuGet
kpm restore
REM start the sample website
k web
View the website at http://localhost:5001.
git checkout Step1
This file contains the dependencies used by the sample project. These dependencies will be downloaded when kpm restore
is run. The packages will be downloaded using NuGet and placed in ./packages.
{
"version": "0.1-alpha-build-0446",
"dependencies": {
"Microsoft.AspNet.Diagnostics": "0.1-alpha-build-0682",
"Microsoft.AspNet.Hosting": "0.1-alpha-build-0572",
"Microsoft.AspNet.Server.WebListener": "0.1-alpha-build-0520",
"Microsoft.AspNet.StaticFiles": "0.1-alpha-build-0443"
},
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001"
},
"configurations": {
"net45": {},
"k10": {}
}
}
Contains ASP.NET vNext NuGet repository entries
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="AspNetVNext" value="https://www.myget.org/F/aspnetvnext/api/v2/" />
<add key="NuGet.org" value="https://nuget.org/api/v2/" />
</packageSources>
<packageSourceCredentials>
<AspNetVNext>
<add key="Username" value="aspnetreadonly" />
<add key="ClearTextPassword" value="4d8a2d9c-7b80-4162-9978-47e918c9658c" />
</AspNetVNext>
</packageSourceCredentials>
</configuration>
The ASP.NET vNext pipeline is initialized with the IBuilder interface. All handlers are a method accepting an HttpContext object and expecting a Task to be returned.
public class Startup
{
public void Configure(IBuilder app)
{
}
// Step 1a: Build a simple handler
public Task MyHandler(HttpContext context)
{
Console.WriteLine("{0} - {1}", context.Request.Method, context.Request.Path.ToString());
return context.Response.WriteAsync("<html><head><title>Sample Page</title></head><body>Hello World!<br/><img src='images/helloWorld.png'/></body></html>");
}
}
Registering the handler is done in the Configure method using the Run method. This will cause this handler to be used for all requests with any URL.
public void Configure(IBuilder app)
{
// Step 1b: Use the simple handler
app.Run(MyHandler);
}
At this point save the file and run the application using k web
. Once the server is running, navigate to http://localhost:5001. The page should load. The image load will fail for now.
A middleware component is different from a handler since it calls the next item in the pipeline. To do this, the component is provided with the next item in the pipeline when it's constructed. The handler created in the previous step is just a middleware component that doesn't call the next item in the pipeline.
// Step 2a: Build a simple header injector middleware (before and after)
public class MyPrivateMiddleware
{
RequestDelegate _next;
public MyPrivateMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
context.Response.Headers.Set("cache-control", "private, max-age=0, no-cache");
await _next(context);
// Do cleanup work here
}
}
The class constructor takes in the RequestDelegate that is next in line. The RequestDelegate defines the actual handler which takes in the HttpContext and returns a Task. In the example above, the class holds the _next delegate and the Invoke method adds a custom header then calls the next delegate.
// Step 2b: Build a simple extension wrapper around middleware registration
public static class MyPrivateMiddlewareExtensions
{
public static void UseMyPrivateMiddleware(this IBuilder app)
{
app.Use(next => new MyPrivateMiddleware(next).Invoke);
}
}
Registration of the middle ware component is done using the IBuilder's Use method. The Use method expects a delegate that takes in the next RequestDelegate and returns a RequestDelegate for the new middleware. In this case an extension method is used to make the registration easier.
public void Configure(IBuilder app)
{
// Step 2c: Use the middleware
app.UseMyPrivateMiddleware();
// Step 1b: Use the simple handler
app.Run(MyHandler);
}
Finally the new extension method is called to register the middleware. Run the application using k web
. Once the server is running, navigate to http://localhost:5001. The page should load and contain a cache-control header in the HTTP response.
Some middleware components ship as part of the framework. The StaticFileMiddleware component can be used to serve static files from your webserver. If it's placed early in the pipeline, it will check to see if the requested file exists on the filesystem and return it. If not, it passes the request down the pipeline.
public void Configure(IBuilder app)
{
// Step 2c: Use the middleware
app.UseMyPrivateMiddleware();
// Step 3: Use static files middleware
app.UseStaticFiles();
// Step 1b: Use the simple handler
app.Run(MyHandler);
}
When the application is run with k web
and opened in the browser, the StaticFile middleware will server the image embedded in the page.
Another piece of useful middleware is the MapMiddleware. It checks the URL requested and if it doesn't match a registered path, it continues down the pipeline by calling the next middleware component. If it does match, execution is diverted to a new pipeline that's configured independently. In this sample it's used to route all requests to the /private path to a different pipeline.
public void Configure(IBuilder app)
{
// Step 4: Add a pipeline for child folders
app.Map("/private", childApp => {
childApp.UseMyPrivateMiddleware();
childApp.Run(MyHandler);
});
// Step 3: Use static files middleware
app.UseStaticFiles();
// Step 1b: Use the simple handler
app.Run(MyHandler);
}
Now when the application is run using k web
, requests to the /private namespace will have the cache-control response header, but requests to the rest of the application will not.