This website uses cookies

This website uses cookies to give you the best and most relevant experience. By continuing to browse this site, you are agreeing to our use of cookies. Learn More.

A QR Code Api Based on a Custom ASP.Net Core Middleware

These are exciting times to be associated with .Net. The introduction of .Net Core is a major rethink of the platform to make it leaner, portable and more flexible. The new modular pipeline - made up of selective middlewares - can be hosted on IIS, its own process or any OWIN based server. This article describes a bare metal approach for creating an api to generate QR codes using a custom middleware without leveraging ASP.NET MVC.

A middleware is a pass through component that can inspect the route and modify the request and response as needed. Middlewares are chained together to form the pipeline. Each middleware is able to choose whether to pass the request to the next component and decide what actions to take before and after that.

The main method of the Startup class is the entry point of the application and calls ConfigureServices and Configure methods. ConfigureServices defines the features available to the application (in this example caching and scoped dependency injection for the QRCode generator) whereas Configure defines the middlewares that make up the pipeline. The MapWhen method sets up the QRCode middleware based on a condition (request path and verb) to be satisfied by the predicate. If that condition is not met, the next middleware is invoked to return 400 bad request status code and a message about how to properly use the api.

The Startup class
public void ConfigureServices(IServiceCollection services)
{
    services.AddCaching();
    services.AddScoped<QRCode.Abstraction.IQRCodeGenerator, QRCode.Implementation.QRCodeGenerator>();
}

public void Configure(IApplicationBuilder app)
{
    app.MapWhen(ctx => ctx.Request.Path.ToString().TrimEnd('/').Equals("/api/qrcode") && ctx.Request.Method.Equals("GET"), HandleQRCode);
    app.Run(async (context) =>
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        await context.Response.WriteAsync("usage:\n/api/qrcode?text=yourtext&size=[1-100]&format=[png,jpeg,gif]\nsize (default=10, 1 for smallest & 100 for largest) and format (default=jpeg) are optional");                
    });
}

private void HandleQRCode(IApplicationBuilder app)
{
    app.UseMiddleware();
}

The QR code middleware is handled in a separate class which follows the Explicit Dependencies Principle and exposes its dependencies in the constructor. It does not inherit from or implement other types. All the dependencies are resolved by the DI container at runtime if they are properly registered. The middleware class defines an async Invoke method which will be called by the underlying infrastructure to fulfill its task.

In this api, the Invoke method parses and validates the query string parameters before using them to build the QR code as an Image, which it then adds to the response's body. The QR code generator uses QRCode.Net to build the image.

Snippet from QRCodeMiddleware class
public async Task Invoke(HttpContext context)
{
    context.Response.StatusCode = StatusCodes.Status400BadRequest;
    QRCodeParameters param = ParseQRParamsFromQueryString(context.Request.Query);            
    if (param.IsValid())
        SendImageToOuput(context, param, GetQRCodeImage(context, param));                
}

private void SendImageToOuput(HttpContext context, QRCodeParameters param, Image img)
{
    context.Response.StatusCode = StatusCodes.Status200OK;
    context.Response.Headers.Add("content-type", "image/" + param.ImageFormat.ToString().ToLower());
    img.Save(context.Response.Body, param.ImageFormat);
}

private Image GetQRCodeImage(HttpContext context, QRCodeParameters param)
{
    Image img = null;
    if (cache.TryGetValue(param.ToString(), out img)) return img;
            
    img = generator.GenerateQRCode(param);
    cache.Set(param.ToString(), img, new MemoryCacheEntryOptions() {SlidingExpiration = DateTime.Now.AddDays(1).TimeOfDay });            
    return img;            
}

Once an image is generated, it is cached for subsequent requests. The api can be referenced directly in the src of an img tag. The full source code is available on my github repo.

A QRCode generated using the api and decrypted by a QRCode reader mobile app