CQRS - 避免切换大小写调用命令处理程序
CQRS - Avoid switch case to call command handler
我正在使用 CQRS 设计模式。我有超过 15 个命令处理程序对应于每个事件类型。我想避免下面的 switch case 来根据事件类型调用相应的命令处理程序。
这是我的 Azure 函数:
[FunctionName("ReceiveEvent")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
ILogger log)
{
//log.LogInformation("ReceiveEvent HTTP trigger function started processing request.");
//log.LogInformation($"Pushing Events to Azure Blob on storage account :-{CloudConfigurationManager.GetSetting("AzureWebJobsStorage")}");
IActionResult actionResult = null;
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var command = await _commandMapper.Map(requestBody);
if (_commandValidator.Validate(req, command, ref actionResult))
{
switch (command.EventType)
{
case EventType.CARD_BLOCK:
_cardBlockCommandHandler.Handle(command as CardBlockCommand);
break;
case EventType.CARD_CANCEL:
_cardCancelledCommandHandler.Handle(command as CardCancelledCommand);
break;
case EventType.CARD_UNBLOCK:
_cardUnBlockHandler.Handle(command as CardUnBlockCommand);
break;
}
//TODO
return actionResult;
}
有没有更好的方法来避免这种情况?
命令处理程序:
public class CardBlockCommandHandler : ICommandHandler<CardBlockCommand>
{
private readonly IAzureBlobStorage _azureBlobStorage;
public CardBlockCommandHandler(IAzureBlobStorage azureBlobStorage)
{
_azureBlobStorage = azureBlobStorage;
}
public void Handle(CardBlockCommand command)
{
try
{
//TODO: Store into blob
//_azureBlobStorage.UploadMessageContentAsync(storageConnectionString: string.Empty,
// storageContainerName: string.Empty, blobName: string.Empty, content: string.Empty);
throw new NotImplementedException();
}
catch
{
}
}
}
ICommandHandler:
public interface ICommandHandler<TCommand> where TCommand : ICommand
{
/// <summary>
/// Execute command
/// </summary>
/// <param name="command"></param>
void Handle(TCommand command);
}
命令:
public abstract class Command : ICommand
{
public EventType EventType { get; }
}
public interface ICommand
{
EventType EventType { get; }
}
这是在详细说明评论中提到的关于使用服务的内容。有一个 ICommandHandlerService 作为依赖注入到你的函数构造函数中(你正在使用 DI 容器,不是吗?)。此接口将具有以下方法:
void HandleCommand(ICommand command);
ICommandHandlerService 的实现将在事件类型和 CommandHandlers 之间有一个字典映射,例如
public class CommandHandlerService : ICommandHandlerService
{
Dictionary<EventType, ICommandHandler> handlerDictionary = new Dictionary<EventType, ICommandHandler>();
//assuming that all your different handlers implement ICommandHandler ?
public void CommandHandlerService()
{
handlerDictionary.Add(EventType.CARD_UNBLOCK, new CardUnBlockCommandHandler());
handlerDictionary.Add(EventType.CARD_BLOCK, new CardBlockCommandHandler());
//setup rest of your associations
}
}
void HandleCommand(ICommand command)
{
if(!handlerDictionary.ContainsKey(command.EventType))
{
//throw suitable exception ?
}
var commandHandler = handlerDictionary[command.EventType];
commandHandler.Handle(command);
}
您的 Azure 函数构造函数将由您的 DI 框架传入 ICommandHandlerService 实例,您可以这样称呼它:
if (_commandValidator.Validate(req, command, ref actionResult))
{
commandHandlerService.Handle(command);
}
我正在使用 CQRS 设计模式。我有超过 15 个命令处理程序对应于每个事件类型。我想避免下面的 switch case 来根据事件类型调用相应的命令处理程序。
这是我的 Azure 函数:
[FunctionName("ReceiveEvent")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
ILogger log)
{
//log.LogInformation("ReceiveEvent HTTP trigger function started processing request.");
//log.LogInformation($"Pushing Events to Azure Blob on storage account :-{CloudConfigurationManager.GetSetting("AzureWebJobsStorage")}");
IActionResult actionResult = null;
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var command = await _commandMapper.Map(requestBody);
if (_commandValidator.Validate(req, command, ref actionResult))
{
switch (command.EventType)
{
case EventType.CARD_BLOCK:
_cardBlockCommandHandler.Handle(command as CardBlockCommand);
break;
case EventType.CARD_CANCEL:
_cardCancelledCommandHandler.Handle(command as CardCancelledCommand);
break;
case EventType.CARD_UNBLOCK:
_cardUnBlockHandler.Handle(command as CardUnBlockCommand);
break;
}
//TODO
return actionResult;
}
有没有更好的方法来避免这种情况?
命令处理程序:
public class CardBlockCommandHandler : ICommandHandler<CardBlockCommand>
{
private readonly IAzureBlobStorage _azureBlobStorage;
public CardBlockCommandHandler(IAzureBlobStorage azureBlobStorage)
{
_azureBlobStorage = azureBlobStorage;
}
public void Handle(CardBlockCommand command)
{
try
{
//TODO: Store into blob
//_azureBlobStorage.UploadMessageContentAsync(storageConnectionString: string.Empty,
// storageContainerName: string.Empty, blobName: string.Empty, content: string.Empty);
throw new NotImplementedException();
}
catch
{
}
}
}
ICommandHandler:
public interface ICommandHandler<TCommand> where TCommand : ICommand
{
/// <summary>
/// Execute command
/// </summary>
/// <param name="command"></param>
void Handle(TCommand command);
}
命令:
public abstract class Command : ICommand
{
public EventType EventType { get; }
}
public interface ICommand
{
EventType EventType { get; }
}
这是在详细说明评论中提到的关于使用服务的内容。有一个 ICommandHandlerService 作为依赖注入到你的函数构造函数中(你正在使用 DI 容器,不是吗?)。此接口将具有以下方法:
void HandleCommand(ICommand command);
ICommandHandlerService 的实现将在事件类型和 CommandHandlers 之间有一个字典映射,例如
public class CommandHandlerService : ICommandHandlerService
{
Dictionary<EventType, ICommandHandler> handlerDictionary = new Dictionary<EventType, ICommandHandler>();
//assuming that all your different handlers implement ICommandHandler ?
public void CommandHandlerService()
{
handlerDictionary.Add(EventType.CARD_UNBLOCK, new CardUnBlockCommandHandler());
handlerDictionary.Add(EventType.CARD_BLOCK, new CardBlockCommandHandler());
//setup rest of your associations
}
}
void HandleCommand(ICommand command)
{
if(!handlerDictionary.ContainsKey(command.EventType))
{
//throw suitable exception ?
}
var commandHandler = handlerDictionary[command.EventType];
commandHandler.Handle(command);
}
您的 Azure 函数构造函数将由您的 DI 框架传入 ICommandHandlerService 实例,您可以这样称呼它:
if (_commandValidator.Validate(req, command, ref actionResult))
{
commandHandlerService.Handle(command);
}