Search code examples
asp.netasp.net-mvcasp.net-coremediatr

How to get the integer value returned in Task <int> format - Asp.net Core MVC - MediaTr


After saving the record to the database, I need to get the Id that will be returned from my Domain layer. For this I am using the features of the MediaTr library.

public class PessoaCommandHandler : CommandHandler,
    IRequestHandler<RegisterNewPessoaCommand, int>,
    IRequestHandler<UpdatePessoaCommand, int>,
    IRequestHandler<RemovePessoaCommand, int>
{
    private readonly IPessoaRepository _pessoaRepository;
    private bool _allowEndTransaction;
    private readonly IMediatorHandler Bus;

    public PessoaCommandHandler(IPessoaRepository pessoaRepository,
                                  IUnitOfWork uow,
                                  IMediatorHandler bus,
                                  INotificationHandler<DomainNotification> notifications) : base(uow, bus, notifications)
    {
        _pessoaRepository = pessoaRepository;
        _allowEndTransaction = true;
        Bus = bus;
    }

    public Task<int> Handle(RegisterNewPessoaCommand message, CancellationToken cancellationToken)
    {
        if (!message.IsValid())
        {
            NotifyValidationErrors(message);
            return Task.FromResult(0);
        }

         var pessoaModel = new Pessoa(message.PessoaNatureza);
         _pessoaRepository.Add(pessoaModel);

        return Task.FromResult(pessoaModel.Id);

    }
}

Now, let's get to the problem: I need to take the integer value that is in the "Result" property and put it into the personId variable, but I don't know how to do that. Does anyone know how to do this?

public void Register(PessoaViewModel pessoaViewModel)
{
    var registerCommand = _mapper.Map<RegisterNewPessoaCommand>(pessoaViewModel);
    var pessoaId = Bus.SendCommand(registerCommand);
}

enter image description here


Solution

  • Probably the easiest way to unwrap the value returned by a Task would be to use async/await.

    Though, you'll want to shy away from async void methods where possible as this results in a "fire and forget" method that cannot be awaited (this will potentially turn into a debugging nightmare as any exceptions will be lost to the void, etc.) -- so let's have the Register method return a Task instead:

    async public Task Register(PessoaViewModel pessoaViewModel)
    {
        var registerCommand = _mapper.Map<RegisterNewPessoaCommand>(pessoaViewModel);
        var pessoaId = await Bus.SendCommand(registerCommand);
    
        // use `pessoaId` as needed
    }
    

    If for some reason async/await is unavailable, the following option is also possible (though, note that this option is synchronous and will block current thread execution, etc.):

    public void Register(PessoaViewModel pessoaViewModel)
    {
        var registerCommand = _mapper.Map<RegisterNewPessoaCommand>(pessoaViewModel);
        var pessoaId = Bus.SendCommand(registerCommand).GetAwaiter().GetResult();
    
        // use `pessoaId` as needed
    }
    

    For completeness, I'll add that it would also be possible to use Bus.SendCommand(registerCommand).Result; but this is generally considered bad practice as it will obfuscate any exceptions inside of an aggregate exception, etc.

    Also, here's a solid answer to a similar question about how the unwrapping occurs.