Чем отличается PushStreamContent от веб-API и веб-API 2?
Я создал два идентичных проекта веб-API, один в VS 2012, а другой в VS 2013, оба предназначались для платформы 4.5 .net. Проекты основаны на учебном пособии по загрузке видео от Филиппа В., который находится здесь: 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 (поток outputStream, содержимое HttpContent, контекст TransportContext) {...}
Не идентифицируется как <action>
больше между веб-API 1 и 2?? Я действительно в замешательстве, поскольку нацеливаюсь на ту же платформу, и я не могу сделать интуитивный скачок в том, как это исправить. Все мои попытки изменить подпись WriteToStream потерпели неудачу.
Кто-нибудь знает, что мне нужно, чтобы PushStreamContent принимал WriteToStream в web api 2 или VS 2013 или новом C#, или где когда-либо существует разница в этом коде?
5 ответов
Я не уверен, если это ошибка в веб-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 изменена. Его параметр onStreamAvailable является универсальным типом Action или Func. Проблема в том, что компилятор не знает, к какому типу привязываться.
Итак, чтобы устранить ошибку, приведите streamAvailableHandler в качестве действия:
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)streamAvailableHandler);
И метод обработчика будет:
private void streamAvailableHandler(Stream stream, HttpContent content, TransportContext context) {
...write to stream
}
Это известная проблема со спецификацией C#. Проверьте этот вопрос SO - Ошибка вызова неоднозначности компилятора - анонимный метод и группа методов с Func<> или Action
Когда мы ввели эту перегрузку, которая возвращает задачу, мы поняли, что это нарушение уровня источника (хотя оно не нарушает двоичную совместимость). Мы все еще продолжали вносить изменения, поскольку их исправление не вызовет новых проблем.
А что касается того, как это исправить, у вас есть два варианта -
- Как ранее предлагал Киран, вы можете использовать синтаксис анонимного метода, чтобы компилятор выбрал правильную перегрузку для вас.
Вы можете использовать явное приведение, как показано ниже,
response.Content = new PushStreamContent ((Action) video.WriteToStream, new MediaTypeHeaderValue ("video /" + ext));
Кстати, будьте осторожны с этим async void
метод. Я предлагаю вам изменить свою подпись на
public async Task WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
Как утверждает RaghuRam Nadiminti, при изменении типа возвращаемого значения WriteToStream с void на Task компиляция будет выполнена успешно, и вам не понадобится явное приведение.
публичная асинхронная задача WriteToStream(поток outputStream, содержимое HttpContent, контекст TransportContext);
Это был мой обходной путь: если вызов был неоднозначным, просто бросьте его:
response.Content = new PushStreamContent(
(Action<Stream, HttpContent, TransportContext>) video.WriteToStream,
new MediaTypeHeaderValue("video/" + ext));