Issue
I’m working with two API’s which are being used to download large documents from an external system.
I call API 1 with some information about a document to be retrieved, API 1 then calls API 2 with that same information acting as a ‘middleman’. API 1 gets document binary back which it then passes along to the original caller.
What I’d like to avoid is creating large in memory objects representing these documents and just pass a stream as the response all the way through, is this possible with the described setup (‘middleman’ API)?
Basic example of what I have (in API 1):
var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com/api/getdocs");
request.Content = parameters;
// 'ResponseHeadersRead' - indicate completion on reading of headers and not entire response...
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (response.StatusCode == HttpStatusCode.OK)
{
var stream = await response.Content.ReadAsStreamAsync();
return this.Ok(stream);
}
else
{
// Logging/error handling...
}
The response from this is being read as a stream by the original caller and then passed to a FileStreamResult
which downloads the document on the client machine.
My question(s):
- Is the
var stream = await response.Content.ReadAsStreamAsync()
line still creating a large in memory object representing the document? - Does the above stream need to be disposed or will the underlying
HttpContent
take care of cleaning up the stream? If it does need to be disposed, how can I do this whilst still passing a stream response to the caller? (is that even possible?)
Solution
The stream
which you are passing to Ok
should not be disposed. Ok
will wrap the stream and feed it back as a response to the client, so if you dispose it then the response will fail.
Technically speaking, at least according to IDisposable
mantra, you should dispose response
. However, doing so will cause it to dispose the stream also, and therefore you should not dispose response
either.
Don’t fear that it will cause anything to leak: HttpResponseMessage
does not dispose anything other than the content stream. See the below source code:
protected virtual void Dispose(bool disposing)
{
// The reason for this type to implement IDisposable is that it contains instances of types that implement
// IDisposable (content).
if (disposing && !disposed)
{
disposed = true;
if (content != null)
{
content.Dispose();
}
}
}
You should however dispose request
with a using
block, although that also just disposes the content, in your case parameters
.
Answered By – Charlieface
Answer Checked By – Terry (BugsFixing Volunteer)