πFlexbase Control Flow
π― Overview
This document explains the complete control flow for Flexbase features - from API call to execution completion. We'll cover one Insert (POST) and one Query (GET) example.
π Insert Feature Flow: AddOrder
1. API Request
POST /api/Orders/AddOrder
Content-Type: application/json
{
"customerId": "12345",
"totalAmount": 299.99,
"orderItems": [...]
}
2. Controller Layer
[HttpPost]
[Route("AddOrder")]
public async Task<IActionResult> AddOrder([FromBody] AddOrderDto dto)
{
return await RunService(201, dto, _processOrdersService.AddOrder);
}
What happens: Controller receives request, validates DTO, calls service
3. Service Layer
public async Task<IActionResult> AddOrder(AddOrderDto dto)
{
var command = new AddOrderCommand { Dto = dto };
await _addOrderHandler.Execute(command, _serviceBusContext);
return new OkResult();
}
What happens: Service creates command, calls handler
4. Command Handler
public async Task Execute(AddOrderCommand cmd, IFlexServiceBusContext serviceBusContext)
{
// 1. Initialize repository
_repoFactory.Init(cmd.Dto);
// 2. Call domain method
_model = _flexHost.GetDomainModel<Order>().AddOrder(cmd);
// 3. Persist to database
_repoFactory.GetRepo().InsertOrUpdate(_model);
await _repoFactory.GetRepo().SaveAsync();
// 4. Publish events
await this.Fire(EventCondition, serviceBusContext);
}
What happens: Handler orchestrates the operation, calls domain, persists data, publishes events
5. Domain Method (Your Business Logic)
public virtual Order AddOrder(AddOrderCommand cmd)
{
// Your business rules
if (cmd.Dto.TotalAmount <= 0)
throw new BusinessException("Invalid amount");
// Apply business logic
this.Convert(cmd.Dto);
this.SetAdded(cmd.Dto.GetGeneratedId());
this.CalculateTotal();
return this;
}
What happens: Domain validates business rules, applies logic, returns entity
6. Database Persistence
_repoFactory.GetRepo().InsertOrUpdate(_model);
await _repoFactory.GetRepo().SaveAsync();
What happens: Entity Framework saves to database
7. Event Publishing
await this.Fire(EventCondition, serviceBusContext);
What happens: Domain events published to message bus for side effects
8. Response
HTTP 201 Created
Location: /api/Orders/{orderId}
π Query Feature Flow: GetOrders
1. API Request
GET /api/Orders/GetOrders?status=Pending
2. Controller Layer
[HttpGet]
[Route("GetOrders")]
public async Task<IActionResult> GetOrders([FromQuery] GetOrdersQuery query)
{
return await RunService(200, query, _processOrdersService.GetOrders);
}
What happens: Controller receives request, calls service
3. Service Layer
public async Task<IActionResult> GetOrders(GetOrdersQuery query)
{
var result = _getOrdersHandler.Fetch();
return new OkObjectResult(result);
}
What happens: Service calls query handler
4. Query Handler
public override IEnumerable<GetOrdersDto> Fetch()
{
return _repoFactory.GetRepo()
.FindAll<Order>()
.Where(o => o.Status == query.Status)
.Include(o => o.Customer)
.SelectTo<GetOrdersDto>()
.ToList();
}
What happens: Handler executes optimized database query with projection
5. Database Query
-- Generated SQL (optimized)
SELECT
o.Id,
c.Name AS CustomerName,
o.TotalAmount,
o.Status,
o.OrderDate
FROM Orders o
LEFT JOIN Customers c ON o.CustomerId = c.Id
WHERE o.Status = @Status
What happens: Only required fields fetched from database
6. Projection Mapping
// AutoMapper automatically maps to DTO
CreateMap<Order, GetOrdersDto>()
.ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.Customer.Name));
What happens: Database results mapped to DTO
7. Response
HTTP 200 OK
[
{
"id": "12345",
"customerName": "John Doe",
"totalAmount": 299.99,
"status": "Pending",
"orderDate": "2024-01-15T10:30:00Z"
}
]
π Complete Flow Summary
Insert Flow:
API Request β Controller β Service β Command Handler β Domain Method β Database β Events β Response
Query Flow:
API Request β Controller β Service β Query Handler β Database Query β Projection β Response
π― Key Points
Insert Features:
Command Pattern - Encapsulates operation
Domain Logic - Business rules in domain layer
Event Publishing - Side effects handled asynchronously
Transaction Management - Automatic rollback on errors
Query Features:
Projection-Based - Only fetch required fields
Optimized SQL - Generated automatically
Type Safety - Compile-time validation
Performance - Database-level optimization
Common Benefits:
Separation of Concerns - Each layer has single responsibility
Testability - Each layer can be tested independently
Maintainability - Clear, readable code structure
Consistency - Same pattern across all features
This control flow ensures reliable, maintainable, and performant enterprise applications with Flexbase.
Last updated