Modeling Services
The Services Designer in Intent Architect is a powerful tool for modeling "Application Services" in your applications. This module enables developers to define how an application can be interacted with at the service level, allowing for the creation of both internal services and publicly exposed endpoints.
What is an Application Service?
An application service is a layer in an application's architecture that serves as an intermediary between the domain layer (business logic) and the presentation layer (e.g., user interface or API). It orchestrates use cases and workflows, delegating detailed domain logic to the domain layer.
Key Characteristics of an Application Service
- Coordinates Use Cases: Encapsulates specific use cases or workflows, such as "Register a User" or "Place an Order."
- Delegates Domain Logic: Delegates core business logic to domain entities or domain services.
- Handles Input/Output: Processes input from the presentation layer (e.g., HTTP requests) and returns output (e.g., HTTP responses or data transfer objects).
- Transaction Management: Manages transaction boundaries, such as starting, committing, or rolling back database transactions.
- Separates Layers: Prevents the presentation layer from interacting directly with the domain layer, maintaining separation of concerns.
- Interacts with Infrastructure: Uses repositories, mappers, or other infrastructure components to fetch or persist data.
Service Modeling Paradigms
Intent Architect provides two paradigms for modeling application services: CQRS (Command Query Responsibility Segregation) and Traditional Services. This flexibility allows you to design services tailored to your system's architectural requirements, whether you prioritize scalability and clarity or prefer a unified approach.
Modeling services focuses on defining the flow of data into and out of your application (data contracts). You can also optionally model implementations for your services.
CQRS Paradigm
- Separates read and write responsibilities into distinct models optimized for their respective purposes.
- Commands handle state-changing operations, focusing on business logic and domain consistency.
- Queries handle data retrieval, often accessing read-optimized data stores or projections.
- Ideal for systems with complex requirements or high scalability demands.
- Use case-centric.

Traditional Service Paradigm
- Combines read and write logic into a single service.
- Simplifies development by using a unified data model and service structure.
- Common in systems with straightforward requirements or minimal scalability concerns.

Intent Architect enables you to effectively model services using either approach.
Exposing an Application Service
By default, application services are only available internally. To expose these services for external consumption, you must take explicit action. This involves making critical decisions:
- Which service endpoints will be exposed?
- Over which technology will they be exposed?
- What are the technology-specific configurations (e.g., security, addressing)?
The methods available for exposing services depend on the modules installed. For example, if you have the Intent.Metadata.WebApi module installed, you can Expose as HTTP Endpoint to expose services over HTTP using REST conventions.
Creating a CQRS Command
- Add a
Commandto a diagram in the Services Designer. - Name the
Command, typically suffixed withCommand(e.g.,CreateCustomerCommand). - Right-click the
Commandand select Add Property to define its data. - Add complex data types as needed:
- DTO for nested structures.
- Enum for enumerations.
- Optional: Define the return type of the
Commandin the property pane or by pressing F2.

Implementing the Command
Once applied to your codebase:
- Right-click on the
Commandand select Open in IDE -> . - Implement your business logic in the
Handlemethod.
Note
Many service implementations are predictable and repetitive. Intent Architect can generate these implementations for you: Modeled Service Implementations.
Tip
Quickly model or bootstrap your services using the CQRS CRUD Accelerator.
Creating a CQRS Query
- Add a
Queryto a diagram in the Services Designer. - Name the
Query, typically suffixed withQuery(e.g.,GetCustomerByIdQuery). - Right-click the
Queryand select Add Property to define its data. - Add complex data types as needed:
- DTO for nested structures.
- Enum for enumerations.
- Select return type of the
Queryin the property pane or by pressing F2 (typically aDTO).

Implementing the Query
Once applied to your codebase:
- Right-click on the
Queryand select Open in IDE -> . - Implement your business logic in the
Handlemethod.
Note
Many service implementations are predictable and repetitive. Intent Architect can generate these implementations for you: Modeled Service Implementations.
Tip
Quickly model or bootstrap your services using the Traditional Service CRUD Accelerator.
Creating a Traditional Application Service
To create a service with operations:
- Right-click on the diagram and select New Service, then provide a unique name.
- Right-click the service and select Add Operation, then provide a name.
- Right-click the operation and select Add Parameter. Specify its name and type. If it represents an inbound payload, select the corresponding DTO.
- Leave the type as
voidfor operations with no return value, or choose an appropriate return type.

Implementing the Service
Once applied to your codebase:
- Right-click the
Serviceand select Open in IDE -> . - Implement your business logic in the method corresponding to your modeled
Operation(e.g.,CreateOrganization).
Note
Many service implementations are predictable and repetitive. Intent Architect can generate these implementations for you: Modeled Service Implementations.
Tip
Quickly model or bootstrap your services using the Traditional Service CRUD Accelerator.
Creating a DTO
To create a DTO:
- Right-click on the Service Package or a containing folder and select New DTO, then provide a unique name.
- Right-click the DTO and select Add Field. Specify the name and type.

Inheriting from a DTO
To inherit one DTO from another:
- Right-click on the DTO that will inherit and select New Inheritance.
- Select the parent DTO.

Mapping an Outbound DTO
To map outbound DTOs:
- Right-click on the DTO that will receive the mapped information and select Map From Domain.
- In the dialog, specify the domain entity and select the attributes to include in the outbound DTO.
- Check the desired attributes and click Done. This links your domain data to the DTO.

Adding a Diagram to the Services Designer
To enhance visual organization:
- Right-click on the Services package and select New Diagram.
- If the designer was in Tree-view, it will switch to a diagram view.
- Rename the diagram by right-clicking it in the Tree-view and selecting Rename.
- Drag services from the Tree-view onto the diagram to create visual representations.
- Optionally, create multiple diagrams for different perspectives. The Tree-view remains the source of truth.

Tip
Hold down CTRL while dragging elements from the Tree-view to include directly associated elements.
Using Accelerators to Rapidly Model Services
Accelerators are macros or scripts that automate repetitive modeling tasks, saving time and ensuring consistency.
Create CRUD CQRS Operations Accelerator
This accelerator models a CQRS service with a CRUD implementation, including the following:
- Commands:
- Create Entity Command
- Update Entity Command
- Delete Entity Command
- Queries:
- Get Entity by Id Query
- Get All Entities Query
Commandsbased on theEntity's operations.
- Right-click on the Services Package, and select Create CRUD CQRS Operations.
- Select the domain
Entityto model the service around.
Note
Not all entities types will be available for selection.
The following entities types will be available:
- Aggregate roots
- Collection composites that are entities of the aggregate root
The following entities will not be available for selection:
- One-to-one composites of the aggregate root
- Value Objects, even when they appear as collection composites under the root

Note
You can also run this accelerator on a Folder in the Services Designer.
Create CRUD Traditional Service Accelerator
This accelerator models a Traditional Service with CRUD implementations, including the following operations:
- Create Entity
- Update Entity
- Delete Entity
- Get Entity by Id
- Get All Entities
Operationsbased on theEntity's operations.
- Right-click on the Services Package, and select Create CRUD Traditional Service.
- Select the domain
Entityto model the service around.
Note
Not all entities types will be available for selection.
The following entities types will be available:
- Aggregate roots
- Collection composites that are entities of the aggregate root
The following entities will not be available for selection:
- One-to-one composites of the aggregate root
- Value Objects, even when they appear as collection composites under the root

Paginate Accelerator
Pagination enables large datasets to be returned in smaller, more manageable chunks. The Paginate accelerator is available for any Operation or Query that returns a collection.
- Right-click on the qualifying Operation or Query.
- Select the Paginate menu item.
Two primary types of pagination are available, dependant on the underlying database provider:
- Offset-based pagination: Common in SQL-based systems. Uses page numbers and sizes.
- Cursor-based pagination: Often used in NoSQL or distributed systems. Uses tokens for consistent, ordered traversal.
Note
If the provider only supports a single pagination type, a single Paginate menu item will be available. If multiple types are supported, multiple options will appear under the Paginate menu.
Offset-based Pagination
When offset-based pagination is applied, the following occurs:
- The return type of the
OperationorQueryis changed fromTReturnTypetoPagedResult<TReturnType>. - Three parameters/properties are added to the
Operation/Query:- PageNo: Specifies the page number to retrieve, based on the PageSize.
- PageSize: Specifies how many records should be included in a single page.
- OrderBy: Specifies how data should be sorted before pagination. This is optional, and defaults to database ordering if omitted. It will order data in ascending order by default.
Note
If using the default CRUD implementation, the PageNo parameter is 1-based by default (first page = 1), renaming the parameter to PageIndex will make it 0-based (first page = 0).
Tip
The CRUD modules treat the OrderBy as a dynamic LINQ statement. The OrderBy parameter supports, a single entity property (e.g., name), multiple entity properties (e.g., created, name), sorting directions for each property (e.g., name desc, created desc, name asc).
Examples of valid OrderBy formats:
namename ascname desccreated, namecreated desc, name asc

The PagedResult returned by the Operation or Query contains the following fields:
TotalCount: Total number of records availablePageCount: Total number of pagesPageSize: Number of records per pagePageNumber: Current page numberData: Collection of returned data records
Cursor-based Pagination
When cursor-based pagination is applied, the following occurs:
- The return type of the
OperationorQueryis changed fromTReturnTypetoCursorPagedResult<TReturnType>. - Three parameters/properties are added to the
Operation/Query:PartitionKey: The partition key to be queriedPageSize: The number of records to include per pageCursorToken: The optional opaque token used to fetch the next set of results. If not set, the first set of results is retrieved.
Note
A default query mapping is applied to filter by PartitionKey. You may remove this parameter if the query is intended to span all partitions.

The CursorPagedResult returned by the Operation or Query contains the following fields:
PageSize: Number of records per pageCursorToken: Token used to retrieve the next set of resultsHasMoreResults: Indicates if there are more results availableData: Collection of returned data records
Modeled Implementations
Create Entity Action
This action allows you to model the creation of a domain Entity (Class) using either an Object Initializer or a Constructor.
It can be applied to a Command, a service Operation, or a Domain Event Handler Association (referred to as the Element below).
Creating a Domain Entity using Object Initialization
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to create. - Right-click on the
Elementand select Create Entity. - Connect the
Elementto theEntityby left-clicking it.
This opens the Create Entity Mapping dialog to map data from the Element to the Entity.
- Double-click the
Entityin the right-hand panel.
A purple line appears, indicating the creation of theEntityusing anObject Initializer. - Map data from the
Elementto theEntity:- Double-click the
Entityagain to map all attributes and add missing ones. - Double-click an
Entityattribute orElementproperty to automatically map (or create and map) them. - Drag an an
Entityattribute orElementproperty to it's counter part*, to map them. - Drag multiple mappable items from either side to the other side's background, this will batch map the items, adding items if applicable.
- Double-click the

Tip
If no mappable property exists, you can define an expression (e.g., true, 0, "") in the text box next to the attribute.

Tip
To revisit the mapping screen, right-click on the Create Entity Action or the association linking the Element and Entity, and select Map Entity Creation.
Creating a Domain Entity using a Constructor
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to create. - Right-click on the
Elementand select Create Entity. - Connect
Elementto aConstructoron theEntityLeft-click on theConstructor.
This will open the Create Entity Mapping Dialog, this dialog helps you map data from the Element to the Entity.
Double-Click the
Constructorin right hand panel. This will add purple line between theElementand theConstructor, this represents how theEntitywill be created i.e. using thisConstructor.Map how the data from the
Elementto theConstructor, this can be done in several ways:- Double-click the
Constructoragain, this map all theConstructorparameters to the correspondingElementproperties, adding missing ones where required. - Double-click an
Constructorattribute orElementproperty to automatically map (or create and map) them. - Drag an an
Constructorattribute orElementproperty to it's counter part*, to map them.
- Double-click the

Tip
If no mappable property exists, you can define an expression (e.g., true, 0, "") in the text box next to the attribute.

Tip
To revisit the mapping screen, right-click on the Create Entity Action or the association linking the Element and Entity, and select Map Entity Creation.
Update Entity Action
This action models updates to a domain Entity (Class) using its Attributes or an entity Operation.
It applies to a Command, a service Operation, or a Domain Event Handler Association (referred to as the Element below).
Updating a Domain Entity Using Its Properties
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to update. - Right-click on the
Elementand select Update Entity. - Connect the
Elementto theEntityby left-clicking theEntity.
This opens the Update Entity Mapping dialog, where you can:
- Map data from the
Elementto theEntity:- Select
Entityattributes, drag them to the background of the left-hand side, mapping theEntityattributes to the correspondingElementproperties. - Double-click an
Entityattribute orElementproperty to automatically map (or create and map) them. - Drag an individual
Elementproperty onto aEntityattribute, this will map the two elements.
- Select
- Click Map Entity Query to define how the
Entityshould be retrieved:- Map the primary key of the
Entityto correspondingElementproperties.
- Map the primary key of the

Tip
Revisit the mapping screen by right-clicking the Update Entity Action or the association and selecting Map Entity Update.
Updating a Domain Entity using a Domain Entity Operation
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to create. - Right-click on the
Elementand select Update Entity. - Connect
Elementto anOperationon theEntityby left-clicking theOperation.
This opens the Update Entity Mapping dialog, where you can:
- Map how the
Operationwill be invoked :- Double-click the
Operationin right hand panel. This will add purple line between theElementand theOperation, this represents the invocation of theOperation. - Map data from the
Elementto theOperation:
- Double-click the
Operationagain, this map all theOperationparameters to the correspondingElementproperties, adding missing ones where required. - Double-click an
Operationparameter orElementproperty to automatically map (or create and map) them. - Drag an individual
Elementproperty onto aOperationparameter, this will map the two elements.
- Double-click the
- Click Map Entity Query to define how the
Entityshould be retrieved:- Map the primary key of the
Entityto correspondingElementproperties.
- Map the primary key of the

Tip
Revisit the mapping screen by right-clicking the Update Entity Action or the association and selecting Map Entity Update.
Delete Entity Action
This action allows you to model the deletion of a domain Entity (Class).
It can be applied to a Command, a service Operation, or a Domain Event Handler Association (referred to as the Element below).
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to delete. - Right-click on the
Elementand select Delete Entity. - Connect the
Elementto theEntityby left-clicking theEntity.

Note
For Domain Event Handler you will need to configure how the Domain Entity is queries, simply right-click on the Delete Entity Action (Connecting Association) and select Map Entity Filter and map the domain Entitys primary key.
Query Entity Action
This action allows you to model the querying of a domain Entity (Class).
It can be applied to a Query, Command, service Operation, or Domain Event Handler Association (referred to as the Element below).
How to Query a single Entity
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to query. - Right-click on the
Elementand select Query Entity. - Connect the
Elementto theEntityby left-clicking theEntity. - Select the
Associationyou just created (Query Entity Action). - Right-click and select Map Entity Query.
This opens the
Query Entity Mappingdialog, where you model the criteria for Entity Select: - Map the filter criteria for querying your Entity, here are a few ways you could do this
- Double-click the primary key of the
Entity. - Map the primary key of the
Entityto correspondingElementproperties. - Map one or more
Entityattributes, which uniquely identify theEntity, to correspondingElementproperties.
- Double-click the primary key of the
- Click Done to complete the mapping (even if no filter criteria are applied).

How to Query a Collection of Entities
- On a diagram, select Add to Diagram and choose the domain
Entityyou want to query. - Right-click on the
Elementand select Query Entity. - Connect the
Elementto theEntityby left-clicking theEntity. - Select the
Associationyou just created (Query Entity Action). - In the Properties pane, check Is Collection (shortcut:
Alt + C). You can also rename the Name entity to "entities" or similar (this will be the name of the variable the query results are assigned to). - Right-click the association and select Map Entity Query.
This opens the
Query Entity Mappingdialog, where you model the criteria for Entity Select: - Optionally Map Filter criteria for the
Entityselection. - Click Done to complete the mapping (even if no filter criteria are applied).

How to apply mapped filters to a Query
- On a Query that has a field used for filtering, right click on the Query action and select Map Entity Query. This opens the
Query Entity Mappingdialog. - Map one or more
Entityattributes, which uniquely identify theEntity, to correspondingQueryproperties. You can double-click on anEntityattribute to create a corresponding field on theQueryelement that is also mapped. - Click Done to complete the mapping.

Note
Currently, filter criteria mapping only supports "==" conditions. More complex filters must be implemented in code.
Service Returns and Query Entity Actions
Query Entity Action is designed specifically for modeling the querying of data and is not directly tied to the Return Type of the Element it is modeled on.
Suppose you are modeling a Query named GetCustomersQuery. This query would likely return a collection of CustomerDtos. The implementation of the GetCustomersQueryHandler would involve the following steps:
- Query the database to get a list of
Customers. - Transform the
Customers toCustomerDtos and return theDTOs.
The Query Entity Action focuses solely on step 1 — querying the database. It is unrelated to step 2, which involves transforming the data into a different return type.
When using Query Entity Action alongside our CRUD modules, these modules employ heuristic algorithms to handle the wiring for step 2 automatically.
This mapping can be established using the Map From Domain context menu option on the DTO. This ensures that the transformation from the queried type (Customer) to the return type (CustomerDto) is recognized and automated.
The return type and query type must also share the same value for Is Collection. If the query retrieves a collection of entities, the return type should also be a collection. Similarly, if the query retrieves a single entity, the return type should not be a collection.
Call Service Operation Action
The Call Service Operation Action allows you to model the invocation of Service or Domain Service operations.
It can be applied to a Command, Query, service Operation, or Domain Event Handler Association (collectively referred to as the Element below).
- On a diagram, select Add to Diagram and choose a
ServiceorDomain Serviceyou want to invoke. - Right-click on the
Elementand select Call Service Operation. - Connect the
Elementto theOperationyou want to invoke, by left-clicking theOperation.
This opens the Service Operation Mapping dialog, where you can:
- Map data from the
Elementto theOperationinvocation:- Double-click the
Operationagain, this map all theOperationparameters to the correspondingElementproperties, adding missing ones where required. - Double-click an
Operationattribute orElementproperty to automatically map (or create and map) them. - Drag an an
Operationattribute orElementproperty to it's counter part, to map them.
- Double-click the

Processing Actions
Warning
This is an experimental feature and likely to change in the future
Add Processing Action allows you configure additional implementation details through additional mappings. These mappings are able to link any existing actions together.
Here are a few examples of what is possible.
- Invoke an Operation on a Domain Entity you are updating.
- Map data from the result of a Service Operation Call onto an entity.