ASP.NET Core 2.2 For Beginners (Part 3): Middleware

In this chapter, you will add middleware that handles HTTP requests, like how the applica­tion behaves if there is an error. One key aspect of the middleware is to perform user authentication and authorization.

By the end of this chapter you will have built a middleware pipeline for a MVC application.

How Does Middleware Work?

Let’s have a look at how middleware works and what it is used for.

When an HTTP request comes to the server, it is the middleware components that handle that request.

Each piece of middleware in ASP.NET is an object with a very limited, specific, and focused role. This means that you will have to add many middleware components for an applica­tion to work properly.

The following example illustrates what can happen when an HTTP POST request to a URL, ending with /reviews, reaches the server.

Logging is a separate middleware component that you might want to use to log informa­tion about every incoming HTTP request. It can see every piece of data, such as the head­ers, the query string, cookies, and access tokens. Not only can it read data from the re­quest, it can also change information about it, and/or stop processing the request.

The most likely scenario with a logger is that it will log information and pass the processing onto the next middleware component in the pipeline.

This mean that middleware is a series of components executed in order.

The next middleware component might be an authorizer that can look at access tokens or cookies to determine if the request will proceed. If the request doesn’t have the correct credentials, the authorizer middleware component can respond with an HTTP error code or redirect the user to a login page.

If the request is authorized, it will be passed to the next middleware component, which might be a routing component. The router will look at the URL to determine where to go next, by looking in the application for something that can respond. This could be a method on a class returning a JSON, XML, or HTML page for instance. If it can’t find anything that can respond, the component could throw a 404 Not Found error.

Let’s say that it found an HTML page to respond; then the pipeline starts to call all the middleware components in reverse order, passing along the HTML. When the response ultimately reaches the first component, which is the logger in our example, it might log the time the request took and then allow the response to go back over the network to the client’s browser.

This is what middleware is, a way to configure how the application should behave. A series of components that handle specific, narrow tasks, such as handle errors, serve up static files and send HTTP requests to the MVC framework. This will make it possible for you to build the example video application.

This book will not go into the nitty-gritty of middleware – only the basics that you need to build a MVC application.

IApplicationBuilder

The IApplicationBuilder interface injected into the Startup class’s Configure method is used when setting up the middleware pipeline.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMessageService msg)
{
    if (env.IsDevelopment()) app.UseDeveloperExceptionPage();

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync(msg.GetMessage());
    });
}

To add middleware, you call extension methods on the app parameter, which contains the dependency-injected object for the IApplicationBuilder interface. Two middleware com­ponents are already defined in the Configure method.

The UseDeveloperExceptionPage middleware component will display a pretty error page to the developer, but not the user; you can see that it is encapsulated inside an if-block that checks if the environment variable is set to the development environment.

The UseDeveloperExceptionPage middleware component then calls the Run middleware component that is used to process every response. Run is not frequently used because it is a terminal piece of middleware, which means that it is the end of the pipeline. No mid­dleware component added after the Run component will execute, because Run doesn’t call into any other middleware components.

app.Run(async (context) =>
{
    await context.Response.WriteAsync(msg.GetMessage());
});

By using the context object passed into the Run method, you can find out anything about the request through its Request object –the header information, for instance. It will also have access to a Response object, which currently is used to print out a string.

In the previous chapter, you called the GetMessage method on the message service inside the Run method.

Most middleware components will be added by calling a method beginning with Use on the app object, such as app.UseDeveloperExceptionPage.

As you can see, there are several middleware components available out of the box using the app object. You can add more middleware components by installing NuGet packages containing middleware.

Handling Exceptions

Let’s have a look at how exception messages are handled by the pipeline. As previously mentioned the app.UseDeveloperExceptionPage middleware is in place to help the devel­oper with any exceptions that might occur. To test this behavior, you can add a throw statement at the top of the Run-block and refresh the application in the browser.

  1. Open the cs file and locate the Run middleware in the Configure method.
  2. Add a throw statement that returns the string Fake Exception! to the Run-block.

app.Run(async (context) =>
{
    throw new Exception("Fake Exception!");
    await context.Response.WriteAsync(msg.GetMessage());
});

  1. Add a using statement for the System namespace to access the Exception

using System;

  1. Press Ctrl+F5 to start it without debugging. Otherwise switch to the browser and refresh the application.
  2. A pretty error message will be displayed. Note that this message will be displayed only when in development mode. On this page, you can read detailed information about the error, query strings, cookie information, and header content.

Now let’s see what happens if you change the environment variable to Production and refresh the page.

  1. Select Project-AspNetCore22Intro Properties in the main menu.
  2. Click on the Debug tab on the left side of the dialog.
  3. Change the ASPNETCORE_ENVIRONMENT property to Production.
  4. Save all files (Ctrl+Shift+S).
  5. Refresh the application in the browser.
  6. Now you will get an HTTP 500 Error- This page isn’t working error, which is what a regular user would see. If you don’t see this message, then you have to manually build the project with Ctrl+F5.
  7. Switch back to Visual Studio and change back the ASPNETCORE_ENVIRONMENT property to Development.
  8. Save all files.
  9. Refresh the application in the browser; you should now be back to the pretty error page.

Now let’s see what happens if we comment out the app.UseDeveloperExceptionPage middleware.

  1. Open the cs file and locate the Configure method.
  2. Comment out the call to the UseDeveloperExceptionPage middleware.

//app.UseDeveloperExceptionPage();

  1. Save the file and build the solution (Ctrl+Shift+B).
  2. Refresh the application in the browser.
  3. The plain HTTP 500 error should be displayed because you no longer are loading the middleware that produces the pretty error message.
  4. Uncomment the code again and save the file.
  5. Refresh the browser one last time to make sure that the pretty error message is displayed.
  6. Remove the throw statement from the Run-block and save the file.

throw new Exception("Fake Exception!");

You can use the IHostingEnvironment object, passed in through dependency injection, to find out information about the environment. You have already used an if statement to determine if the environment variable is set to Development, if it is, a pretty error page will be displayed. You can also use it to find out the absolute path to the wwwroot directory in the project with the WebRootPath property.

Serving Up Static Files

A feature that nearly all web applications need is the ability to serve up static files, such as JSON, CSS, and HTML files. To allow ASP.NET to serve up files, you must add a new middle­ware component that is called with the UseStaticFiles method, located in the Microsoft
.AspNetCore.StaticFiles
NuGet package, which is installed with the default Microsoft
.AspNetCore.App
NuGet package.

Without the UseStaticFiles middleware component, the application will display the mes­sage from the Run middleware.

Let’s add an HTML file to the wwwroot folder and see what happens, and why. Static files must be added to the wwwroot folder for ASP.NET to find them.

  1. Right click on the project node in the Solution Explorer and select Add-New Folder wwwroot folder and select.
  2. Add tree folders named css, js and lib to the wwwroot Right click on the wwwroot folder and select Add-New Folder.
  3. Right click on the wwwroot folder and select Add-New Item.
  4. Search for the HTML Page template and select it.
  5. Name the file html and click the Add button.
  6. Add the text An HTML Page to the <title> tag, and Hello, from index.html in the <body>
  7. Save all files and navigate to the /index.html page in the browser.
  8. The message Hello, from configuration is displayed, which probably isn’t what you expected.

The reason why the message Hello, from configuration is displayed is that there currently is no middleware that can serve up the static file. Instead the message in the Run middle­ware, which is accessible, will be displayed.

Let’s fix this by adding a new middleware located in the Microsoft.AspNetCore.StaticFiles NuGet package, which is installed by deafult.

When the UseStaticFiles method is called on the app object, ASP.NET will look in the wwwroot folder for the desired file. If a suitable file is found, the next piece of middleware will not be called.

  1. Open the cs file and locate the Configure method.
  2. Add a call to the UseStaticFiles method on the app object above the Run

app.UseStaticFiles();

  1. Save all the files and start the application with F5.
  2. Navigate to the html file. The message Hello, from index.html should be displayed.

The complete code for the Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMessageService msg)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseStaticFiles();

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync(msg.GetMessage());
    });
}

Configuring ASP.NET MVC

The last thing you will do in this chapter is to set up the ASP.NET MVC middleware and add a simple controller to test that it works.

The NuGet Microsoft.AspNetCore.Mvc package, which is installed by default, contains the MVC middleware that you will add to the HTTP pipeline and the MVC service that you will add to the services collection.

You will add a controller class with an Index action method that can be requested from the browser. In ASP.NET MVC, static HTML files, such as index.html, are not used. Instead views are usually used to serve up the HTML, JavaScript, and CSS content to the user. You will learn more about MVC in the next chapter. For now, let’s look at a simple example.

  1. Add a controller that can respond to the HTTP requests coming in to the application pipeline. The convention is to add controller classes to a folder named Controllers. Right click on the project node and select Add-New Folder and name it Controllers.
  2. Right click on the Controllers folder and select Add-Class.
  3. Name the class HomeController (the convention for a default controller) and click the Add Inherit the Controller class. Add a using stgatement for the Microsoft.AspNetCore.Mvc namespace.

public class HomeController : Controller
{
}

  1. Add a public method named Index that returns a string, to the HomeController Return the string Hello, from the controller! in the method.

public string Index()
{
    return "Hello, from the controller!";
}

  1. Save all files and run the application (F5). Navigate to the index.html page. Note that the html file still is being served up to the user, displaying the text Hello, from index.html. This is because you haven’t yet added the MVC service and middleware.
  2. Stop the application in Visual Studio.
  3. Delete the html file you added to the wwwroot folder; you won’t be needing it anymore since you want the controller to respond instead. You can do this either from the Solution Explorer or a File Explorer window in Windows.
  4. Open the cs file and locate the Configure method.
  5. Add the MVC middleware after the UseStaticFiles middleware method call, by calling the UseMvcWithDefaultRoute Adding it before the UseStaticFiles middleware would give the application a different behavior.

app.UseMvcWithDefaultRoute();

  1. Save all files and run the application (F5). You will be greeted by an exception message telling you that the necessary MVC service hasn’t been added.
  2. Stop the application and open the Startup class and locate the ConfigureServices
  3. Add the MVC services to the services collection at the top of the method. This will give ASP.NET everything it needs to run a MVC application.

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

  1. Save all files and run the application (F5). Now the message Hello, from the controller! will be displayed in the browser. This means that MVC is installed and working correctly. In the next chapter, you will implement a more sophisticated controller.

The complete code in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddSingleton<IMessageService,
        ConfigurationMessageService>();
}

 

The complete code in the Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMessageService msg)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync(msg.GetMessage());
    });
}

 

Summary

In this chapter, you learned how to configure middleware in the Configure method of the Startup class.

The application now has several middleware components, including a developer error page and MVC. The MVC middleware can forward a request to an action method in a con­troller class to serve up content.

In the next chapter, you will learn more about controllers, and that you can use many different controllers in the same application, and how to route the HTTP requests to the appropriate one.

You will also create controller actions that return HTML, instead of just a string, as in the previous example.

Stay connected with news and updates!

Join our mailing list to receive the latest news and updates from our team.
Don't worry, your information will not be shared.

Subscribe
Close

50% Complete

Two Step

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.