WCF Stream.Read всегда возвращает 0 в клиенте - PullRequest
1 голос
/ 06 января 2011

Я провел большую часть своего дня, пытаясь понять, почему это не работает.У меня есть служба WCF, которая передает объект клиенту.Затем клиент должен записать файл на свой диск.Но когда я звоню stream.Read(buffer, 0, bufferLength), он всегда возвращает 0. Вот мой код:

namespace StreamServiceNS
{
    [ServiceContract]
    public interface IStreamService
    {
        [OperationContract]
        Stream downloadStreamFile();
    }
}
class StreamService : IStreamService
{
    public Stream downloadStreamFile()
    {
        ISSSteamFile sFile = getStreamFile();
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream stream = new MemoryStream();
        bf.Serialize(stream, sFile);
        return stream;
    }
}

Файл конфигурации службы:

<system.serviceModel>
<services>
  <service name="StreamServiceNS.StreamService">
    <endpoint address="stream" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IStreamService"
              name="BasicHttpEndpoint_IStreamService" contract="SWUpdaterService.ISWUService" />
  </service>
</services>
<bindings>
  <basicHttpBinding>
    <binding name="BasicHttpBinding_IStreamService" transferMode="StreamedResponse" 
             maxReceivedMessageSize="209715200"></binding>
  </basicHttpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior>
      <serviceThrottling maxConcurrentCalls ="100" maxConcurrentSessions="400"/>
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

Клиент:

TestApp.StreamServiceRef.StreamServiceClient client = new StreamServiceRef.StreamServiceClient();
        try
        {
            Stream stream = client.downloadStreamFile();
            int bufferLength = 8 * 1024;
            byte[] buffer = new byte[bufferLength];

            FileStream fs = new FileStream(@"C:\test\testFile.exe", FileMode.Create, FileAccess.Write);
            int bytesRead;
            while ((bytesRead = stream.Read(buffer, 0, bufferLength)) > 0)
            {
                fs.Write(buffer, 0, bytesRead);
            }
            stream.Close();
            fs.Close();
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }

Клиентapp.config:

    <system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpEndpoint_IStreamService" maxReceivedMessageSize="209715200" transferMode="StreamedResponse">
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://[server]/StreamServices/streamservice.svc/stream"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpoint_IStreamService"
            contract="StreamServiceRef.IStreamService" name="BasicHttpEndpoint_IStreamService" />
    </client>
    </system.serviceModel>

(некоторый код для краткости обрезан)

Я прочитал все, что могу найти при создании потоковых сервисов WCF, и мой код не отличается от их.Я могу заменить потоковую передачу буферизацией и отправить объект таким образом, но когда я пытаюсь выполнить потоковую передачу, клиент всегда видит поток как «пустой».testFile.exe создается, но его размер составляет 0 КБ.

Чего мне не хватает?

ОБНОВЛЕНИЕ
Хм.Ну, я не могу отладить его, потому что при попытке сказать мне, что тестовый клиент WCF не поддерживает потоки.Но я знаю, что что-то делает это в потоке, потому что, если я не помещу цикл while, а просто имею один fs.Write (...), он закроет 8KB, как только поток закроется.Итак, что-то пересекается.

Я посмотрел ваш пост и добавил:

[MessageContract]
public class FileDownloadMessage
{
    [MessageBodyMember(Order = 1)]
    public MemoryStream FileByteStream;
}

в мой IStreamService.И downloadStreamFile() теперь возвращает FileDownloadMessage объект.

Но после обновления ссылки на службу на моем клиенте он думает, что downloadStreamFile() возвращает TestApp.StreamServiceRef.MemoryStream объект.
Он также создал downloadStreamFileRequest()класс, который я не сделал и понятия не имею, откуда он.

Ответы [ 4 ]

4 голосов
/ 12 апреля 2013

У меня также была эта проблема, и для меня сработало установление позиции потока в 0, прежде чем отправить ее обратно клиенту.

2 голосов
/ 06 января 2011

Прежде всего, вы можете отладить сервис и посмотреть, содержит ли поток какие-либо данные на этой стороне, прежде чем он будет отправлен клиенту?

Я также возвращаю поток из моей службы WCF. У меня тоже была проблема, хотя и не совсем та. Надеюсь, решение, которое я нашел, поможет. Я нашел решение здесь . Это решение имеет дело с загрузкой потока, но реализация в моем сервисе загрузки работала нормально.
Мой SO вопрос / решение здесь (Мой собственный ответ - это тот, на который вы, вероятно, должны смотреть, а не принятый ответ, так как он специфичен для AJAX)

РЕДАКТИРОВАТЬ: Основные различия заключаются в том, что я обернул свой поток в MessageContract, где я указал поток в качестве единственного элемента сообщения, и атрибут привязки basicHttp «TransferMode» является «Потоковый». Я новичок в WCF, поэтому я не уверен, что это поможет, но я надеюсь, что это поможет!

РЕДАКТИРОВАТЬ 2 : Я бы не стал пользоваться сервисной ссылкой. Вы можете запустить (из командной строки cmd) 'svcutil.exe [mex url]', чтобы получить файл конфигурации и файл .cs, которые могут быть более точными, чем то, что вы получаете из справочника службы. У меня даже нет ссылки на сервис в моем проекте, и он работает нормально. Просто добавьте этот сгенерированный файл .cs в ваш проект и добавьте для него оператор использования. Кроме того, вы можете добавить параметры конфигурации в ваше приложение или файл веб-конфигурации на клиенте. Эти 2 сгенерированных файла создаются в каталоге, в котором вы запускаете команду svcutil.

Класс DownloadStreamFileRequest - это просто объект запроса, который клиент передает в base.Channel при вызове службы. В моем коде ниже он называется GetExportedFileRequest

В моем сгенерированном файле .cs у меня есть следующий метод, который возвращает System.IO.MemoryStream, и он получает этот поток из объекта FileDownloadMessage:

public System.IO.MemoryStream GetExportedFile()
{
    GetExportedFileRequest inValue = new GetExportedFileRequest();
    FileDownloadMessage retVal = ((IDailyBillingParser)(this)).GetExportedFile( inValue );
    return retVal.FileByteStream;
}
0 голосов
/ 24 ноября 2018

В случае, если кто-то ищет здесь, я по моей ошибке возвращал FileStream вместо Stream из моей службы WCF - это всегда возвращало пустой поток.Изменение типа возвращаемого значения в Stream решило мою проблему.

0 голосов
/ 06 января 2011

По какой причине вы хотите использовать " BinaryFormatter "? Если нет, вы можете вернуть поток из wcf следующим образом

вернуть новый FileStream (@ "D: \ yourFileName.txt", FileMode.Open, FileAccess.Read)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...