Create or modify a CoreEx Application-layer service. USE FOR: new service class (exception-based or Result<T>), adding CRUD/business operations, CQRS read service (XxxReadService), adapter interface in Application/Adapters/, policy class in Application/Policies/, application-level mapper (Domain → Contract). DO NOT USE FOR: Infrastructure repositories (use coreex-repository), validators (use coreex-validator), controller endpoints (use coreex-api).
Scanned 8/31/2026
Install to Claude Code
npx -y skills add Avanade/CoreEx --skill coreex-app-service --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Coreex App Service?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/avanade-coreex-app-service)More formats (shields.io, HTML) on the badges page.
---
name: coreex-app-service
description: "Create or modify a CoreEx Application-layer service. USE FOR: new service class (exception-based or Result<T>), adding CRUD/business operations, CQRS read service (XxxReadService), adapter interface in Application/Adapters/, policy class in Application/Policies/, application-level mapper (Domain → Contract). DO NOT USE FOR: Infrastructure repositories (use coreex-repository), validators (use coreex-validator), controller endpoints (use coreex-api)."
argument-hint: "Optional: entity name, operations needed (get/create/update/delete/query/custom), exception-based or Result<T> pipeline, cross-domain calls needed"
tags: ["application-service", "application-layer", "unit-of-work", "cqrs", "events", "adapter", "policy", "result", "coreex"]
---
<!--
AI workflow asset — dual-audience notice:
- In the Avanade/CoreEx repository: this file is the authored source. Edit it here.
- In a consumer repository: this file was generated by `dotnet new coreex-ai` (or refreshed via
`dotnet new coreex-ai --force` / the `/coreex-docs-sync` skill). Do not hand-edit it directly —
propose the change upstream in Avanade/CoreEx instead, then refresh once it is released.
-->
# CoreEx: Application Service
Guides you through creating or modifying a CoreEx Application-layer service in `Application/`. Covers CRUD operations, business actions, unit-of-work + events, CQRS read services, adapters, and policies.
## When to Use
- New service class for an entity (scaffold interface + implementation)
- Adding a mutation operation (create / update / delete / custom business action)
- Adding a CQRS read service (`{Name}ReadService`) for queries and read-model shapes
- Adding an adapter interface (`Application/Adapters/`) for a cross-domain or external-service call
- Adding a policy class (`Application/Policies/`) for guard logic that requires I/O
- Switching a method between exception-based and `Result<T>` pipeline styles
## When Not to Use
- Infrastructure repositories — use the `coreex-repository` skill
- Validators — use the `coreex-validator` skill
- Controller endpoints — use `coreex-api`
- Domain aggregates, entities, value objects — those belong in the Domain layer
## Quick Reference
**Clarifying questions before writing any code:**
0. Resolve `rop-enabled` (exception vs `Result<T>`), whether a `*.Domain` project exists (aggregate mapping vs direct-CRUD), and `outbox-enabled` (event publishing) from the solution-root `AGENTS.md` **Feature Configuration** and project structure before asking the rest; only prompt for what is unresolved and re-state resolved values for confirmation.
1. Exception-based or `Result<T>` pipeline style? (→ Path A or B — per-project choice)
2. Which operations? Get / Create / Update / Delete / custom business action? (**never assume Query**)
3. Any cross-domain or external-service calls? (→ adapter interface, Path D)
4. Any policy guard checks requiring I/O? (→ policy class, Path D)
5. Domain layer present? (→ `Application/Mapping/` mapper; used in Path B)
6. Read-only queries or collection results needed? (→ CQRS read service, Path C)
**Key rules at a glance:**
- `[ScopedService<IInterface>]` on every service — auto-registers via `AddDynamicServicesUsing<T>()`
- **Only inject**: repository, unit of work, adapter interfaces, logger — **never** validators, mappers, policies
- `ValidateAndThrowAsync` (exception style) / `ValidateWithResultAsync` (Result<T>) — **never bare `ValidateAsync`**
- Service assigns `Id` after validation: `value.Id = Runtime.NewId()` (string key) / `Runtime.NewGuid()` (Guid)
- All mutations in `_unitOfWork.TransactionAsync(...)` — event added inside, never outside
- `WhereMutated(v => ...)` for Create/Update (`DataResult<T>` carries value); `WhereMutated(() => ...)` for Delete
- Delete event: `EventData.CreateEvent<T>(EventAction.Deleted).WithKey(id)` — **no value body**
- Check `EventAction` before reaching for `CreateEventWith(v, "string")` — most business actions (`Confirmed`, `Cancelled`, `Started`, `Completed`, `Suspended`, `Closed`, `Expired`, etc.) already have an enum member; the raw-string overload is only for genuinely novel actions
- `NotFoundException.ThrowIfDefault(entity)` after any Get that must find the entity
- Validators / Mappers / Policies: **not DI-registered** — call or instantiate at point of use
- `Validator<T, TSelf>`: call via singleton — `{Name}Validator.Default.ValidateAndThrowAsync(...)`
- `Validator<T>` (with injection): instantiate at call site — `new {Name}Validator(_dep).ValidateAndThrowAsync(...)`
- All interface methods include `CancellationToken cancellationToken = default` as the last parameter; pass through to every async call and `TransactionAsync(async ct => ..., cancellationToken)`
- CQRS: mutations + `GetAsync` → `{Name}Service`; queries + `GetAsync` → `{Name}ReadService` (both have `GetAsync`)
- **Before building Path C:** confirm `I{Name}Repository` already has `QueryAsync`/`QuerySchemaAsync` backed by a `{Name}QueryArgsConfig`. If not, stop and invoke `coreex-repository` first — never add filtering/ordering logic or a hand-rolled query in the service to work around a missing repository method
- Always `.ConfigureAwait(false)` on every `await`
- A Domain value object persisted via a JSON column (e.g. `Basket.ShippingAddress`) is mapped with a `BiDirectionMapper<TDomain, TContract, TSelf>` in `Application/Mapping/` (not the uni-directional `Mapper<TSource,TDest,TSelf>` used for the root aggregate) — see [`coreex-application-services.instructions.md#json-backed-value-object-mapping`](/.github/instructions/coreex-application-services.instructions.md#json-backed-value-object-mapping)
For full workflow and code examples see [`references/workflow.md`](references/workflow.md).
## Key References
- [`/.github/instructions/coreex-application-services.instructions.md`](/.github/instructions/coreex-application-services.instructions.md) — full conventions: guard clauses, events, CQRS, adapters, policies, Result<T> operators
- Related skills: [`coreex-repository`](../coreex-repository/SKILL.md) (persistence the service injects), [`coreex-validator`](../coreex-validator/SKILL.md) (invoked before mutations), [`coreex-policy`](../coreex-policy/SKILL.md) (I/O guard logic), [`coreex-adapter`](../coreex-adapter/SKILL.md) (cross-domain calls), [`coreex-contract`](../coreex-contract/SKILL.md) (the entity/request types), [`coreex-aggregate`](../coreex-aggregate/SKILL.md) (Domain layer + mapping), [`coreex-api`](../coreex-api/SKILL.md) (consumes the service), [`coreex-test-api`](../coreex-test-api/SKILL.md) (tests the service through the host)
- [Application layer deep-dive](/.github/docs/coreex/application-layer.md) — optional (after `/coreex-docs-sync`)
- Illustrative examples (CoreEx sample — not present in your project):
- [`ProductService` + `ProductReadService`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Products.Application) — exception-based CRUD + business actions, CQRS read
- [`BasketService` + `BasketReadService`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Shopping.Application) — Result<T> + adapter + policy
- [`ProductPolicy`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Shopping.Application/Policies) — policy example
- [`IProductAdapter`](https://github.com/Avanade/CoreEx/tree/main/samples/src/Contoso.Shopping.Application/Adapters/Products) — adapter interface example
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!