【问题标题】:WCF Stream.Read always returns 0 in clientWCF Stream.Read 总是在客户端返回 0
【发布时间】:2011-01-05 21:48:35
【问题描述】:

我一天中的大部分时间都在试图弄清楚为什么这不起作用。我有一个将对象流式传输到客户端的 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 已创建,但其大小为 0KB。

我错过了什么?


更新
人力资源管理系统。好吧,我无法调试它,因为当我尝试它时它告诉我 WCF 测试客户端不支持 Streams。但是,我知道有些东西正在流中传递,因为如果我不放置 while 循环,而只有一个 fs.Write(...),一旦流关闭,它将写入 8KB。所以有些事情正在发生。

我看了你的帖子并补充道:

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

到我的 IStreamService。 downloadStreamFile() 现在返回一个 FileDownloadMessage 对象。

但在我的客户端更新服务引用后,它认为downloadStreamFile() 返回一个TestApp.StreamServiceRef.MemoryStream 对象。
它还创建了一个 downloadStreamFileRequest() 类,我没有创建它,也不知道它来自哪里。

【问题讨论】:

    标签: c# wcf streaming wcf-streaming


    【解决方案1】:

    我也遇到了这个问题,对我有用的是将流的位置设置为 0,然后再将其发送回客户端。

    【讨论】:

    • 我知道我不应该在 cmets 中说谢谢,但说真的,非常感谢。你是传奇
    • 它总是让你绊倒的愚蠢的东西
    【解决方案2】:

    首先,您能否调试服务并查看流在发送到客户端之前是否包含该端的任何数据?

    我也从我的 WCF 服务返回一个流。我也遇到了问题,虽然不是完全相同的问题。希望我找到的解决方案会有所帮助。我找到了解决方案here。此解决方案正在处理上传流,但我的下载服务中的实现工作正常。
    我的 SO 问题/解决方案是 here(我自己的答案是您可能应该查看的答案,而不是特定于 AJAX 的公认答案)

    编辑:基本区别在于我将 Stream 包装在 MessageContract 中,在其中我将 Stream 指定为消息的唯一成员,并且 basicHttp 绑定“transferMode”属性是“Streamed”。我是 WCF 的新手,所以我不确定这是否会有所帮助,但我希望它会有所帮助!

    编辑 2: 我不会使用服务参考。您可以运行(从 cmd 提示符)“svcutil.exe [mex url]”来获取配置文件和 .cs 文件,这可能比从服务参考中获得的更准确。我的项目中什至没有服务参考,它工作正常。只需将生成的 .cs 文件添加到您的项目中并为此添加“使用”语句。此外,您可以将配置设置添加到客户端上的应用程序或 Web 配置文件中。这 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;
    }
    

    【讨论】:

    • 我不会使用服务参考。您可以运行(从 cmd 提示符)“svcutil.exe [mex url]”来获取配置文件和 .cs 文件,这可能比您从服务参考中获得的更准确。我的项目中什至没有服务参考,它工作正常。只需将生成的 .cs 文件添加到您的项目中并为此添加“使用”语句。编辑:另外,您可以将配置设置添加到客户端上的应用程序或 Web 配置文件中。这 2 个生成的文件是在您运行 svcutil 命令的目录中创建的。
    • 谢谢。我使用 svcutil 进行“参考”,并在代码中完成了所有配置。我最终也将流作为文件流而不是内存流发送,出于某种原因,这似乎有所帮助。
    【解决方案3】:

    他们有什么理由要使用“BinaryFormatter”吗?如果没有,你可以像这样从 wcf 返回流

    return new FileStream(@"D:\yourFileName.txt", FileMode.Open, FileAccess.Read)

    【讨论】:

    • 我使用了BinaryFormatter,因为我放入流中的对象在内存中;它尚未写入磁盘。
    【解决方案4】:

    如果有人在这里搜索,我的错误是从我的 WCF 服务返回 FileStream 而不是 Stream - 这总是返回一个空流。将返回类型更改为 Stream 解决了我的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多