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.
Update 15.Dec.2025: After years of frustration with WordPress, I am finally abandoning this blog. The content will likely stay here for some time, but new content will appear here:
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.
- Convert Entry JSON to Entry Model – Deliverystack.net
- Expose Entry JSON from Entry Model – Deliverystack.net
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.
- Prototype Content Delivery .NET Typed Clients for the Contentstack SaaS Headless CMS – Deliverystack.net
- ASP.NET Core Razor Pages and SaaS Headless Content Management Systems – Deliverystack.net
There really is not much to it and I factored in some other changes as well.

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>

Update 2.May.2021: One step further:
3 thoughts on “-Expose Headless CMS Entry JSON in Entry Models, ASP.NET Core Razor Pages Edition”