如何在不使用磁盘且内存不足的情况下将大型文件从api流式传输到api?

时间:2018-10-18 20:23:09

标签: c# .net asp.net-web-api asp.net-web-api2

我有一个API HTTPGET,可以从另一个API检索文件并将其吐出。这适用于较小的文件,但是我遇到的问题是,检索到的文件可能很大(最大2gb),而MemoryStream是一个限制。有什么想法如何在不使用磁盘的情况下流式传输文件内容并避免“内存不足”异常?

控制器:

[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;
}

谢谢。

1 个答案:

答案 0 :(得分:0)

因此,不是GetContentFile将整个流读入数组并返回它,而是返回该流。不需要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);
}