Kinetq Development Group, LLC. - Middleware Setup

Middleware

ASP.NET Core middleware

Install the ASP.NET Core companion package:

dotnet add package Kinetq.LiquidPages.AspNetCore

Register LiquidPages services, initialize startup registrations, and map LiquidPages endpoints:

using Kinetq.LiquidPages.AspNetCore;
using Kinetq.LiquidPages.Helpers;
using Kinetq.LiquidPages.Interfaces;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLiquidPages(typeof(Program).Assembly);

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var startup = scope.ServiceProvider.GetRequiredService<ILiquidStartup>();
    await startup.RegisterPageModels();
    await startup.RegisterFilters();

    string workingDirectory = Directory.GetCurrentDirectory();
    startup.RegisterFileProvider("/", new PhysicalFileProvider(workingDirectory));
}

app.UseLiquidPagesErrorHandling();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapLiquidPages();
});

await app.RunAsync();

GenHTTP middleware

Install the GenHTTP companion package:

dotnet add package Kinetq.LiquidPages.GenHTTP

Resolve ILiquidResponseMiddleware and ILiquidRoutesManager from your container and pass both to LiquidHandlerBuilder:

var middleware = serviceProvider.GetRequiredService<ILiquidResponseMiddleware>();
var routesManager = serviceProvider.GetRequiredService<ILiquidRoutesManager>();

await Host.Create()
          .Handler(new LiquidHandlerBuilder(middleware, routesManager))
          .Bind(IPAddress.Any, 8080)
          .RunAsync();

LiquidHandlerBuilder implements IHandlerBuilder<LiquidHandlerBuilder>, so you can attach any GenHTTP concern (compression, caching, CORS, etc.) before the handler is built. See the full GenHTTP documentation for a complete walkthrough.

EmbedIO middleware

Install the EmbedIO companion package and attach LiquidPages to your WebServer:

dotnet add package Kinetq.LiquidPages.EmbedIO
var middleware = serviceProvider.GetRequiredService<ILiquidResponseMiddleware>();
var routesManager = serviceProvider.GetRequiredService<ILiquidRoutesManager>();

webServer.WithLiquidPages(middleware, routesManager);

If you need lower-level control, LiquidWebModule now takes ILiquidRoutesManager in its constructor:

webServer.WithModule(new LiquidWebModule("/", routesManager)
{
    LiquidResponseMiddleware = middleware
});

Custom Middleware

Otherwise if there is no existing middleware for your webserver, the implementation would still be simple and look something like this:

 try
        {
            var liquidRequest = new LiquidRequestModel()
            {
                Route = request.Url.AbsolutePath,
                QueryParams = request.Url.Query.GetQueryParams(),
                Headers = request.Headers
            };

            if (request.HasEntityBody)
            {
                using var reader = new StreamReader(request.InputStream, Encoding.UTF8);
                liquidRequest.Body = await reader.ReadToEndAsync();
            }

            var responseModel =
                await LiquidResponseMiddleware.HandleRequestAsync(liquidRequest);

            response.ContentLength64 = responseModel.Content.Length;
            response.ContentType = responseModel.ContentType;
            response.StatusCode = responseModel.StatusCode;

            await response.OutputStream.WriteAsync(responseModel.Content);
        }
        catch (Exception ex)
        {
            response.StatusCode = 500;
            byte[] errorBuffer = Encoding.UTF8.GetBytes($"Internal Server Error: {ex.Message}");
            response.ContentLength64 = errorBuffer.Length;
            response.ContentType = "text/html";
            await response.OutputStream.WriteAsync(errorBuffer);
        }
        finally
        {
            response.Close();
        }
    }

Liquid Response Middleware

The ILiquidResponseMiddleware is the engine that ties everything together. After injecting it into your application, you call HandleRequestAsync with a LiquidRequestModel that encapsulates the incoming request. The middleware then orchestrates route matching, data retrieval, template parsing, and response generation, returning a LiquidResponseModel ready to be written to the output stream.

  • ILiquidResponseMiddleware is the core service; its HandleRequestAsync method accepts a LiquidRequestModel containing the route, query parameters, body, and headers.

  • The middleware iterates through all registered routes, matching the request path against each RoutePattern (regex).

  • When a match is found, it optionally invokes the route’s Execute delegate to obtain a view model.

  • The middleware then parses the Liquid template using the Fluid engine, passing the view model (accessible as view_model) and any custom filters registered in the system.

  • If no route matches, it attempts to serve static files (e.g., CSS, images) from the default file provider.

  • If neither a route nor a static file is found, it falls back to any configured error routes (such as the 404 route described above) to produce an appropriate response.

  • The final output is a byte array with the correct MIME type and HTTP status code, packaged in a LiquidResponseModel.

  • This design makes the middleware adaptable to any web server, as demonstrated in the generic integration example at the beginning of this document. For a detailed look at the implementation, see the LiquidResponseMiddleware.cs file in the repository.

Do you have more questions? Contact us

Contact us