Skip to main content

Live Demo API Blueprint (.NET)

Try in Playground

Packages to install

dotnet add package PrimusSaaS.Identity.Validator
dotnet add package PrimusSaaS.Logging
dotnet add package PrimusSaaS.Notifications
dotnet add package PrimusSaaS.Documents

Baseline configuration (appsettings.*)

{
"PrimusLogging": {
"ApplicationId": "LiveDemoApi",
"Environment": "Development",
"MinLevel": 1,
"Targets": [
{ "Type": "console", "Pretty": true },
{
"Type": "file",
"Path": "logs/livedemo-api.log",
"Async": true,
"MaxFileSize": 10485760,
"MaxRetainedFiles": 5,
"CompressRotatedFiles": true
}
],
"Pii": {
"MaskEmails": true,
"MaskCreditCards": true,
"MaskSSN": true,
"MaskPasswords": true,
"MaskTokens": true,
"MaskSecrets": true
}
},
"PrimusIdentity": {
"RequireHttpsMetadata": true,
"ValidateLifetime": true,
"ClockSkew": "00:05:00",
"Issuers": [
{
"Name": "Auth0",
"Type": "Auth0",
"Authority": "https://YOUR-TENANT.auth0.com/",
"Issuer": "https://YOUR-TENANT.auth0.com/",
"Audiences": [ "https://your-api-identifier/" ]
},
{
"Name": "LocalDev",
"Type": "Jwt",
"Issuer": "https://primus.local",
"Audiences": [ "api://primus-livedemo" ],
"Secret": "your-32-character-minimum-secret-key-here"
}
],
"Diagnostics": {
"EnableDetailedErrors": true,
"IncludeTokenHintsInChallenges": true,
"IncludeDebugHeaders": true,
"LogTokenRejectionReasons": true,
"MaxRecentFailures": 50,
"AutoDetectDevelopment": true
}
},
"Notifications": {
"Smtp": {
"Host": "",
"Port": 587,
"Username": "",
"Password": "",
"EnableSsl": true,
"FromAddress": "",
"FromName": "Primus Live Demo"
},
"Twilio": {
"AccountSid": "",
"AuthToken": "",
"FromNumber": "",
"MessagingServiceSid": "",
"ValidateOnStartup": false
}
},
"PrimusDocuments": {
"Provider": "Default",
"TempStoragePath": "temp/documents",
"MaxContentLength": 20000,
"LinkTtl": "00:10:00",
"SelfTestEnabled": true,
"TitleFontSize": 24,
"BodyFontSize": 12,
"BrandName": "Primus Live Demo",
"IncludeTimestampInFooter": true,
"IncludeTenantInFooter": true
},
"PrimusFeatureFlags": {
"Provider": "InMemory",
"DefaultValue": false,
"CacheDurationSeconds": 30,
"Logging": {
"LogEvaluations": true,
"IncludeUserContext": false
},
"Flags": {
"NewDashboard": {
"Enabled": true,
"Description": "Enable the new dashboard UI experience",
"RolloutPercentage": 100
}
}
},
"DemoLocalAuth": {
"Email": "demo@primus.local",
"Password": "",
"Name": "Primus Demo User",
"Subject": "local-demo-user"
}
}

Store secrets in User Secrets/Key Vault/App Service settings; dont commit them.

Service registration (Program.cs)

using PrimusSaaS.Identity.Validator;
using PrimusSaaS.Notifications;
using PrimusSaaS.Logging.Extensions;
using Primus.Documents;

var builder = WebApplication.CreateBuilder(args);

// Logging + Application Insights
builder.Logging.ClearProviders();
builder.Logging.AddPrimus(opts => builder.Configuration.GetSection("PrimusLogging").Bind(opts));
var ai = builder.Configuration["PrimusLogging:ApplicationInsights:ConnectionString"];
if (!string.IsNullOrWhiteSpace(ai) && ai != "your-application-insights-connection-string")
builder.Services.AddApplicationInsightsTelemetry(o => o.ConnectionString = ai);

// Primus modules
builder.Services.AddPrimusIdentity(o => builder.Configuration.GetSection("PrimusIdentity").Bind(o));
builder.Services.AddPrimusNotifications(notifications =>
{
var templatesPath = Path.Combine(builder.Environment.ContentRootPath, "NotificationTemplates");
notifications.UseFileTemplates(templatesPath, validateOnStartup: true, watchForChanges: builder.Environment.IsDevelopment());
notifications.UseLogger();
notifications.UseInMemoryQueue(o =>
{
o.BoundedCapacity = 500;
o.MaxParallelHandlers = 2;
o.BaseRetryDelayMs = 250;
});
notifications.UseSmtp(builder.Configuration.GetSection("Notifications:Smtp"));
notifications.UseTwilio(builder.Configuration, "Notifications:Twilio", validateOnStartup: false);
notifications.ConfigureDispatch(o =>
{
o.ThrowOnFailure = true;
o.FallbackToLogger = false;
o.QueueOnFailure = false;
});
});
builder.Services.AddPrimusDocumentRenderer(o => builder.Configuration.GetSection("PrimusDocuments").Bind(o));

builder.Services.AddAuthorization();
builder.Services.AddCors(o => o.AddPolicy("AllowFrontend", policy =>
policy.WithOrigins("http://localhost:5173", "https://localhost:5173")
.AllowAnyHeader()
.AllowAnyMethod()));

Middleware order

app.UseCors("AllowFrontend");
app.UseHttpsRedirection();
app.UsePrimusLogging(); // request logging + correlation IDs
app.UseAuthentication(); // from AddPrimusIdentity
app.UseAuthorization();

Keep authentication/authorization between HTTPS redirection and your endpoints. The sample exposes /public (no auth) and /secure (auth) instead of a root endpoint; hit those when testing.

Golden-path endpoints to keep or adapt

These come from the Live Demo; remove them for production or put them behind strong auth (and role checks) if you must keep them.

EndpointPurpose
GET /primus/diagnosticsIssuer/config diagnostics (optional)
GET /whoamiAuthenticated user context echo
POST /log/testLogging demo with PII redaction
POST /notifications/testRender PasswordReset template without sending
GET /notifications/healthChannel health snapshot
POST /notifications/welcomeSend welcome email (Email + Logger)
POST /notifications/smsSend SMS via Twilio or logger
POST /notifications/templates/previewRender template content safely
GET/PUT /notifications/templates/{type}/{channel}Retrieve/update Liquid templates
GET /notifications/templatesList available templates
POST /documents/renderRender text/HTML/Markdown (plain-text output) to PDF (direct bytes)
POST /documents/render/linkRender to PDF and return a one-time download token
GET /documents/download/{token}Consume a token and download PDF
POST /documents/self-testRenderer self-diagnostics (Basic/Extended)
GET /telemetry/summaryApp Insights + process stats (dev-only)
GET /logs/recentTail the demo log file (dev-only; remove or lock down)
POST /auth/auth0Auth0 client-credentials proxy (dev-only; remove)
POST /auth/azureAzure CLI token proxy (dev-only; remove)
POST /auth/localLocal shared-secret JWT for demos

Production hardening checklist

  • Remove /auth/auth0, /auth/azure, /logs/recent, and any demo secrets; if temporarily kept, require strict auth and audit.
  • Disable IdentityModelEventSource.ShowPII outside local dev.
  • Lock down CORS origins to real frontends; require HTTPS everywhere.
  • Swap the in-memory notification queue for a durable provider in production.
  • Store SMTP/Twilio secrets in Key Vault/User Secrets; never in appsettings.json.
  • Protect or remove template management endpoints; require auth/roles on any that remain.

Quick verification steps

  • GET /whoami returns authenticated user context; 401 when unauthenticated.
  • POST /notifications/test renders templates without error.
  • GET /feature-flags/test returns definitions with user context.
  • POST /documents/self-test returns success: true.
  • Application Insights receives request/dependency telemetry when configured.