-
Notifications
You must be signed in to change notification settings - Fork 1
Migration Guide
This guide explains how to migrate existing projects from the old atc-rest-api-generator CLI tool to the new atc-rest-api-source-generator Roslyn-based source generator.
The old CLI tool (atc-rest-api-generator) required running scripts to generate code before building. The new source generator (Atc.Rest.Api.SourceGenerator) automatically generates code at build time - no manual steps required.
| Aspect | Old CLI Generator | New Source Generator |
|---|---|---|
| Generation | Manual script execution | Automatic at build time |
| Package |
atc-rest-api-generator (CLI tool) |
Atc.Rest.Api.SourceGenerator (NuGet) |
| Generated Code | Committed to repo | Generated on-the-fly (not committed) |
| Project Naming |
*.Api.Generated, *.ApiClient.Generated
|
*.Api.Contracts, *.ApiClient
|
| Configuration | *GeneratorOptions.json |
Marker files (.atc-rest-api-*) |
| Target Framework | .NET 8+ | .NET 10+ |
Before starting, verify all items:
- Project uses the old
atc-rest-api-generatorCLI tool - Valid OpenAPI 3.x specification file exists and passes validation
- Project is under git version control with a clean working tree
- All current tests pass (
dotnet test) - CI/CD pipeline is green (no pre-existing failures)
- Team is aware of the migration (generated code will change significantly)
- You have read this entire guide before executing any commands
- Ready to upgrade to .NET 10 with C# 14
β οΈ Important: The migration modifies project structure, renames projects, and changes namespaces. Always work on a dedicated branch and have a rollback plan ready.
dotnet tool install -g atc-rest-api-genOr update if already installed:
dotnet tool update -g atc-rest-api-genRun the validation command to check if your project is ready for migration:
atc-rest-api-gen migrate validate -s <spec-path> [--solution <solution-path>]Example:
atc-rest-api-gen migrate validate -s D:\Code\MyProject\src\Specs\api.yamlThe solution (.sln or .slnx) is found by itself: the nearest folder with one, searched from the
specification's folder upwards (here D:\Code\MyProject), then from the current directory upwards. Pass
--solution <path> to choose it explicitly.
π‘ Like every other command,
migratetakes the specification with-s|--specification(since 2.1.1). Earlier versions used-sfor the solution and-p|--specfor the specification. That spelling still works: a-sthat points at a.sln/.slnxfile or a folder is taken as the solution, and-p|--specis still accepted for the specification.
The validator will check:
- Solution structure (Api.Generated, Domain, Host API projects)
- OpenAPI specification validity
- Target framework compatibility
- Package references
- Handler implementations
The validation output shows what the migration will do:
ATC REST API
Migration Validator
Solution: D:\Code\MyProject\MyProject.slnx
Specification: D:\Code\MyProject\src\Specs\api.yaml
[blue]Project Structure[/]
β Solution file found: MyProject.slnx
β Api.Generated project found: MyProject.Api.Generated
β Domain project found: MyProject.Domain
β Host API project found: MyProject.Api
[blue]Target Framework & Language Version[/]
β Target framework: net9.0 (upgrade required β net10.0)
β Language version: C# 13 (upgrade required β C# 14)
[yellow]![/] Upgrade to .NET 10 / C# 14 will be required
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[yellow]! Project is eligible for migration (with .NET 10 / C# 14 upgrade)[/]
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Before running migration, commit all your changes to git:
git add .
git commit -m "Pre-migration commit"This allows easy rollback if needed.
Preview what changes will be made without executing them:
atc-rest-api-gen migrate execute -s <spec-path> [--solution <solution-path>] --dry-runReview the output carefully to understand all changes.
Run the migration:
atc-rest-api-gen migrate execute -s <spec-path> [--solution <solution-path>]The migration will:
- Check git status - Warn if uncommitted changes exist
- Confirm upgrade - Prompt for .NET 10 / C# 14 upgrade
-
Create marker files -
.atc-rest-api-server,.atc-rest-api-client,.atc-rest-api-server-handlers - Update project files - Add source generator package, configure AdditionalFiles
-
Handle ATC Coding Rules - Update or set up
atc-coding-rules-updater.json - Clean generated code - Delete old generated files (Contracts/, Endpoints/, etc.)
-
Rename projects -
Api.GeneratedβApi.Contracts,ApiClient.GeneratedβApiClient - Update solution - Update project references and solution file
- Update GlobalUsings - Update namespace references in Domain project
- Migrate parameter names - Update handler code for parameter name changes
After migration, build your project:
dotnet buildThe source generator will automatically generate all code at build time.
| Old Name | New Name |
|---|---|
MyProject.Api.Generated |
MyProject.Api.Contracts |
MyProject.ApiClient.Generated |
MyProject.ApiClient |
-
.atc-rest-api-serverin Api.Contracts project -
.atc-rest-api-clientin ApiClient project (if exists) -
.atc-rest-api-server-handlersin Domain project
From Api.Contracts (formerly Api.Generated):
-
Contracts/folder -
Endpoints/folder -
Resources/folder GlobalUsings.csIApiContractAssemblyMarker.cs
From ApiClient (formerly ApiClient.Generated):
-
Contracts/folder -
Endpoints/folder GlobalUsings.cs
// Before
global using MyProject.Api.Generated.Accounts.Handlers;
global using MyProject.Api.Generated.Accounts.Results;
// After
global using MyProject.Api.Contracts.Generated.Accounts.Handlers;
global using MyProject.Api.Contracts.Generated.Accounts.Results;The migration tool automatically updates handler code when parameter property names differ between generators:
// Before (old generator)
var token = parameters.Continuation;
// After (new generator)
var token = parameters.ContinuationToken;This applies to both the Domain and Domain.Tests projects.
If something goes wrong, use git to revert:
# Revert all changes
git checkout -- .
git clean -fd
# Or reset to pre-migration commit
git reset --hard HEAD~1Validates a project for migration readiness.
atc-rest-api-gen migrate validate -s <spec-path> [--solution <solution-path>] [options]| Option | Description |
|---|---|
-s, --specification <PATH> |
Path to OpenAPI specification file (required) |
--solution <PATH> |
Solution file (.sln/.slnx) or its directory. Default: the nearest folder with a .sln/.slnx above the specification, then above the current directory |
--verbose |
Show detailed validation output |
--output-report <PATH> |
Save validation report to file |
Performs the actual migration.
atc-rest-api-gen migrate execute -s <spec-path> [--solution <solution-path>] [options]| Option | Description |
|---|---|
-s, --specification <PATH> |
Path to OpenAPI specification file (required) |
--solution <PATH> |
Solution file (.sln/.slnx) or its directory. Default: the nearest folder with a .sln/.slnx above the specification, then above the current directory |
--dry-run |
Preview changes without executing |
--force |
Skip confirmation prompts |
If the migration fails or produces unexpected results, you can roll back at any point.
If you committed before migration (Step 4), simply reset to that commit:
# Discard all migration changes
git reset --hard HEAD~1
# Or if multiple commits were made during migration
git log --oneline -5 # Find the pre-migration commit
git reset --hard <commit-hash>If the migration partially succeeded and you want to keep some changes:
# See what changed
git diff --stat
# Selectively discard files
git checkout -- src/MyProject.Api.Generated/ # Restore old generated project
git checkout -- MyProject.slnx # Restore old solution fileAfter rolling back, verify everything works:
# Restore packages
dotnet restore
# Build
dotnet build
# Run tests
dotnet test
# Verify the old CLI generation still works
atc-rest-api-generator generate server -s api.yaml -o src/MyProject.Api.GeneratedIf the migration succeeded but you see build errors:
- Check the Troubleshooting section below first β most errors are namespace mismatches
- Run
dotnet clean && dotnet buildto clear stale caches - Check that all
AdditionalFilesentries in.csprojare correct
π‘ Tip: Always migrate on a dedicated branch (
git checkout -b migration/source-generator). This makes rollback trivial β just switch back to your main branch.
If you see this error, it means the migration was partially completed before. Either:
- Delete the target directory and re-run migration
- Or manually complete the migration
- Check that all namespace references are updated
- Verify the OpenAPI spec file path in
.csprojis correct - Ensure marker files are included as
AdditionalFiles - Clean and rebuild:
dotnet clean && dotnet build
If handler code has errors like "Property 'Continuation' not found", the parameter name migration may not have caught all usages. Search for the old name and update manually:
# Find remaining usages
grep -r "parameters.Continuation" src/These changes affect the C# client output. Almost all of them are additive β no generated type was renamed or removed, so existing code keeps compiling as-is. The one exception is the new ATC_API_SCH021 warning, which can break the build of a project that treats warnings as errors β see Spec-declared ProblemDetails is now reported.
The TypedClient mode now emits an interface alongside the client, in the same namespace, declaring every public operation:
public interface IMyApiClient
{
Task<MeteringPointsApiResponse> GetMeteringPointsAsync(
GetMeteringPointsParameters parameters,
CancellationToken cancellationToken = default);
}
public sealed class MyApiClient : IMyApiClient { /* ... */ }There is no opt-in flag β the interface is always generated.
What to do: change constructor parameters and DI resolutions from MyApiClient to IMyApiClient so the client can be mocked in tests. This is optional but recommended.
- public sealed class MeteringPointReportService(MyApiClient client)
+ public sealed class MeteringPointReportService(IMyApiClient client)When Microsoft.Extensions.Http is referenced, an Add{ClientName}() extension is also emitted and registers the interface:
services.AddMyApiClient(client => client.BaseAddress = new Uri("https://api.example.com"));
var client = provider.GetRequiredService<IMyApiClient>();βΉοΈ The generated client has two public constructors, so it is registered via an explicit typed-client factory rather than
AddHttpClient<TInterface, TImplementation>. If you previously hand-rolledAddHttpClient<IMyApiClient, MyApiClient>(), replace it with the generatedAddMyApiClient()β the manual form fails at resolve time, not compile time.
Every {Operation}EndpointResult now exposes static factory methods, one per documented response:
GetMeteringPointsEndpointResult.Ok(content); // 200 + body
GetMeteringPointsEndpointResult.Unauthorized(problem); // 401 + body
GetMeteringPointsEndpointResult.Forbidden(); // 403, no bodyWhat to do: if you wrote a local EndpointResultFactory helper to make results in tests, you can delete it and call the generated factories instead.
- var ok = EndpointResultFactory.Ok(response);
+ var ok = GetMeteringPointsEndpointResult.Ok(response);Each generated {Operation}EndpointResult is declared partial instead of sealed, so you can add members to it from your own code without wrapping it:
// Your file β same namespace as the generated result
public partial class GetMeteringPointsEndpointResult
{
public int MeteringPointCount
=> OkContent?.Result?.Count ?? 0;
}This needs no marker-file flag. It is unrelated to generatePartialModels, which controls the models only and remains opt-in and off by default.
What to do: nothing. Removing sealed is source- and binary-compatible; the only visible effect is that the type can now be derived from and extended.
βΉοΈ The generated typed client is still
sealed. Depend on its generatedI{ClientName}interface rather than deriving from the class.
In EndpointPerOperation mode the generator emits its own ProblemDetails and ValidationProblemDetails. If your specification also declares a schema with one of those names, that schema was previously materialized into {project}.Generated.{Segment}.Models and then never used β C# resolves the unqualified name against the enclosing namespace first, so the built-in always won and the spec type was silently discarded.
The spec-declared schema is now skipped rather than emitted, and the override is reported as ATC_API_SCH021 (see Analyzer Rules).
What to do: if you own the specification, rename the schema. If the spec is a third party's and your project builds with TreatWarningsAsErrors, suppress the rule:
<PropertyGroup>
<!-- Third-party spec declares ProblemDetails; the built-in type is used instead. -->
<NoWarn>$(NoWarn);ATC_API_SCH021</NoWarn>
</PropertyGroup>Switching the client to a TypedClient mode is the other option: that mode has no built-in ProblemDetails, so a spec-declared one is generated and used.
βΉοΈ This also removes an ambiguity that earlier versions could produce. With only one
ProblemDetailsin scope, call sites no longer need to fully qualify it.
See Working with C# Client Testing for the full testing guidance.
- Getting Started with Basic - Setting up a new project
- Getting Started with CLI - Using the CLI for project scaffolding
- Marker Files - Configuration options for marker files
- Working with CLI - Full CLI command reference
- Working with C# Client Testing - Testing code that uses a generated client
π Home
- πΌ FAQ Business Value
- π Getting Started with Basic
- π οΈ Getting Started with CLI
- π Migration Guide
- β¬οΈ Upgrading to v2
- π Working with OpenAPI
- π³οΈ Working with Nullability
- π οΈ Working with CLI
- π How-To Guides
- π Working with Security
- π¦ Working with Rate Limiting
- π Working with Resilience
- ποΈ Working with Caching
- π’ Working with Versioning
- β Working with Validations
- π Working with Webhooks
- βοΈ Working with Aspire
- π£οΈ Working with Endpoint Definitions
- π Working with Multi-Part Specs
- π§ͺ Working with Code Coverage
- π Working with C# Client
- π§ͺ Working with C# Client Testing
- π¦ Working with TypeScript Client
- πͺ Showcase Demo
- π§ͺ Working with E2E Testing
- βοΈ Working with Configuration
- π Marker Files
- π API Reference
- π Analyzer Rules
- β FAQ and Troubleshooting
- πΊοΈ Roadmap
- π§ Development Notes
- π¦ GitHub Repository
- π₯ NuGet Package
- π Report Issues