From ABP Sensei
Guides ABP Framework microservice development: solution structure, Integration Services, distributed events (RabbitMQ Outbox/Inbox), YARP gateway, OpenIddict auth server, database-per-service.
How this skill is triggered — by the user, by Claude, or both
Slash command
/abp-sensei:abp-microservicesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
ABP Framework v10.4 microservice solution template (Business+ license). A distributed system with synchronous (Integration Services) and asynchronous (distributed events) inter-service communication, a YARP gateway, and an OpenIddict auth server.
ABP Framework v10.4 microservice solution template (Business+ license). A distributed system with synchronous (Integration Services) and asynchronous (distributed events) inter-service communication, a YARP gateway, and an OpenIddict auth server.
MyMicroservice/
├── apps/ # UI applications
│ ├── web/ # Web application
│ ├── public-web/ # Public site
│ └── auth-server/ # Authentication server (OpenIddict)
├── gateways/ # BFF — one gateway per UI
│ └── web-gateway/ # YARP reverse proxy
├── services/ # Microservices
│ ├── administration/ # Permission, setting, feature
│ ├── identity/ # User, role
│ └── [business-services]/ # Your own business services
└── etc/
├── docker/ # docker compose for local infra
└── helm/ # Kubernetes deployment
Each microservice has a simplified single-project structure:
services/ordering/
├── OrderingService/ # Main project
│ ├── Entities/
│ ├── Services/
│ ├── IntegrationServices/ # For inter-service communication
│ ├── Data/ # DbContext (IHasEventInbox, IHasEventOutbox)
│ └── OrderingServiceModule.cs
├── OrderingService.Contracts/ # Interface, DTO, ETO (shared)
└── OrderingService.Tests/
For synchronous inter-service calls, use an Integration Service, not a regular application service.
// In the CatalogService.Contracts project
[IntegrationService]
public interface IProductIntegrationService : IApplicationService
{
Task<List<ProductDto>> GetProductsByIdsAsync(List<Guid> ids);
}
// In the CatalogService project
[IntegrationService]
public class ProductIntegrationService : ApplicationService, IProductIntegrationService
{
public async Task<List<ProductDto>> GetProductsByIdsAsync(List<Guid> ids)
{
var products = await _productRepository.GetListAsync(p => ids.Contains(p.Id));
return ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
}
}
// CatalogServiceModule.cs
Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ExposeIntegrationServices = true;
});
abp generate-proxy -t csharp -u http://localhost:44361 -m catalog --without-contracts
[DependsOn(typeof(CatalogServiceContractsModule))]
public class OrderingServiceModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddStaticHttpClientProxies(
typeof(CatalogServiceContractsModule).Assembly, "CatalogService");
}
}
// appsettings.json
"RemoteServices": {
"CatalogService": { "BaseUrl": "http://localhost:44361" }
}
public class OrderAppService : ApplicationService
{
private readonly IProductIntegrationService _productIntegrationService;
public async Task<List<OrderDto>> GetListAsync()
{
var orders = await _orderRepository.GetListAsync();
var productIds = orders.Select(o => o.ProductId).Distinct().ToList();
var products = await _productIntegrationService.GetProductsByIdsAsync(productIds);
// ...
}
}
Why an Integration Service? Application services are for the UI (with different authorization/validation/optimization needs). Integration services are designed for service-to-service communication.
When: Immediate response + data needed to complete the current operation (e.g. product details to show in an order list).
For loosely coupled state notifications.
// ETO — in the Contracts project
[EventName("Product.StockChanged")]
public class StockCountChangedEto { public Guid ProductId { get; set; } public int NewCount { get; set; } }
// Publish
await _distributedEventBus.PublishAsync(new StockCountChangedEto { ... });
// Subscribe (in another service)
public class StockChangedHandler : IDistributedEventHandler<StockCountChangedEto>, ITransientDependency
{
public async Task HandleEventAsync(StockCountChangedEto eventData) { }
}
The DbContext must implement
IHasEventInboxandIHasEventOutboxfor the Outbox/Inbox pattern.When: State change notifications (order placed, stock updated), operations that don't require an immediate response and where services should remain independent.
// Registration
context.Services.AddEntityCache<Product, ProductDto, Guid>();
// Usage (automatically invalidated when the entity changes)
private readonly IEntityCache<ProductDto, Guid> _productCache;
public Task<ProductDto> GetProductAsync(Guid id) => _productCache.GetAsync(id);
npx claudepluginhub burakdmir/abp-skills --plugin abp-senseiProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.