Sample Clean Architecture .NET 8 WebApi demonstrating the Axlis Sitecore Headless GraphQL ORM.
Note: This project demonstrates production-ready patterns for integrating Axlis into a Clean Architecture solution. Axlis-specific documentation uses the .AXLIS.md suffix (e.g., CHANGELOG.AXLIS.md, CONTRIBUTING.AXLIS.md).
Axlis.CleanArchitecture.Sample is a working example of integrating the Axlis ORM into a Clean Architecture ASP.NET Core WebApi. It demonstrates:
- Wiring Axlis and Axlis.GraphQL services via dependency injection
- Defining strongly-typed Sitecore template POCOs
- Using the Axlis facade (
ISitecoreFacade) in CQRS handlers - Exercising field types: TextField, ImageField, MultilistField, ItemReferenceField
- Axes traversal: Parent, Children, Siblings, GetChildren, GetDescendants
- The WithResult rich API: value, metadata, and diagnostics
This is a sample project, not a template. It demonstrates production-ready patterns for integrating Axlis into a Clean Architecture solution. All Axlis packages are published to NuGet.org at v0.1.0, so you can use this as a reference for your own projects.
The solution follows Clean Architecture with strict dependency rules. Axlis is wired in the WebApi composition root and consumed by the Application layer via ISitecoreFacade.
ββββββββββββββββββββββββββββββββββββββββββββββββ
β WebApi β Composition root Β· Axlis DI Β· user-secrets
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β Presentation β Controllers Β· SitecoreController (/v1/sitecore)
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β Application β CQRS handlers Β· Sitecore template POCOs
β βββ Sitecore/ β Disclaimer, HomePage, DictionaryRoot, Style
ββββββββββββββββββββββββββββββββββββββββββββββββ€
β Infrastructure β DateTimeProvider Β· Operational wiring
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββ€
β Domain β Shared β BaseEntity Β· IAggregateRoot β Enums
ββββββββββββββββββββββββ΄ββββββββββββββββββββββββ
| Layer | Project | Axlis Integration |
|---|---|---|
| WebApi | CleanArchitecture.WebApi |
Registers AddAxlis() and AddAxlisGraphQL(), wires UseAxlis(), reads config from appsettings + user-secrets |
| Presentation | CleanArchitecture.Presentation |
SitecoreController exposes /v1/sitecore/showcase endpoint |
| Application | CleanArchitecture.Application |
Defines Sitecore template POCOs, CQRS handler uses ISitecoreFacade |
| Infrastructure | CleanArchitecture.Infrastructure |
No Axlis code (clean separation) |
| Domain | CleanArchitecture.Domain |
No Axlis code (pure domain) |
| Shared | CleanArchitecture.Shared |
No Axlis code (shared types) |
Axlis.CleanArchitecture.Sample/
βββ src/
β βββ CleanArchitecture.Domain/ # BaseEntity, IAggregateRoot
β βββ CleanArchitecture.Shared/ # Enums, constants
β βββ CleanArchitecture.Application/ # CQRS handlers, Sitecore template POCOs
β β βββ Api/
β β β βββ Samples/ # PowerCSharp Cache sample endpoints
β β β βββ Sitecore/ # Axlis showcase: Query, Handler, Response
β β βββ Sitecore/
β β β βββ Templates/ # Disclaimer, HomePage, DictionaryRoot, Style
β β βββ Common/ # Behaviors, BaseRequestHandler
β βββ CleanArchitecture.Operational/ # Polly retry policies
β βββ CleanArchitecture.Infrastructure/ # DateTimeProvider
β βββ CleanArchitecture.Presentation/ # Controllers, ApiResponse<T>
β β βββ Controllers/v1/
β β βββ SamplesController # PowerCSharp Cache demo
β β βββ SitecoreController # Axlis showcase endpoint
β βββ CleanArchitecture.WebApi/ # Program.cs (Axlis DI, user-secrets)
βββ tests/
β βββ CleanArchitecture.Tests.Shared/
β βββ CleanArchitecture.WebApi.UnitTests/
β βββ CleanArchitecture.WebApi.IntegrationTests/
βββ .github/
β βββ workflows/
β βββ ci.yml
βββ Directory.Build.props
βββ global.json
βββ PowerCSharp.CleanArchitecture.sln
- Axlis service registration in
Program.csviaAddAxlis()andAddAxlisGraphQL() - Ambient lazy-loader wired via
UseAxlis()for ExtendedItem.Axes traversal - User-secrets for sensitive config (Endpoint, ApiKey) β never committed
- NuGet packages at v0.1.0 (Axlis, Axlis.Abstractions, Axlis.Core, Axlis.GraphQL) from nuget.org
- Configurable caching via PowerCSharp.Feature.Cache providers (BitFaster, Disk)
- Diagnostic support via EnableDiagnostics option for troubleshooting
Located in src/CleanArchitecture.Application/Sitecore/Templates/:
System Templates:
- Language β Language settings including charset, encoding, ISO codes, and fallback language
- MainSection β Base system template (foundation for other templates)
- Node β Base template for hierarchical structures
- PublishingTarget β Publishing target database configuration
Sample Templates:
- SampleItem β Demonstrates TextField usage with Title and Text fields
All template classes include comprehensive XML documentation explaining their purpose and field mappings.
GET /v1/sitecore/showcase exercises six Axlis API pivots:
- TextField β SampleItem.Title and SampleItem.Text field access
- Axes traversal β Parent, Children, Grandparent, Siblings navigation
- GetDescendants β Recursive traversal with template type filtering (Language items)
- WithResult rich API β Metadata (ItemId, ItemPath, ItemVersion, Timestamp) and Diagnostics (warnings, errors, info)
- Lazy-loading β Demonstrates Axes lazy-fetch behavior for items beyond initial fetch
- Caching β Shows how Axlis caching integrates with the facade
The handler includes comprehensive developer notes explaining each API pattern, performance considerations, and best practices.
- Strict dependency rule enforced by project references
- CQRS via MediatR with
BaseRequestHandler<T, TResponse> - FluentValidation integration
ApiResponse<T>envelope on all endpointsLoggingBehavior<TRequest, TResponse>pipeline behavior
- CORS, Cache (BitFaster), DiskCache, Samples feature modules
- Flag-gating via
PowerFeatures:<Key>:Enabledinappsettings.json - Samples feature enabled in Development for showcase endpoint access
| Tool | Version |
|---|---|
| .NET SDK | 8.0 or later |
| Git | any recent version |
| Sitecore Headless GraphQL endpoint | accessible from dev machine |
git clone https://github.com/marioarce/Axlis.CleanArchitecture.Sample.git
cd Axlis.CleanArchitecture.Sample
dotnet restore
dotnet buildcd src/CleanArchitecture.WebApi
dotnet user-secrets set "AxlisGraphQL:Endpoint" "https://your-sitecore-instance/sitecore/api/graph/edge"
dotnet user-secrets set "AxlisGraphQL:ApiKey" "{YOUR-API-KEY}"dotnet run --project src/CleanArchitecture.WebApi/CleanArchitecture.WebApi.csprojThe API starts on https://localhost:7xxx / http://localhost:5xxx. Open the Swagger UI at /swagger.
curl "https://localhost:7235/v1/sitecore/showcase?rootPath=/sitecore/content/home"Adjust rootPath to match your Sitecore content tree structure.
# All tests
dotnet test
# Unit tests only
dotnet test tests/CleanArchitecture.WebApi.UnitTests
# Integration tests only
dotnet test tests/CleanArchitecture.WebApi.IntegrationTestsIntegration tests use WebApplicationFactory<Program> β no external dependencies required.
appsettings.json contains the Axlis and AxlisGraphQL sections:
{
"Axlis": {
"CacheTtl": "00:30:00",
"EnableDiagnostics": true
},
"AxlisGraphQL": {
"Endpoint": "",
"BatchSize": 10,
"TimeoutSeconds": 30
}
}The Endpoint and ApiKey values are intentionally empty in appsettings.json. Set them via user-secrets:
dotnet user-secrets set "AxlisGraphQL:Endpoint" "https://your-sitecore-instance/sitecore/api/graph/edge"
dotnet user-secrets set "AxlisGraphQL:ApiKey" "{YOUR-API-KEY}"The Samples feature flag must be enabled to access the showcase endpoint:
{
"PowerFeatures": {
"Samples": {
"Enabled": true
}
}
}This is already set to true in appsettings.json for this sample.
This sample uses the published NuGet packages from nuget.org:
Axlisv0.1.0Axlis.Abstractionsv0.1.0Axlis.Corev0.1.0Axlis.GraphQLv0.1.0
All packages are configured in the respective project files:
src/CleanArchitecture.Application/CleanArchitecture.Application.csprojβ referencesAxlis.Coresrc/CleanArchitecture.WebApi/CleanArchitecture.WebApi.csprojβ referencesAxlisandAxlis.GraphQL
The sample template POCOs use placeholder GUIDs. Replace these with the real template IDs from your Sitecore instance:
System Templates:
Language.csβ{F68F13A6-3395-426A-B9A1-FA2DC60D94EB}MainSection.csβ{E3E2D58C-DF95-4230-ADC9-279924CECE84}Node.csβ{239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B}PublishingTarget.csβ{E130C748-C13B-40D5-B6C6-4B150DC3FAB3}
Sample Templates:
SampleItem.csβ{76036F5E-C477-44E2-8178-773413C533F7}
To find your template GUIDs in Sitecore:
- Navigate to the template in the Content Editor
- Click the item and view the Quick Info section
- Copy the ID value
For detailed Axlis documentation, see:
Clean API vs Rich API:
GetItemByPathAsync<T>()β Returns T? (null if not found). Use for simple fetches.GetItemByPathWithResultAsync<T>()β ReturnsAxlisResult<T>with Value, Metadata, and Diagnostics. Use for troubleshooting or when you need provenance data.
Lazy Loading:
- Axes traversal (Parent, Children, Siblings) may trigger lazy-fetches if data wasn't included in the initial GraphQL response
- Lazy fetches are synchronous (property getter cannot be async)
- Safe in ASP.NET Core, but avoid deep traversal in non-ASP environments
- Use
GetItemsByPathsAsyncfor batch pre-fetch in performance-critical scenarios
Caching:
- Powered by
ICacheServicefrom PowerCSharp.Feature.Cache.Abstractions - Dual-indexing (by ID and path) with null-safety (null results never cached)
- Configure CacheTtl in
AddAxlisoptions (default: 60 minutes) - Use
SitecoreItemCacheManager.InvalidateAsync(key)to evict specific items
Field Types:
TextFieldβ Simple text fieldsImageFieldβ Image metadata (Src, Alt, etc.)MultilistFieldβ Multi-select item referencesItemReferenceFieldβ Single item reference- All fields inherit from
BaseFieldwith FieldName, RawValue, and IsEmpty
This project is licensed under the MIT License.
README.mdβ This file (main project documentation)CHANGELOG.AXLIS.mdβ Axlis-specific changelogCONTRIBUTING.AXLIS.mdβ Contribution guidelines for this sampleSECURITY.AXLIS.mdβ Security considerations for Axlis integration