-
Notifications
You must be signed in to change notification settings - Fork 69
ServiceCommand
The ServiceCommand is the actor responsible for orchestrating initialization logic, validation/business rule execution, and data proxy invocation. ServiceCommand inherits from Command and implements ICommand, and instances of it are returned from the public methods of ServiceBase.
ServiceCommand is meant to serve as an easy way to deliver custom command functionality from your service implementations without the hassle of having to create your own command implementations. However, if you don't find ServiceCommand to be flexible enough, you can also create your own commands that inherit from Peasy.Core.Command or alternatively, implement Peasy.Core.ICommand;
ServiceCommand uses a functional design pattern that wraps functions Func
and actions Action
that participate in the command execution pipeline. This pattern was used to offer a quick and easy way to expose command methods from your service classes.
ServiceCommand exposes many contructor overloads, each requiring different variations of arguments of type Func
and Action
covering different use cases. For example, many times you will not need initialization logic or business rules to execute before executing command logic and interacting with data proxies. Other times, you may want to inject initialization logic into the command execution pipeline, but forego business rule validation. Below are a couple of examples:
public ICommand<InventoryItem> GetByProductCommand(long productID)
{
var proxy = DataProxy as IInventoryItemDataProxy;
return new ServiceCommand<InventoryItem>
(
executeMethod: () => proxy.GetByProduct(productID),
executeAsyncMethod: () => proxy.GetByProductAsync(productID)
);
}
In this example, we expose the GetByProductCommand
method that returns ICommand<InventoryItem>
. Within this method, we instantiate a new ServiceCommand (ServiceCommand<InventoryItem>
) passing in functions for the command execution methods. These functions simply interact with its data proxy to retrieve an inventory item.
Note that in this example, we chose the constructor overload that only accepts execution methods, as we don't require any initialization logic or validation of any validation/business rules in our execution pipeline. Also note that we include the parameter names with the constructor args for better readability and that this practice is optional.
Here is an example that specifies the logic to execute during command execution and injects business rules into the command execution pipeline offering both synchronous and asynchronous support:
public ICommand<OrderItem> SubmitCommand(long orderItemID)
{
var proxy = DataProxy as IOrderItemDataProxy;
return new ServiceCommand<OrderItem>
(
executeMethod: () => proxy.Submit(orderItemID, DateTime.Now),
executeAsyncMethod: () => proxy.SubmitAsync(orderItemID, DateTime.Now),
getBusinessRulesMethod: () => GetBusinessRulesForSubmit(orderItemID),
getBusinessRulesAsyncMethod: () => GetBusinessRulesForSubmitAsync(orderItemID)
);
}
private IEnumerable<IRule> GetBusinessRulesForSubmit(long orderItemID)
{
var orderItem = DataProxy.GetByID(orderItemID);
yield return new CanSubmitOrderItemRule(orderItem);
}
private async Task<IEnumerable<IRule>> GetBusinessRulesForSubmitAsync(long orderItemID)
{
var orderItem = await DataProxy.GetByIDAsync(orderItemID);
return new[] { new CanSubmitOrderItemRule(orderItem) };
}
In this example, we create an instance of ServiceCommand, but this time we specify business rule methods in addition to our execution methods.