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

Template Hierarchy & Inheritance

ConnectSoft templates follow a three-layer model to ensure maximum reuse, consistency, and flexibility.

Base Microservice Template

The foundational layer, providing the core structure and common infrastructure for all microservices. It is domain-agnostic.

Structure: Includes projects for Host, Domain (base entities/value objects), Application (base interfaces), Infrastructure (base persistence/messaging setup), and Tests (base testing infrastructure).

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 Identity, Auth Server, Audit, and Worker templates.

Structure: Each specialized template is its own repository, including the base template as a Git submodule. It adds domain-specific projects (e.g., Identity.Api, Identity.Domain, Identity.Infrastructure), domain-specific tests, and domain-specific documentation.

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 (MicroserviceTemplate.Base/)

MicroserviceTemplate.Base/
├── src/                      # Core source code projects (Host, Domain, Application, Infrastructure)
├── tests/                    # Base testing infrastructure (Base.Testing.Infrastructure)
├── docs/                     # Base documentation (overview.md, architecture.md)
└── template/                 # Template metadata for dotnet new
    ├── template.json         # Canonical template parameters
    ├── ide.host.json         # IDE-specific host configuration
    └── dotnetcli.host.json   # CLI-specific host configuration

Specialized Template Folder Structure (IdentityBackendTemplate/)

IdentityBackendTemplate/
├── .gitmodules               # Defines git submodule for base-template
├── base-template/            # Git submodule pointing to MicroserviceTemplate.Base
│   ├── src/                  # Base source code
│   ├── tests/                # Base tests
│   └── docs/                 # Base docs
├── src/                      # Identity-specific source code (Identity.Api, Identity.Domain, etc.)
├── tests/                    # Identity-specific tests (Identity.UnitTests, Identity.AcceptanceTests)
├── docs/                     # Identity-specific documentation (identity-overview.md, identity-auth-flows.md)
└── template/                 # Overlay metadata
    ├── identity.template.extend.json # Extends base template.json for Identity
    └── worker.template.extend.json   # Optional: Extends for Worker functionality

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 directly reference base projects (e.g., Identity.Domain references Base.Domain).
  • Test Projects: Base provides generic testing infrastructure (e.g., Base.Testing.Infrastructure), which specialized templates reference and extend (e.g., Identity.AcceptanceTests uses Base.Testing.Infrastructure).
  • 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 Repository<br/>(e.g., IdentityBackendTemplate)]
    SUBMODULE[Git Submodule<br/>(MicroserviceTemplate.Base)]
    SPECIALIZED_SRC[Specialized Source Code<br/>(Identity.Api, Identity.Domain)]
    SPECIALIZED_TESTS[Specialized Tests<br/>(Identity.AcceptanceTests)]
    SOLUTION_FILE[IdentityBackend.sln]

    SUBGRAPH_REPO --> SUBMODULE
    SUBMODULE --> BASE_SRC[Base Source Code<br/>(Host, Base.Domain)]
    SUBMODULE --> BASE_TESTS[Base Testing Infrastructure<br/>(Base.Testing.Infrastructure)]

    SPECIALIZED_SRC -->|References| BASE_SRC
    SPECIALIZED_TESTS -->|References| BASE_TESTS
    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