Kinetq Development Group, LLC. - Custom Routing

Custom Routing

By default all routing is handled by the RegisterPageModels method. Routes are wired up with the attributes used to decorate your LiquidPageModels. If you would like more fine grained control over the routing and templates you can do one of two things.

First, you can use the constructore overload for RegisterPageModels that takes in a delegate that assists in building configuration. Currently you can only add additional routes per page:

   await _liquidStartup.RegisterPageModels((options) =>
   {
       options.AddPageRoute(typeof(DocumentModel), "^/docs$");
   });

By calling AddPageRoute you can add many different routes to be processed by the same Liquid Page Model.

Otherwise, you can use the custom routing method that bypasses the LiquidPages altogether. You would start off by instead of calling RegisterPageModels, call RegisterRoutes on the ILiquidStartup service.

public class WebsiteStartup : IStartup
{
    private readonly ILiquidStartup _liquidStartup;

    public WebsiteStartup(ILiquidStartup liquidStartup)
    {
        _liquidStartup = liquidStartup;
    }

    public async Task Execute()
    {
        await _liquidStartup.RegisterRoutes();
        await _liquidStartup.RegisterFilters();
    }
}

You define routes by implementing the ILiquidRoute interface, which returns a LiquidRoute object containing all the information needed to match an incoming request and produce a response.

  • Routes are classes that implement ILiquidRoute and provide a LiquidRoute via the GetRoute() method.

  • LiquidRoute requires three mandatory properties:

    • RoutePattern: a regular expression that tests the request path.

    • LiquidTemplatePath: the path to the Liquid template file inside the specified FileProvider.

    • FileProvider: supplies the template and any related assets.

  • An optional Execute delegate can be attached to run server‑side logic before rendering. It receives a LiquidRequestModel and returns a view model, which becomes available in the template as view_model.

  • The following example, taken from the Liquid Pages GitHub repository, demonstrates a route that matches /about-us, fetches data from an index, and returns a WebPageViewModel:

public class AboutUsRoute : ILiquidRoute
{
    private readonly IIndexProvider _indexProvider;
    private readonly SiteConfig _siteConfig;
    private readonly ILiquidFileProvider _liquidFileProvider;

    public AboutUsRoute(IIndexProvider indexProvider, SiteConfig siteConfig, ILiquidFileProvider liquidFileProvider)
    {
        _indexProvider = indexProvider;
        _siteConfig = siteConfig;
        _liquidFileProvider = liquidFileProvider;
    }

    public async Task<LiquidRoute> GetRoute()
    {
        return new LiquidRoute
        {
            RoutePattern = new Regex($"^/about-us$"),
            LiquidTemplatePath = "about.liquid",
            FileProvider = _liquidFileProvider.GetFileProvider(),
            Execute = (async model =>
            {
                var webPage = await _indexProvider.Search()
                    .Must(() => new TermQuery(new Term(nameof(WebPage.SafeName), model.Route.TrimStart('/'))))
                    .SingleResult<WebPage>();

                string seoDescription = webPage.Hit.SeoDescription;

                string seoTitle = !string.IsNullOrEmpty(webPage.Hit.SeoTitle)
                    ? webPage.Hit.SeoTitle
                    : webPage.Hit.Name;

                seoTitle = _siteConfig.SeoTitle + seoTitle;

                return new WebPageViewModel()
                {
                    Title = webPage.Hit.Name,
                    Body = webPage.Hit.Body,
                    SeoDescription = seoDescription,
                    SeoTitle = seoTitle
                };
            })
        };
    }
}

Error Routes

Liquid Pages makes it easy to serve custom error pages by introducing the ILiquidErrorRoute interface. This works just like a normal route but is associated with a specific HTTP status code, allowing you to design branded 404, 500, or other error pages.

  • Error routes implement ILiquidErrorRoute, which extends the route concept with a StatusCode property.

  • The GetRoute() method returns a LiquidRoute—typically containing a FileProvider and a LiquidTemplatePath—that will be used when an error with that status code occurs.

  • The StatusCode property tells the middleware which HTTP error this route handles (e.g., 404 for Not Found).

  • You can omit the Execute delegate if the error page does not require dynamic data.

  • The example below, taken from the Liquid Pages repository, demonstrates a simple 404 error route:

public class NotFoundRoute : ILiquidErrorRoute
{
    private readonly ILiquidFileProvider _liquidFileProvider;

    public NotFoundRoute(ILiquidFileProvider liquidFileProvider)
    {
        _liquidFileProvider = liquidFileProvider;
    }

    public async Task<LiquidRoute> GetRoute()
    {
        return new LiquidRoute
        {
            FileProvider = _liquidFileProvider.GetFileProvider(),
            LiquidTemplatePath = "status_codes/404.liquid"
        };
    }

    public int StatusCode => 404;
} 

Do you have more questions? Contact us

Contact us