Skip to content

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: DefaultMicroserviceRegistration keeps 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
Hold "Alt" / "Option" to enable pan & zoom

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 final template.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]
Hold "Alt" / "Option" to enable pan & zoom

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 for dotnet 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 .sln file 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>.*Tests projects; 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
Hold "Alt" / "Option" to enable pan & zoom

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.cs modifications), 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 like ITestAppFactory (e.g., in Base.Testing.Infrastructure).
  • Specialized Implementations: Specialized templates provide concrete implementations (e.g., IdentityTestAppFactory in Identity.AcceptanceTests) that configure a WebApplicationFactory<TProgram> for their specific service.
  • Abstract Base Tests: Base test classes (e.g., AcceptanceTestBase) use this factory to create HttpClient instances and access IServiceProvider, allowing domain-specific tests to reuse common test patterns.

How Base Documentation References Specialized Documentation

  • Build Time: Specialized template mkdocs.yml can 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 IMetricsFeature and IConfigureOptions<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
Hold "Alt" / "Option" to enable pan & zoom