A .NET 10 library for building headless sites with Optimizely CMS 12. Combines content type definition (synced via the Content Definitions API), content querying (via Optimizely Graph or Content Delivery API), and ASP.NET Core MVC rendering into a single NuGet package.
- Type Builder -- Define CMS content types as .NET POCOs with attributes. Types are automatically synced to your CMS 12 instance on startup via the Content Definitions API (create/update only, never deletes).
- Content Client -- Query content from Optimizely Graph (GraphQL) or the CMS 12 Content Delivery API (REST). Supports fluent query building with filters, search with facets and pagination.
- MVC Integration -- Content routing, tag helpers (
<graph-image>,<graph-link>,<graph-rich-text>,<graph-content-area>), view components for composition rendering, and CMS preview support.
dotnet add package CodeArt.Optimizely.HeadlessKitCMS12Add to appsettings.json:
{
"CMS12": {
"ApiBaseUrl": "https://your-cms12-site.com/",
"ClientId": "<your-client-id>",
"ClientSecret": "<your-client-secret>",
"SyncOnStartup": true
},
"OptimizelyGraph": {
"GraphEndpoint": "https://cg.optimizely.com/content/v2",
"SingleKey": "<your-single-key>"
}
}// Register type sync (content definitions)
builder.Services.AddCMS12TypeBuilder(builder.Configuration);
// Register Graph content client + MVC integration
builder.Services.AddOptimizelyGraph(builder.Configuration);
// Or, to use the Content Delivery API instead of Graph:
// builder.Services.AddCodeArtContentDeliveryClient(builder.Configuration);
// builder.Services.AddOptimizelyGraphMvc();using CodeArt.Optimizely.HeadlessKit.Core.Models;
using CodeArt.Optimizely.HeadlessKit.TypeBuilder.Annotation;
using CodeArt.Optimizely.HeadlessKit.TypeBuilder.Models;
[ContentType("a1b2c3d4-e5f6-7890-abcd-ef1234567890", BaseTypes.Page)]
public class StandardPage : GraphPageContent
{
[CultureSpecific]
[CMSProperty(Format = PropertyFormats.TextArea)]
public string Title { get; set; }
public GraphContentRichText Body { get; set; }
public GraphContentReference MainImage { get; set; }
}
[ContentType("b2c3d4e5-f6a7-8901-bcde-f12345678901", BaseTypes.Block)]
public class HeroBlock : GraphBlock
{
[CultureSpecific]
public string Heading { get; set; }
public GraphContentUrl ButtonLink { get; set; }
}Content is queried automatically via content routing, or manually:
// Via the content repository (cached)
var page = await contentRepository.GetContentByPath<StandardPage>("/en/about");
// Via the fluent query builder (Graph only)
var articles = await client.Query<ArticlePage>()
.Where(f => f.Metadata.Status.Eq("Published"))
.Take(10)
.ToListAsync();@addTagHelper *, CodeArt.Optimizely.HeadlessKitCMS12
<graph-image content="@Model.Image" width="800" alt="Hero" css-class="hero-img" />
<graph-link content="@Model.Link" css-class="btn">Click here</graph-link>
<graph-rich-text content="@Model.Body" />
<graph-content-area composition="@Model.CurrentContent?.Composition" />- Getting Started -- Full setup guide
- Content Types -- Attribute reference and type sync
- Content Querying -- Fluent queries, filters, search
- MVC Integration -- Routing, tag helpers, view components, preview
# Build the solution
dotnet build src/CodeArt.Optimizely.HeadlessKitCMS12.sln
# Run tests
dotnet test test/CodeArt.Optimizely.HeadlessKitCMS12.Tests/CodeArt.Optimizely.HeadlessKitCMS12.Tests.csproj
# Create NuGet package
dotnet pack src/CodeArt.Optimizely.HeadlessKitCMS12/CodeArt.Optimizely.HeadlessKitCMS12.csprojMIT -- see LICENSE for details.