You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CQRSLite时,如何从POST操作返回结果?

Hey there! I’ve worked with CQRSLite quite a bit, so let me walk you through practical ways to return results from your POST operations when using this library.

Common Solutions for Returning Results with CQRSLite

1. Synchronous Command Handling (Direct Result)

While CQRS leans toward fire-and-forget commands, you can still get immediate results by passing state back through the command object itself (since commands are reference types). This works great for simple scenarios where you need a value like a newly created entity ID.

First, define your command with a property to hold the result:

public class CreateOrderCommand : ICommand
{
    public Guid Id { get; set; }
    public string CustomerName { get; set; }
    // Property to store the generated order ID after processing
    public Guid GeneratedOrderId { get; set; }
}

Then update your command handler to populate this property:

public class CreateOrderCommandHandler : ICommandHandler<CreateOrderCommand>
{
    private readonly ISession _session;

    public CreateOrderCommandHandler(ISession session)
    {
        _session = session;
    }

    public async Task Handle(CreateOrderCommand command)
    {
        var newOrder = new Order(command.CustomerName);
        command.GeneratedOrderId = newOrder.Id; // Pass the ID back via the command
        await _session.Add(newOrder);
        await _session.Commit();
    }
}

Finally, access the result in your POST controller:

[HttpPost("orders")]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderCommand command)
{
    await _commandDispatcher.Dispatch(command);
    return Ok(new { OrderId = command.GeneratedOrderId });
}

2. Asynchronous Result via Event Tracking

For more complex, async workflows (like when commands are processed in a background queue), you can use a TaskCompletionSource to wait for the corresponding domain event and return the result once it fires.

First, add a TaskCompletionSource to your command:

public class CreateOrderCommand : ICommand
{
    public Guid Id { get; set; }
    public string CustomerName { get; set; }
    public TaskCompletionSource<Guid> OrderIdCompletionSource { get; set; } 
        = new TaskCompletionSource<Guid>();
}

Next, use an event handler to resolve the completion source when the order is created:

// In-memory store to track active commands (use distributed cache for multi-instance apps)
private static readonly Dictionary<Guid, CreateOrderCommand> _activeCommands = new();

public class OrderCreatedEventHandler : IEventHandler<OrderCreatedEvent>
{
    public Task Handle(OrderCreatedEvent @event)
    {
        if (_activeCommands.TryGetValue(@event.CommandId, out var command))
        {
            command.OrderIdCompletionSource.SetResult(@event.AggregateId);
            _activeCommands.Remove(@event.CommandId);
        }
        return Task.CompletedTask;
    }
}

Then update your controller to wait for the event:

[HttpPost("orders")]
public async Task<IActionResult> CreateOrder([FromBody] CreateOrderCommand command)
{
    command.Id = Guid.NewGuid();
    _activeCommands.Add(command.Id, command);
    
    await _commandDispatcher.Dispatch(command);
    var orderId = await command.OrderIdCompletionSource.Task;
    
    return Ok(new { OrderId = orderId });
}

3. Return Command ID for Subsequent Queries

This is the most CQRS-aligned approach: return a command ID immediately, then let clients query a separate endpoint to check status or retrieve the final result.

Controller code:

[HttpPost("orders")]
public IActionResult CreateOrder([FromBody] CreateOrderCommand command)
{
    command.Id = Guid.NewGuid();
    // Dispatch asynchronously (e.g., via a message queue)
    _commandDispatcher.DispatchAsync(command);
    
    // Return command ID and a link to check status
    return AcceptedAtAction(
        nameof(GetCommandStatus), 
        new { commandId = command.Id }, 
        new { CommandId = command.Id, Message = "Order creation in progress" }
    );
}

[HttpGet("commands/{commandId}")]
public async Task<IActionResult> GetCommandStatus(Guid commandId)
{
    var commandStatus = await _commandStatusRepo.GetById(commandId);
    if (commandStatus == null) return NotFound();
    
    if (commandStatus.IsCompleted)
    {
        var order = await _orderRepo.GetById(commandStatus.AggregateId);
        return Ok(new { Status = "Completed", Order = order });
    }
    
    return Ok(new { Status = "Processing" });
}

You’ll need a CommandStatus entity to track whether the command succeeded/failed and link to the created aggregate.


内容的提问来源于stack exchange,提问作者KDS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:32:54