This document demonstrates the complete Insert flow using the AddToShipping feature from the EBusiness application. The flow starts with a POST request to the controller and ends with event publishing and subscriber processing.
Complete Flow Architecture
POST Request → Controller → Service → PreBus Plugins → Command Handler → RESTClient → External System
↓
Response ← Controller ← Service ← Command Handler ← RESTClient ← External System
Side Effects → Emails, notifications, inventory updates
Additional Events → Can trigger more business processes
External Communication Flow
Internal DTO → Request DTO mapping
RESTClient Call → HTTP request to external system
External Response → Response DTO from external system
Response Mapping → Response DTO to Internal DTO
Data Integration → External data integrated with internal data
Key Benefits
Separation of Concerns: Each layer has a single responsibility
Testability: Each component can be tested independently
Scalability: Asynchronous processing handles high loads
Maintainability: Clear, readable code structure
Event-Driven: Loose coupling between components
This AddToShipping example demonstrates how FlexBase enables clean, maintainable, and scalable insert operations with proper separation of concerns and event-driven architecture! 🚀
public async Task<CommandResult> AddToShipping(AddToShippingDto dto)
{
var packet = await ProcessBusinessRuleSequence<AddToShippingDataPacket, AddToShippingSequence, AddToShippingDto, FlexAppContextBridge>(dto);
if (packet.HasError)
{
return new CommandResult(Status.Failed, packet.Errors());
}
else
{
dto.SetGeneratedId(_pkGenerator.GenerateKey());
AddToShippingCommand cmd = new AddToShippingCommand
{
Dto = dto,
};
await ProcessCommand(cmd);
CommandResult cmdResult = new CommandResult(Status.Success);
AddToShippingResultModel outputResult = new AddToShippingResultModel();
outputResult.Id = dto.GetGeneratedId();
cmdResult.result = outputResult;
return cmdResult;
}
}
public class AddToShippingSequence : FlexiBusinessRuleSequenceBase<AddToShippingDataPacket>
{
public AddToShippingSequence()
{
this.Add<ValidateShipping>();
}
}
public partial class AddToShippingDataPacket : FlexiFlowDataPacketWithDtoBridge<AddToShippingDto, FlexAppContextBridge>
{
protected readonly ILogger<AddToShippingDataPacket> _logger;
public AddToShippingDataPacket(ILogger<AddToShippingDataPacket> logger)
{
_logger = logger;
}
#region "Properties
//Models and other properties goes here
#endregion
}
public partial class ValidateShipping : FlexiBusinessRuleBase, IFlexiBusinessRule<AddToShippingDataPacket>
{
public override string Id { get; set; } = "3a1cd0401f931dd4a01587e229b720dc";
public override string FriendlyName { get; set; } = "ValidateShipping";
protected readonly ILogger<ValidateShipping> _logger;
protected readonly RepoFactory _repoFactory;
public ValidateShipping(ILogger<ValidateShipping> logger, RepoFactory repoFactory)
{
_logger = logger;
_repoFactory = repoFactory;
}
public virtual async Task Validate(AddToShippingDataPacket 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 partial class AddToShippingHandler : IAddToShippingHandler
{
protected string EventCondition = "";
protected readonly ILogger<AddToShippingHandler> _logger;
protected readonly IFlexHost _flexHost;
protected ShippingRESTClient _restClient;
protected FlexAppContextBridge? _flexAppContext;
public AddToShippingHandler(ILogger<AddToShippingHandler> logger, IFlexHost flexHost, ShippingRESTClient restClient)
{
_logger = logger;
_flexHost = flexHost;
_restClient = restClient;
}
public virtual async Task Execute(AddToShippingCommand cmd, IFlexServiceBusContext serviceBusContext)
{
// Convert internal DTO to Request DTO
AddToShippingRequestDto requestParams = new AddToShippingRequestDto
{
OrderId = cmd.Dto.OrderId,
ShippingAddress = cmd.Dto.ShippingAddress,
TrackingNumber = cmd.Dto.TrackingNumber,
TotalWeight = cmd.Dto.ShippingItems?.Sum(x => x.Weight) ?? 0,
ShippingItems = cmd.Dto.ShippingItems?.Select(x => new ShippingItemRequestDto
{
ProductId = x.ProductId,
Quantity = x.Qty,
Weight = x.Weight,
Volume = x.Volume
}).ToList()
};
// Call external REST service
var response = await _restClient.AddToShipping(requestParams);
// Process response
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var responseDto = JsonConvert.DeserializeObject<AddToShippingResponseDto>(responseContent);
_logger.LogDebug("Shipping created successfully with external ID: {ExternalId}", responseDto?.Id);
// Set success condition for event firing
EventCondition = "CONDITION_ONSUCCESS";
}
else
{
_logger.LogError("Failed to create shipping. Status: {StatusCode}", response.StatusCode);
EventCondition = "CONDITION_ONFAILED";
}
await this.Fire(EventCondition, serviceBusContext);
}
}
public class AddToShippingNsbHandler : NsbCommandHandler<AddToShippingCommand>
{
readonly ILogger<AddToShippingNsbHandler> _logger;
readonly IFlexHost _flexHost;
readonly IAddToShippingHandler _handler;
public AddToShippingNsbHandler(ILogger<AddToShippingNsbHandler> logger, IFlexHost flexHost, IAddToShippingHandler handler)
{
_logger = logger;
_flexHost = flexHost;
_handler = handler;
}
public override async Task Handle(AddToShippingCommand message, IMessageHandlerContext context)
{
_logger.LogTrace($"Executing {nameof(AddToShippingNsbHandler)}");
await _handler.Execute(message, new NsbHandlerContextBridge(context));
}
}
public class ShippingAddedEvent : FlexEventBridge<FlexAppContextBridge>
{
// Event data is automatically populated by FlexBase
}
public async Task<HttpResponseMessage> AddToShipping(AddToShippingRequestDto model)
{
var httpClient = _httpClientFactory.CreateClient(ShippingServicesRESTClientMaster.Name);
var serializedModel = JsonConvert.SerializeObject(model);
var request = new HttpRequestMessage(
HttpMethod.Post,
$"yourUri");
request.Content = new StringContent(serializedModel, Encoding.UTF8, "application/json");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
return await response.HandleHttpResponse();
}
public partial class AddToShippingRequestDto
{
public string OrderId { get; set; }
public string ShippingAddress { get; set; }
public string TrackingNumber { get; set; }
public decimal TotalWeight { get; set; }
public ICollection<ShippingItemRequestDto> ShippingItems { get; set; }
}
public partial class AddToShippingResponseDto
{
public string Id { get; set; }
public string Status { get; set; }
public string Message { get; set; }
public DateTime ProcessedDate { get; set; }
public string ExternalReferenceId { get; set; }
}
public partial class NotifyLogisticsOnShippingAdded : INotifyLogisticsOnShippingAdded
{
protected readonly ILogger<NotifyLogisticsOnShippingAdded> _logger;
protected string EventCondition = "";
public NotifyLogisticsOnShippingAdded(ILogger<NotifyLogisticsOnShippingAdded> logger)
{
_logger = logger;
}
public virtual async Task Execute(ShippingAddedEvent @event, IFlexServiceBusContext serviceBusContext)
{
_flexAppContext = @event.AppContext;
//TODO: Write your business logic here:
// - Send shipping confirmation email
// - Update inventory levels
// - Notify logistics system
// - Update tracking information
await this.Fire<NotifyLogisticsOnShippingAdded>(EventCondition, serviceBusContext);
}
}
public partial class AddToShippingDto : DtoBridge
{
[StringLength(100)]
public string OrderId { get; set; }
[StringLength(200)]
public string ShippingAddress { get; set; }
public ICollection<AddToShippingDto_ShippingItem> ShippingItems { get; set; }
}
public class AddToShippingCommand : FlexCommandBridge<AddToShippingDto, FlexAppContextBridge>
{
// Command data is automatically populated by FlexBase
}
public partial class AddToShippingRequestDto
{
public string OrderId { get; set; }
public string ShippingAddress { get; set; }
public string TrackingNumber { get; set; }
public decimal TotalWeight { get; set; }
public ICollection<ShippingItemRequestDto> ShippingItems { get; set; }
}
public partial class AddToShippingResponseDto
{
public string Id { get; set; }
public string Status { get; set; }
public string Message { get; set; }
public DateTime ProcessedDate { get; set; }
public string ExternalReferenceId { get; set; }
}