如何在ASP.Net MVC 中实现视频文件流?

How to implement video file streaming in ASP.Net MVC?

我想实现简单的视频文件流。 这是我的 API 控制器:

[HttpGet]
[Route("api/VideoContent")]
public HttpResponseMessage GetVideoContent([FromUri] string fileName)
{
    if (fileName == null)
    {
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
    }

    if (Request.Headers.Range != null)
    {
        try
        {
            //using (FileStream fileStream = _videoFileProvider.GetFileStream(fileName))
            //{
                HttpResponseMessage partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
                FileStream fileStream = _videoFileProvider.GetFileStream(fileName);
                partialResponse.Content = new ByteRangeStreamContent(fileStream, Request.Headers.Range, new MediaTypeHeaderValue("video/mp4"));
                return partialResponse;
            //}

        }
        catch (Exception)
        {
            return new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }
    }

    return new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable);
}

此代码有效,但如您所见,fileStream 未被释放。我尝试使用 using 块(注释行),但此代码不起作用 - 在调试模式方法 运行 中无一例外,但浏览器显示响应 500 错误代码。

我的错误在哪里?为什么我会收到 500 Internal Server Error?如何正确处理我的文件流?

AFAIK,您在不处理文件流的情况下下载内容的实现是正确的。

因为您一直在使用 HttpResponseMessage 返回响应,该响应在完成向客户端发送响应后由框架本身自动处理。

这已经被MSFT guy in comment of another post

指出

如果你查看 HttpResponseMessage in source code 的 dispose 方法,

        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();
                }
            }
        }

您可以看到 _content 已被处置,类型为 HttpContent 即在您的情况下,ByteRangeStreamContent 的对象设置在 Content 属性 HttpResponseMessage.

按以下方式处理 ByteRangeStreamContent 对象:

        protected override void Dispose(bool disposing)
        {
            Contract.Assert(_byteRangeContent != null);
            if (disposing)
            {
                if (!_disposed)
                {
                    _byteRangeContent.Dispose();
                    _content.Dispose();
                    _disposed = true;
                }
            }
            base.Dispose(disposing);
        }

ByteRangeStreamContent的上述Dispose方法中,你可以看到它正在处理自身并处理_content(在你的情况下FileStream)也是用于创建 ByteRangeStreamContent 对象的流。

我坚信,您没有处理文件流的实现是正确的,因为在完成向客户端发送响应后处理会按顺序开始。