Creating Custom Middleware in ASP.NET Core (Part 1)
Tags: dotnet, csharp, tutorial
Published: 2019-08-25 19:53:22

---
canonical_url: https://austincooper.dev/2019/08/25/creating-custom-middleware-in-.net-core/
---

Original post: https://austincooper.dev/2019/08/25/creating-custom-middleware-in-.net-core/

## What is middleware?

Simply, middleware is code that becomes part of a pipeline to handle requests and responses in a web app.  In ASP.NET Core, middleware is a big deal!  All requests are handled by a pipeline of middleware.

![Middleware Flow](https://thepracticaldev.s3.amazonaws.com/i/oygysmf4brke1eycd8uk.png)

If you've created an ASP.NET Core app before, you are probably aware of the `UseDeveloperExceptionPage` middleware.  This middleware adds special exception handling.  If an exception is thrown later in the pipeline, the exception bubbles up to this middleware, which returns a nice page with details as a response to the request.  Because middleware is a pipeline, order matters.  For the developer exception page, it's important that it is one of the first middleware added to the pipeline.

Find the code for this post on [GitHub](https://github.com/cooperaustinj/create-middleware)!

## Getting started

For this guide, I'm starting with a project creating using `dotnet new web`.  This command creates an ASP.NET Core project with the minimum amount of boilerplate.

```csharp
// Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}
```

Even in this most basic project, we already have two middleware components: `UseDeveloperExceptionPage` and `Run`.  We already know about `UseDeveloperExceptionPage`.  `Run` is a *terminal middleware*.  A terminal middleware stops processing additional middleware for the request.

`Use` is a another middleware we can use.  It is not *necessarily* a terminal middleware, like `Run`.  It can be terminal or non-terminal depending on whether the next middleware is called.  `Use` will be how we write our first custom middleware.

## Custom Middleware

Let's add some custom middleware to our `Startup.Configure` method.

```diff
- public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
 {
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
+
+    app.Use(async (context, next) =>
+    {
+        logger.LogInformation("Request started");
+        await next.Invoke();
+        logger.LogInformation("Request finished");
+    });

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
 }
```

We added a logger and an `app.Use` section.  This is always a non-terminal middleware, because we call `next.Invoke` for all code paths within the middleware.  To try this out, run `dotnet run` and navigate to `http://localhost:5000`.  You should see `Hello World!` on the page, and something like this in the console:

```yaml
info: CreatingMiddleware.Startup[0]
      Request started
info: CreatingMiddleware.Startup[0]
      Request finished
```

## Enhance!

So we've created a super simple custom middleware that logs when a request is started and completed.  Cool... but what else can we do?  Let's make some changes to our `app.Use` block...

```csharp
app.Use(async (context, next) =>
{
    if (context.Request.Path.ToString().StartsWith("/test"))
    {
        await context.Response.WriteAsync("Welcome to Test");
    }
    else
    {
        await next.Invoke();
    }
});
```

Now, our middleware is terminal when the request path starts with `/test`, returning the response `Welcome to Test`.  To verify, navigate to `http://localhost:5000/test`.  For routes that don't start with `/test`, we just pass-through to the next middleware.

You've likely noticed that we have access to the entire `HttpContext` in our middleware.  We can check whether the user is authenticated, pull information out of the route, and read the body of the request.  Of course, those are just some examples of the information we can get from `HttpContext`.

## That's All for Now

Middleware is a pretty deep rabbit-hole, so I'm going to call this post here.  I have more to write about, but that will have to come in later posts - I don't want to overload post with everything.  Visit my personal site at http://austincooper.dev to subscribe and be notified when Part 2 comes out.