"Create or modify a CoreEx Infrastructure-layer adapter (anti-corruption layer). USE FOR: new adapter interface in Application/Adapters/{ExternalDomain}/, new adapter implementation in Infrastructure/Adapters/{ExternalDomain}/, new typed HTTP client in Infrastructure/Clients/{ExternalDomain}/, event-driven sync/replication adapter (IXxxSyncAdapter), unit tests for HTTP clients with MockHttpClientFactory. DO NOT USE FOR: repositories within the same domain (use coreex-repository), application services that call adapters (use coreex-app-service), event subscriber hosts that drive sync adapters (see coreex-event-subscribers.instructions.md)."
Resources
1Install
npx skillscat add avanade/coreex/coreex-adapter Install via the SkillsCat registry.
CoreEx: Adapter (Anti-Corruption Layer)
Guides you through adding or modifying an adapter — the boundary that isolates your domain from an external system. Covers the Application-layer interface, Infrastructure-layer implementation, typed HTTP client, sub-folder conventions, registration, and unit testing.
When to Use
- Add an
IXxxAdapterinterface for a new external-domain dependency - Add a synchronous real-time adapter (HTTP call + optional local store read/event publish)
- Add a replication adapter (
IXxxSyncAdapter) for event-driven data sync into your local store - Add or extend a typed HTTP client (
XxxHttpClient) inInfrastructure/Clients/{ExternalDomain}/ - Validate consumed response fields inside a typed HTTP client using
WithValidator - Unit-test HTTP client response-code handling with
MockHttpClientFactory
When Not to Use
- Sending a command end-to-end (call site, queue topology, tests, Aspire) — use
coreex-command-publish-e2e, which invokes this skill for the adapter step - EF repositories within the same domain — use
coreex-repository - Application services that consume the adapter — use
coreex-app-service - Event subscriber hosts that drive
IXxxSyncAdapter— usecoreex-subscriber
Resolve project-wide choices from state before asking. Read the solution-root
AGENTS.md
Feature Configuration formessaging-provider(does this domain publish/consume events?) anddata-provider(SqlServer/Postgres/Cosmos/None)
(provider-specific local-store replication vs HTTP). Only prompt for what is unrecorded; re-state resolved values for confirmation.
Quick Reference
- Always use a sub-folder per external domain:
Application/Adapters/{ExternalDomain}/,Infrastructure/Adapters/{ExternalDomain}/,Infrastructure/Clients/{ExternalDomain}/ - Interface surface must be domain-idiomatic — never a mirror of the remote API's shape
- Returns
ResultorResult<T>— not plain values or thrown exceptions [ScopedService<IXxxAdapter>]on the implementation — auto-discovered viaAddDynamicServicesUsing<T>()- Typed HTTP client registered via
builder.AddTypedHttpClient<XxxHttpClient>("ServiceName")inProgram.cs - Never call
HttpClientdirectly in adapter methods — always delegate to the typed client class - Response validation belongs to the client, not
Application/Validators/. For small, client-only rules use a private static readonlyValidator<T>configured once withValidator.Create<T>().HasProperty(...), thenresponse.WithValidator(_validator).ToResultAsync(ct). Validate fields the consumer requires; do not copy create/update rules or add identifier matching by default. Extract a colocated validator only when complexity or genuine reuse warrants it; see the workflow. - Dispose the response with
using var;WithValidatordoes not own it. Reported validation errors becomeHttpRequestExceptionfailures with inner diagnostics, not caller validation errors. Test inline rules through the client, including invalid 2xx responses and success; cached adapters must not cache invalid responses. response.ToResultAsync()maps HTTP status toResult(2xx →Success, error + ProblemDetails →BusinessException/ProblemDetailsException, plain error →HttpRequestException)response.ToResultAsync<T>()is for responses that must carry a value — a null/empty body (including 204) is anHttpRequestExceptionfailure, so the result isResult<T>with a non-nullTand callers need no null handling. UseToResultOrDefaultAsync<T>()(→Result<T?>) only where a missing body is genuinely valid;GetValueAsync<T>()/GetValueOrDefaultAsync<T>()are the throwing equivalents. Map a 404 yourself before calling (Result.NotFoundError()) when "not found" is an expected outcome- Real-time read adapters should cache successes with
IHybridCache.GetOrCreateWithResultAsync<T>(key, factory, options, ct)— the adapter method becomes one line; only successful results are cached (failures such as not-found are never cached). Use short expiry viaHybridCacheEntryOptions.CreateFor<T>(...)(overridable throughCoreEx:Caching:{Type}:*). Concurrent cache misses are collapsed to one factory call per key per node withFusionHybridCache(cross-node needs an opt-in FusionCache distributed locker; non-FusionCache implementations such asMemoryOnlyHybridCachedon't collapse them) — keep the factory an idempotent read. Tests must then clear the cache per test and register a hybrid cache in the unit-test host (seereferences/workflow.md→ "Caching a real-time adapter") - Two distinct adapter roles in the samples — synchronous (real-time HTTP + events) and replication (event-driven local-store write; EF in relational domains,
CosmosDbcontainers in Cosmos domains); separate interfaces, separate implementations - Generate
*.Test.Unit/Clients/{ExternalDomain}/{External}HttpClientTests.csfor a typed HTTP client used by a synchronous or replication adapter — cover success (2xx), server error (5xx), and business error (422/ProblemDetails) per endpoint; skip for store-only replication adapters (no HTTP) and for combined local-store+HTTP+events orchestration adapters (mock the client viaTest.ReplaceHttpClientFactoryin integration tests instead)
For full workflow and code examples see `references/workflow.md`.
Key References
- `/.github/instructions/coreex-repositories.instructions.md` — Infrastructure conventions (adapters, clients, mapping)
- `/.github/instructions/coreex-application-services.instructions.md` — Application conventions (adapter interfaces, anti-corruption layer)
- Related skills: `coreex-repository` (same-domain persistence), `coreex-app-service` (consumes the adapter), `coreex-subscriber` (drives
IXxxSyncAdapter) - Infrastructure layer deep-dive — optional (after
/coreex-docs-sync) - Illustrative examples (CoreEx sample — not present in your project):
- synchronous + replication adapter interfaces —
IProductAdapter,IProductSyncAdapter - adapter + client implementations and the typed HTTP client
- real-time cached adapter (
ICustomerAdapter) and its value-returning client — the alternate, no-replication pattern
- synchronous + replication adapter interfaces —