Returning async stream of query results
Since this is a WebAPI action method, HTTP restricts you to a single response. If you just return an IEnumerable<T>
, then ASP.NET will enumerate it in-memory and then send the response.
If you're fine with this in-memory process, then you can just do the same thing yourself:
public async Task<List<Location>> Get()
{
var result = new List<Location>();
var query = AsyncDocumentSession.Query<Foo, FooIndex>();
using (var enumerator = await AsyncDocumentSession.Advanced.StreamAsync(query))
while (await enumerator.MoveNextAsync())
result.Add(enumerator.Current.Document);
return result;
}
However, I believe it would be better to use a streamed response, which you can get via PushStreamContent
; something like this:
public HttpResponseMessage Get()
{
var query = AsyncDocumentSession.Query<Foo, FooIndex>();
HttpResponseMessage response = Request.CreateResponse();
response.Content = new PushStreamContent(
async (stream, content, context) =>
{
using (stream)
using (var enumerator = await AsyncDocumentSession.Advanced.StreamAsync(query))
{
while (await enumerator.MoveNextAsync())
{
// TODO: adjust encoding as necessary.
var serialized = JsonConvert.SerializeObject(enumerator.CurrentDocument);
var data = UTF8Encoding.UTF8.GetBytes(serialized);
var countPrefix = BitConverter.GetBytes(data.Length);
await stream.WriteAsync(countPrefix, 0, countPrefix.Length);
await stream.WriteAsync(data, 0, data.Length);
}
}
});
return response;
}
The streamed response doesn't require your server to hold the entire response in memory; however, you'll have to decide on the proper way to write documents to the response stream. The example code above just converts them to JSON, encodes in UTF8, and (binary) length-prefixes those strings.