CoreEx.Template
4.0.0-preview-5
dotnet new install CoreEx.Template@4.0.0-preview-5
CoreEx.Template
Provides the
dotnet newtemplate pack for scaffolding CoreEx-based domain microservice solutions -- seven composable templates, onedotnet new install.
Overview
CoreEx.Template is a PackageType=Template NuGet package that installs seven dotnet new templates as a single unit. Together they cover AI workflow assets, the full project topology for a CoreEx domain-based microservice (shared solution core plus independently deployable host processes), an optional domain layer, and an optional Aspire AppHost for local orchestration.
| Short name | Template | Emits |
|---|---|---|
coreex-ai |
CoreEx AI assets | .github/ instructions, prompts, skills, and agents + .claude/ commands — run at repo root; supports --app-folder for monorepos |
coreex |
CoreEx domain-based microservice application | Solution scaffold: src/ libraries + tools/ projects + tests/ (Test.Common + Test.Unit) |
coreex-domain |
CoreEx Domain layer | src/[name].Domain/ DDD project — add-on, run after coreex when domain complexity warrants it |
coreex-api |
CoreEx API host | src/[name].Api/ host project + tests/[solution].Test.Api/ integration test project |
coreex-relay |
CoreEx Outbox Relay host | src/[name].Relay/ host project + tests/[solution].Test.Relay/ integration test project |
coreex-subscribe |
CoreEx Subscriber host | src/[name].Subscribe/ host project + tests/[solution].Test.Subscribe/ integration test project |
coreex-aspire |
CoreEx Aspire AppHost | src/[name].Aspire/ AppHost project orchestrating this solution's own hosts — add-on, run after the hosts it references already exist |
Parameters are consistent across templates -- the same --data-provider, --messaging-provider, and feature flags appear in every template that needs them, ensuring the generated code is coherent regardless of which templates you use.
Installation
dotnet new install CoreEx.Template
To verify:
dotnet new list --tag CoreEx
To update after a new release:
dotnet new update
To uninstall:
dotnet new uninstall CoreEx.Template
AI-Guided Scaffolding
coreex-ai is the primary way to install CoreEx AI workflow assets into any repository. It outputs only .github/ and .claude/ artefacts and is intentionally decoupled from the implementation scaffolding:
.github/instructions/coreex.instructions.md-- CoreEx coding context (replacescopilot-instructions.md).github/instructions/*.instructions.md-- scoped coding conventions per layer/file type.github/prompts/coreex-scaffold.prompt.md--/coreex-scaffold: interviews for project needs and recommends the smallest safedotnet new coreex*command set.github/agents/coreex-expert.agent.md--/coreex-expert: architecture guidance.claude/commands/coreex-expert.md--/coreex-expertfor Claude Code.claude/commands/coreex-docs-sync.md--/coreex-docs-sync: refresh the local CoreEx doc cache after a version bump
Recommended day-1 workflow:
# Step 1 (always from repo root): install AI workflow assets
dotnet new coreex-ai
# For monorepos where CoreEx lives under a subfolder:
dotnet new coreex-ai --app-folder backend
# Step 2 (from the solution directory): scaffold the implementation
dotnet new coreex -n Avanade.Erp.Sales --data-provider SqlServer ...
coreex and the host templates no longer emit any .github/ artefacts -- run coreex-ai separately to get AI context. The two are independent and can be combined in any order.
For a brand-new blank repository, run /coreex-bootstrap after dotnet new coreex-ai. The skill generates root guidance files (README.md, AGENTS.md, CLAUDE.md) and immediately chains to /coreex-scaffold for solution shaping.
Typical greenfield flow:
# Step 1: install AI workflow assets (includes /coreex-bootstrap skill)
dotnet new coreex-ai
# Step 2: generate root guidance files and begin solution interview
# (run in Copilot Chat or Claude Code)
/coreex-bootstrap
Then answer the /coreex-scaffold questions. The workflow derives the required coreex, coreex-domain (optional), coreex-api, coreex-relay, coreex-subscribe, and coreex-aspire (optional) commands.
Naming Convention
The templates use dot-delimited names that encode the solution hierarchy. Understanding this is essential -- the name you supply drives all file names, namespace declarations, project cross-references, and configuration values automatically.
Recommended format: [Company].[Product].[Domain]
| Segment | Example | Role |
|---|---|---|
| Company | Avanade |
Organisation |
| Product | Erp |
Product or system |
| Domain | Sales |
The bounded context being scaffolded |
For the solution template (coreex) the name is the three-part solution root, e.g. Avanade.Erp.Sales. For each host template (coreex-api, coreex-relay, coreex-subscribe) the name appends the host suffix, e.g. Avanade.Erp.Sales.Api.
Derived values (example: Avanade.Erp.Sales.Api)
| Derived symbol | Value | Used for |
|---|---|---|
domain-name |
Sales |
Class names, namespaces, DB identifiers (mixed case) |
domain-name-lower |
sales |
Service Bus topic/subscription names, Postgres database name |
solution-name |
Avanade.Erp.Sales |
Cross-project references in host .csproj files |
solution-parent-name |
Avanade.Erp |
CoreEx:Host:SolutionName in appsettings.json |
Template 1 -- coreex-ai (AI workflow assets)
Installs CoreEx AI workflow assets into any repository. Always run from the repo root — this is where .github/ must land for GitHub Copilot to read it.
This template emits nothing but .github/ and .claude/ artefacts: no AGENTS.md, no README.md, no implementation scaffolding. It is safe to run against an existing repository. Root guidance files for a brand-new, empty repository are generated by the /coreex-bootstrap skill instead (shipped as part of this template's .github/skills/ output) -- see the recommended day-1 workflow above.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
--app-folder |
string | (empty) | The subfolder where the CoreEx application lives, relative to the repo root (for monorepos, e.g. backend or services/api). Leave blank for single-repo projects. |
Outputs
.github/
instructions/
coreex.instructions.md # CoreEx coding context (applyTo: "**" or "<app-folder>/**")
coreex-api-controllers.instructions.md
coreex-application-services.instructions.md
coreex-contracts.instructions.md
coreex-conventions.instructions.md
coreex-domain.instructions.md
coreex-event-subscribers.instructions.md
coreex-host-setup.instructions.md
coreex-repositories.instructions.md
coreex-tests.instructions.md
coreex-tooling.instructions.md
coreex-validators.instructions.md
prompts/
coreex-scaffold.prompt.md
agents/
coreex-expert.agent.md
.claude/
commands/
coreex-bootstrap.md # /coreex-bootstrap blank-repo initialisation command
coreex-scaffold.md # /coreex-scaffold guided solution scaffolding command
coreex-expert.md # /coreex-expert architecture guidance command
coreex-docs-sync.md # /coreex-docs-sync doc cache refresh command
--app-folder behaviour
When --app-folder is absent (single-repo), each instruction file retains its original scoped applyTo glob (e.g. applyTo: "**/*.cs"). When --app-folder is provided, each instruction file's applyTo glob is prefixed with the subfolder path (e.g. applyTo: "backend/**/*Validator*.cs"), keeping per-file instruction targeting while scoping Copilot context to that subfolder.
Examples
# Single-repo (most common — no args needed):
dotnet new coreex-ai
# Monorepo — CoreEx under backend/:
dotnet new coreex-ai --app-folder backend
# Monorepo — CoreEx under a nested path:
dotnet new coreex-ai --app-folder services/shopping
Template 2 -- coreex (Solution scaffold)
Scaffolds the shared solution core: the .slnx solution file, solution-wide configuration files (.editorconfig, Directory.Build.props, Directory.Packages.props), the Contracts, Application, Infrastructure class-library projects, and the Database and CodeGen tooling projects. The optional Domain project is a separate add-on — see "Template 3 -- coreex-domain" below.
Run this once per domain from the solution root directory.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-n / --name |
string | (required) | Solution base name, e.g. Avanade.Erp.Sales. Drives all file names and namespaces. Format: [Company].[Product].[Domain]. |
--refdata-enabled |
bool | true |
Includes the reference-data pattern: IReferenceDataRepository (Application), ReferenceDataService (Application), ReferenceDataRepository (Infrastructure), and the CodeGen tool project. |
--rop-enabled |
bool | false |
Enables Railway-Oriented Programming -- Result/Result<T> return types throughout the solution. |
--data-provider |
SqlServer | Postgres | None |
SqlServer |
The data persistence technology. None is for facade scenarios (e.g. over Dynamics 365) where there is no local database -- the Database tool project, EF Core packages, DbContext, and EfDb are all omitted. |
--outbox-enabled |
bool | true |
Includes transactional-outbox wiring in the Infrastructure project. Has no effect when --data-provider None. |
--messaging-provider |
ServiceBus | None |
ServiceBus |
The messaging technology. None omits all messaging configuration. |
Output
[name].slnx
.editorconfig
.gitignore
.filenesting.json
Directory.Build.props
Directory.Packages.props
src/
[name].Contracts/
[name].Contracts.csproj
GlobalUsing.cs
[name].Application/
[name].Application.csproj
GlobalUsing.cs
ReferenceDataService.cs (refdata-enabled only)
Repositories/
IReferenceDataRepository.cs (refdata-enabled only)
[name].Infrastructure/
[name].Infrastructure.csproj
GlobalUsing.cs
Repositories/
[Domain]DbContext.cs (data-provider != None)
[Domain]EfDb.cs (data-provider != None)
ReferenceDataRepository.cs (refdata-enabled && data-provider != None)
tools/
[name].Database/ (data-provider != None)
[name].Database.csproj
Program.cs
[name].CodeGen/ (refdata-enabled && data-provider != None)
[name].CodeGen.csproj
Program.cs
ref-data.yaml
tests/
[name].Test.Common/
[name].Test.Common.csproj
TestData.cs
Data/ (data-provider != None -- embedded seed data for DbEx)
[name].Test.Unit/
[name].Test.Unit.csproj
Examples
Default (PostgreSQL, refdata, Service Bus outbox):
dotnet new coreex -n Avanade.Erp.Sales
PostgreSQL with no refdata:
dotnet new coreex -n Avanade.Erp.Sales --data-provider Postgres --refdata-enabled false
Facade over an external system (no local database or messaging):
dotnet new coreex -n Avanade.Erp.Sales --data-provider None --messaging-provider None
Domain-driven design with ROP, Postgres, no outbox:
dotnet new coreex -n Avanade.Erp.Sales --rop-enabled true --data-provider Postgres --outbox-enabled false
dotnet new coreex-domain -n Avanade.Erp.Sales.Domain
dotnet sln Avanade.Erp.Sales.slnx add src/Avanade.Erp.Sales.Domain
dotnet add src/Avanade.Erp.Sales.Application/Avanade.Erp.Sales.Application.csproj reference src/Avanade.Erp.Sales.Domain/Avanade.Erp.Sales.Domain.csproj
Template 3 -- coreex-domain (Domain layer add-on)
Scaffolds an optional *.Domain class-library project for solutions where domain complexity warrants domain-driven design: aggregate roots, child entities, value objects, and PersistenceState-driven mutation methods via CoreEx.DomainDriven. Most solutions do not need this -- add it only when the Application layer's CRUD-style orchestration is no longer enough.
Run this after coreex, from the solution root. Like coreex-api/coreex-relay/coreex-subscribe, this template requires the solution base name with its own suffix appended (e.g. Avanade.Erp.Sales.Domain, not the bare Avanade.Erp.Sales) -- passing the bare base name emits into the wrong folder and breaks the Contracts project reference. Unlike those hosts, coreex-domain does not add itself to the .slnx -- wire it in yourself with dotnet sln add. You must also add a project reference from Application to the new Domain project (dotnet add ... reference ...) -- Application is the only layer with a direct dependency on Domain (Infrastructure only reaches it transitively through Application), and nothing else wires that reference for you.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-n / --name |
string | (required) | Solution base name plus the .Domain suffix, e.g. Avanade.Erp.Sales.Domain. |
Output
src/
[name].Domain/
[name].Domain.csproj
GlobalUsing.cs
Example
dotnet new coreex -n Avanade.Erp.Sales --rop-enabled true --data-provider Postgres --outbox-enabled false
dotnet new coreex-domain -n Avanade.Erp.Sales.Domain
dotnet sln Avanade.Erp.Sales.slnx add src/Avanade.Erp.Sales.Domain
dotnet add src/Avanade.Erp.Sales.Application/Avanade.Erp.Sales.Application.csproj reference src/Avanade.Erp.Sales.Domain/Avanade.Erp.Sales.Domain.csproj
Template 4 -- coreex-api (API host)
Scaffolds an ASP.NET Core Web API host project. Wires up CoreEx execution context, optional reference-data orchestration, FusionCache L1/L2 caching with Redis backplane, the selected database provider and EF Core, outbox publishing, NSwag OpenAPI, and OpenTelemetry.
Run this from the solution root (the directory created by coreex). The template emits into both src/ and tests/ so it must be run at the root level.
Note: If
--refdata-enabled trueand*.CodeGenhas already been run once (e.g. this host is being added to an existing solution), re-rundotnet run --project tools/[solution].CodeGenafterward. CodeGen only emits the reference-data controller into an*.Apiproject directory that exists at generation time -- it silently skips it (a log warning, not an error) for a host added later.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-n / --name |
string | (required) | Full project name, e.g. Avanade.Erp.Sales.Api. Must match the solution name with .Api appended. |
--refdata-enabled |
bool | true |
Wires up ReferenceDataOrchestrator and dynamic service registration for reference-data caching. Match the value used with coreex. |
--data-provider |
SqlServer | Postgres | None |
SqlServer |
Database technology. Selects the Aspire connection, CoreEx database, unit-of-work, and outbox publisher registration. |
--outbox-enabled |
bool | true |
Registers the outbox publisher (SqlServerOutboxPublisher or PostgresOutboxPublisher) as the IEventPublisher. Has no effect when --data-provider None. |
Output
src/
[name].Api/
[name].Api.csproj
Program.cs
GlobalUsing.cs
appsettings.json
appsettings.Development.json
AGENTS.md
tests/
[solution-name].Test.Api/
[solution-name].Test.Api.csproj
appsettings.json (illustrative -- values are replaced at generation time):
{
"CoreEx": {
"Host": {
"SolutionName": "Avanade.Erp", // Company.Product (solution-parent-name)
"DomainName": "Sales" // Domain (domain-name)
},
"Events": {
"Destination": "sales" // Topic/queue name (domain-name-lower)
}
},
"Logging": { ... }
}
appsettings.Development.json (connection strings vary by --data-provider):
{
"Aspire": {
// SQL Server (implement-sqlserver):
"Microsoft": { "Data": { "SqlClient": { "ConnectionString": "Data Source=127.0.0.1,1433;Initial Catalog=Sales;..." } } },
// OR PostgreSQL (implement-postgres):
"Npgsql": { "ConnectionString": "Server=127.0.0.1;Database=sales;..." },
"StackExchange": { "Redis": { "ConnectionString": "localhost:6379" } }
}
}
Examples
Default (PostgreSQL, refdata, outbox):
dotnet new coreex-api -n Avanade.Erp.Sales.Api
PostgreSQL, no refdata:
dotnet new coreex-api -n Avanade.Erp.Sales.Api --data-provider Postgres --refdata-enabled false
Facade (no database):
dotnet new coreex-api -n Avanade.Erp.Sales.Api --data-provider None
Template 5 -- coreex-relay (Outbox Relay host)
Scaffolds an ASP.NET Core background-service host that reads committed events from the transactional outbox table and forwards them to the messaging provider. Does not reference the solution's shared projects -- it is a standalone host that requires only a database connection and a messaging connection.
Run this from the solution root (the directory created by coreex). The template emits into both src/ and tests/ so it must be run at the root level.
Note: When
--data-provider Noneis selected the outbox relay has nothing to relay. Scaffold this host only when your solution uses the outbox pattern (i.e.--data-providerisSqlServerorPostgresand--outbox-enabled true).
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-n / --name |
string | (required) | Full project name, e.g. Avanade.Erp.Sales.Relay. |
--data-provider |
SqlServer | Postgres | None |
SqlServer |
Database technology used for reading the outbox. |
--messaging-provider |
ServiceBus | None |
ServiceBus |
Messaging provider to publish forwarded events to. |
Output
src/
[name].Relay/
[name].Relay.csproj
Program.cs
appsettings.json
appsettings.Development.json
AGENTS.md
tests/
[solution-name].Test.Relay/
[solution-name].Test.Relay.csproj
appsettings.json (illustrative):
{
"CoreEx": {
"Host": {
"SolutionName": "Avanade.Erp",
"DomainName": "Sales",
"Services": {
"Interval": "00:00:00.500",
"OutboxRelay": {
"BatchSize": 10,
"PerWorkerPartitionCount": 2,
"LeaseDuration": "00:00:05",
"BackoffDuration": "00:00:05",
"ServicesCount": 4
}
}
}
}
}
appsettings.Development.json (connection strings vary by provider):
{
"Aspire": {
// SQL Server or PostgreSQL connection (same pattern as coreex-api)
"Azure": {
// implement-servicebus only:
"Messaging": { "ServiceBus": { "ConnectionString": "Endpoint=sb://localhost;..." } }
}
}
}
Examples
SQL Server outbox → Azure Service Bus:
dotnet new coreex-relay -n Avanade.Erp.Sales.Relay
PostgreSQL outbox → Azure Service Bus:
dotnet new coreex-relay -n Avanade.Erp.Sales.Relay --data-provider Postgres
Template 6 -- coreex-subscribe (Subscriber host)
Scaffolds an ASP.NET Core background-service host that receives events from a messaging provider, dispatches them through the CoreEx SubscribedManager, and processes them via subscriber implementations. Optionally includes reference-data caching and a database connection for subscriber logic that needs persistence.
Run this from the solution root (the directory created by coreex). The template emits into both src/ and tests/ so it must be run at the root level.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-n / --name |
string | (required) | Full project name, e.g. Avanade.Erp.Sales.Subscribe. |
--refdata-enabled |
bool | true |
Wires up ReferenceDataOrchestrator and dynamic service registration for reference-data caching. Match the value used with coreex. |
--data-provider |
SqlServer | Postgres | None |
SqlServer |
Database technology. When not None, EF Core and outbox publisher are wired so subscriber logic can persist state and emit its own events. |
--messaging-provider |
ServiceBus | None |
ServiceBus |
Messaging provider to receive events from. When None, no receiver is configured. |
Output
src/
[name].Subscribe/
[name].Subscribe.csproj
Program.cs
GlobalUsing.cs
appsettings.json
appsettings.Development.json
AGENTS.md
tests/
[solution-name].Test.Subscribe/
[solution-name].Test.Subscribe.csproj
appsettings.json (illustrative):
{
"CoreEx": {
"Host": {
"SolutionName": "Avanade.Erp",
"DomainName": "Sales",
"Services": { "Interval": "00:00:00.500" }
},
"Events": {
"Destination": "sales" // Outbound event topic/queue (domain-name-lower)
}
}
}
appsettings.Development.json (connection strings vary by provider):
{
"Aspire": {
// SQL Server or PostgreSQL connection (same pattern as coreex-api)
"Azure": {
// implement-servicebus only:
"Messaging": {
"ServiceBus": {
"ConnectionString": "Endpoint=sb://localhost;...",
"QueueOrTopicName": "avanade.erp", // solution-name-lower
"SubscriptionName": "sales" // domain-name-lower
}
}
},
"StackExchange": { "Redis": { "ConnectionString": "localhost:6379" } }
}
}
Examples
Default (PostgreSQL, refdata, Service Bus):
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe
PostgreSQL, no refdata:
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe --data-provider Postgres --refdata-enabled false
Messaging only (no local database):
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe --data-provider None
Template 7 -- coreex-aspire (Aspire AppHost)
Scaffolds a .NET Aspire AppHost project that orchestrates this solution's own Api/Relay/Subscribe hosts for local development, plus an Extensions.cs providing dashboard sugar (health-check deep links, and "Pause all services"/"Resume all services" buttons for hosts running CoreEx hosted services).
Run this from the solution root, after the host projects it will reference already exist. Unlike coreex-api/coreex-relay/coreex-subscribe, host inclusion is not derived from a shared coreex parameter -- pass --has-api/--has-relay/--has-subscribe explicitly to match whichever hosts this solution actually has.
Note: If a new host is added to the solution after
coreex-aspirehas already been run, don't re-run it with--force-- that would overwrite any customisation already made toAppHost.cs/Extensions.cs. Add the missing<ProjectReference>andbuilder.AddProject<...>(...)line by hand instead.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
-n / --name |
string | (required) | Full project name, e.g. Avanade.Erp.Sales.Aspire. |
--has-api |
bool | true |
Include a project reference and AddProject<...> call for this solution's Api host. |
--has-relay |
bool | false |
Include a project reference and AddProject<...> call for this solution's Relay host. |
--has-subscribe |
bool | false |
Include a project reference and AddProject<...> call for this solution's Subscribe host. |
Output
src/
[name].Aspire/
[name].Aspire.csproj
AppHost.cs
Extensions.cs
appsettings.json
appsettings.Development.json
Properties/launchSettings.json
AGENTS.md
AppHost.cs (illustrative, all three hosts included):
var builder = DistributedApplication.CreateBuilder(args);
// Sales domain.
builder.AddProject<Projects.Avanade_Erp_Sales_Api>("sales-api").AddEndpoints("/health/ready/detailed");
builder.AddProject<Projects.Avanade_Erp_Sales_Relay>("sales-relay").AddEndpoints("/health/ready/detailed").AddHostedServiceSupport();
builder.AddProject<Projects.Avanade_Erp_Sales_Subscribe>("sales-subscribe").AddEndpoints("/health/ready/detailed").AddHostedServiceSupport();
builder.Build().Run();
Examples
API only:
dotnet new coreex-aspire -n Avanade.Erp.Sales.Aspire --has-api true
Full event-driven (API + Relay + Subscribe):
dotnet new coreex-aspire -n Avanade.Erp.Sales.Aspire --has-api true --has-relay true --has-subscribe true
Typical Workflow
These templates are independent -- use only the ones your solution needs (an optional coreex-domain add-on can be scaffolded after Step 1 when DDD complexity warrants it; see the coreex-domain template above). The following shows a full event-driven microservice topology:
Step 1 -- Create the solution root
mkdir Avanade.Erp.Sales
cd Avanade.Erp.Sales
dotnet new coreex -n Avanade.Erp.Sales
Produces the .slnx, solution configuration files, src/ class libraries, tools/ projects, and tests/ (Test.Common + Test.Unit). The current directory becomes the solution root.
Step 2 -- Scaffold host projects
Run from the solution root. Each template emits into both src/ and tests/:
dotnet new coreex-api -n Avanade.Erp.Sales.Api
dotnet new coreex-relay -n Avanade.Erp.Sales.Relay
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe
Step 3 -- Add hosts and their test projects to the solution
dotnet sln Avanade.Erp.Sales.slnx add src/Avanade.Erp.Sales.Api
dotnet sln Avanade.Erp.Sales.slnx add tests/Avanade.Erp.Sales.Test.Api
dotnet sln Avanade.Erp.Sales.slnx add src/Avanade.Erp.Sales.Relay
dotnet sln Avanade.Erp.Sales.slnx add tests/Avanade.Erp.Sales.Test.Relay
dotnet sln Avanade.Erp.Sales.slnx add src/Avanade.Erp.Sales.Subscribe
dotnet sln Avanade.Erp.Sales.slnx add tests/Avanade.Erp.Sales.Test.Subscribe
Step 4 -- Add an Aspire AppHost (optional)
Once the hosts above exist, optionally scaffold an AppHost for local orchestration:
dotnet new coreex-aspire -n Avanade.Erp.Sales.Aspire --has-api true --has-relay true --has-subscribe true
dotnet sln Avanade.Erp.Sales.slnx add src/Avanade.Erp.Sales.Aspire
Resulting directory structure
Avanade.Erp.Sales/
Avanade.Erp.Sales.slnx
.editorconfig | .gitignore | Directory.Build.props | Directory.Packages.props
src/
Avanade.Erp.Sales.Contracts/
Avanade.Erp.Sales.Application/
Avanade.Erp.Sales.Infrastructure/
Avanade.Erp.Sales.Api/
Avanade.Erp.Sales.Relay/
Avanade.Erp.Sales.Subscribe/
Avanade.Erp.Sales.Aspire/
tools/
Avanade.Erp.Sales.Database/
Avanade.Erp.Sales.CodeGen/
tests/
Avanade.Erp.Sales.Test.Common/
Avanade.Erp.Sales.Test.Unit/
Avanade.Erp.Sales.Test.Api/
Avanade.Erp.Sales.Test.Relay/
Avanade.Erp.Sales.Test.Subscribe/
Scenario Examples
Full event-driven (SQL Server, Service Bus, refdata)
All defaults -- no flags required:
dotnet new coreex -n Avanade.Erp.Sales
dotnet new coreex-api -n Avanade.Erp.Sales.Api
dotnet new coreex-relay -n Avanade.Erp.Sales.Relay
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe
dotnet new coreex-aspire -n Avanade.Erp.Sales.Aspire --has-api true --has-relay true --has-subscribe true
PostgreSQL variant
dotnet new coreex -n Avanade.Erp.Sales --data-provider Postgres
dotnet new coreex-api -n Avanade.Erp.Sales.Api --data-provider Postgres
dotnet new coreex-relay -n Avanade.Erp.Sales.Relay --data-provider Postgres
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe --data-provider Postgres
Facade over an external system (e.g. Dynamics 365)
No local database, no outbox, no messaging infrastructure -- the API is a pure HTTP facade:
dotnet new coreex -n Avanade.Erp.Sales --data-provider None --messaging-provider None
dotnet new coreex-api -n Avanade.Erp.Sales.Api --data-provider None
No relay or subscriber needed -- omit those templates entirely.
API + Subscriber only (no outbox relay)
When using an at-least-once messaging pattern without transactional outbox:
dotnet new coreex -n Avanade.Erp.Sales --outbox-enabled false
dotnet new coreex-api -n Avanade.Erp.Sales.Api --outbox-enabled false
dotnet new coreex-subscribe -n Avanade.Erp.Sales.Subscribe
Package Design Notes
Single install, six project-scaffolding templates. All six ship inside the same NuGet package as coreex-ai (PackageType=Template). A single dotnet new install CoreEx.Template makes all short names available: coreex, coreex-domain, coreex-api, coreex-relay, coreex-subscribe, and coreex-aspire.
Version stamping. Each template.json carries COREEX_VERSION as a placeholder. During dotnet pack, an inline MSBuild ReplaceTextInFile task stamps the actual $(Version) into generated copies of the five template.json files (CoreEx.Ai, CoreEx.Core, CoreEx.Api, CoreEx.Relay, CoreEx.Subscribe) before they are packed. The source copies in content/ retain the placeholder and remain editable. CoreEx.Domain and CoreEx.Aspire have no COREEX_VERSION token (neither depends on a CoreEx NuGet package) and are packed directly, unstamped.
Central Package Management. All PackageReference entries in generated projects carry no Version attribute -- versions are resolved from the Directory.Packages.props emitted by the coreex solution template. The host templates therefore require that the coreex solution template has been applied first (since Directory.Packages.props lives at the solution root). coreex-aspire is the one exception: its single extra package (the MessagePack CVE override) uses a per-project VersionOverride instead, since it is designed to be run standalone without requiring a Directory.Packages.props update.
Conditional file exclusion. The template engine's sources.modifiers with glob patterns handle all conditional file output -- no empty placeholder files are emitted. The .slnx solution file uses specialCustomOperations to enable `` XML-style conditionals (the template engine does not recognise .slnx as XML by default).
preferNameDirectory. All six project-scaffolding templates set preferNameDirectory: false so they generate into the current directory rather than creating an extra named subdirectory. The solution template generates its content directly into the current directory. Host templates (and the coreex-domain/coreex-aspire add-ons) generate their content into src/[ProjectName]/ (and tests/[solution-name].Test.X/ for hosts) subdirectories, which are created by the template itself as part of the source layout -- not by the preferNameDirectory mechanism.
solution-name file renaming. The solution-name derived symbol (everything before the last dot-segment of the -n value) carries fileRename: "solution-name" in all host templates. This causes directory names like solution-name.Test.Api to be substituted at generation time, producing correctly-named test project folders (e.g. Avanade.Erp.Sales.Test.Api) that match the CoreEx sample naming convention.
Validating Template Changes
dotnet build/dotnet test on CoreEx.sln never compiles anything under content/ -- it's raw dotnet new template source, not a C# project. A change to a host's Program.cs, GlobalUsing.cs, .csproj, or a template.json symbol is only proven correct by actually scaffolding it and building the result. Run ../../tools/validate-template-pack.ps1 (also run in CI) -- it packs and installs the template, scaffolds every parameter combination in its $testScenarios array into temp directories, asserts expected file presence/content, and dotnet builds the scenarios flagged Build = $true.
When adding a template, a host, or a new parameter, add a matching scenario. Most existing host-template scenarios (coreex-api-*, coreex-relay-*, coreex-subscribe-*) scaffold in isolation and set Build = $false because they have no coreex-generated siblings to compile against -- so a symbol-conditional bug (an unconditional global using/ProjectReference that should have been gated behind has-data-provider, implement-servicebus, etc.) will only be caught by a scenario that scaffolds coreex plus the host together in the same directory and builds the host's own .csproj.
Additional Resources
- CoreEx -- The framework these templates scaffold for.
- CoreEx.CodeGen -- The reference-data code-generation tool project scaffolded by the
coreextemplate when--refdata-enabled true. - dotnet templating wiki -- Full reference for
template.jsonconfiguration.
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0-preview-5 | 86 | 8/23/2026 |
| 4.0.0-preview-4 | 66 | 8/21/2026 |
| 4.0.0-preview-3 | 81 | 8/4/2026 |
| 4.0.0-preview-2 | 84 | 7/10/2026 |
| 4.0.0-preview-1 | 107 | 6/20/2026 |