Reputation: 9013
I'm confused with streams, return value and dispose. I.e. I use Stream and want to return stream from method. Next code:
public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR)
{
HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
using (var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open))
{
length = stream.Length;
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = length;
return result;
}
}
and
public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR)
{
long length = 0;
HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
using (var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open))
{
length = stream.Length;
result.Content = new StreamContent(stream);
}
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = length;
return result;
}
returns 504 status code:
ReadResponse() failed: The server did not return a complete response for this request. Server returned 0 bytes.
so, as I understand, stream is disposed when we go out from method
If I don't call Dispose at all:
public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR)
{
long length = 0;
HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open);
length = stream.Length;
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = length;
return result;
}
sometimes I get that file is blocked by another process. How to make it correctly?
Upvotes: 0
Views: 282
Reputation: 2699
Some background: Generally speaking, if you wish to stream the content of a file, what you want to do is read from the file stream and write to the output stream of HTTP response. Example:
using (var source = new FileStream(...))
{
byte[] buffer = new byte[4096];
int byteCount;
while ((byteCount = await source.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await output.WriteAsync(buffer, 0, byteCount);
}
}
Now, in your particular case, you are using a framework/pattern which requires of you to pass it a stream with your content, instead of allowing you to write to the output yourself. In this scenario, you are forced to shift the responsibility of disposing the stream to the invoker of your handler method.
Specifics: If your issue is the file being locked, then you can allow shared read/write access when you open the stream:
var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
This will allow other processes to have read and write access to the file while you read from it.
EDIT: As noted by @Evk, a safer option is to only share access with readers (attempts to open the file for writing will be denied):
var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.Read);
Improvements: If your file fits in memory, it would be wise to mem-cache it instead of streaming directly from disk. If you have thousand of simultaneous requests to fetch this file, your disk will become a huge bottleneck. Use a cache with retention/expiration policy and read and cache the entire file on cache misses. This way you also minimize the window in which you have file handle open (open, linear I/O read, close; very fast).
Upvotes: 2