asp.net-core

Working with Environments and Launch Settings in ASP.NET Core

I'm continuing my series of deep dives into ASP.NET Core, on my never-ending quest to keep my coding career from becoming obsolete. In this part of the series, let's discuss a new feature in ASP.NET Core that will make debugging and testing much more intuitive and pain-free: Environments and Launch Settings.

ASP.NET Core includes the native ability to modify how an application behaves (and what it displays) based upon the environment it is currently executing in. This ends up being quite useful, since now we can do things as simple as not showing the error page to people using the application in a production environment. But it requires just a tiny bit of setup, and some knowledge of how environments are controlled.

ASPNETCORE_ENVIRONMENT

At the heart of all the stuff ASP.NET Core can do with environments is the ASPNETCORE_ENVIRONMENT environment variable. This variable controls what type of environment the current build will run in. You can edit this variable manually by right-clicking your project file and selecting "Properties", then navigating to the "Debug" tab.

There are three "default" values for this variable:

  • Development
  • Staging
  • Production

Each of those values corresponds to certain methods we can use in our Startup.cs file. In fact, the Startup.cs file includes several extension methods that make modifying our application based it's current environment quite simple.

Selecting an Environment

The Startup.cs file that every ASP.NET Core application needs does many things, not the least of which is setting up the environment in which the application runs. Here's a snippet of the default Startup.cs file that was generated when I created my sample project for this post:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Notice the IHostingEnvironment variable. That variable represents the current environment in which the application runs, and ASP.NET Core includes four extension methods that allow us to check the current value of ASPNETCORE_ENVIRONMENT:

  • IsDevelopment()
  • IsStaging()
  • IsProduction()
  • IsEnvironment()

Notice what we're setting up in the Startup.cs file: if the current environment is Development, we use the Developer Exception Page (which was formerly the Yellow Screen of Death) as well as enabling Browser Link in Visual Studio, which helps us test our application in several browsers at once.

But we don't want those features enabled in a Production environment, so instead our configuration establishes an error handling route "/Home/Error".

This is the coolest thing about this feature: you can decide what services are enabled for your application in each environment without ever touching a configuration file!

However, what if you need more environments? For example, at my day job we have up to four environments: Development, Staging, Production, and Testing, and very often I'll need to change application behaviors or display based on which environment it's currently running in. How do I do that in ASP.NET Core?

The launchSettings.json File

ASP.NET Core 1.0 includes a new file called launchSettings.json; in any given project, you'll find that file under the Properties submenu:

This file sets up the different launch environments that Visual Studio can launch automatically. Here's a snippet of the default launchSettings.json file that was generated with my demo project:

{
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "CoreEnvironmentBehaviorDemo": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

At the moment we have two profiles: one which runs the app using IIS Express and one which runs the app using a command-line handler. The interesting thing about these two profiles is that they correspond directly to the Visual Studio play button:

In other words: the launchSettings.json file controls what environments you can run your app in using Visual Studio. In fact, if we add a new profile, it automatically adds that profile to the button, as seen on this GIF I made:

All this together means that we can run the app in multiple different environment settings from Visual Studio, simply by setting up the appropriate launch profiles.

The Environment Tag Helper

Quite a while ago I wrote a post about Tag Helpers and how awesome they are, and I want to call out a particular helper in this post: the <environment> tag helper.

With this helper, we can modify how our MVC views are constructed based upon which environment the application is currently running in. In fact, the default _Layout.cshtml file in Visual Studio 2015 comes with an example of this:

<environment names="Development">  
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
</environment>  
<environment names="Staging,Production">  
    <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
            asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
            asp-fallback-test="window.jQuery">
    </script>
    <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
            asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
    </script>
    <script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>  

In this sample, when we run the app in Development mode we use the local files for jQuery, Bootstrap, and our custom Javascript; but if we're running in the Staging or Production environments, we use copies of those libraries files found on the ASP.NET content delivery network (CDN). In this way, we improve performance, because a CDN can deliver these static files from one of many centers around the globe, rather than needing to round-trip all the way to the source server to get those files.

But, remember, in our sample we have the custom environment Testing. The environment tag helper also supports custom environments:

<div class="row">  
    <environment names="Development">
        <span>This is the Development environment.</span>
    </environment>
    <environment names="Testing">
        <span>This is the Testing environment.</span>
    </environment>
    <environment names="Production">
        <span>This is the Production environment.</span>
    </environment>
</div>  

Summary

Working with environments (both default and custom) gets a whole lot easier in ASP.NET Core, and with the new Launch Settings feature, getting the app started in different environment modes is a breeze! Using these features, we can:

  • Create and use custom environments.
  • Enable or disable application services based on the environment the app is running in.
  • Use the environment tag helper (<environment>) to modify our MVC views based on the current execution environment.

You can check out my sample project over on GitHub to see this code in action. Feel free to mention any cool tips and tricks you've found when dealing with environments and launch settings in the comments!

Happy Coding!

Injecting Services into MVC Views With ASP.NET Core

I've been exploring ASP.NET Core 1.0 for a little while now, and every step I take reinforces my opinion that Core is going to be a huge step forward for ASP.NET developers. However, in my eagerness to share all the stuff I'm learning, occasionally I forget to include something in one of my posts that really should have been there.

A young girl gives the Image found on Flickr and used under license

So I wrote a post about dependency injection in ASP.NET Core, but I totally missed one of the cooler features that Core added: you can now inject services into MVC views.

Yes, seriously. Here's how it works. Let's say that we have the following User class and the corresponding UserRepository interface and class:

public class User  
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
}

public interface IUserRepository  
{
    List<User> GetAll();
}

public class UserRepository : IUserRepository  
{
    public List<User> GetAll()
    {
        return new List<User>()
        {
            new User()
            {
                FirstName = "Jyn",
                LastName = "Erso",
                DateOfBirth = new DateTime(1983, 10, 17)
            },
            new User()
            {
                FirstName = "Cassion",
                LastName = "Andor",
                DateOfBirth = new DateTime(1979, 12, 29)
            },
            new User()
            {
                FirstName = "Bodhi",
                LastName = "Rook",
                DateOfBirth = new DateTime(1982, 12, 1)
            }
        };
    }
}

With such a setup, we're ready to use ASP.NET Core's native dependency injection container. Remember that in order to use said container we must register services in the Startup.cs file. Such a registration looks like this:

public void ConfigureServices(IServiceCollection services)  
{
    // Add framework services.
    services.AddMvc();

    services.AddTransient<IUserRepository, UserRepository>();
}

The next step is to create the (admittedly very simple) implementation of our Controller, which is as follows:

[Route("users")]
public class UsersController : Controller  
{
    [HttpGet]
    [Route("all")]
    [Route("~/")]
    public IActionResult GetAll()
    {
        return View();
    }
}

Finally, we can inject the service into a .cshtml view using the @inject keyword, which is new to ASP.NET Core 1.0. Here's the view for displaying these users:

@inject ViewInjectionCoreDemo.Repositories.IUserRepository userRepo

<h2>All Users</h2>

<table>  
    <thead>
        <tr>
            <th>
                First Name
            </th>
            <th>
                Last Name
            </th>
            <th>
                Date of Birth
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var user in userRepo.GetAll())
        {
            <tr>
                <td>
                    @user.FirstName
                </td>
                <td>
                    @user.LastName
                </td>
                <td>
                    @user.DateOfBirth
                </td>
            </tr>
        }
    </tbody>
</table>  

Running our sample app displays the following page:

That's really all there is to it! ASP.NET Core's Dependency Injection framework continues to impress me, and I'm looking forward to getting to use it all the time.

If you want to take a look at the repository for this demo, it's over on GitHub.

Happy Coding!

Getting Started with Dependency Injection in ASP.NET Core

I've lately been feeling my way around getting an actual, production-ready ASP.NET Core app developed, and one of the features I've really been digging (one of many) is native support for Dependency Injection (DI). DI is huge in modern web apps, so making it the default for ASP.NET Core applications is, IMO, a big step forward for this framework.

But, at the moment, the documentation page for dependency injection in ASP.NET Core has an example that just didn't click with me, and I believe that's because they didn't have any code examples to provide. In this post, I will provide two examples: one of my own design, and one which recreates an example provided in the official documentation; both of these sample projects are now over on GitHub. Let's learn how to use Dependency Injection in ASP.NET Core!

What Is Dependency Injection?

First, a few basics. The idea of Dependency Injection is that, when a class is created, it should have its dependent classes injected into it rather than created by it. This provides a situation in which we have loose coupling and high cohesion, an ideal which many software programs strive toward.

The ASP.NET Core documents explains it like this:

"[When using DI, ]Rather than directly instantiating collaborators, or using static references, the objects a class needs in order to perform its actions are provided to the class in some fashion. Most often, classes will declare their dependencies via their constructor, allowing them to follow the Explicit Dependencies Principle. This approach is known as 'constructor injection'."

Constructor injection is by far the most common approach to implementing DI, though not the only one. ASP.NET Core uses constructor injection in its solution, so (obviously) we will also do so.

Finally, note that there are many DI frameworks out there in addition to the native ASP.NET Core one, including StructureMap, Autofac, Ninject, SimpleInjector, and several others. StructureMap is my personal favorite, but all of these frameworks do roughly the same thing. Try a few to figure out which fits your style; in this demo I will use the native ASP.NET Core DI container.

A Basic DI Example

To demonstrate how Dependency Injection works in an ASP.NET Core app, let's set up a basic MVC app as a demo.

Pretend we need to model a list of users for our application. The class which represents these users might look like this:

public class User  
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Username { get; set; }
}

We will also need an interface and repository for retrieving the users. The interface and class will look like this:

public interface IUserRepository  
{
    List<User> GetAll();
}

public class UserRepository : IUserRepository  
{
    public List<User> GetAll()
    {
        return new List<User>()
        {
            new User()
            {
                FirstName = "Ash",
                LastName = "Ketchum",
                DateOfBirth = new DateTime(1997, 12, 30),
                Username = "ichooseyou"
            },
            new User()
            {
                FirstName = "Brock",
                LastName = "Harrison",
                DateOfBirth = new DateTime(1992, 3,31),
                Username = "rockrulez"
            },
            new User()
            {
                FirstName = "Misty",
                LastName = "",
                DateOfBirth = new DateTime(1999, 5,4),
                Username = "ihearttogepi"
            }
        };
    }
}

The reason we need an interface here is because our MVC controllers will reference the interface, not the class. Speaking of the controller, let's define one now:

public class HomeController : Controller  
{
    private readonly IUserRepository _userRepo;

    public HomeController(IUserRepository userRepo)
    {
        _userRepo = userRepo;
    }

    [HttpGet]
    public IActionResult Index()
    {
        return View(_userRepo.GetAll());
    }
}

Notice the setup here. We have a private readonly instance of our interface IUserRepository, and the constructor takes an instance of IUserRepository and sets our private instance to the passed-in instance. This is constructor injection at its simplest.

But we're not done yet. As I've discussed previously on this blog, ASP.NET Core projects have a Startup.cs file, which configures the environment in which our app will run. The Startup.cs file also places services into ASP.NET Core's Services layer, which is what enables dependency injection.

Here's how we must modify our Startup.cs file to inject IUserRepository into our controller:

public void ConfigureServices(IServiceCollection services)  
{
    // Add framework services.
    services.AddMvc();

    //Basic demo
    services.AddTransient<IUserRepository, UserRepository>();
}

We'll discuss what AddTransient<>() means in the next section. For now, let's run the app.

Here's what our page looks like when we get there:

Note that once we added the IUserRepository to the Services layer, ASP.NET Core automatically injected it into our HomeController class. That's pretty neat!

But, what exactly does AddTransient<>() do in the Startup file? To discuss that, we must first discuss what ASP.NET Core uses as lifetimes for its services.

Dependency Injection Lifetimes

In ASP.NET Core's DI implementation, we see the concept of "lifetimes". A lifetime specifies when a DI-injected object gets created or recreated. There are three possibilities:

  • Transient: Created each time they are requested.
  • Scoped: Created once per request.
  • Singleton: Created the first time they are requested. Each subsequent request uses the instance that was created the first time.

The ASP.NET Core official documentation provides a walkthrough of sorts for how these lifetimes behave, but I'm not satisfied with that example as it skips over a few sections of code that I think are rather important and doesn't provide a working example. I've reproduced it here, with a full working codebase which, like the earlier example, is over on GitHub.

To demonstrate how these lifetimes work, let's define a few interfaces. We'll need an interface IOperation which represents an operation being done in each of these lifetimes. Said operation will do one thing: it will return either Guid.NewGuid() or the passed-in Guid value from its one method. We'll also define four additional interfaces, each of which represents that operation during a specific lifetime:

public interface IOperation  
{
    Guid GetCurrentID();
}

public interface IOperationTransient : IOperation { }

public interface IOperationScoped : IOperation { }

public interface IOperationSingleton : IOperation { }

public interface IOperationSingletonInstance : IOperation { }  

IOperationSingletonInstance is a special form of this operation which will always return a blank Guid.

Now we can define the Operation class itself, which implements the four lifetime interfaces and defines the GetCurrentID() method.

public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance  
{
    public Guid Guid { get; set; }

    public Operation()
    {
        Guid = Guid.NewGuid();
    }

    public Operation(Guid guid)
    {
        Guid = guid;
    }

    public Guid GetCurrentID()
    {
        return Guid;
    }
}

Our Operation class will either return Guid.NewGuid() or used the Guid passed in to the constructor (this scenario is for the IOperationSingletonInstance interface demo).

However, to fully show how Transient operations work, we also need to define another class which represents a separate set of instances of these interfaces (separate from the ones being injected into our controller). We'll call this class OperationServices and it looks like this:

public class OperationService  
{
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public OperationService(IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)
    {
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = instanceOperation;
    }
}

Now we need to register the four lifetime interfaces and our OperationServices class into our Dependency Injection container. We do so in the Startup class's ConfigureServices() method, just like we registered the IUserRepository class earlier.

public void ConfigureServices(IServiceCollection services)  
{
    // Add framework services.
    services.AddMvc();

    //Basic demo
    services.AddTransient<IUserRepository, UserRepository>();

    //Lifetimes demo
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
    services.AddTransient<OperationService, OperationService>();
}

With all our dependencies registered, we can now create an OperationsController which will demo how these lifetimes work.

public class OperationsController : Controller  
{
    private readonly OperationService _operationService;
    private readonly IOperationTransient _transientOperation;
    private readonly IOperationScoped _scopedOperation;
    private readonly IOperationSingleton _singletonOperation;
    private readonly IOperationSingletonInstance _singletonInstanceOperation;

    public OperationsController(OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _operationService = operationService;
        _transientOperation = transientOperation;
        _scopedOperation = scopedOperation;
        _singletonOperation = singletonOperation;
        _singletonInstanceOperation = singletonInstanceOperation;
    }

    public IActionResult Index()
    {
        // viewbag contains controller-requested services
        ViewBag.Transient = _transientOperation;
        ViewBag.Scoped = _scopedOperation;
        ViewBag.Singleton = _singletonOperation;
        ViewBag.SingletonInstance = _singletonInstanceOperation;

        // operation service has its own requested services
        ViewBag.Service = _operationService;
        return View();
    }
}

For posterity, I will also include the .cshtml file which displays the results of that Index() action:

@{
    ViewData["Title"] = "ASP.NET Core Dependency Injection Demo";
}

<h2>Lifetimes</h2>

<span>Controller Operations</span>  
<ul>  
    <li><strong>Transient:</strong> @ViewBag.Transient.GetCurrentID()</li>
    <li><strong>Scoped:</strong> @ViewBag.Scoped.GetCurrentID()</li>
    <li><strong>Singleton:</strong> @ViewBag.Singleton.GetCurrentID()</li>
    <li><strong>Singleton Instance:</strong> @ViewBag.SingletonInstance.GetCurrentID()</li>
</ul>  
<span>OperationService Operations</span>  
<ul>  
    <li><strong>Transient:</strong> @ViewBag.Service.TransientOperation.GetCurrentID()</li>
    <li><strong>Scoped:</strong> @ViewBag.Service.ScopedOperation.GetCurrentID()</li>
    <li><strong>Singleton:</strong> @ViewBag.Service.SingletonOperation.GetCurrentID()</li>
    <li><strong>Singleton Instance:</strong> @ViewBag.Service.SingletonInstanceOperation.GetCurrentID()</li>
</ul>  

Testing the Lifetimes

With all of our code in place, we are now ready to test. Let's look at two screenshots of that demo page. The first screenshot is when we first load the page.

The second screenshot is of the same page after doing a refresh:

We need to notice a few things about the differences in these screenshots:

  • Each time it shows up, the Transient Guid is different.
  • The Scoped Guids are the same for both calls in a single screenshot, but not in each screenshot.
  • The Singleton Guids are the same all four times they are called.
  • The Singleton Instance Guids (as expected) are always 0s.

I personally find that the differences are easier to spot if I see them in real-time, so I made this gif:

A short demo showing the differences between Transient, Scoped, and Singleton services in ASP.NET Core

Summary

One of the best new features coming from ASP.NET Core is the inclusion of its own lightweight Dependency Injection container. In this post, we've seen how to inject a simple service into a controller, and we've seen the three DI lifetimes (Transient, Scoped, Singleton) and how they behave differently from one another.

As always, please feel free to check out the code base for this post over on GitHub and let me know if you see any improvements I could make.

Happy Coding!

Writing Custom Middleware in ASP.NET Core 1.0

One of the new features from ASP.NET Core 1.0 is the idea of Middleware. Middleware are components of an application that examine the requests responses coming in to and going out from an ASP.NET Core application. It's a long-overdue piece of customization for ASP.NET apps that gives us developers total control over the HTTP pipeline. It might even help you avoid endless questions from annoying coworkers (maybe!).

As part of my ongoing learning process about ASP.NET Core, I decided to build a sample application that has a few pieces of middleware, so that I could play around with order, tasks, and so forth. It helped me understand what Middleware does, and why it might be important, so hopefully it'll help you too. Let's get started!

NOTE: This post was written using RC1 (Release Candidate 1) of ASP.NET Core, and as the framework gets closer to final release, some things may change. If they do, I'll do my best to keep this post up-to-date. If you notice anything that needs to be updated, let me know in the comments.

What Is Middleware?

Middleware, as explained above, are components that "sit" on the HTTP pipeline and examine requests and responses. This means that they are effectively "gateway" classes that can decide whether or not to continue allowing the request to be processed by other Middleware components further down the stream. The pipeline looks like this:

Image is © Microsoft, taken from docs.asp.net

The idea of Middleware, at least in ASP.NET, comes from the Open Web Interface for .NET (OWIN) project. OWIN's stated goal is to

...decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

Considering their ideas have been fully integrated into ASP.NET Core 1.0, I'd say they've more than achieved this goal.

At any rate, Middleware defines a system by which we can exert complete control over the HTTP pipeline into and out of our apps. It effectively replaces the functionality that was formerly covered by things like HttpModules and HttpHandlers.

Default Middleware

In some default ASP.NET Core 1.0 apps, particularly the ones created by Visual Studio, you are already using Middleware. Here's a sample from my earlier post covering the Startup.cs file in ASP.NET Core 1.0:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseBrowserLink(); //Middleware
        app.UseDeveloperExceptionPage(); //Middleware
    }
    else
    {
        app.UseExceptionHandler("/Home/Error"); //Middleware
    }

    app.UseIISPlatformHandler(); //Middleware

    app.UseStaticFiles(); //Middleware

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });  //Middleware
}

In this method, any time you see app.UseX(), you are using some of ASP.NET's default Middleware components. The concept of Middleware and the HTTP pipeline is central to how ASP.NET Core apps are developed. You can check out the other built-in Middleware by reading the docs.

Defining a Custom Middleware Component

A Middleware component, in an ASP.NET Core project, is a class like any other. The difference is that the Middleware component needs to have a private property of type RequestDelegate, like so:

public class AuthorizationMiddleware  
{
    private readonly RequestDelegate _next;

    public AuthorizationMiddleware(RequestDelegate next)
    {
        _next = next;
    }
}

The _next property represents a delegate for the next component in the pipeline. Each component must also implement an async task called Invoke:

public async Task Invoke(HttpContext context)  
{
    await _next.Invoke(context);
}

At the moment, this method does nothing other than call the next Middleware component in the pipeline. Let's see a simple task that we can do with our new Middleware component.

Middleware Tasks

Since each piece of Middleware can examine the incoming request and the corresponding response, one possible task Middleware could accomplish is that of authorization.

For a (trivial) example, let's say that each request must NOT have a header "X-Not-Authorized", and if it does, the response must be returned immediately with a 401 Unauthorized status code. Our Middleware component's Invoke method would now look like this:

public async Task Invoke(HttpContext context)  
{
    if (context.Request.Headers.Keys.Contains("X-Not-Authorized"))
    {
        context.Response.StatusCode = 401; //Unauthorized
        return;
    }

    await _next.Invoke(context);
}

If we call any method in our app with a tool such as Postman, we'll get the following response:

Middleware can accomplish many sorts of things. For example:

  • You might want to examine each incoming request to see if they have requested an image, and if they have, redirect them to an image handler, much like you would when we used HttpHandlers.
  • You might have a component that logs all requests.
  • You might have a component that checks to see if you annoying coworker Doug from down the hall is making a request, and if he is, redirect all his requests to Mary just so you don't have to deal with him anymore.

The possibilities are endless!

Other Example Middleware

For our sample project, we've already got one Middleware component (AuthorizationMiddleware) defined. Now we will define two more. First up is RequestHeaderMiddleware:

public class RequestHeaderMiddleware  
{
    private readonly RequestDelegate _next;

    public RequestHeaderMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Headers.Keys.Contains("X-Cancel-Request"))
        {
            context.Response.StatusCode = 500;
            return;
        }

        await _next.Invoke(context);

        if (context.Request.Headers.Keys.Contains("X-Transfer-By"))
        {
            context.Response.Headers.Add("X-Transfer-Success", "true");
        }
    }
}

This Middleware component does two things:

  1. If the request contains a header called "X-Cancel-Request" then the server returns 500 Internal Server Error as the response.
  2. If the request contains a header called "X-Transfer-By" then the server adds a header to the response called "X-Transfer-Success".

Finally, let's add a third piece of middleware, called ProcessingTimeMiddleware:

public class ProcessingTimeMiddleware  
{
    private readonly RequestDelegate _next;

    public ProcessingTimeMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        var watch = new Stopwatch();
        watch.Start();

        await _next(context);

        context.Response.Headers.Add("X-Processing-Time-Milliseconds", new[] { watch.ElapsedMilliseconds.ToString() });
    }
}

This component starts an instance of Stopwatch to record how long each request takes, then returns a header called "X-Processing-Time-Milliseconds" with that time in the response.

Now that we've got all the Middleware components we're going to use, let's see how we can insert them into our ASP.NET Core 1.0 app's pipeline!

Adding Middleware to the HTTP Pipeline

The environment for an ASP.NET Core 1.0 is set up in that app's Startup.cs file. In order to use our newly-created Middleware, we need to register them with the environment created by Startup.

There are two ways we can register the Middleware in the pipeline. One way is to go to the Startup file's Configure method and call a method on the IApplicationBuilder interface (simplified):

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    ...
    app.UseMiddleware<AuthorizationMiddleware>();
    ...
}

Another way, and the way we're going to use, is to create extension methods for each piece of Middleware you want to register, and then call those methods from the Configure() method. Here's our Extensions class:

public static class MiddlewareExtensions  
{
    public static IApplicationBuilder UseRequestHeaderMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestHeaderMiddleware>();
    }

    public static IApplicationBuilder UseAuthorizationMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<AuthorizationMiddleware>();
    }

    public static IApplicationBuilder UseProcessingTimeMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ProcessingTimeMiddleware>();
    }
}

Now we can call these extensions in Startup like so (the below code contains a bug, read it carefully):

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        app.UseBrowserLink();
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseIISPlatformHandler();
    app.UseStaticFiles();
    app.UseProcessingTimeMiddleware();
    app.UseRequestHeaderMiddleware();
    app.UseAuthorizationMiddleware();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Did you spot it?

When you are registering Middleware with your environment, the order in which you add the Middleware components is very important. In the above code, we add ProcessingTimeMiddleware first, then RequestHeaderMiddleware, then AuthorizationMiddleware. This is the exact opposite order of what we should be using. The correct order looks like this (simplified):

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{
    ...
    app.UseAuthorizationMiddleware();
    app.UseRequestHeaderMiddleware();
    app.UseProcessingTimeMiddleware();
    ...
}

Testing With Postman

Now that we've got our Middleware components in place, let's see some example request/response calls to a controller action in our app. The controller action we're using is very simple:

[HttpGet]
public IActionResult TestMiddleware()  
{
    return Ok();
}

NOTE: Don't forget that, in ASP.NET Core 1.0 and MVC 6, MVC and Web API use the same stack.

Now let's make some Postman calls. First, let's make a call with no headers at all.

A Postman response, showing the status code 200 OK and including the

This is what we would expect to see. Neither the Authorization nor the RequestHeader Middleware components prevents execution, so the ProcessingTime component added the header and we got back the Action's 200 OK response.

Now let's see what happens if we add in the X-Not-Authorized header:

A Postman response, showing the status code 401 Unauthorized and missing the

Great! The AuthorizationMiddleware component returned 401 Unauthorized, and because there's no "X-Processing-Time-Milliseconds" header isn't included in the response, the ProcessingTimeMiddleware component didn't fire. This is what we expect.

I'm sure you see where this is going by now. For the last test, let's see a request without "X-Not-Authorized" header but including "X-Transfer-By":

A Postman response, showing status code 200 OK and including

In this case, we see that both "X-Processing-Time-Milliseconds" and "X-Transfer-Success" returned, which means that both RequestHeaderMiddleware and ProcessingTimeMiddleware successfully fired. Looks like our scenarios work!

Let's try one more request.

A Postman response, showing a request header

Perfect!

Summary

Remember these three major points about Middleware in ASP.NET Core 1.0:

  1. Middleware components allow you complete control over the HTTP pipeline in your app.
  2. Among other things, Middleware components can handle authorization, redirects, headers, and even cancel execution of the request.
  3. The order in which Middleware components are registered in the Startup file is very important.

You can see the sample code for this project in the GitHub repository. As always, let me know what you think about this post in the comments, particularly if I missed something important.

Happy Coding!