4

I have a query class that implements Mediatr.IRequest like below:

public class ExportDataQuery : IRequest<IAsyncEnumerable<byte[]>> {}

The query handler has been implemented as follows:

public class ExportDataQueryHandler : IRequestHandler<ExportDataQuery, IAsyncEnumerable<byte[]>>
{
  public async IAsyncEnumerable<byte[]> Handle(ExportDataQuery query, CancellationToken cancellationToken)
  {
     for (int page = 1; page <= pageCount; ++page)
     {
        // Get paginated data asynchronously.
        var data = await _dbUtils.GetDataAsync(page, pageSize);
        yield return data;
     }
  }
}

But I am getting the following build error on compiling the above code:

Error CS0738 'ExportDataQueryHandler' does not implement interface member 'IRequestHandler<ExportDataQuery, IAsyncEnumerable<byte[]>>.Handle(ExportDataQuery, CancellationToken)'. 'ExportDataQueryHandler.Handle(ExportDataQuery, CancellationToken)' cannot implement 'IRequestHandler<ExportDataQuery, IAsyncEnumerable<byte[]>>.Handle(ExportDataQuery, CancellationToken)' because it does not have the matching return type of 'Task<IAsyncEnumerable<byte[]>>'.

When I change return type of Handle to Task<IAsyncEnumerable<byte[]>>, I get the following error:

Error CS1624 The body of 'ExportDataQueryHandler.Handle(ExportDataQuery, CancellationToken)' cannot be an iterator block because 'Task<IAsyncEnumerable<byte[]>>' is not an iterator interface type.

Is there any way to use yield return in above request handler to return each page data one at a time?

  • 2
    You method marked as `async`, but there is no `await`. How is `GetData` implemented? – Pavel Anikhouski Jan 10 '20 at 12:12
  • Sorry my bad, I added await in GetDataAsync(). Basically this method retrieve paginated data from MongoDB collection and convert it to byte array asynchronously and returns it to the caller. – Muhammad Fahad Ahmed Jan 10 '20 at 13:35
  • Handle has to return type `Task>` to implement the IRequestHandler interface. Could you create a private method, which returns `IAsyncEnumerable`, and in this method use yield return? Then call this method from Handle? – Sjolfr Jan 10 '20 at 15:07

1 Answers1

0

Could you do this; Modify your call to return the collection AsAsyncEnumerable and then use the synchronous request type by inheriting from RequestHandler<T> so it doesn't wrap the result in Task<T>

public class ExportDataQueryHandler : RequestHandler<ExportDataQuery, IAsyncEnumerable<byte[]>>
{
    protected override IAsyncEnumerable<byte[]> Handle(ExportDataQuery query)
    {            
        return _dbUtils.GetDataAsync(page, pageSize).AsAsyncEnumerable();           
    }
}
jimmy_b
  • 163
  • 1
  • 7