Expose Headless CMS Entry JSON in Entry Models, ASP.NET Core Razor Pages Edition

This blog post is basically a reminder that you may want to store the raw JSON of entries even if you use entry models. The JSON can have advantages in during development by allowing programmers to access data in new content types and fields before creating corresponding entry model classes and properties but can also be useful for diagnosing issues or rendering JSON inline in a page body for Jamstack or other client applications to render as markup. This is sort of an update to the following blog post but using now ASP.NET Core Razor Pages rather than ASP.NET MVC and a typed (HTTP) client rather than the Contentstack .NET SDK, although most of the code is almost identical.

You can make the JSON available to views and for other uses in at least two ways: by retrieving and storing the raw JSON representation of entries from the CMS and converting that JSON to the entry model instances when needed, or by adding a property to the entry model class(es) to store the JSON. Either way, be sure to configure JSON serialization to support any requirements for the entry model classes.

The CMS vendor HTTPS API always returns JSON, so the question is about how to retrieve that JSON and how to store it. To retrieve the data, you can either use the vendor’s SDK or you can implement your own code. You can then store it as a string, something equivalent to a JObject, or as an instance of your entry model type, which may contain a property exposing the JSON string or JObject.

Using the vendor SDK, you can retrieve the JSON string or JObject and convert it to entry model instances when needed, or you can retrieve an entry model and store the JObject as a property of the entry model. The following blog post demonstrates these two techniques.

I prefer using my own code and entry models rather than using the vendor’s SDK or converting JObjects to entry models manually. Specifically, I will enhance the solution described by the following blog posts to store the JSON in a property of my entry models.

There really is not much to it and I factored in some other changes as well.

Visual Studio Solution Explorer

The new EntryModelBase class provides a base class for entry models, which views access through the EntryModel property of the IndexModel PageModel. The EntryModelBase class exposes the string Title property to hold the Title field common to all entries and a JObject property named Json that is the JSON representation of the entry.

using Newtonsoft.Json.Linq;

public abstract class EntryModelBase
{
    public string Title { get; set; }
    public JObject Json { get; set; }
}

The new abstract PageModelBase provides a custom base class for page models, containing some of the logic that had previously been in the concrete IndexModel PageModel, and from which IndexModel now derives.

using Microsoft.AspNetCore.Mvc.RazorPages;

using ContentstackRazorPages.Core.DeliveryClient;

public abstract class PageModelBase : PageModel
{
    // connection to CMS
    private readonly IContentDeliveryClient _contentClient;

    // represents entry specified in URL
    public EntryModelBase EntryModel { get; private set; }

    // DI infrastructure passes CMS connection to constructor
    public PageModelBase(IContentDeliveryClient contentClient)
    {
        _contentClient = contentClient;
    }

    // infrastructure passes values from URL to page handler
    public void OnGet(string contentType, string entryId)
    {
        //TODO: determine type derived from WebPageEntryModelBase for 
        // this content type
        EntryModel = _contentClient.AsObjectAsync<EntryModelBase>(
            new EntryIdentifier(contentType, entryId)).Result;
    }
}

...

using Microsoft.Extensions.Logging;

using ContentstackRazorPages.Core.DeliveryClient;
using ContentstackRazorPages.Core.Models;

public class IndexModel : PageModelBase
{
    private readonly ILogger<IndexModel> _logger;
 
    // DI infrastructure passes CMS connection to constructor
    public IndexModel(ILogger<IndexModel> logger, 
        IContentDeliveryClient contentClient) : base(contentClient)
    {
        _logger = logger;
    }
}

Beyond rearrangement, the main code change is to the AsObjectAsync() method of ContentstackDeliveryClient that returns the entry model representing an entry, which retrieves the JSON, converts it to an entry model that derives from the EntryModelBase class (now required by constraints in the method signature), and stores the JSON to the Json property of that entry model.

public async Task<TType> AsObjectAsync<TType>(EntryIdentifier entryId) where TType : EntryModelBase
{
    //TODO: configure serialization - JsonConverters for modular blocks
    JObject temp = JObject.Parse(await AsStringAsync(entryId));
    TType result = temp.SelectToken("$.entry").ToObject<TType>();
    result.Json = (JObject) temp.SelectToken("$.entry");
    return result;
}

Now we can update the view (index.cshtml) to make the JSON available to the client , which can improve performance by delivering data with markup and script to render it, typically access additional entries from the CMS, search, commerce, experience management, and other services.

@page  "/get/{contentType}/{entryId}"
@model IndexModel

<div class="text-center">
    <h1 id="heading" class="display-4"></h1>
</div>
<pre id="json"></pre>

<script>
    var json = @(new Microsoft.AspNetCore.Html.HtmlString(Model.EntryModel.Json.ToString()));
    document.getElementById('heading').innerHTML = json.title;
    document.getElementById('json').appendChild(
        document.createTextNode(JSON.stringify(json, null, 4)));
</script>
Result in browser showing title and JSON.

Update 2.May.2021: One step further:

3 thoughts on “Expose Headless CMS Entry JSON in Entry Models, ASP.NET Core Razor Pages Edition

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: