Documentation Index Fetch the complete documentation index at: https://mintlify.com/IntentArchitect/Intent.Modules.NET/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Intent.Application.Contracts.Clients module generates client-side service contracts for consuming your application services from other applications. This is particularly useful for microservices architectures, integration projects, and creating client SDKs.
Module : Intent.Application.Contracts.ClientsVersion : 5.1.6+Dependencies :
Intent.Common.CSharp
Intent.Modelers.Services
Intent.Modelers.Services.CQRS
Intent.Modelers.Types.ServiceProxies
Key Features
Client DTOs : Generate client-side DTO contracts
Service Proxies : Interface definitions for service clients
Paginated Results : Client-side pagination support
Type Safety : Strongly-typed contracts
Enum Contracts : Client-side enum definitions
Separation of Concerns : Keep client contracts separate from server implementation
Use Cases
Microservices Service A consumes Service B’s contracts
Client SDKs Distribute client libraries for your API
Integration Projects Connect to external services
BFF Pattern Backend-for-Frontend service integration
Installation
intent install Intent.Application.Contracts.Clients
Architecture
Typical Setup
YourSolution/
├── OrderService.Api/ # Service provider
│ ├── Application/
│ │ ├── Interfaces/ # Server contracts
│ │ │ └── IOrderService.cs
│ │ └── Orders/
│ │ └── OrderDto.cs
│ └── ...
│
├── Warehouse.Api/ # Service consumer
│ ├── Application/
│ │ └── IntegrationServices/ # Client contracts
│ │ ├── Contracts/ # Client DTOs
│ │ │ ├── OrderDto.cs
│ │ │ └── OrderStatus.cs
│ │ └── IOrderServiceClient.cs
│ └── ...
│
└── Shared.Contracts/ # Alternative: Shared library
└── Orders/
├── OrderDto.cs
└── IOrderService.cs
Generated Components
Client DTO Contracts
Server DTO (Source)
Client DTO (Generated)
// In OrderService.Api
namespace OrderService . Application . Orders
{
public class OrderDto
{
public Guid Id { get ; set ; }
public string OrderNumber { get ; set ; }
public OrderStatus Status { get ; set ; }
public decimal TotalAmount { get ; set ; }
public List < OrderItemDto > Items { get ; set ; }
}
}
Client Service Contract
Generated Client Interface
namespace Warehouse . Application . IntegrationServices
{
public interface IOrderServiceClient
{
Task < OrderDto > GetOrderAsync (
Guid id ,
CancellationToken cancellationToken = default );
Task < PagedResult < OrderDto >> GetOrdersAsync (
int pageNo ,
int pageSize ,
CancellationToken cancellationToken = default );
Task < Guid > CreateOrderAsync (
CreateOrderDto dto ,
CancellationToken cancellationToken = default );
Task UpdateOrderStatusAsync (
Guid id ,
OrderStatus status ,
CancellationToken cancellationToken = default );
}
}
Client Enum Contracts
namespace Warehouse . Application . IntegrationServices . Contracts
{
public enum OrderStatus
{
Pending = 0 ,
Confirmed = 1 ,
Shipped = 2 ,
Delivered = 3 ,
Cancelled = 4
}
}
Paginated Results
The module generates client-side pagination types:
namespace Warehouse . Application . IntegrationServices . Contracts
{
public class PagedResult < T >
{
public int TotalCount { get ; set ; }
public int PageCount { get ; set ; }
public int PageSize { get ; set ; }
public int PageNumber { get ; set ; }
public IEnumerable < T > Data { get ; set ; }
}
}
Configuration in Designer
Creating a Service Proxy
Add Service Proxy
In the Service Proxies Designer, add a new Service Proxy
Reference Source Service
Point to the source service in the external application
Select Operations
Choose which operations to expose in the client contract
Generate
Run Software Factory to generate client contracts
Implementation Examples
HTTP Client Implementation
Implement the client interface using HttpClient:
using System . Net . Http . Json ;
using Warehouse . Application . IntegrationServices ;
using Warehouse . Application . IntegrationServices . Contracts ;
public class OrderServiceClient : IOrderServiceClient
{
private readonly HttpClient _httpClient ;
private readonly ILogger < OrderServiceClient > _logger ;
public OrderServiceClient (
HttpClient httpClient ,
ILogger < OrderServiceClient > logger )
{
_httpClient = httpClient ;
_logger = logger ;
}
public async Task < OrderDto > GetOrderAsync (
Guid id ,
CancellationToken cancellationToken )
{
var response = await _httpClient . GetAsync (
$"api/orders/ { id } " ,
cancellationToken );
response . EnsureSuccessStatusCode ();
return await response . Content . ReadFromJsonAsync < OrderDto >(
cancellationToken : cancellationToken )
?? throw new InvalidOperationException ( "Failed to deserialize order" );
}
public async Task < PagedResult < OrderDto >> GetOrdersAsync (
int pageNo ,
int pageSize ,
CancellationToken cancellationToken )
{
var response = await _httpClient . GetAsync (
$"api/orders?pageNo= { pageNo } &pageSize= { pageSize } " ,
cancellationToken );
response . EnsureSuccessStatusCode ();
return await response . Content . ReadFromJsonAsync < PagedResult < OrderDto >>(
cancellationToken : cancellationToken )
?? throw new InvalidOperationException ( "Failed to deserialize orders" );
}
public async Task < Guid > CreateOrderAsync (
CreateOrderDto dto ,
CancellationToken cancellationToken )
{
var response = await _httpClient . PostAsJsonAsync (
"api/orders" ,
dto ,
cancellationToken );
response . EnsureSuccessStatusCode ();
return await response . Content . ReadFromJsonAsync < Guid >(
cancellationToken : cancellationToken );
}
public async Task UpdateOrderStatusAsync (
Guid id ,
OrderStatus status ,
CancellationToken cancellationToken )
{
var response = await _httpClient . PutAsJsonAsync (
$"api/orders/ { id } /status" ,
new { Status = status },
cancellationToken );
response . EnsureSuccessStatusCode ();
}
}
Dependency Injection Setup
services . AddHttpClient < IOrderServiceClient , OrderServiceClient >( client =>
{
client . BaseAddress = new Uri ( "https://orderservice.example.com" );
client . Timeout = TimeSpan . FromSeconds ( 30 );
});
// With Polly for resilience
services . AddHttpClient < IOrderServiceClient , OrderServiceClient >( client =>
{
client . BaseAddress = new Uri ( "https://orderservice.example.com" );
})
. AddTransientHttpErrorPolicy ( policy =>
policy . WaitAndRetryAsync ( 3 , retryAttempt =>
TimeSpan . FromSeconds ( Math . Pow ( 2 , retryAttempt ))))
. AddTransientHttpErrorPolicy ( policy =>
policy . CircuitBreakerAsync ( 5 , TimeSpan . FromSeconds ( 30 )));
Using the Client
public class WarehouseService : IWarehouseService
{
private readonly IOrderServiceClient _orderServiceClient ;
private readonly IWarehouseRepository _repository ;
public WarehouseService (
IOrderServiceClient orderServiceClient ,
IWarehouseRepository repository )
{
_orderServiceClient = orderServiceClient ;
_repository = repository ;
}
public async Task ProcessShipmentAsync (
Guid orderId ,
CancellationToken cancellationToken )
{
// Get order details from Order Service
var order = await _orderServiceClient . GetOrderAsync (
orderId ,
cancellationToken );
// Process shipment
var shipment = await _repository . CreateShipmentAsync (
order ,
cancellationToken );
// Update order status in Order Service
await _orderServiceClient . UpdateOrderStatusAsync (
orderId ,
OrderStatus . Shipped ,
cancellationToken );
}
}
gRPC Client Support
For gRPC services, implement the client differently:
using Grpc . Net . Client ;
using OrderService . Grpc ;
public class OrderServiceGrpcClient : IOrderServiceClient
{
private readonly OrderService . OrderServiceClient _grpcClient ;
public OrderServiceGrpcClient ( GrpcChannel channel )
{
_grpcClient = new OrderService . OrderServiceClient ( channel );
}
public async Task < OrderDto > GetOrderAsync (
Guid id ,
CancellationToken cancellationToken )
{
var request = new GetOrderRequest { Id = id . ToString () };
var response = await _grpcClient . GetOrderAsync ( request , cancellationToken : cancellationToken );
return new OrderDto
{
Id = Guid . Parse ( response . Id ),
OrderNumber = response . OrderNumber ,
Status = ( OrderStatus ) response . Status ,
TotalAmount = response . TotalAmount
};
}
// ... other methods
}
Advanced Scenarios
Authentication & Authorization
Add authentication to client calls:
public class AuthenticatedOrderServiceClient : IOrderServiceClient
{
private readonly HttpClient _httpClient ;
private readonly ITokenProvider _tokenProvider ;
public AuthenticatedOrderServiceClient (
HttpClient httpClient ,
ITokenProvider tokenProvider )
{
_httpClient = httpClient ;
_tokenProvider = tokenProvider ;
}
public async Task < OrderDto > GetOrderAsync (
Guid id ,
CancellationToken cancellationToken )
{
var token = await _tokenProvider . GetAccessTokenAsync ( cancellationToken );
using var request = new HttpRequestMessage ( HttpMethod . Get , $"api/orders/ { id } " );
request . Headers . Authorization = new AuthenticationHeaderValue ( "Bearer" , token );
var response = await _httpClient . SendAsync ( request , cancellationToken );
response . EnsureSuccessStatusCode ();
return await response . Content . ReadFromJsonAsync < OrderDto >(
cancellationToken : cancellationToken )
?? throw new InvalidOperationException ();
}
}
Circuit Breaker Pattern
services . AddHttpClient < IOrderServiceClient , OrderServiceClient >( client =>
{
client . BaseAddress = new Uri ( "https://orderservice.example.com" );
})
. AddPolicyHandler ( Policy < HttpResponseMessage >
. Handle < HttpRequestException >()
. OrResult ( msg => ! msg . IsSuccessStatusCode )
. CircuitBreakerAsync (
handledEventsAllowedBeforeBreaking : 3 ,
durationOfBreak : TimeSpan . FromSeconds ( 30 ),
onBreak : ( result , duration ) =>
{
Log . Warning ( "Circuit breaker opened for {Duration}s" , duration . TotalSeconds );
},
onReset : () =>
{
Log . Information ( "Circuit breaker reset" );
}));
Caching
Add caching to reduce service calls:
public class CachedOrderServiceClient : IOrderServiceClient
{
private readonly IOrderServiceClient _inner ;
private readonly IMemoryCache _cache ;
public CachedOrderServiceClient (
IOrderServiceClient inner ,
IMemoryCache cache )
{
_inner = inner ;
_cache = cache ;
}
public async Task < OrderDto > GetOrderAsync (
Guid id ,
CancellationToken cancellationToken )
{
var cacheKey = $"order_ { id } " ;
if ( _cache . TryGetValue < OrderDto >( cacheKey , out var cachedOrder ))
{
return cachedOrder ! ;
}
var order = await _inner . GetOrderAsync ( id , cancellationToken );
_cache . Set ( cacheKey , order , TimeSpan . FromMinutes ( 5 ));
return order ;
}
// ... other methods
}
Testing
Mocking Client Contracts
public class WarehouseServiceTests
{
private readonly Mock < IOrderServiceClient > _mockOrderClient ;
private readonly WarehouseService _service ;
public WarehouseServiceTests ()
{
_mockOrderClient = new Mock < IOrderServiceClient >();
_service = new WarehouseService ( _mockOrderClient . Object , .. .);
}
[ Fact ]
public async Task ProcessShipment_ValidOrder_UpdatesStatus ()
{
// Arrange
var orderId = Guid . NewGuid ();
var order = new OrderDto
{
Id = orderId ,
OrderNumber = "ORD-001" ,
Status = OrderStatus . Confirmed
};
_mockOrderClient
. Setup ( c => c . GetOrderAsync ( orderId , It . IsAny < CancellationToken >()))
. ReturnsAsync ( order );
_mockOrderClient
. Setup ( c => c . UpdateOrderStatusAsync (
orderId ,
OrderStatus . Shipped ,
It . IsAny < CancellationToken >()))
. Returns ( Task . CompletedTask );
// Act
await _service . ProcessShipmentAsync ( orderId , CancellationToken . None );
// Assert
_mockOrderClient . Verify (
c => c . UpdateOrderStatusAsync (
orderId ,
OrderStatus . Shipped ,
It . IsAny < CancellationToken >()),
Times . Once );
}
}
Best Practices
Use Interface Segregation
Create focused client interfaces that only expose the operations a particular client needs: // ✅ Good - Focused client
public interface IOrderQueryClient
{
Task < OrderDto > GetOrderAsync (...);
Task < List < OrderDto >> GetOrdersAsync (...);
}
public interface IOrderCommandClient
{
Task < Guid > CreateOrderAsync (...);
Task UpdateOrderAsync (...);
}
// ❌ Bad - Exposing everything
public interface IOrderServiceClient
{
// 20+ methods
}
Use versioned namespaces or separate packages for different API versions: namespace Warehouse . Application . IntegrationServices . V1 . Contracts
namespace Warehouse . Application . IntegrationServices . V2 . Contracts
Always add retry logic, circuit breakers, and timeouts: services . AddHttpClient < IOrderServiceClient , OrderServiceClient >()
. AddTransientHttpErrorPolicy ( p => p . WaitAndRetryAsync ( 3 , _ => TimeSpan . FromSeconds ( 2 )))
. AddTransientHttpErrorPolicy ( p => p . CircuitBreakerAsync ( 5 , TimeSpan . FromSeconds ( 30 )));
Handle Failures Gracefully
Always handle potential failures: try
{
var order = await _orderClient . GetOrderAsync ( id , ct );
}
catch ( HttpRequestException ex )
{
_logger . LogError ( ex , "Failed to retrieve order {OrderId}" , id );
// Return cached data, default, or rethrow
}
Default Output Location
Generated client contracts are placed in:
YourProject.Application/IntegrationServices/
├── Contracts/ # Client DTOs and enums
│ ├── OrderDto.cs
│ ├── OrderStatus.cs
│ └── PagedResult.cs
└── IOrderServiceClient.cs
Troubleshooting
Issue : Client contracts aren’t being created.Solution :
Verify Intent.Application.Contracts.Clients is installed
Check that Service Proxy is properly configured in the designer
Ensure source service is correctly referenced
Run Software Factory
Issue : Client DTOs don’t match server DTOs.Solution :
Ensure both applications use the same source designer files
Regenerate both server and client contracts
Check for designer synchronization issues
External Resources