PushStreamContent在Web API和Web API 2之间有何不同?

11

我创建了两个完全相同的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项目中按照相同步骤操作时,我会遇到以下两个错误:

 

Error 1
  调用在以下方法或属性之间模棱两可:   'PushStreamContent(System.Func<Stream,HttpContent,TransportContext,Task>, MediaTypeHeaderValue)'   和   'PushStreamContent(System.Action<System.IO.Stream,HttpContent,TransportContext>, MediaTypeHeaderValue)'

    

Error 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) {...}

在Web API 1和2之间不再被标识为<action>??我真的很困惑,因为我针对相同的框架,并且似乎无法跨越直觉上修复。我尝试更改WriteToStream签名的尝试都失败了。

有人知道我需要什么才能使PushStreamContent在Web API 2或VS 2013或新的C#中接受WriteToStream吗?还是这段代码存在差异的地方?

5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
14
PushStreamContent构造函数的签名已更改。它的onStreamAvailable参数是一个Action或Func泛型类型。问题在于编译器不知道要绑定哪种类型。 为了解决这个错误,请将streamAvailableHandler强制转换为Action类型。
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)streamAvailableHandler);

处理程序方法应该是:

private void streamAvailableHandler(Stream stream, HttpContent content, TransportContext context) {
  ...write to stream
}

10

我不确定这是否是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();
    }
});

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


昨晚很晚我终于找到了你的确切解决方案,当时我在查看另一个我找到的PushStreamContent示例。这促使我在VS 12和13中都使用“转到定义”,我想我应该从一开始就这样做。在12中,PSC有3个重载,但在13中有6个重载。仔细看,似乎现在需要传递一个额外的参数(Task)给外部方法,而以前不需要。我可以确认上述解决方案确实有效。 - huxley

5

这是C#规范中已知的问题。请查看此SO问题 - 编译器模棱两可的调用错误-匿名方法和使用Func<>或Action的方法组

当我们引入返回Task的重载时,我们意识到这是一种源级别的破坏性更改(尽管它不会破坏二进制兼容性)。我们仍然进行了更改,因为不修复它将导致更多问题。

关于如何修复它,您有两个选项 -

  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)

1
如果你将void更改为Task,那么你的转换也必须更改为(Func <Stream,HttpContent,TransportContext,Task>)。 - CaMiX

0
正如RaghuRam Nadiminti所建议的那样,通过将WriteToStream方法的返回类型从void更改为Task,编译将成功运行,而您不需要进行显式转换。 public async Task WriteToStream(Stream outputStream,HttpContent content,TransportContext context);

-1
这是我的解决方法:如果调用不明确,就进行强制转换:
response.Content = new PushStreamContent(
    (Action<Stream, HttpContent, TransportContext>) video.WriteToStream,
new MediaTypeHeaderValue("video/" + ext));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,