【发布时间】:2011-11-13 17:09:38
【问题描述】:
关于这个,还有许多其他类似的问题。不幸的是,许多人似乎在某些方面互相欺骗。我希望这个可以帮助其他人并解决其他问题。
我的项目要求是通过 IIS 将 250MB 文件上传到 IIS 中托管的后端 WCF 服务。我为 IIS 中托管的后端 WCF 服务创建了一些单元测试。它们是:
1) Upload 1MB File
2) Upload 5MB File
3) Upload 10MB file
4) Upload 20MB File
5) Upload 200MB File
马上,很明显我们需要使用某种流式传输或分块文件传输。 I used this sample.
该示例描述了一种使用 .NET Stream 对象的方法。使用流对象的一个副作用是您必须使用消息契约。将 Stream 放在函数的参数列表中是不够的。所以我们这样做了。
默认情况下,此 WCF 服务的 web.config 非常精简。没有任何效果:
System.ServiceModel.ProtocolException: The remote server returned an unexpected response: (400) Bad Request. ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.
经过大量搜索和试验,很明显BasicHttpBinding与Stream对象和MessageContract的这种组合是不兼容的。 我们必须切换到 WSHttpBinding。
为此,服务器的 web.config 在以下部分变得稍微复杂一些:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
</behavior>
<behavior name="FileServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500" maxConcurrentInstances="500"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<wsHttpBinding>
<binding name="FileServiceBinding" closeTimeout="10:01:00"
maxBufferPoolSize="104857600"
maxReceivedMessageSize="104857600" openTimeout="10:01:00"
receiveTimeout="10:10:00" sendTimeout="10:01:00"
messageEncoding="Mtom">
<readerQuotas maxDepth="104857600" maxStringContentLength="104857600"
maxArrayLength="104857600" maxBytesPerRead="104857600"
maxNameTableCharCount="104857600" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="FileServiceBehavior" name="OMS.Service.FileService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="FileServiceBinding" contract="OMS.Service.IFileService"></endpoint>
</service>
</services>
</system.serviceModel>
不用多说,1MB 的文件现在可以顺利通过了。
为了让大于 4MB 的文件通过,您必须在 IIS(WCF 服务的服务器端)的 web.config 中调整一个设置This article from Microsoft explains what that setting is. 例如,如果您将其设置为 8192,那么您'将能够上传 5MB 的文件,但不能上传更大的文件。
<httpRuntime maxRequestLength="8192" />
我将我的设置为淫秽的东西进行测试 - 2147483647。前 4 个文件通过了这个门。
这 200MB 没有机会进入这个大门,原因如下:
System.InsufficientMemoryException: Failed to allocate a managed memory buffer of 279620368 bytes. The amount of available memory may be low. ---> System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
这个问题的解释描述的很好,by this poster。
这样想。 200MB 的文件从未从客户端中取出。它必须由客户端完全加载,加密然后传输到服务器。
当您使用 Visual Studio 2010 为服务生成代理类时,它会将一些内容放入您的 app.config。对我来说,它看起来像这样:
<binding
name="Binding_IFileService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Mtom"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true" />
</security>
</binding>
关键是安全模式。默认设置为“消息”。该值由服务器上设置的任何内容获取。默认情况下,您的服务器使用消息级安全性。
如果你试图在服务器上强制它是这样的:
<security mode="None">
你得到这个错误:
System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at http://localhost:8080/oms/FileService.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
(我确实记得更新客户端代理)
所以,这就是它代表我的地方......帮助!
【问题讨论】:
-
没有答案,但流式处理适用于 BasicHttpBinding 和消息协定。在那个阶段没有看到您的 .config,我无法告诉您是什么导致了您的 400...
-
这不是一个真正的答案,但是当我在绑定和端点配置方面遇到问题时,我会使用 VS2010 中的工具来帮助使 XML 不那么混乱。转到“工具”->“WCF 服务配置编辑器”。您可以使用它来编辑客户端和主机配置。正如答案中已经提到的,两者都需要匹配,否则您将收到端点未找到错误或安全错误。顺便说一句,很好的详细问题!
-
也没有答案。如何为 NetTcpBinding 做到这一点?我不想提出一个重复的问题......有什么想法吗?