1. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 1/14
Searchforarticles,questions,tipsQ&A forums loungearticles
Rate:Neal Pandey, 27 Dec 2016 MIT
Create HTTP request pipeline using ASP.NET Core custom middleware:
build/run on Mac, Windows, Linux or Docker container
This tutorial is about building HTTP request pipeline on ASP.NET Core. We will start from scratch using Command Line, write custom middleware in C# and finish with adding builtin
middleware to pipeline. We will build and run the demo application on Mac, Windows and Docker container in Linux.
Introduction
Just as I/O is the means a computer uses to exchange information, the World Wide Web uses RequestResponse pattern to communicate. HTTP is the protocol for RequestResponse
communication between clientserver on web. In this article we will build a pipeline to process HTTP request using middleware components on ASP.NET Core. One of the big advantages of
building HTTP request pipeline on ASP.NET Core is that you can make a lean and modular pipeline which can run on Windows, Linux and Mac. ASP.NET Core is opensource and there
are many NuGet packages that can help in making custom pipeline to serve your needs. You can also write your own custom middleware. ASP.NET Core has builtin support for Depedency
Injection (DI), a technique used to achieve loose coupling in your application.
The HTTP request pipeline we build can be used to develop custom microservices running in a Docker container. It is ideal for small independent task but being modular can be extended
with more features.
Background
As the old saying goes, you can't know where you are going until you know where you have been. So how does HTTP request flows in classic ASP.NET page running on Microsoft IIS web
server? In an integrated approach, IIS and ASP.NET request pipelines will be combined to process the request through native and managed modules. Below diagram from IIS.net illustrates
the flow of HTTP request in IIS 7.
Reference: https://www.iis.net/learn/getstarted/introductiontoiis/introductiontoiisarchitecture
In classic ASP.NET the HTTP request passes through several events of an HTTP application pipeline. Developers can write their code to run when events are raised. They can also create
custom modules using IHttpModule interface and add to the configuration section of the application's Web.config file.
In comparison ASP.NET Core is designed for performance with minimal footprint. You start with a clean slate and add features you need to request pipeline using middleware. This article is
about how to add middleware to build your custom HTTP request pipeline.
Prerequisites
If you intend to follow the tutorial, you will need to install following items:
1) Install .NET Core SDK
5.00 (14 votes)
12,664,425 members (31,558 online) 1.2K Sign out Neal Pandey
2. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 2/14
2) We will use Command Line and start from scratch for a better understanding. Initially I suggest using a text editor of your choice. Later on you can open the project in Visual Studio Code
or Visual Studio 2015 to take advantage of IDE.
Let's get started
In this section we will create a working app directory 'DemoApp' and create a new application using Command Line. We will also update project file and install required packages using
Command Line.
Create App Directory and build new project
First check that .NET Core is installed. Create a directory to hold your application, and make it your working directory. On my machine the working directory is located at
"C:ProjectsDemoApp". Open Command Prompt and change the directory to your working directory. Use the ‘dotnet new’ command to create a new application.
dotnet new
The above screenshot shows the dotnet version, the working directory and the two files in the new C# project.
We are starting with bare minimum in our project. Since we are our building our app on AspNet Core, we will need to add required dependencies in project.json file. Open project.json file add
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0" as one of the dependencies.
{
"version": "1.0.0‐*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0"
},
"frameworks": {
"netcoreapp1.1": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.1.0"
}
},
"imports": "dnxcore50"
}
}
Our current app is a simple Console Application with one Program.cs file with Main method which outputs to Console. We will change the Program.cs file to create a host that will use Kestrel
web server and Startup class to run our app. Replace the code in Program.cs with below code.
using System;
using Microsoft.AspNetCore.Hosting;
namespace DemoApp
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseUrls("http://*:5000")
.UseKestrel()
.UseStartup<Startup>()
Hide Copy Code
Hide Copy Code
3. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 3/14
.Build();
host.Run();
}
}
}
In classic ASP.Net the Application_Start and Application_End events in Global.asax (which is derived from the HttpApplication) were called during the application life cycle. In ASP.NET Core
the application is initialized in the Main method of the Program.cs. The Main method in our code creates an instance of WebHostBuilder and uses various extension methods to specify the
URL, the Server and the Startup class to build Host and run the application. The Startup class (which we will create next) is the entry point of our HTTP request pipeline.
In ASP.NET Core we program using conventions. Create a new Startup.cs file and add the following code. The Startup Constructor can optionally accept dependencies like
IHostingEnvironment which will be provided through dependency injection.
The optional ConfigureServices method is used to define and configure the services available to the application. The ConfigureServices can only take the parameter of IServiceCollection
type.
The Configure method is to build the pipeline using Middleware and how to handle request response. The Configure method must take IApplicationBuilder type parameter. Services of type
IApplicationBuilder, IHostingEnvironment and ILoggerFactory can be passed as parameter and they will injected if available.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace DemoApp
{
public class Startup
{
// Use this method to add framework services (MVC, EF, Identity, Logging)
// and application services
public void ConfigureServices(IServiceCollection services)
{
}
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
app.Run(context =>
{
return context.Response.WriteAsync("Hello from ASP.NET Core!");
});
}
}
}
Let us restore the dependencies specified in Project.json by using below command.
dotnet restore
This will create a new file project.lock.json which contains list of all the NuGet packages used by the app.
We will now run the project using below command. This will compile and execute our project.
dotnet run
Hide Copy Code
4. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 4/14
If your project compiled successfully, open your browser and go to http://localhost:5000/.
Congratulations, you have successfully build a simple http application on ASP.NET core.
Custom Middleware
Middleware are components that handle request and response in HTTP request pipeline. These components chained together compose a pipeline. RequestDelegate is used to chain the
middlewares. What is RequestDelegate? A RequestDelegate is a function that accepts HttpContext type and returns Task type (a promise).
Each middleware in pipeline invokes the next middleware in sequence or terminates the request. You can perform actions both before and after the next middleware is invoked. Let us add
an inline demo middleware to HTTP request pipeline in Configure method in Statup.cs file.
public void Configure(IApplicationBuilder app)
{
// add inline demo middleware
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello from inline demo middleware...");
// invoke the next middleware
await next.Invoke();
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Welcome to ASP.NET Core!");
});
}
In above the code the inline demo middleware code is registered with app.Use. Note that if you don’t call next.Invoke() it will shortcircuit the request pipeline. Also note that in app.Run
method what you have is a terminal middleware which is called at the end of HTTP request pipeline. I have changed the text to differentiate messages.
In our inline demo middleware we are passing HttpContext and RequestDelegate to a lambda expression but for a complex middleware processing you should create its own class. Below is
the code for DemoMiddleware class. It has a constructor that accepts a RequestDelegate and an Invoke method that accepts HttpContext.
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace DemoApp
{
public class DemoMiddleware
{
private readonly RequestDelegate _next;
public DemoMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
await context.Response.WriteAsync("Message from DemoMiddleware...");
Hide Copy Code
Hide Copy Code
5. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 5/14
await _next(context);
}
}
}
In order to register the DemoMiddleware, we will create a class that will extend IApplicationBuilder to provide an easy way to add middleware to the request pipeline. Below is the code for
DemoMiddlewareExtensions.cs.
using Microsoft.AspNetCore.Builder;
namespace DemoApp
{
public static class DemoMiddlewareExtensions
{
public static void UseDemoMiddleware(this IApplicationBuilder builder)
{
builder.UseMiddleware<DemoMiddleware>();
}
}
}
Now by calling app.UseDemoMiddleware() in Configure method of Startup class we can add DemoMiddleware to HTTP request pipleline.
public void Configure(IApplicationBuilder app)
{
// inline demo middleware
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello from inline demo middleware...");
// invoke the next middleware
await next.Invoke();
});
// standalone DemoMiddleWare;
app.UseDemoMiddleware();
// terminal middleware
app.Run(async (context) =>
{
await context.Response.WriteAsync("Welcome to ASP.NET Core!...");
});
}
On successfully compiling and executing our DemoApp project using dotnet run, and browsing to http://localhost:5000/ you should see messages from inline middleware, standalone
middleware and terminal middleware added to Http request pipeline in Configure method of Startup class.
Note that the http request is processed in same order as the sequence of middleware components and the response is processed in reverse. It is important to understand the business logic
followed by chaining middleware in http pipeline. The sequence of middleware can make a big difference in security, performance and behavior of your application.
Dependency Injection and Strategy Design Pattern
ASP.NET core framework is designed to support dependency injection. It has builtin Inversion of Control (IoC) container, also called DI container. The builtin DI container provide services
which are responsible for providing instances of types configured in ConfigureServices method of the Startup class.
If we want our DemoMiddleware class to provide custom message we can use Strategy design pattern. We will create an Interface and provide implementation of this interface as
parameters. You can keep using your favorite Text Editor or IDE. To open the DemoApp project in Visual Studio 2015, go to File menu, select Open > Project/Solution. In Open Project dialog
box, select project.json in DemoApp folder. To open the Demo Project in Visual Studio Code, go to File menu, select Open and then open DemoApp folder. Here is the screenshot of
DemoApp project when opened first time in Visual Studio Code on Mac.
Hide Copy Code
Hide Copy Code
6. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 6/14
Here is the code for our interface IMessage.cs
namespace DemoApp
{
public interface IMesssage
{
string Info();
}
}
We will implement above interface in one of RuntimeMessage class to provide information about OS and Framework where DemoApp is running. Below is the code for RuntimeMessage.cs
using System.Runtime.InteropServices;
namespace DemoApp
{
public class RuntimeMessage : IMesssage
{
public string Info()
{
return $@"
OS Description: {RuntimeInformation.OSDescription}
OS Architecture: {RuntimeInformation.OSArchitecture}
Framework: {RuntimeInformation.FrameworkDescription}
Process Architecture: {RuntimeInformation.ProcessArchitecture}";
}
}
}
In DemoMiddleware class we will update the constructor to accept IMessage as parameter and update the Invoke method to write the response returned from above Info method. The
updated DemoMiddleware.cs is as follow.
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace DemoApp
{
public class DemoMiddleware
{
private readonly RequestDelegate _next;
private readonly IMesssage _message;
public DemoMiddleware(RequestDelegate next, IMesssage message)
{
_next = next;
_message = message;
}
public async Task Invoke(HttpContext context)
{
await context.Response.WriteAsync("rnMessage from DemoMiddleware:");
Hide Copy Code
Hide Copy Code
Hide Copy Code
7. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 7/14
await context.Response.WriteAsync(_message.Info() + "rn");
await _next(context);
}
}
}
In order to resolve IMessage to RuntimeMessage we will register our dependencies in ConfigureServices method of Startup class. The AddTransient method is used to map abstract types to
concrete types (ASP.NET's container refers to the types it manages as services) whenever it is requested.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IMesssage, RuntimeMessage>();
}
Let us compile and run the code. You can use dotnet run in Command line or press F5 to debug in Visual Studio tools. Below screenshot is when I debug code in Visual Studio Code on Mac.
Build and run application on Mac, Windows, Linux or Docker container.
The runtime info message from DemoMiddleware will be based on the platform on which DemoApp is running. The above runtime info message I got is when I ran DemoApp on my Mac OS
X El Capitan.
Hide Copy Code
8. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 8/14
ASP.NET Core can run on Windows, Linux and Mac, you have choice where you want to run application. On Windows 10 computer the runtime info message in Chrome browser looks as
follow:
Below image is when I ran application in a Docker container.
Docker is an excellent platform for building and running Microservices. Installing Docker, building Docker image, publishing and running the app in a Docker container are topics by itself.
There are some excellent documents on these topics at https://docs.docker.com/ and https://www.microsoft.com/net/core#dockercmd. If you do have Docker running in your machine, you
can copy below code in a dockerfile in your DemoApp folder and use it to build your Docker image.
FROM microsoft/dotnet:1.1.0‐sdk‐projectjson
COPY . /demoapp
WORKDIR /demoapp
EXPOSE 5000
ENV ASPNETCORE_URLS http://+:5000
RUN dotnet restore
RUN dotnet build
ENTRYPOINT ["dotnet", "run"]
You can build docker image in Command Line from DemoApp working directory.
docker build . t np:demoapp
When the Docker image is built successfully, spin the Docker container using below command.
docker run d p 80:5000 t np:demoapp
You can see list of all containers with command
docker ps a
For more Docker commands refer to https://docs.docker.com/engine/reference/commandline/. Here is the screenshot of bulding docker image of demoapp commandline
Hide Copy Code
9. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 9/14
Builtin Middleware
The ASP.NET Core 1.1 comes with builtin middleware such as Authentication, CORS, Routing, Session, Static Files, Diagnostics, URL Rewriting, Response Caching and Response
Compression. There are also many middleware available in nugget packages.
In our DemoApp we will add Diagnostics middleware for exception handling, Static Files middleware to serve content from www folder and Response Compression middleware for GZip
content for faster network transfers. In adding middleware we follow these steps:
10. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 10/14
1. Add package dependencies to project.json
2. If required add services for middleware in ConfigureServices method of Startup.cs.
3. Add middleware to HTTP request pipeline in Configure method of Startup.cs
Let us add following dependencies in project.json
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.ResponseCompression": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0"
It should be obvious from the package names, the features we can provide to our DemoApp. You can run dotnet restore using CLI or use Visual Studio Code or Visual Studio to restore
packages. With ASP.NET Core is crossplatform and you can develop applications on Mac, Linux or Windows. You can use your favorite tool and I going to open the DemoApp project in
Visual Studio 2015. As soon as I add above dependencies in Project.json and save the file, Visual Studio will restore packages as seen below.
Because ASP.NET Core has a builtin dependency injection, we will be able to inject services (types managed by DI container) by passing appropriate Interface as a parameter in methods of
Startup class. You can also replace the DI container (represented by the IServiceProvider interface) provided by framework with Autofac, NInject or any other Inversion of Control containers.
In our DemoApp we will use the default dependency injection provided by ASP.NET Core framework.
The constructor and Configure method of Startup class accept IHostingEnvironment and ILoggerFactory as parameters to request appropriate services required. In below code I added
WelcomePage builtin middleware in Diagnostics package. I want to add this middleware only for production hosting environment. I have included IHostingEnvironment as parameter in
Configure method to get information about the environment.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// WelcomePage middleware added to pipeline for Production environment.
if (env.IsProduction())
{
app.UseWelcomePage();
}
To add environment variable right click DemoApp, select Properties > Debug and click Add to enter values as shown in below screen. This will create or update launchSetting.json in
Properties folder under DemoApp project.
Hide Copy Code
Hide Copy Code
11. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 11/14
Press F5 to start debugging which will launch the Command Window on successful build.
Once your application is started, browse to http://localhost:5000 to see Welcome page as seen in below image.
12. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 12/14
If you want to see above page on a different path, WelcomePageMiddleware has few overloaded versions. For example UseWelcomePage(“/home”) will show welcome page only on
http://localhost:5000/home path.
To use GZip Compression service available to our DI container we need to add middleware in ConfigureServices method of Startup class.
public void ConfigureServices(IServiceCollection services)
{
// add GZipCompression service
services.AddResponseCompression();
To use GZip compression using the fastest compresson level, add ResponseCompression middleware to HTTP pipeline in Configure method of Startup class.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Response Compression Middleware
app.UseResponseCompression();
Now if you build and browse the site and view the response in developer tools of your browser, you should see response content encoded in GZip.
We will end this tutorial by adding file serving features to our HTTP request pipeline. The files will be served from the web root of the folder which has public content. I want www folder to be
the root folder serving static pages and single page application (SPA). We can specify the root folder using UseWebRoot extension method of WebHostBulder class in program.cs.
var host = new WebHostBuilder()
.UseUrls("http://*:5000")
.UseKestrel()
.UseWebRoot(Directory.GetCurrentDirectory() + "/www")
.UseStartup<Startup>()
.Build();
By adding following static file middlewares in Configure method of Startup class we can enable default files, serve static files and directory browsing for www folder and subfolders inside.
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseDirectoryBrowser();
Let us change the environment to Development in launchSettings.json, build and run DemoApp to verify the file serving feature added to HTTP request pipeline. I have added html pages,
single page application and a Angularjs client API in subfolders of web root folder. You can add any static content such as html, images, videos, css, text, json and javascript.
Hide Copy Code
Hide Copy Code
Hide Copy Code
Hide Copy Code
13. 12/29/2016 Create HTTP request pipeline using ASP.NET Core custom middleware: build/run on Mac, Windows, Linux or Docker container - CodeProject
https://www.codeproject.com/Articles/1158001/Create-HTTP-request-pipeline-using-ASP-NET-Core 13/14
Conclusion
In this tutorial I have demonstrated on how to build a custom and lightweight HTTP request pipeline on a new ASP.NET Core framework. I started from scratch and then added custom
middleware to a request pipeline. I used Dependency Injection in Startup class to configure middleware to provide custom messages. I also later on added builtin middlewares in ASP.NET
core to the pipeline. Generally I use my favorite IDE installed on my computer for development but here I have used Command Line Interface, Visual Studio Code and Visual Studio 2015 for
development and demonstrated compiling and running of ASP.NET Core application on Mac, Linux and Windows.
History
I understand this is a long (tl;dr) crossplatform tutorial on a new technology. I appreciate your suggestions or corrections. Any changes or improvements I made here will be posted here.
December 27, 2016: Added uncompiled source code for DemoApp.
References
https://docs.microsoft.com/enus/dotnet/
https://docs.microsoft.com/enus/aspnet/
https://github.com/aspnet/
License
This article, along with any associated source code and files, is licensed under The MIT License
Share
About the Author
You may also be interested in...
Mobile App Playbook Increase System Availability by Leveraging Apache Tomcat Clustering
EMAIL
Neal Pandey
Technical Lead / Consultant
United States
I am a Full Stack Web Developer/Architect with 15+ years of experience. My primarily expertise is in building Web Application on .NET stack but I do often indulge in open source
technologies and NoSQL world. C# and SQL are my favorite languages but I don't mind learning anything new which makes life easier for us. My genuine interest in software technology
motivates me to evaluate different technologies and develop solution that suits the best.