Multi-Blog Setup (Blazor)

A single Blazor application can host multiple independent Postnomic blogs, each with its own API key, blog slug, and base path. Instead of path-based automatic resolution (as used in the ASP.NET Core ...

Overview

A single Blazor application can host multiple independent Postnomic blogs, each with its own API key, blog slug, and base path. Instead of path-based automatic resolution (as used in the ASP.NET Core integration), the Blazor integration uses the PostnomicBlogScope component to explicitly declare which blog registration applies to a given page.

This explicit model fits naturally into Blazor's component tree and works equally well in Blazor Server, Blazor WebAssembly, and hybrid (Server + WASM) applications.

Registration

Register each blog with the named overload of AddPostnomicBlog. Each registration needs a unique name and a distinct BasePath.

// Default (unnamed) blog at /blog
builder.Services.AddPostnomicBlog(options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = "pk_company_blog_key";
    options.BlogSlug = "company-blog";
    options.BasePath = "/blog";
});

// Named blog at /blog/engineering
builder.Services.AddPostnomicBlog("engineering", options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = "pk_engineering_blog_key";
    options.BlogSlug = "engineering-blog";
    options.BasePath = "/blog/engineering";
});

Branding is now server-enforced per blog. The API returns a showBranding value in each blog's info response, and the SDK uses that value automatically. You do not need to set ShowBranding in your client options — the server determines the correct value based on each blog owner's subscription tier.

ShowBranding on PostnomicClientOptions is a fallback that applies only before the blog info loads. If you want to set an explicit fallback for a free-tier blog you can still do so, but it is optional:

// Server will enable branding for free-tier blogs automatically
builder.Services.AddPostnomicBlog(options =>
{
    options.BaseUrl      = "https://api.postnomic.com";
    options.ApiKey       = "pk_company_blog_key";
    options.BlogSlug     = "company-blog";
    options.BasePath     = "/blog";
    options.ShowBranding = true; // Optional fallback — server value takes precedence
});

// Server will suppress branding for paid-plan blogs automatically
builder.Services.AddPostnomicBlog("engineering", options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = "pk_engineering_blog_key";
    options.BlogSlug = "engineering-blog";
    options.BasePath = "/blog/engineering";
    // ShowBranding omitted — server handles it automatically
});

Complete Program.cs Example

The following example sets up a Blazor Server application with two blogs. The AddAdditionalAssemblies call ensures the Blazor router discovers the built-in blog components from the package.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

// Default blog — company news at /blog
builder.Services.AddPostnomicBlog(options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = builder.Configuration["Postnomic:CompanyBlog:ApiKey"]!;
    options.BlogSlug = "company-blog";
    options.BasePath = "/blog";
});

// Engineering blog at /blog/engineering
builder.Services.AddPostnomicBlog("engineering", options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = builder.Configuration["Postnomic:EngineeringBlog:ApiKey"]!;
    options.BlogSlug = "engineering-blog";
    options.BasePath = "/blog/engineering";
});

var app = builder.Build();

app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddAdditionalAssemblies(typeof(Postnomic.Client.Blazor._Imports).Assembly);

app.Run();

The PostnomicBlogScope Component

PostnomicBlogScope is a wrapper component that sets the active blog context for everything inside it. It provides the named IPostnomicBlogService to descendant components via a Blazor cascading parameter, so all blog components — BlogPage, PostPage, AuthorPage — automatically use the correct blog without any extra wiring.

The BlogName parameter on PostnomicBlogScope must match the name you passed to AddPostnomicBlog. Use an empty string or omit the parameter entirely to use the unnamed default registration.

Page Examples

Create your own routable Blazor pages and wrap the built-in blog components with PostnomicBlogScope:

Company blog index (/blog):

@page "/blog"

<PostnomicBlogScope>
    <BlogPage />
</PostnomicBlogScope>

Engineering blog index (/blog/engineering):

@page "/blog/engineering"

<PostnomicBlogScope BlogName="engineering">
    <BlogPage />
</PostnomicBlogScope>

Engineering post page (/blog/engineering/{Slug}):

@page "/blog/engineering/{Slug}"

<PostnomicBlogScope BlogName="engineering">
    <PostPage Slug="@Slug" />
</PostnomicBlogScope>

@code {
    [Parameter] public string Slug { get; set; } = string.Empty;
}

Engineering author page (/blog/engineering/author/{AuthorId}):

@page "/blog/engineering/author/{AuthorId}"

<PostnomicBlogScope BlogName="engineering">
    <AuthorPage AuthorId="@AuthorId" />
</PostnomicBlogScope>

@code {
    [Parameter] public string AuthorId { get; set; } = string.Empty;
}

Dynamic Blog Selection via Route Parameters

If your application hosts many blogs and you want to avoid creating a separate page file for each one, you can use a route parameter to drive the blog name dynamically:

@page "/blogs/{BlogName}"
@page "/blogs/{BlogName}/{*Slug}"

<PostnomicBlogScope BlogName="@BlogName">
    @if (string.IsNullOrEmpty(Slug))
    {
        <BlogPage />
    }
    else
    {
        <PostPage Slug="@Slug" />
    }
</PostnomicBlogScope>

@code {
    [Parameter] public string BlogName { get; set; } = string.Empty;
    [Parameter] public string? Slug { get; set; }
}

In this pattern, a single page component handles any registered blog. The BlogName route segment must exactly match the name used in AddPostnomicBlog("engineering", ...).

Server + WASM Hybrid Applications

In hybrid (Server + WASM) applications, you must register all blogs in both the server project and the client (WASM) project. The registrations must be identical — the same names, API keys, and base paths — so that components render consistently regardless of which host is active.

Server Program.cs:

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();

builder.Services.AddPostnomicBlog(options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = builder.Configuration["Postnomic:CompanyBlog:ApiKey"]!;
    options.BlogSlug = "company-blog";
    options.BasePath = "/blog";
});

builder.Services.AddPostnomicBlog("engineering", options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = builder.Configuration["Postnomic:EngineeringBlog:ApiKey"]!;
    options.BlogSlug = "engineering-blog";
    options.BasePath = "/blog/engineering";
});

Client Program.cs:

builder.Services.AddPostnomicBlog(options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = "pk_company_blog_key";
    options.BlogSlug = "company-blog";
    options.BasePath = "/blog";
});

builder.Services.AddPostnomicBlog("engineering", options =>
{
    options.BaseUrl  = "https://api.postnomic.com";
    options.ApiKey   = "pk_engineering_blog_key";
    options.BlogSlug = "engineering-blog";
    options.BasePath = "/blog/engineering";
});

Note that in the WASM client project, configuration is typically embedded directly rather than read from server-side IConfiguration. Store API keys carefully and consider whether WASM exposure is appropriate for your security model — see API Key Authentication for guidance.

Backward Compatibility

Existing Blazor applications that use the single-blog setup continue to work without modification. Components used without a PostnomicBlogScope wrapper resolve to the unnamed default registration exactly as before. The PostnomicBlogScope component is only required when you need to select a non-default blog.

Next Steps

  • See Multi-Blog Setup (ASP.NET Core) for the path-based equivalent in Razor Pages applications
  • See API Key Authentication for managing separate keys per blog securely
  • See Caching to configure per-blog cache durations

Was this article helpful?

Thank you for your feedback!