难以使用WCF上传大文件

010*_*101 19 c# iis wcf

关于此,还有许多其他类似的问题.不幸的是,许多人似乎在某些方面相互欺骗.我希望这个会帮助别人并解决其他问题.

我的项目要求是通过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
Run Code Online (Sandbox Code Playgroud)

马上就可以了,我们需要使用某种流式传输或分块文件传输. 我用过这个样本.

该示例描述了一种使用.NET Stream对象的方法.使用流对象的一个​​副作用是必须使用Message contract.将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.
Run Code Online (Sandbox Code Playgroud)

经过大量的搜索和实验,很明显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>
Run Code Online (Sandbox Code Playgroud)

没有任何工作可言,1MB文件现在通过没有问题.

为了传递大于4MB的文件,您必须调整IIS中的web.config中的设置(WCF服务的服务器端) Microsoft的这篇文章解释了该设置是什么. 例如,如果您将其设置为8192,那么您将能够上传5MB文件,但不能更大.

<httpRuntime maxRequestLength="8192" />
Run Code Online (Sandbox Code Playgroud)

我设置了一些淫秽的测试 - 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.
Run Code Online (Sandbox Code Playgroud)

这张海报很好地描述了这个问题的解释.

想想这样.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>
Run Code Online (Sandbox Code Playgroud)

关键是安全模式. 它默认设置为"消息".该值由服务器上设置的任何值拾取.默认情况下,您的服务器使用消息级别安全性.

如果您尝试在服务器上强制它像这样:

 <security mode="None">
Run Code Online (Sandbox Code Playgroud)

你收到这个错误:

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.
Run Code Online (Sandbox Code Playgroud)

(我记得更新客户端代理)

所以,这就是它代表我的地方......帮助!

Shi*_*iji 0

好详细的问题:)

您的最后一条错误消息是 404 文件未找到。通常这是因为文件丢失或站点已关闭。检查这一点只是为了排除这种情况。

  • 尝试浏览到您的 svc 文件
  • 测试它是否仍然适用于较小的文件。

根据上次更改,您已关闭基于消息的加密。此更改需要在客户端和服务器上完成。如果一侧正在加密,而另一侧不希望消息被加密,那么就会感到困惑。