This document demonstrates the complete Update flow using the UpdateOrder feature from the EBusiness application. The flow starts with a PUT request to the controller and ends with event publishing and subscriber processing.
Complete Flow Architecture
PUT Request → Controller → Service → PreBus Plugins → Command Handler → Domain Model → Database → Event Publishing → Subscribers
Side Effects → Manager notifications, inventory updates, analytics
Key Benefits
Data Integrity: Ensures entity exists before updating
Audit Trail: Tracks who made changes and when
Business Rules: Validates update is allowed
Event-Driven: Notifies other systems of changes
Testable: Each component can be tested independently
Maintainable: Clear separation of concerns
This UpdateOrder example demonstrates how FlexBase enables clean, maintainable, and scalable update operations with proper validation, audit trails, and event-driven architecture! 🚀
public async Task<CommandResult> UpdateOrder(UpdateOrderDto dto)
{
var packet = await ProcessBusinessRuleSequence<UpdateOrderDataPacket, UpdateOrderSequence, UpdateOrderDto, FlexAppContextBridge>(dto);
if (packet.HasError)
{
return new CommandResult(Status.Failed, packet.Errors());
}
else
{
dto.SetGeneratedId(_pkGenerator.GenerateKey());
UpdateOrderCommand cmd = new UpdateOrderCommand
{
Dto = dto,
};
await ProcessCommand(cmd);
CommandResult cmdResult = new CommandResult(Status.Success);
UpdateOrderResultModel outputResult = new UpdateOrderResultModel();
cmdResult.result = outputResult;
return cmdResult;
}
}
public class UpdateOrderSequence : FlexiBusinessRuleSequenceBase<UpdateOrderDataPacket>
{
public UpdateOrderSequence()
{
this.Add<IsValidOrder>();
}
}
public partial class UpdateOrderDataPacket : FlexiFlowDataPacketWithDtoBridge<UpdateOrderDto, FlexAppContextBridge>
{
protected readonly ILogger<UpdateOrderDataPacket> _logger;
public UpdateOrderDataPacket(ILogger<UpdateOrderDataPacket> logger)
{
_logger = logger;
}
#region "Properties
//Models and other properties goes here
#endregion
}
public partial class IsValidOrder : FlexiBusinessRuleBase, IFlexiBusinessRule<UpdateOrderDataPacket>
{
public override string Id { get; set; } = "3a1cd500a49d178e88f75ed6bccaed88";
public override string FriendlyName { get; set; } = "IsValidOrder";
protected readonly ILogger<IsValidOrder> _logger;
protected readonly RepoFactory _repoFactory;
public IsValidOrder(ILogger<IsValidOrder> logger, RepoFactory repoFactory)
{
_logger = logger;
_repoFactory = repoFactory;
}
public virtual async Task Validate(UpdateOrderDataPacket packet)
{
//Uncomment the below line if validating against a db data using your repo
//_repoFactory.Init(packet.Dto);
//If any validation fails, uncomment and use the below line of code to add error to the packet
//packet.AddError("key", "ErrorMessage");
await Task.CompletedTask; //If you have any await in the validation, remove this line
}
}
public virtual async Task Execute(UpdateOrderCommand cmd, IFlexServiceBusContext serviceBusContext)
{
_flexAppContext = cmd.Dto.GetAppContext();
_repoFactory.Init(cmd.Dto);
_model = _repoFactory.GetRepo().FindAll<Order>().Where(m=>m.Id == cmd.Dto.Id).FirstOrDefault();
if (_model != null)
{
_model.UpdateOrder(cmd);
_repoFactory.GetRepo().InsertOrUpdate(_model);
int records = await _repoFactory.GetRepo().SaveAsync();
if (records > 0)
{
_logger.LogDebug("{} with {} updated into Database: ", typeof(Order).Name, _model.Id);
}
else
{
_logger.LogWarning("No records updated for {} with {}", typeof(Order).Name, _model.Id);
}
await this.Fire(EventCondition, serviceBusContext);
}
}
public virtual Order UpdateOrder(UpdateOrderCommand cmd)
{
Guard.AgainstNull("Order model cannot be empty", cmd);
this.Convert(cmd.Dto);
this.LastModifiedBy = cmd.Dto.GetAppContext()?.UserId;
//Map any other field not handled by Automapper config
this.SetModified();
//Set your appropriate SetModified for the inner object here
return this;
}
public class UpdateOrderNsbHandler : NsbCommandHandler<UpdateOrderCommand>
{
readonly ILogger<UpdateOrderNsbHandler> _logger;
readonly IFlexHost _flexHost;
readonly IUpdateOrderHandler _handler;
public UpdateOrderNsbHandler(ILogger<UpdateOrderNsbHandler> logger, IFlexHost flexHost, IUpdateOrderHandler handler)
{
_logger = logger;
_flexHost = flexHost;
_handler = handler;
}
public override async Task Handle(UpdateOrderCommand message, IMessageHandlerContext context)
{
_logger.LogTrace($"Executing {nameof(UpdateOrderNsbHandler)}");
await _handler.Execute(message, new NsbHandlerContextBridge(context));
}
}
public class OrderUpdatedEvent : FlexEventBridge<FlexAppContextBridge>
{
// Event data is automatically populated by FlexBase
}
public partial class UpdateManagerOnUpdateOrder : IUpdateManagerOnUpdateOrder
{
protected readonly ILogger<UpdateManagerOnUpdateOrder> _logger;
protected string EventCondition = "";
public UpdateManagerOnUpdateOrder(ILogger<UpdateManagerOnUpdateOrder> logger)
{
_logger = logger;
}
public virtual async Task Execute(OrderUpdatedEvent @event, IFlexServiceBusContext serviceBusContext)
{
_flexAppContext = @event.AppContext;
//TODO: Write your business logic here:
// - Notify managers of order changes
// - Update inventory levels
// - Send update notifications
// - Update analytics
await this.Fire<UpdateManagerOnUpdateOrder>(EventCondition, serviceBusContext);
}
}
public partial class UpdateOrderDto : DtoBridge
{
public string Id { get; set; }
}
public class UpdateOrderCommand : FlexCommandBridge<UpdateOrderDto, FlexAppContextBridge>
{
// Command data is automatically populated by FlexBase
}