Measure response time using middleware

A common way to measure the response time of ASP.NET Core actions is by using a middleware component. As seen in Chapter 3, Working with the Middleware Pipeline, these components act at the edge of the ASP.NET Core request life cycle, and they are useful for performing cross-cutting implementations. Measuring the response time of an action method falls into this implementation case. Furthermore, middleware is the first component hit by a request and the last one that can process an outgoing response. This means that we can analyze and include almost the whole life cycle of the request.

Let's take a look at an implementation of ResponseTimeMiddlewareAsync:

using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace Catalog.API.Infrastructure.Middleware
{
public class ResponseTimeMiddlewareAsync {

private const string X_RESPONSE_TIME_MS = "X-Response-Time-ms";

private readonly RequestDelegate _next;

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

public Task InvokeAsync(HttpContext context) {

var watch = new Stopwatch();

watch.Start();

context.Response.OnStarting(() => {

watch.Stop();

var responseTimeForCompleteRequest = watch.ElapsedMilliseconds;
context.Response.Headers[X_RESPONSE_TIME_MS] = responseTimeForCompleteRequest.ToString();

return Task.CompletedTask;
});

return _next(context);
}
}
}

The previous class defines an async middleware to detect the response time of the requests. It follows these steps:

  1. It declares a Stopwatch instance in the InvokeAsync method.
  2. It executes the Start() method of the Stopwatch instance.
  3. It defines a new response delegate using the OnStarting method. The OnStarting method, which allows us to declare a delegate action to be invoked just before the response headers, will be sent to the client.
  4. It calls the Stop() method and sets the ElapsedMilliseconds property as a custom header using the X-Response-Time-ms header.

It is possible to include the ResponseTimeMiddlewareAsync class in the middleware pipeline by adding the following line in the Startup class:

...
public void
Configure(IApplicationBuilder app, IWebHostingEnvironment env)
{
...
app.UseMiddleware<ResponseTimeMiddlewareAsync>();
...
}
...

Furthermore, it is also possible to test the middleware by following the same approach we took for testing the controllers by implementing the following:

using System.Threading.Tasks;
using Shouldly;
using Catalog.Fixtures;
using Xunit;

namespace Catalog.API.Tests.Middleware
{
public class ResponseTimeMiddlewareTests : IClassFixture<InMemoryApplicationFactory<Startup>>
{
public ResponseTimeMiddlewareTests(InMemoryApplicationFactory<Startup> factory)
{
_factory = factory;
}

private readonly InMemoryApplicationFactory<Startup> _factory;


[Theory]
[InlineData("/api/items/?pageSize=1&pageIndex=0")]
[InlineData("/api/artist/?pageSize=1&pageIndex=0")]
[InlineData("/api/genre/?pageSize=1&pageIndex=0")]
public async Task middleware_should_set_the_correct_response_time_custom_header(string url)
{
var client = _factory.CreateClient();
var response = await client.GetAsync(url);

response.EnsureSuccessStatusCode();
response.Headers.GetValues("X-Response-Time-ms").ShouldNotBeEmpty();
}
}
}

The ResponseTimeMiddlewareTests class allows us to make an HTTP call by extending the InMemoryApplicationFactory class. We can check whether the X-Response-Time-ms header exists in the response object. It is important to note that the other measurement doesn't include the startup time of the web server or the application pool. Furthermore, it takes some additional time when the webserver is not initialized. 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.191.22