如何在不使用磁盘和 运行 内存不足的情况下将大文件从 api 流式传输到 api?
How do I stream a large file from api to api without using disk and running out of memory?
我有一个 API HTTPGET,它从另一个 API 检索文件并将其吐出。这适用于较小的文件,但我遇到的问题是检索到的文件可能相当大(最大 2gb),并且 MemoryStream 是一个限制。关于如何在不使用磁盘的情况下流式传输文件内容并避免 'out of memory' 异常的任何想法?
控制器:
[Route("{id}/file", Name = "GetContentFile")]
[HttpGet]
public IHttpActionResult GetContentFile(string id)
{
if (String.IsNullOrEmpty(id))
return BadRequest();
ContentFile cfl = new ContentFile();
var ret = new HttpResponseMessage(HttpStatusCode.OK);
try
{
cfl = otcrepo.GetContentFile(id);
var mstream = new MemoryStream(cfl.Data);
ret.Content = new StreamContent(mstream);
ret.Content.Headers.ContentType = new MediaTypeHeaderValue(cfl.ContentType);
ret.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
}
catch
{
return InternalServerError();
}
if (cfl != null)
{
ResponseMessageResult responseMessageResult = ResponseMessage(ret);
return responseMessageResult;
}
else
{
return NotFound();
}
}
型号:
public class ContentFile
{
public string Filename { get; set; }
public byte[] Data { get; set; }
public StreamContent DataStream { get; set; }
public string ContentType { get; set; }
}
存储库调用:
public ContentFile GetContentFile(string id)
{
ContentFile fl = new ContentFile();
using (var htc = new HttpClient())
{
var response = htc.GetAsync(ConfigurationManager.AppSettings["BaseUrl"] + "/api/v2/nodes/" + id + "/content/").Result;
fl.Data = response.Content.ReadAsByteArrayAsync().Result;
fl.ContentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
}
return fl;
}
谢谢。
因此,我们 return 不是 GetContentFile
将完整的流读入数组并 return 对其进行处理。比没有必要 MemoryStream
.
[Route("{id}/file", Name = "GetContentFile")]
[HttpGet]
public async Task<IHttpActionResult> GetContentFile(string id)
{
...
var result = await otcrepo.GetContentFile(id);
ret.Content = new StreamContent(result.stream);
ret.Content.Headers.ContentType = new MediaTypeHeaderValue(result.contentType);
...
}
public async Task<(Stream stream, string contentType)> GetContentFile(string id)
{
var htc = new HttpClient()
var response = await htc.GetAsync(ConfigurationManager.AppSettings["BaseUrl"] + "/api/v2/nodes/" + id + "/content/");
var stream = await response.Content.ReadAsStreamAsync();
var contentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
return (stream, contentType);
}
我有一个 API HTTPGET,它从另一个 API 检索文件并将其吐出。这适用于较小的文件,但我遇到的问题是检索到的文件可能相当大(最大 2gb),并且 MemoryStream 是一个限制。关于如何在不使用磁盘的情况下流式传输文件内容并避免 'out of memory' 异常的任何想法?
控制器:
[Route("{id}/file", Name = "GetContentFile")]
[HttpGet]
public IHttpActionResult GetContentFile(string id)
{
if (String.IsNullOrEmpty(id))
return BadRequest();
ContentFile cfl = new ContentFile();
var ret = new HttpResponseMessage(HttpStatusCode.OK);
try
{
cfl = otcrepo.GetContentFile(id);
var mstream = new MemoryStream(cfl.Data);
ret.Content = new StreamContent(mstream);
ret.Content.Headers.ContentType = new MediaTypeHeaderValue(cfl.ContentType);
ret.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
}
catch
{
return InternalServerError();
}
if (cfl != null)
{
ResponseMessageResult responseMessageResult = ResponseMessage(ret);
return responseMessageResult;
}
else
{
return NotFound();
}
}
型号:
public class ContentFile
{
public string Filename { get; set; }
public byte[] Data { get; set; }
public StreamContent DataStream { get; set; }
public string ContentType { get; set; }
}
存储库调用:
public ContentFile GetContentFile(string id)
{
ContentFile fl = new ContentFile();
using (var htc = new HttpClient())
{
var response = htc.GetAsync(ConfigurationManager.AppSettings["BaseUrl"] + "/api/v2/nodes/" + id + "/content/").Result;
fl.Data = response.Content.ReadAsByteArrayAsync().Result;
fl.ContentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
}
return fl;
}
谢谢。
因此,我们 return 不是 GetContentFile
将完整的流读入数组并 return 对其进行处理。比没有必要 MemoryStream
.
[Route("{id}/file", Name = "GetContentFile")]
[HttpGet]
public async Task<IHttpActionResult> GetContentFile(string id)
{
...
var result = await otcrepo.GetContentFile(id);
ret.Content = new StreamContent(result.stream);
ret.Content.Headers.ContentType = new MediaTypeHeaderValue(result.contentType);
...
}
public async Task<(Stream stream, string contentType)> GetContentFile(string id)
{
var htc = new HttpClient()
var response = await htc.GetAsync(ConfigurationManager.AppSettings["BaseUrl"] + "/api/v2/nodes/" + id + "/content/");
var stream = await response.Content.ReadAsStreamAsync();
var contentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
return (stream, contentType);
}