INSERT : Services

BasicCRUD Insert Query with Bridge

Now let us look at the services layer. ProcessServices is present in PreBus.

public partial interface IProcessCustomerService
{
/// <summary>
/// YourRemarksForMethod
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
Task<CommandResult> AddCustomer(AddCustomerParams @param);
}
/// <summary>
///
/// </summary>
public class AddCustomerParams : ProcessServiceInputParameterBridge
{
public AddCustomerInputAPIModel Model { get; set; }
}
public partial class ProcessCustomerService : IProcessCustomerService
{
/// <summary>
/// YourRemarksForMethod
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public async Task<CommandResult> AddCustomer(AddCustomerParams param)
{
AddCustomerDataPacket packet = _flexHost.GetFlexiFlowDataPacket<AddCustomerDataPacket>();
packet.InputParams = param;
try
{
FlexiBusinessRuleSequenceBase<AddCustomerDataPacket> sequence = _flexHost.GetFlexiBusinessRuleSequence<AddCustomerSequence, AddCustomerDataPacket>();
await FlexiBusinessRule.Run(sequence, packet);
}
catch (FlexiFlowAbnormalTerminationException ex)
{
packet.AddError("requesterror", ex);
return new CommandResult(Status.Failed, packet.Errors());
}
if (packet.HasError)
{
return new CommandResult(Status.Failed, packet.Errors());
}
else
{
AddCustomerCommand cmd = new AddCustomerCommand
{
Id = _pkGenerator.GenerateKey(),
model = param.Model,
HostContextInfo=param.HostContextInfo
};
await ProcessCommand(cmd);
CommandResult cmdResult = new CommandResult(Status.Success);
AddCustomerResultModel outputResult = new AddCustomerResultModel();
outputResult.Id = cmd.Id;
cmdResult.result = outputResult;
return cmdResult;
}
}
}
public class AddCustomerResultModel : FlexOutputAPIModelForCreate
{
}

Now let us look at the IProcessCustomerService and ProcessCustomerService, here we have the IProcessCustomerService_AddCustomer where we have AddCustomerParams, which is in turn derived from the ProcessServiceInputParameterBridge which contains the HostContextInfo, which enables you to pass the host info from the controller as we saw earlier. In AddCustomer, it takes the data packet that carries the input received from the form throughout the plugins using this data packet. It creates a FlexiSequence which contains the Plugins and then BusinessRule will execute the sequence.

public class AddCustomerSequence : FlexiBusinessRuleSequenceBase<AddCustomerDataPacket>
{
/// <summary>
///
/// </summary>
public AddCustomerSequence()
{
this.Add<IsUnique>(); this.Add<DoesNotStartWithNumber>();
}
}

Whenever you are generating your code the FlexiSequence will be always overwritten and all the plugins mentioned in the feature diagram automatically it will get configured in the generated code. You have to just write the logic of your validations in the plugins. The plugins will never be over written in any of the code generation, so the code that you have already written remains safe.

if (packet.HasError)
{
return new CommandResult(Status.Failed, packet.Errors());
}
else
{
AddCustomerCommand cmd = new AddCustomerCommand
{
Id = _pkGenerator.GenerateKey(),
model = param.Model,
HostContextInfo=param.HostContextInfo
};
await ProcessCommand(cmd);
CommandResult cmdResult = new CommandResult(Status.Success);
AddCustomerResultModel outputResult = new AddCustomerResultModel();
outputResult.Id = cmd.Id;
cmdResult.result = outputResult;
return cmdResult;
}

If the packet is filled with any error in any of the plugin validations during the business rule validation, it will return to the controller and then controller will return the messages back to the user giving the details of the errors. If everything is validated without any errors, a command created and the primary key is generated and passed along with the command for further processing. default PK generator will generate a Sequential GUID for you. You can replace the logic and configure it with the DI provider in the startup code.

public partial class ProcessCustomerService : IProcessCustomerService
{
private async Task ProcessCommand(AddCustomerCommand cmd)
{
await _bus.Send(cmd);
}
}

So by default, the services will follow have eventual consistency processing. So here bus.send will be called to send the message in the bus. It will send the command in the bus which will be received by the Handler end point, we saw that how the Handler end point mapping is happening and how it will identify the Handler in our earlier videos. There is another option for non-eventual consistency. In non-eventual consistency mode (it can be configured during code generation), the message is not sent into the bus and the execution happens in the same web api end point process.

If the transaction is not like a very critical transaction like a money withdraw transaction in banking and update the amount immediately, you can prefer the eventual consistency using Bus, so that your scaling can happen with ease as you grow your business. In real life scenario, you can handle most of the transactions in an eventual consistency mode. Amazon uses this pattern in most of its operations.