大二进制 (byte[]) 通过 WCF 传输文件
Posted
技术标签:
【中文标题】大二进制 (byte[]) 通过 WCF 传输文件【英文标题】:Large Binary (byte[]) File transfer through WCF 【发布时间】:2011-08-27 04:08:27 【问题描述】:我正在尝试构建一个 WCF 服务,允许我将大型二进制文件从客户端发送到服务。
但是,我只能成功传输最大 3-4MB 的文件。 (当我尝试传输 4.91MB 以及其他任何内容时失败了)
我尝试发送 4.91MB 文件时遇到的错误是:
异常消息:接收到http://localhost:56198/Service.svc 的 HTTP 响应时出错。这可能是由于服务端点绑定未使用 HTTP 协议。这也可能是由于服务器中止了 HTTP 请求上下文(可能是由于服务关闭)。有关详细信息,请参阅服务器日志。
内部异常消息:底层连接已关闭:接收时发生意外错误。
内部异常消息:无法从传输连接读取数据:现有连接被远程主机强行关闭。
内部异常消息:现有连接被远程主机强行关闭
只要将 byte[] 文件作为方法参数发送到公开的服务方法,就会在客户端发生此错误。
我在服务方法的第一行有一个断点,以防文件传输成功(低于 3MB),该断点被命中并且文件被传输。但是在这种情况下,只要调用该方法,就会出现错误。如果出现此错误,则不会命中服务中的断点。
我将粘贴我的 Service Web.config 和 Asp Page (Client) Web.config 部分。如果您还需要发送文件并接受文件的代码,请告诉我,我也会发送。
服务 Web.Config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpEndpointBinding" closeTimeout="01:01:00"
openTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedRequest"
useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="DragDrop.Service.ServiceBehavior" name="DragDrop.Service.Service">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpEndpointBinding" contract="DragDrop.Service.IService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DragDrop.Service.ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
客户端(Asp.net 页面)Web.Config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483646" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedResponse"
useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646"
maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="">
<extendedProtectionPolicy policyEnforcement="Never" />
</transport>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="debuggingBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://localhost:56198/Service.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference.IService"
name="BasicHttpBinding_IService" behaviorConfiguration="debuggingBehaviour" />
</client>
</system.serviceModel>
【问题讨论】:
抱歉正在编辑(有些我的服务配置没有显示出来......)仍然需要任何 c# 代码......??? 我已经解决了这个问题:***.com/questions/998927/… 【参考方案1】:(虽然我同意streaming transfer 更可取,但下面的内容应该可以使其正常工作而无需任何其他更改)
您还需要在 Web.config 中增加最大消息长度:
<configuration>
<system.web>
<httpRuntime maxMessageLength="409600"
executionTimeoutInSeconds="300"/>
</system.web>
</configuration>
这会将最大消息长度设置为 400 MB(参数以 kB 为单位)。更多信息请查看this MSDN page。
【讨论】:
谢谢......它工作......我刚刚测试了一个 30MB 的文件,它正在工作,我会做一个 1-2GB 的测试,然后看看它是怎么回事,但现在,我的问题得到了回答....非常感谢。 对于 1-2GB,我会认真考虑查看流媒体功能,而不是使用byte[]
。一方面,.NET 框架甚至无法分配这样大小的数组,更不用说传输它们了。
我没明白。您的意思是我应该以块的形式传输文件(并且每个块都通过流传输,就像我们在上面对 30MB 所做的那样)。然后当所有块都到达服务器时,将它们连接在一起......这会起作用吗,或者他们有更好的方法吗?
或者你的意思是你在上面分享的链接中解释的方式:msdn.microsoft.com/en-us/library/ms789010.aspx
无意劫持这个答案,但我添加了一个答案,表明:-) 基本上,您“返回”Stream
而不是byte[]
。祝你好运!【参考方案2】:
正如所指出的,尝试使用Streaming Transfer,这里有一些示例代码显示了使用流传输发送和接收(可能)大量数据。
像这样使用绑定,注意MaxReceivedMessageSize
和TranferMode
设置。
<binding name="Streaming_Binding" maxReceivedMessageSize="67108864"
messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed">
</binding>
添加一些服务代码:
[OperationContract]
public Stream GetLargeFile()
return new FileStream(path, FileMode.Open, FileAccess.Read);
[OperationContract]
public void SendLargeFile(Stream stream)
// Handle stream here - e.g. save to disk
ProcessTheStream(stream);
// Close the stream when done processing it
stream.Close();
还有一些客户端代码:
public Stream GetLargeFile()
var client = /* create proxy here */;
try
var response = client.GetLargeFile();
// All communication is now handled by the stream,
// thus we can close the proxy at this point
client.Close();
return response;
catch (Exception)
client.Abort();
throw;
public void SendLargeFile(string path)
var client = /* create proxy here */;
client.SendLargeFile(new FileStream(path, FileMode.Open, FileAccess.Read));
另外,请确保您没有超时,大文件可能需要一段时间才能传输(但默认的 receiveTimeout 是 10 分钟)。
您可以下载 Microsoft WCF/WF 示例代码 here(顶部 C# 链接在撰写本文时已损坏,但其他示例代码似乎还可以)。
【讨论】:
谢谢 Jakob,我有点明白你的答案,但我在这里不明白的是,你正在从服务返回一个流给客户端。我想要反过来,客户端会将大文件上传到服务器.....还是我的回答有误? 啊哈,对不起,错过了,嗯,这或多或少是一个逆转过程的问题。添加了代码来证明这一点! 正确!我更改了名称以避免将来混淆。 样本链接像往常一样被破坏(不是你的错) @Veverke:谢谢,更新了链接,尽管示例页面仍然有些损坏【参考方案3】:您是否了解过使用流式传输?
Windows 通信基础 (WCF) 可以使用任一发送消息 缓冲或流传输。在里面 默认缓冲传输模式,a 消息必须完全传递 在接收器可以读取它之前。在 流传输模式,接收器 可以开始处理消息 在它完全交付之前。这 流模式是有用的,当 传递的信息很长 并且可以串行处理。 流模式也很有用,当 消息太大而不能完全 缓冲。
http://msdn.microsoft.com/en-us/library/ms789010.aspx
【讨论】:
我使用“Streamed”作为传输模式。在我的服务器 Web.config 我有: messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed" 在上面的配置中我有 transferMode="StreamedRequest",我也试过了,但是也没用 您还需要修改您的合约以使用 Stream 对象。 我正在尝试添加传输模式,但在 web.config 文件中它给出了错误。【参考方案4】:我会回应其他人所说的,并说使用流传输是使用 Windows Communication Foundation 时要走的路。下面是一个很好的指南,它解释了通过 WCF 流式传输文件的所有步骤。它非常全面且内容丰富。
这里是:Guide on Streaming Files over WCF。
【讨论】:
以上是关于大二进制 (byte[]) 通过 WCF 传输文件的主要内容,如果未能解决你的问题,请参考以下文章