Using DeliveryClient For Complex Link Resolving In Kentico Kontent

The Kentico Kontent ASP.NET Core boilerplate contains a CustomContentLinkUrlResolver class that allows all links within your content to be transformed into a custom URL path based on the content-type a link is referencing. The out-of-the-box boilerplate solution works for most scenarios. But there will be times when links cannot be resolved in such a simplistic fashion, especially if your project is using dynamic page routing.

What we need to do is make a small tweak to the CustomContentLinkUrlResolver class so we can use Kontent’s DeliveryClient object, which in turn allows us to query the API and carry out a complex ruleset for resolving URL’s.

To give a frame of reference, the out-of-the-box CustomContentLinkUrlResolver class contains the following code:

public class CustomContentLinkUrlResolver : IContentLinkUrlResolver
{
    /// <summary>
    /// Resolves the link URL.
    /// </summary>
    /// <param name="link">The link.</param>
    /// <returns>A relative URL to the page where the content is displayed</returns>
    public string ResolveLinkUrl(ContentLink link)
    {
        return $"/{link.UrlSlug}";
    }

    /// <summary>
    /// Resolves the broken link URL.
    /// </summary>
    /// <returns>A relative URL to the site's 404 page</returns>
    public string ResolveBrokenLinkUrl()
    {
        // Resolves URLs to unavailable content items
        return "/404";
    }
}

This will be changed to:

public class CustomContentLinkUrlResolver : IContentLinkUrlResolver
{
    IDeliveryClient deliveryClient;
    public CustomContentLinkUrlResolver(DeliveryOptions deliveryOptions)
    {
        deliveryClient = DeliveryClientBuilder.WithProjectId(deliveryOptions.ProjectId).Build();
    }

    /// <summary>
    /// Resolves the link URL.
    /// </summary>
    /// <param name="link">The link.</param>
    /// <returns>A relative URL to the page where the content is displayed</returns>
    public string ResolveLinkUrl(ContentLink link)
    {                
        switch (link.ContentTypeCodename)
        {
            case Home.Codename:
                return "/";
            case BlogListing.Codename:
                return "/Blog";
            case BlogPost.Codename:
                return $"/Blog/{link.UrlSlug}";
            case NewsArticle.Codename:
                // A simplistic example of the Delivery Client in use to resolve a link...
                NewsArticle newsArticle = Task.Run(async () => await deliveryClient.GetItemsAsync<NewsArticle>(
                                                                            new EqualsFilter("system.id", link.Id),
                                                                            new ElementsParameter("url"),
                                                                            new LimitParameter(1)
                                                                        )).Result?.Items.FirstOrDefault();

                if (!string.IsNullOrEmpty(newsArticle?.Url))
                    return newsArticle.Url;
                else
                    return ResolveBrokenLinkUrl();
            default:
                return $"/{link.UrlSlug}"; 
        }
    }

    /// <summary>
    /// Resolves the broken link URL.
    /// </summary>
    /// <returns>A relative URL to the site's 404 page</returns>
    public string ResolveBrokenLinkUrl()
    {
        // Resolves URLs to unavailable content items
        return "/404";
    }
}

In the updated code, we are using DeliveryClientBuilder.WithProjectId() method to create a new instance of the DeliveryClient object, which can then be used if a link needs to resolve a News Article content type. You have may have also noticed the class is now accepting a DeliveryOptions object as its parameter. This object is populated on startup with Kontent’s core settings from the appsettings.json file. All we’re interested in is retrieving the Project ID.

A small update to the Startup.cs file will also need to be carried out where the CustomContentLinkUrlResolver class is referenced.

public void ConfigureServices(IServiceCollection services)
{
    ...

    var deliveryOptions = new DeliveryOptions();
    Configuration.GetSection(nameof(DeliveryOptions)).Bind(deliveryOptions);

    IDeliveryClient BuildBaseClient(IServiceProvider sp) => DeliveryClientBuilder
        .WithOptions(_ => deliveryOptions)
        .WithTypeProvider(new CustomTypeProvider())
        .WithContentLinkUrlResolver(new CustomContentLinkUrlResolver(deliveryOptions)) // Line to update.
        .Build();

    ...
}

I should highlight at this point the changes that have been illustrated above have been made on an older version of the Kentico Kontent boilerplate. But the same approach applies. The only thing I’ve noticed that normally changes between boilerplate revisions is the Startup.cs file. The DeliveryOptions class is still in use, but you may have to make a small tweak to ascertain its values.


Leave A Comment

If you have any questions or suggestions, feel free to leave a comment. I do get inundated with messages regarding my posts via LinkedIn and leaving a comment below is a better place to have an open discussion. Your comment will not only help others, but also myself. :-)