Web api和web api 2之间的PushStreamContent有什么不同?

hux*_*ley 10 c# download large-files asp.net-web-api

我创建了两个相同的web api项目,一个在VS 2012中,另一个在VS 2013中,两者都针对4.5 .net框架.这些项目基于Filip W的视频下载教程:http: //www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/

将教程中的代码复制并粘贴到VS 2012项目中(使用web api 1?)不会产生错误(在我添加正确的'using'语句之后).

但是,当我在VS 2013项目中执行相同的步骤时,我会收到以下两个错误:

错误1
以下方法或属性之间的调用不明确:'PushStreamContent(System.Func <Stream,HttpContent,TransportContext,Task>,MediaTypeHeaderValue)'和'PushStreamContent(System.Action <System.IO.Stream,HttpContent,TransportContext>,MediaTypeHeaderValue)'

错误
2'void video_stream.Controllers.VideoStream.WriteToStream(System.IO.Stream,System.Net.Http.HttpContent,System.Net.TransportContext)'具有错误的返回类型

所以我的猜测是错误2是真正的问题,因为这段代码:

public async void WriteToStream(Stream outputStream,HttpContent content,TransportContext context){...}

<action>在web api 1和2之间不再被识别为?? 我真的很困惑,因为我的目标是相同的框架,我似乎无法在如何解决它方面做出直观的飞跃.我尝试更改WriteToStream签名都失败了.

有没有人知道我需要什么才能让PushStreamContent接受web api 2或VS 2013中的WriteToStream或新的C#或者这段代码的差异在哪里?

Bil*_*man 14

PushStreamContent构造函数的签名已更改.其onStreamAvailable参数是Action或Func泛型类型.问题是编译器不知道要绑定哪种类型.

因此,要解决错误,请将streamAvailableHandler强制转换为Action:

response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)streamAvailableHandler);
Run Code Online (Sandbox Code Playgroud)

处理程序方法将是:

private void streamAvailableHandler(Stream stream, HttpContent content, TransportContext context) {
  ...write to stream
}
Run Code Online (Sandbox Code Playgroud)


Kir*_*lla 8

我不确定这是否是Web API中的错误,我们将对其进行调查.同时您可以尝试以下解决方法:

response.Content = new PushStreamContent(async (Stream outputStream, HttpContent content, TransportContext context) =>
{
    try
    {
        var buffer = new byte[65536];

        using (var video = File.Open(filename, FileMode.Open, FileAccess.Read))
        {
            var length = (int)video.Length;
            var bytesRead = 1;

            while (length > 0 && bytesRead > 0)
            {
                bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
                await outputStream.WriteAsync(buffer, 0, bytesRead);
                length -= bytesRead;
            }
        }
    }
    finally
    {
        outputStream.Close();
    }
});
Run Code Online (Sandbox Code Playgroud)

注意:我对代码进行了另一次更改(删除了catch块)以允许传播异常.这是为了让您的客户知道服务中发生了一些错误,否则他们会认为一切顺利.


Rag*_*nti 5

这是 C# 规范的一个已知问题。看看这个SO问题 - Compiler Ambigeous incalling error - Anonymous method and method group with Func<> or Action

当我们引入这个返回任务的重载时,我们确实意识到这是一个源代码级别的破坏性更改(尽管它不会破坏二进制兼容性)。我们仍然继续进行更改,因为不修复它会导致更多问题。

关于如何修复它,您有两种选择 -

  1. 正如 Kiran 之前建议的,您可以使用匿名方法语法,以便编译器为您选择正确的重载。
  2. 您可以使用显式强制转换,如下所示,

    response.Content = new PushStreamContent((Action)video.WriteToStream, new MediaTypeHeaderValue("video/"+ext));

顺便说一句,请小心使用该async void方法。我建议你将其签名更改为

public async Task WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
Run Code Online (Sandbox Code Playgroud)