Network Commands
The Matrix Communication Framework provides a command system for declarative remote procedure invocation between distributed services.
Command Definition
<ServiceNode Name="OrderService">
<!-- Define commands at service level -->
<ServiceNode.Commands>
<NetworkCommand Name="CreateOrder"
Path="/orders/create"
ResponseType="{x:Type OrderResponse}">
<NetworkCommand.Parameters>
<Parameter Name="orderId" Type="string" Required="true"/>
<Parameter Name="items" Type="List<OrderItem>" Required="true"/>
<Parameter Name="customerId" Type="string" Required="true"/>
</NetworkCommand.Parameters>
</NetworkCommand>
<NetworkCommand Name="CancelOrder"
Path="/orders/cancel"
CanExecute="CanCancelOrder">
<NetworkCommand.Parameters>
<Parameter Name="orderId" Type="string" Required="true"/>
<Parameter Name="reason" Type="string" Required="false"/>
</NetworkCommand.Parameters>
</NetworkCommand>
</ServiceNode.Commands>
<!-- Command bindings -->
<ServiceNode.CommandBindings>
<CommandBinding Command="CreateOrder"
Executed="OnCreateOrder"
CanExecute="CanCreateOrder"/>
</ServiceNode.CommandBindings>
</ServiceNode>Command Implementation
public class NetworkCommand : CommunicationElement
{
public static readonly DependencyProperty PathProperty =
DependencyProperty.Register(
"Path",
typeof(string),
typeof(NetworkCommand)
);
public static readonly DependencyProperty ParametersProperty =
DependencyProperty.Register(
"Parameters",
typeof(CommandParameterCollection),
typeof(NetworkCommand)
);
public static readonly DependencyProperty ResponseTypeProperty =
DependencyProperty.Register(
"ResponseType",
typeof(Type),
typeof(NetworkCommand)
);
public string Path
{
get => (string)GetValue(PathProperty);
set => SetValue(PathProperty, value);
}
public CommandParameterCollection Parameters
{
get => (CommandParameterCollection)GetValue(ParametersProperty);
set => SetValue(ParametersProperty, value);
}
public Type ResponseType
{
get => (Type)GetValue(ResponseTypeProperty);
set => SetValue(ResponseTypeProperty, value);
}
public async Task<object> ExecuteAsync(IDictionary<string, object> parameters)
{
ValidateParameters(parameters);
var message = new CommandMessage
{
CommandPath = Path,
Parameters = parameters,
Timestamp = DateTimeOffset.UtcNow
};
return await _dispatcher.SendCommandAsync(message);
}
}Command Binding System
public class NetworkCommandBinding : CommunicationElement
{
private readonly INetworkDispatcher _dispatcher;
private readonly ICommandValidator _validator;
public async Task<bool> CanExecuteAsync(NetworkCommand command, object parameter)
{
// Check network availability
if (!await _dispatcher.IsAvailableAsync(command.Path))
return false;
// Validate parameters
if (!_validator.ValidateParameters(command, parameter))
return false;
// Check custom conditions
return await InvokeCanExecuteAsync(command, parameter);
}
public async Task ExecuteAsync(NetworkCommand command, object parameter)
{
try
{
// Pre-execution hooks
await OnCommandExecutingAsync(command, parameter);
// Execute command
var result = await command.ExecuteAsync(
ConvertToParameters(parameter)
);
// Post-execution hooks
await OnCommandExecutedAsync(command, result);
}
catch (NetworkException ex)
{
await HandleCommandFailureAsync(command, ex);
}
}
}Command Usage
public class OrderProcessor : ServiceNode
{
private readonly NetworkCommand _createOrderCommand;
private readonly ILogger<OrderProcessor> _logger;
public OrderProcessor(ILogger<OrderProcessor> logger)
{
_logger = logger;
_createOrderCommand = FindCommand("CreateOrder");
}
private async Task<bool> CanCreateOrder(object parameter)
{
var order = parameter as OrderRequest;
if (order == null) return false;
// Check business rules
if (!await ValidateInventoryAsync(order.Items))
return false;
// Check customer status
return await ValidateCustomerAsync(order.CustomerId);
}
private async Task OnCreateOrder(object parameter)
{
var order = parameter as OrderRequest;
try
{
var response = await _createOrderCommand.ExecuteAsync(
new Dictionary<string, object>
{
["orderId"] = Guid.NewGuid().ToString(),
["items"] = order.Items,
["customerId"] = order.CustomerId
}
);
await ProcessOrderResponseAsync(response as OrderResponse);
}
catch (CommandExecutionException ex)
{
_logger.LogError(ex, "Failed to create order");
throw;
}
}
}Best Practices
-
Command Design
- Keep commands focused and atomic
- Define clear parameter contracts
- Implement proper validation
- Handle partial failures
- Support command composition
-
Error Handling
- Implement retry policies
- Handle timeouts gracefully
- Provide detailed error information
- Support compensation actions
- Log command execution
-
Performance
- Cache command metadata
- Batch related commands
- Optimize parameter serialization
- Monitor execution times
- Implement circuit breakers
-
Security
- Validate command sources
- Authorize command execution
- Encrypt sensitive parameters
- Audit command usage
- Implement rate limiting