Search code examples
hyprlinkr

Customize Hyprlinkr to use the name of a route's template


Context

Given the following route

config.Routes.MapHttpRoute(
    name: "FooBarBazRoute",
    routeTemplate: "foo-bar-baz/{id}",
    defaults: new
    {
        controller = "FooBarBaz",
        id = RouteParameter.Optional
    });

and by using Hyprlinkr

var linker = new RouteLinker(this.Request);
var id = "813bafcc-8329-<trimmed>"
var href = this
    .linker
    .GetUri<FooBarBazController>(
        c => c.Get(id))
    .ToString()

the value of href looks like this:

"http://d59503db-1e96-<trimmed>/foobarbaz/813bafcc-8329-<trimmed>"

Question

Is it possible to customize Hyprlinkr so that href looks like:

"http://d59503db-1e96-<trimmed>/foo-bar-baz/813bafcc-8329-<trimmed>"

That is, instead of foobarbaz, it'd be nice if Hyprlinkr creates foo-bar-baz – similar to the route template, which is foo-bar-baz/{id}.


Solution

  • Yes, this is possible. That's one of the main reasons for the existence of the IRouteDispatcher interface in Hyprlinkr.

    Define a custom implementation of IRouteDispatcher, like this:

    public class MyDispatcher : IRouteDispatcher
    {
        private readonly IRouteDispatcher dispatcher;
    
        public MyDispatcher(IRouteDispatcher dispatcher)
        {
            this.dispatcher = dispatcher;
        }
    
        public Rouple Dispatch(
            MethodCallExpression method,
            IDictionary<string, object> routeValues)
        {
            if (method.Method.ReflectedType == typeof(FooBarBazController))
                return new Rouple("FooBarBazRoute", routeValues);
    
            return this.dispatcher.Dispatch(method, routeValues);
        }
    }
    

    Use this to create your RouteLinker instance:

    var linker = new RouteLinker(
        request,
        new MyDispatcher(new DefaultRouteDispatcher()));
    

    You can add more special cases to MyDispatcher.Dispatch if you have more named routes to which you need to dispatch.