Template Architecture Specification¶
This document provides a comprehensive technical specification for ConnectSoft's template architecture. It serves as the authoritative contract for how templates are structured, how they inherit and compose functionality, and the mechanisms for extension at both build-time and generation-time. It is written for architects, engineers, and developers involved in template development and usage.
Document Purpose¶
This specification provides:
- Complete technical contract for template hierarchy and inheritance
- Rules and mechanisms for template JSON/CLI inheritance
- Build-time vs generation-time extension patterns
- Reference wiring mechanisms for tests, docs, and infrastructure
- Authoritative source for template developers
BaseTemplate DI Extensibility Contract¶
For DI orchestration extensibility in Layer 2/Layer 3 templates, use the hook model documented in BaseTemplate DI Extensibility.
Terminology used across template docs:
- base + add: keep default BaseTemplate registration and append template-specific behavior.
- replace whole step: override one protected virtual registration stage entirely.
- default-preserving hooks:
DefaultMicroserviceRegistrationkeeps baseline behavior unchanged. - submodule refresh: consume BaseTemplate updates by updating submodule reference, not by editing submodule content directly.
Template Hierarchy & Inheritance¶
ConnectSoft templates follow a three-layer model to ensure maximum reuse, consistency, and flexibility.
Base Microservice Template (ConnectSoft.BaseTemplate)¶
The foundational layer, providing the core structure and common infrastructure for all microservices. It is domain-agnostic.
Structure: Prefixed model projects under src/, for example ConnectSoft.BaseTemplate (host), ConnectSoft.BaseTemplate.DomainModel, ConnectSoft.BaseTemplate.ApplicationModel, ConnectSoft.BaseTemplate.Application, ConnectSoft.BaseTemplate.PersistenceModel.*, ConnectSoft.BaseTemplate.FlowModel.*, ConnectSoft.BaseTemplate.MessagingModel, ConnectSoft.BaseTemplate.ServiceModel.*, plus optional stacks (actors, schedulers, AI, MCP) as included in ConnectSoft.BaseTemplate.slnx. Shared NuGet versions are pinned in Directory.Packages.props; see ConnectSoft.Extensions catalog.
Responsibilities: Bootstrapping, common health checks, resilience patterns, base CI/CD, base documentation structure, and canonical template.json metadata.
Specialized Templates (Overlays)¶
These templates add domain-specific functionality on top of the base template. Examples include ConnectSoft.IdentityTemplate, Auth Server, Audit, and Worker templates.
Structure: Each specialized template is its own repository, including ConnectSoft.BaseTemplate as a Git submodule at base-template/. It adds parallel ConnectSoft.<ProductTemplate>.* projects (same Model naming as base), domain-specific tests, and documentation. Many extended solutions **replace* ConnectSoft.BaseTemplate.Application with ConnectSoft.<ProductTemplate>.Application while keeping other base projects as submodule references.
Composition: At generation time, these specialized templates act as "overlays" that are applied to the base template.
Multi-Overlay Composition¶
Multiple overlays can be composed to create highly specialized services. For example, an Identity Backend with Worker functionality.
flowchart TD
Layer1[Shared Libraries<br/>(NuGet Packages)] --> Layer2[Base Microservice Template<br/>(Git Submodule)]
Layer2 --> Layer3A[Identity Backend Template<br/>(Overlay)]
Layer2 --> Layer3B[Auth Server Template<br/>(Overlay)]
Layer2 --> Layer3C[Worker Template<br/>(Overlay)]
Layer3A --> Composed[Composed Template:<br/>Base + Identity]
Layer3A & Layer3C --> MultiComposed[Composed Template:<br/>Base + Identity + Worker]
subgraph TemplateHierarchy[Template Hierarchy]
Layer1
Layer2
Layer3A
Layer3B
Layer3C
end
Template Folder Structure & Organization¶
Templates are organized to support both independent development and automated composition.
Base template folder structure (ConnectSoft.BaseTemplate/)¶
ConnectSoft.BaseTemplate/
├── src/ # ConnectSoft.BaseTemplate.* projects (host, *Model layers, optional stacks)
├── tests/
├── Directory.Build.props
├── Directory.Packages.props # ConnectSoft.Extensions.* and third-party versions
└── template/ # Template metadata for dotnet new
├── template.json
├── ide.host.json
└── dotnetcli.host.json
Specialized template folder structure (ConnectSoft.IdentityTemplate/ example)¶
ConnectSoft.IdentityTemplate/
├── .gitmodules
├── base-template/ # Submodule -> ConnectSoft.BaseTemplate
├── ConnectSoft.TemplateRepositoryDirectory.Build.props
├── Directory.Build.props
├── Directory.Packages.props # Imports base-template/Directory.Packages.props
├── build/DisableMicrosoftExtensionsStackForMinimalHost.props
├── ConnectSoft.IdentityTemplate.slnx
├── ConnectSoft.IdentityTemplate/ # Host
├── ConnectSoft.IdentityTemplate.Application/ # Fork/replace of base Application in this solution
├── ConnectSoft.IdentityTemplate.DomainModel/
├── ConnectSoft.IdentityTemplate.* / # Other *Model projects at repo root
├── ConnectSoft.IdentityTemplate.*Tests/
├── Docs/
└── template/
├── identity.template.extend.json
└── worker.template.extend.json
Template JSON Inheritance System¶
The template.json files define the parameters and post-actions for dotnet new templates. Inheritance is managed through "extend files" and a merge process.
Base template.json¶
Defines canonical parameters, classifications, tags, and post-actions common to all microservices.
Extend Files (*.template.extend.json)¶
Specialized templates use extend files to:
- Override top-level fields (name, shortName, description).
- Override existing symbols (parameters) like
defaultValue,description. - Add new domain-specific symbols (e.g.,
UseExternalIdp,RequireEmailConfirmation). - Add additional
postActions(e.g., running domain-specific migrations). - Add additional
primaryOutputs.
Rules for Overriding and Inheritance¶
- Must Inherit: Core infrastructure parameters (e.g.,
ServiceName,RootNamespace,PersistenceType,MessagingType) must always be present in the finaltemplate.json. Specialized templates can override their default values or descriptions but cannot remove them. - Can Override:
name,shortName,description,tags,classifications, and properties of existing symbols (e.g.,defaultValue,displayName,description,choices). - Can Add: New symbols, post-actions, and primary outputs specific to the specialized template.
- Cannot Remove: Existing symbols or post-actions from the base template.
Merge Process Flow¶
The pack-template.ps1 script orchestrates the merging of template.json and extend files.
flowchart TD
BASE_JSON[Base template.json]
IDENTITY_EXTEND[identity.template.extend.json]
WORKER_EXTEND[worker.template.extend.json]
MERGE_PROCESS[Template Metadata Merge Process]
BASE_JSON --> MERGE_PROCESS
IDENTITY_EXTEND --> MERGE_PROCESS
WORKER_EXTEND --> MERGE_PROCESS
MERGE_PROCESS --> APPLY_OVERRIDES[Apply identityOverrides]
APPLY_OVERRIDES --> APPLY_SYMBOL_OVERRIDES[Apply symbolOverrides]
APPLY_SYMBOL_OVERRIDES --> APPLY_SYMBOL_ADDS[Apply symbolAdds]
APPLY_SYMBOL_ADDS --> APPLY_POST_ACTIONS[Apply postActionsAdds]
APPLY_POST_ACTIONS --> APPLY_PRIMARY_OUTPUTS[Apply primaryOutputsAdds]
APPLY_PRIMARY_OUTPUTS --> FINAL_JSON[Final Composed template.json]
IDE & CLI Configuration Inheritance¶
Similar to template.json, ide.host.json and dotnetcli.host.json also support inheritance.
ide.host.json: Provides IDE-specific configurations (e.g., default project to open, debug profiles). Specialized templates can extend this to add domain-specific debug profiles or settings.dotnetcli.host.json: Provides CLI-specific configurations (e.g., default arguments fordotnet new). Specialized templates can extend this to add domain-specific CLI options.
Configuration Merge Rules¶
- JSON Patching: Configurations are merged using a JSON Patch-like mechanism, where properties from extend files override or add to properties in the base configuration.
- Arrays: Arrays are typically appended or replaced, depending on the specific configuration section.
- Override vs. Extend: Explicit rules define whether a section is fully replaced (override) or incrementally added to (extend).
Build-Time vs Generation-Time Extension¶
ConnectSoft templates are designed for a dual-mode approach.
Build-Time Extension (Developer Experience)¶
- Mechanism: Git submodules are used to include the base template directly within specialized template repositories.
- Solution File Composition: The specialized template's
.slnfile includes projects from both the base template and the specialized template. - Project References: Specialized projects reference selected
base-template/src/ConnectSoft.BaseTemplate.*projects included in the extended.slnx(for example ConnectSoft.IdentityTemplate.DomainModel references base domain or application model projects as designed). - Test Projects: Specialized templates add
ConnectSoft.<Template>.*Testsprojects; shared test helpers come from ConnectSoft.Extensions.Testing and base test projects as referenced. - Documentation: Base documentation is available via the submodule, and specialized documentation extends this structure.
- Metrics/Options Libraries: Base provides extension points (
IMetricsFeature,IConfigureOptions<T>) that specialized templates implement.
graph TD
SUBGRAPH_REPO[Specialized template repo e.g. ConnectSoft.IdentityTemplate]
SUBMODULE[Git submodule ConnectSoft.BaseTemplate at base-template]
SPECIALIZED_SRC[ConnectSoft.IdentityTemplate.* source projects]
SPECIALIZED_TESTS[ConnectSoft.IdentityTemplate.*Tests]
SOLUTION_FILE[ConnectSoft.IdentityTemplate.slnx]
SUBGRAPH_REPO --> SUBMODULE
SUBMODULE --> BASE_SRC[base-template ConnectSoft.BaseTemplate.* subset]
SUBMODULE --> BASE_TESTS[base-template tests as included]
SPECIALIZED_SRC -->|project references| BASE_SRC
SPECIALIZED_TESTS -->|project references| BASE_SRC
SOLUTION_FILE --> BASE_SRC
SOLUTION_FILE --> SPECIALIZED_SRC
SOLUTION_FILE --> BASE_TESTS
SOLUTION_FILE --> SPECIALIZED_TESTS
Generation-Time Extension (Factory Composition)¶
- Mechanism: Overlays are applied sequentially to a base template artifact.
- Overlay Application: The Factory's template generator merges code, documentation, and metadata from overlays into a flattened, final template.
- Token Replacement: Placeholders (e.g.,
{{ServiceName}},{{RootNamespace}}) are replaced with user-provided values. - File Merging: New files are added, existing files are patched (e.g.,
Program.csmodifications), and content is inserted between markers. - Documentation Merging: Base documentation and overlay-specific documentation are combined.
Reference Wiring Mechanisms¶
This section details how different components of the template system are connected and how extensibility is achieved.
How Base Test Infrastructure References Specialized Services¶
ITestAppFactory: The base testing infrastructure defines an interface likeITestAppFactory(e.g., inBase.Testing.Infrastructure).- Specialized Implementations: Specialized templates provide concrete implementations (e.g.,
IdentityTestAppFactoryinIdentity.AcceptanceTests) that configure aWebApplicationFactory<TProgram>for their specific service. - Abstract Base Tests: Base test classes (e.g.,
AcceptanceTestBase) use this factory to createHttpClientinstances and accessIServiceProvider, allowing domain-specific tests to reuse common test patterns.
How Base Documentation References Specialized Documentation¶
- Build Time: Specialized template
mkdocs.ymlcan include base documentation files via relative paths to the submodule. - Generation Time: The template generator merges documentation files from the base and overlays into the final documentation site structure. Cross-links are maintained and updated during this process.
How Base Metrics/Options Infrastructure Discovers Specialized Implementations¶
- Extension Point Interfaces: Base libraries define interfaces like
IMetricsFeatureandIConfigureOptions<T>. - DI Scanning: The base host's
Program.cs(or a dedicated extension method) uses dependency injection (DI) container scanning (e.g.,services.Scan().FromApplicationDependencies().AddClasses().AsImplementedInterfaces()) to automatically discover and register all implementations of these interfaces from loaded assemblies (including specialized domain projects). - Runtime Registration: This allows specialized templates to "plug in" their domain-specific metrics and options configurations without the base having any explicit knowledge or references to them.
graph TD
BASE_HOST[Base Host Application<br/>(Program.cs)]
BASE_DI[Base DI Container<br/>(services.Scan)]
BASE_METRICS_INFRA[ConnectSoft.Extensions.Metrics<br/>(IMetricsFeature)]
BASE_OPTIONS_INFRA[ConnectSoft.Extensions.Options<br/>(IConfigureOptions<T>)]
IDENTITY_METRICS[Identity.Infrastructure<br/>(IdentityMetricsFeature)]
IDENTITY_OPTIONS[Identity.Infrastructure<br/>(ConfigureIdentitySecurityOptions)]
IDENTITY_TEST_FACTORY[Identity.AcceptanceTests<br/>(IdentityTestAppFactory)]
BASE_HOST --> BASE_DI
BASE_DI -->|Discovers & Registers| IDENTITY_METRICS
BASE_DI -->|Discovers & Registers| IDENTITY_OPTIONS
BASE_METRICS_INFRA -->|Defines Interface| IDENTITY_METRICS
BASE_OPTIONS_INFRA -->|Defines Interface| IDENTITY_OPTIONS
BASE_TEST_INFRA[Base.Testing.Infrastructure<br/>(ITestAppFactory, AcceptanceTestBase)]
BASE_TEST_INFRA -->|Defines Interface & Base Class| IDENTITY_TEST_FACTORY
Related Documents¶
- Template Layering and Reuse - Three-layer architecture guide
- Template Metadata Composition - Template.json composition details
- Template Overlays Specification - Overlay system and versioning
- Metrics, Options and Testing Extensibility - Extension point patterns