title: Template Layering and Reuse description: Comprehensive guide to ConnectSoft's three-layer template architecture: shared libraries, base service template, and specialized templates with overlays and submodules. tags: - templates - architecture - layering - reuse - submodules - overlays
Template Layering and Reuse¶
This document provides a comprehensive guide to ConnectSoft's template layering architecture. It is written for architects and engineers who need to understand how templates are structured, how they reuse code and documentation, and how the build-time and generation-time processes differ.
ConnectSoft avoids copy-pasting and "template inheritance" by splitting responsibilities across three layers: shared libraries, base service template, and specialized templates. This architecture enables maximum reuse while maintaining flexibility and avoiding duplication.
Important
The three-layer model is fundamental to ConnectSoft's template architecture. Understanding this model is essential for working with templates, extending them, or creating new specialized templates.
Goals¶
The template layering architecture is designed to achieve:
- Zero Duplication - No code, docs, or configuration is duplicated across templates
- Maximum Reuse - Common infrastructure is shared via libraries and base template
- Build-Time Development - Templates remain fully buildable as normal .NET solutions
- Generation-Time Composition - Final templates are composed from base + overlays at generation time
- Domain Flexibility - Specialized templates add domain-specific logic without modifying base
- Maintainability - Changes to base infrastructure propagate to all templates automatically
Practical playbook
For Layer 3 repos that use a base-template/ submodule (MSBuild, Docker, CI, template installer, overlays): follow Extended templates: full multi-layer alignment playbook. It uses IdentityTemplate + BaseTemplate as the canonical walkthrough.
DI Extensibility in Layering¶
Layer 2 (ConnectSoft.BaseTemplate) owns the default DI orchestration pipeline. Layer 3 templates should extend it via registration hooks, not by copying full DI pipelines.
Use the canonical guide: BaseTemplate DI Extensibility.
Compile-time feature flags and Central Package Management for extended repos are separate from DI; see MSBuild layering in extended template repos below.
The Three-Layer Model¶
ConnectSoft templates are organized into three distinct layers, each with specific responsibilities:
flowchart TB
subgraph Layer1["Layer 1: Shared Libraries"]
LIB[ConnectSoft.Extensions NuGet packages]
end
subgraph Layer2["Layer 2: Base Service Template"]
BASE[ConnectSoft.BaseTemplate<br/>Model projects and host<br/>Bootstrapping and infrastructure]
end
subgraph Layer3["Layer 3: Specialized Templates"]
IDENTITY[ConnectSoft.IdentityTemplate and others]
WORKER[Worker and domain templates]
end
Layer1 -->|NuGet CPM| Layer2
Layer1 -->|NuGet CPM| Layer3
Layer2 -->|Git submodule base-template| Layer3
Layer 1: Shared Libraries (ConnectSoft.Extensions.*)¶
Purpose: All generic, cross-cutting infrastructure delivered as NuGet packages.
Responsibilities:
- Observability (logging, OpenTelemetry wiring helpers)
- Messaging (MassTransit and NServiceBus integration packages)
- Persistence (NHibernate, MongoDB, database model helpers)
- Options, validation, compliance, service discovery, health checks, and more
Characteristics:
- Delivered as NuGet packages
- Used by all templates and services
- Versioned independently (pinned in ConnectSoft.BaseTemplate
Directory.Packages.props) - No domain-specific logic
Catalog: The authoritative package list and MSBuild conditions are in ConnectSoft.Extensions catalog.
SaaS platform program (Layer 1 — additional):
ConnectSoft.Extensions.Saas.*— Tenant context abstractions, ASP.NET Core middleware, options, testing helpers (ConnectSoft.Extensions.Saas.*libraries). One repository per package. These packages are introduced in Phase 2 of the SaaS roadmap afterConnectSoft.Saas.*Templaterepositories prove layout and ServiceModel packaging; Phase 1 templates may use inlined stubs marked for replacement.
SaaS platform program (Layer 2 — submodule for SaaS templates):
ConnectSoft.BaseTemplate— The Git submodule used inside eachConnectSoft.Saas.<Context>Templaterepository (SaaS backend template + scaffold). This is the SaaS program’s base kernel for new bounded-context templates; it is not rebranded as “MicroserviceTemplate.Base” in SaaS naming. See SaaS platform — solution plan.
SaaS platform program (Layer 3):
ConnectSoft.Saas.<Context>Template— One specialized template repo per in-scope bounded context (Tenants, Product catalog, Entitlements, Billing, Metering), each submoduling ConnectSoft.BaseTemplate and shippingdotnet newoutput plus ServiceModel projects. See SaaS bounded contexts andConnectSoft.Saas.*Templatematrix.
Layer 2: Base Service Template (ConnectSoft.BaseTemplate)¶
Purpose: One canonical repository containing the microservice "kernel": shared model projects, host, bootstrapping, and infrastructure without product-domain logic.
Responsibilities:
- Solution layout: prefixed projects under
src/such asConnectSoft.BaseTemplate(host),ConnectSoft.BaseTemplate.DomainModel,ConnectSoft.BaseTemplate.ApplicationModel,ConnectSoft.BaseTemplate.Application,ConnectSoft.BaseTemplate.PersistenceModel.*,ConnectSoft.BaseTemplate.FlowModel.*,ConnectSoft.BaseTemplate.MessagingModel,ConnectSoft.BaseTemplate.ServiceModel.*,ConnectSoft.BaseTemplate.Options,ConnectSoft.BaseTemplate.Metrics, plus optional stacks (actors, schedulers, AI, MCP, etc.) as enabled in the solution - Program/Host bootstrapping and DI orchestration (see BaseTemplate DI Extensibility)
- Common health checks, resilience patterns
- Base CI/CD pipelines (Azure Pipelines; shared templates from ConnectSoft.AzurePipelines)
- Base testing infrastructure
- Base template metadata (
/template/template.json) - Central Package Management:
Directory.Packages.propspins ConnectSoft.Extensions.* and third-party versions
Characteristics:
- Single canonical repository (ConnectSoft.BaseTemplate)
- No product-domain logic (no Identity product domain, etc.)
- Fully buildable as a normal .NET solution
- Used as git submodule
base-template/by specialized templates
Structure (illustrative — see repo ConnectSoft.BaseTemplate.slnx for the full set):
ConnectSoft.BaseTemplate/
├── src/
│ ├── ConnectSoft.BaseTemplate/ # Host
│ ├── ConnectSoft.BaseTemplate.Application/
│ ├── ConnectSoft.BaseTemplate.ApplicationModel/
│ ├── ConnectSoft.BaseTemplate.DomainModel/
│ ├── ConnectSoft.BaseTemplate.DomainModel.Impl/
│ ├── ConnectSoft.BaseTemplate.EntityModel/
│ ├── ConnectSoft.BaseTemplate.PersistenceModel.NHibernate/
│ ├── ConnectSoft.BaseTemplate.ServiceModel.RestApi/
│ ├── ConnectSoft.BaseTemplate.ServiceModel.Grpc/
│ └── … (FlowModel, MessagingModel, optional stacks, etc.)
├── tests/
├── Directory.Build.props
├── Directory.Packages.props
├── azure-pipelines.yml
└── template/
└── template.json
Layer 3: Specialized Templates (Identity, Auth, Audit, Worker, etc.)¶
Purpose: Each specialized template adds domain-specific functionality on top of the base template.
Responsibilities:
- Domain-specific projects (Identity, Auth, Worker, etc.)
- Domain-specific tests
- Domain-specific documentation
- Overlay metadata for template.json and docs
Characteristics:
- Each template is its own repository
- Includes base as git submodule (
base-template/) - Adds domain-specific projects
- Fully buildable as normal .NET solution without Factory
- Defines overlay metadata for generation-time composition
Structure example (ConnectSoft.IdentityTemplate — see ConnectSoft.IdentityTemplate.slnx):
ConnectSoft.IdentityTemplate/
├── base-template/ # Git submodule -> ConnectSoft.BaseTemplate
├── build/
│ └── DisableMicrosoftExtensionsStackForMinimalHost.props
├── ConnectSoft.TemplateRepositoryDirectory.Build.props
├── Directory.Build.props # Imports template repo props + base-template/Directory.Build.props
├── Directory.Packages.props # Imports base-template/Directory.Packages.props
├── ConnectSoft.IdentityTemplate.slnx # Base projects under /BaseTemplate/; Identity *Model projects at repo root
├── ConnectSoft.IdentityTemplate/ # Host
├── ConnectSoft.IdentityTemplate.Application/ # Replaces ConnectSoft.BaseTemplate.Application in this solution
├── ConnectSoft.IdentityTemplate.DomainModel/
├── ConnectSoft.IdentityTemplate.ApplicationModel/
├── ConnectSoft.IdentityTemplate.PersistenceModel.NHibernate/
├── ConnectSoft.IdentityTemplate.ServiceModel.RestApi/
├── … (other Identity *Model projects)
├── ConnectSoft.IdentityTemplate.UnitTests/
├── ConnectSoft.IdentityTemplate.AcceptanceTests/
├── Docs/
└── azure-pipelines.yml
Base Service Template and Specialized Templates¶
Base Template Responsibilities¶
The base template provides:
- Solution Structure - Clean Architecture expressed as ConnectSoft.BaseTemplate.* model projects (DomainModel, ApplicationModel, PersistenceModel, ServiceModel, FlowModel, MessagingModel, host, tests), not as four generic single-folder names
- Bootstrapping - Program.cs, Host setup, DI configuration
- Common Infrastructure - Health checks, resilience, observability wiring
- Base Testing - Test infrastructure, base test classes, test helpers
- Base Documentation - Architecture docs, testing guides, common patterns
- Template Metadata - Base template.json with common parameters
Specialized Template Responsibilities¶
Specialized templates add:
- Domain Logic - Domain-specific entities, aggregates, domain services
- Domain Infrastructure - Domain-specific repositories, external service clients
- Domain APIs - Domain-specific controllers, endpoints, request/response models
- Domain Tests - Domain-specific unit and acceptance tests
- Domain Documentation - Domain-specific flows, endpoints, metrics
- Overlay Metadata - Extend files that add to base template.json
Relationship: Submodules at Build Time¶
At build time, specialized templates include the base template as a git submodule:
flowchart LR
subgraph IdentityRepo["ConnectSoft.IdentityTemplate"]
BASE[base-template submodule]
IDENTITY[ConnectSoft.IdentityTemplate.* projects]
TESTS[ConnectSoft.IdentityTemplate.*Tests]
DOCS[Docs/]
end
subgraph BaseRepo["ConnectSoft.BaseTemplate"]
BASESRC[src ConnectSoft.BaseTemplate.*]
BASETESTS[tests]
end
BASE -.->|points to| BaseRepo
Benefits:
- Base template changes propagate to all specialized templates
- No code duplication
- Each template repo is self-contained and buildable
- Clear separation of concerns
MSBuild layering in extended template repos¶
Extended templates (for example ConnectSoft.IdentityTemplate) must compile against the same Directory.Build.props feature flags as ConnectSoft.BaseTemplate while only including a subset of base projects in the solution. Identity therefore wires MSBuild in this order:
- Repo root
Directory.Build.propsimportsConnectSoft.TemplateRepositoryDirectory.Build.props, which setsConnectSoftBaseTemplateDirectoryPostImporttobuild/DisableMicrosoftExtensionsStackForMinimalHost.props. - The same root file imports
base-template/Directory.Build.props(from the submodule). - Base template props apply analyzers and optional stacks; the post-import minimal-host file turns off flags for stacks Identity does not build (for example AI/agent/vector, MongoDB, HangFire, Log4Net, and optional service models), so MSBuild does not expect outputs for projects outside the solution.
- Projects that live only under
base-template/src/...still loadbase-template/Directory.Build.props, which can applyDisableMicrosoftExtensionsStackForMinimalHost.propsvia a fallback path whenConnectSoftBaseTemplateDirectoryPostImportis unset—see comments in the base template props file.
Satellite vs host (CPM): the entry DisableMicrosoftExtensionsStackForMinimalHost.props file uses two conditional top-level Import elements: ExtendedHost.BaseTemplateSatelliteDefaults.props for paths under base-template, and a strict minimal *Host.props fragment for Layer 3 projects. That avoids NU1010 and MSB4067 (Import inside Choose). Full operational detail: Extended templates: full multi-layer alignment playbook — MSBuild and Central Package Management.
Central Package Management: the extended repo’s Directory.Packages.props should import base-template/Directory.Packages.props and add only template-specific PackageVersion rows (with optional overrides using Remove—see Identity’s file comments).
flowchart TD
hostProps[RepoRoot Directory.Build.props]
tmplProps[ConnectSoft.TemplateRepositoryDirectory.Build.props]
baseProps[base-template Directory.Build.props]
minimal[build DisableMicrosoftExtensionsStackForMinimalHost.props]
hostProps --> tmplProps
hostProps --> baseProps
tmplProps --> minimal
baseProps --> minimal
CI/CD: both ConnectSoft.BaseTemplate and ConnectSoft.IdentityTemplate reference shared pipeline templates from ConnectSoft/ConnectSoft.AzurePipelines. The base repo’s azure-pipelines.yml is heavily parameterized (including conditional service containers). Identity’s pipeline is a concrete variant (fixed containers and variables such as SQL credentials) suited to its tests; treat it as a sibling pattern, not an unmodified copy.
Build Time vs Generation Time¶
ConnectSoft distinguishes between two modes of operation:
Build Time (Developer Experience)¶
Goal: Open solution, hit dotnet build / dotnet test, everything just works.
Characteristics:
- Specialized template repo includes base as git submodule
- Solution file includes projects from both base and specialized template
- Developer works on a real, concrete application
- No Factory required to build or test
- Documentation references both base docs (via submodule) and specialized docs
Example structure (repository layout):
ConnectSoft.IdentityTemplate/
├── base-template/ # Submodule: ConnectSoft.BaseTemplate
│ └── src/ConnectSoft.BaseTemplate.*/
├── ConnectSoft.IdentityTemplate.slnx
├── ConnectSoft.IdentityTemplate.*/
└── ConnectSoft.IdentityTemplate.*Tests/
Workflow:
- Developer clones ConnectSoft.IdentityTemplate
- Initialize the
base-templatesubmodule (git submodule update --init --recursive) - Open
ConnectSoft.IdentityTemplate.slnx - Build and test work immediately
- All base infrastructure is available
Generation Time (Factory / Template Packaging)¶
Goal: Produce a final, flattened project template that the AI Factory or dotnet new uses.
Characteristics:
- Start from base template (code + docs + metadata)
- Apply one or more overlays (Identity, Worker, etc.) in a recipe
- Resolve tokens (ServiceName, Namespace, etc.)
- Output flattened template artifact
- Push to Azure DevOps / Git with pipelines/work items
Generation Pipeline:
flowchart TD
BASE[Base Template<br/>Code + Docs + Metadata]
OVERLAY1[Identity Overlay<br/>Domain Code + Docs + Metadata]
OVERLAY2[Worker Overlay<br/>Worker Code + Docs + Metadata]
RECIPE[Recipe:<br/>base + identity + worker]
GENERATOR[Template Generator]
OUTPUT[Final Template Artifact<br/>Flattened Structure]
BASE --> GENERATOR
OVERLAY1 --> GENERATOR
OVERLAY2 --> GENERATOR
RECIPE --> GENERATOR
GENERATOR --> OUTPUT
Overlay Operations:
- Add files - Domain code, hosted workers, docs
- Patch existing files - Program.cs, pipelines
- Insert between markers -
// @@MODULE_REGISTRATION_BEGIN/END - Token replacements - ServiceName, Namespace, etc.
- Patch YAML - mkdocs.yml, config files
Submodules at Build Time vs Overlays at Generation Time¶
Build Time: Git Submodules¶
What: Base template is included as a git submodule in specialized template repos.
Why:
- Enables building specialized templates as normal .NET solutions
- Base changes propagate automatically
- No duplication of base code
How:
Result: Specialized template repo contains both base and specialized code, fully buildable.
Generation Time: Overlays¶
What: Overlays are applied on top of base template to create final template artifact.
Why:
- Enables composition of multiple overlays (Identity + Worker)
- Produces flattened template for
dotnet newor Factory - Allows recipe-based template generation
How:
# Recipe example
templateId: identity-worker-service
displayName: "Identity Backend with Worker"
layers:
- base: microservice/base
- overlay: microservice/overlays/identity-backend
- overlay: microservice/overlays/worker
Result: Final template artifact with all overlays applied, ready for generation.
Multi-Overlay Scenarios (Identity + Worker)¶
Specialized templates can combine multiple overlays. For example, an Identity Backend template might support both Identity domain logic and Worker functionality.
Overlay Stacking¶
flowchart TB
BASE[Base Template]
IDENTITY[Identity Overlay]
WORKER[Worker Overlay]
BASE --> IDENTITY
IDENTITY --> WORKER
WORKER --> FINAL[Final Template:<br/>Base + Identity + Worker]
Example: Identity + Worker Template¶
ConnectSoft.WorkerTemplate is a first-class Layer 3 repository (not only a generation overlay): it uses the same base-template/ submodule, MSBuild/Central Package Management import chain, and Docker build context from the repository root as ConnectSoft.IdentityTemplate.
ConnectSoft.ApiGatewayTemplate is also a first-class Layer 3 repository with the same submodule, MSBuild/CPM chain, Docker context from the repository root, and template installer pipeline pattern (staging pack, composed template.json, dotnet new CI gate); see Extended templates: full multi-layer alignment playbook.
Build-time layout follows the same ConnectSoft.* model-project pattern as ConnectSoft.IdentityTemplate (host + DomainModel, ApplicationModel, ServiceModel, optional worker projects); see the live solution and submodule for exact project names.
Illustrative tree:
ConnectSoft.IdentityTemplate/ # or another extended template with Worker
├── base-template/
├── ConnectSoft.*.slnx
├── ConnectSoft.*.DomainModel/
├── ConnectSoft.*.Application/
└── template/
├── identity.template.extend.json
└── worker.template.extend.json
Generation Time Recipe:
templateId: identity-worker-service
layers:
- base: microservice/base
- overlay: microservice/overlays/identity-backend
- overlay: microservice/overlays/worker
Result: Final template supports both Identity domain logic and Worker patterns.
Docs Reuse (Base + Specialized)¶
Documentation follows the same layering pattern as code.
Build-Time Docs (Template Repos)¶
Base repo:
Identity repo (example):
ConnectSoft.IdentityTemplate/
├── base-template/ # Submodule includes base docs when published there
└── Docs/ # Identity-specific MkDocs sources (see repo mkdocs.yml)
mkdocs.yml (pattern): include both submodule paths and repo-local Docs/ entries as needed for your site.
Result: At build time, docs reference both base (via submodule) and specialized docs. No physical merge needed.
Generation-Time Docs (Final Service)¶
When generating a final service repo, docs are physically merged:
Overlay Operations:
- Copy base docs →
docs/base/(or merge flat) - Copy identity docs →
docs/identity/ - Copy worker docs (if overlay present) →
docs/worker/ - Patch mkdocs.yml to include all sections
Result: Generated service has all docs physically present in its repo with unified navigation.
Template Metadata Composition – Overview¶
Template metadata (/template/template.json) follows the same composition pattern. See Template Metadata Composition for detailed information.
Key Points:
- Base template defines
/template/template.jsonwith common parameters - Specialized templates define extend files (e.g.,
identity.template.extend.json) - At generation time, extend files are merged with base template.json
- Final template.json includes all parameters from base + overlays
Practical example: ConnectSoft.IdentityTemplate¶
Repository structure¶
See ConnectSoft.IdentityTemplate. At a high level:
base-template/— git submodule pointing at ConnectSoft.BaseTemplateConnectSoft.IdentityTemplate.slnx— includes a subset ofbase-template/src/ConnectSoft.BaseTemplate.*projects (solution folder/BaseTemplate/) plus allConnectSoft.IdentityTemplate.*projects at the repository rootConnectSoft.IdentityTemplate.Applicationis used instead ofConnectSoft.BaseTemplate.Applicationin this solution (same pattern as other extended templates that fork the application project)- MSBuild — root
Directory.Build.props,ConnectSoft.TemplateRepositoryDirectory.Build.props, andbuild/DisableMicrosoftExtensionsStackForMinimalHost.props(see MSBuild layering) - NuGet —
Directory.Packages.propsimports the base template’s CPM file
Solution file structure¶
From base (submodule), examples:
base-template/src/ConnectSoft.BaseTemplate/ConnectSoft.BaseTemplate.csproj(host reference model; Identity host isConnectSoft.IdentityTemplate)base-template/src/ConnectSoft.BaseTemplate.ApplicationModel/...base-template/src/ConnectSoft.BaseTemplate.DomainModel/...- Additional base projects as included in
ConnectSoft.IdentityTemplate.slnx
From Identity template (repo root), examples:
ConnectSoft.IdentityTemplate/ConnectSoft.IdentityTemplate.csproj(host)ConnectSoft.IdentityTemplate.Application/ConnectSoft.IdentityTemplate.Application.csprojConnectSoft.IdentityTemplate.DomainModel/ConnectSoft.IdentityTemplate.DomainModel.csprojConnectSoft.IdentityTemplate.ServiceModel.RestApi/...ConnectSoft.IdentityTemplate.UnitTests/...,ConnectSoft.IdentityTemplate.AcceptanceTests/...
Build process¶
-
Clone repository:
-
Open solution:
-
Build:
-
Test:
Everything works as a normal .NET solution. No Factory required.
Generation Process¶
When the Factory generates a service from this template:
- Load Base Template - Read base template code, docs, metadata
- Apply Identity Overlay - Add Identity domain code, patch files, merge metadata
- Apply Worker Overlay (if requested) - Add Worker code, merge metadata
- Resolve Tokens - Replace ServiceName, Namespace, etc.
- Output Final Template - Flattened structure ready for
dotnet new
Rules and Best Practices¶
Do's¶
✅ Use git submodules for base template in specialized templates
✅ Keep base template domain-agnostic - no Identity/Audit/etc. logic
✅ Build specialized templates as normal solutions - they should compile without Factory
✅ Use overlays for generation-time composition - enables recipe-based templates
✅ Reference base docs via submodule at build time
✅ Merge docs physically at generation time
Don'ts¶
❌ Don't duplicate base code - use submodules instead
❌ Don't put domain logic in base - base is infrastructure only
❌ Don't modify base template.json directly - use extend files
❌ Don't copy base docs - reference via submodule
❌ Don't require Factory to build - templates must build as normal solutions
Related Documents¶
- Template Architecture Specification - Comprehensive technical specification covering template hierarchy, inheritance, JSON/CLI inheritance, build-time vs generation-time extension, and reference wiring mechanisms
- Template Overlays Specification - Detailed overlay system specification covering overlay architecture, application process, versioning, compatibility, and recipe system
- Metrics, Options and Testing Extensibility - How to extend base infrastructure with domain-specific metrics, options, and tests
- Template Metadata Composition - Detailed guide to template.json composition and extend files
- Microservice Template Architecture - Architecture details of the microservice template
- Templates Overview - Overview of all ConnectSoft templates
- Templates Dependencies - Dependencies between templates and libraries
- ConnectSoft.Extensions catalog - NuGet packages pinned by ConnectSoft.BaseTemplate