Large Binary (byte[]) File transfer through WCF

2020-02-02 08:35发布

I am trying to build a WCF service that allows me to send large binary files from clients to the service.

However I am only able to successfully transfer files up to 3-4MB. (I fail when I try to transfer 4.91MB and, off course, anything beyond)

The Error I get if I try to send the 4.91MB file is:

Exception Message: An error occurred while receiving the HTTP response to http://localhost:56198/Service.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.

Inner Exception Message: The underlying connection was closed: An unexpected error occurred on a receive.

Inner Exception Message: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

Inner Exception Message: An existing connection was forcibly closed by the remote host

This error occurs at client side as soon as the byte[] file is sent as a method parameter to the exposed service method.

I have a breakpoint at the service method's first line, in case of successful file transfers (below 3MB) that break point is hit and the file gets transferred. However in this case as soon as the method is called, the error comes. The breakpoint in the service is not hit in case of this error.

I am going to paste my sections of my Service Web.config and Asp Page (Client) Web.config. If you also require the code that send the file and accepts the file, let me know, I'll send that as well.

Service 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>

Client (Asp.net page) 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>

4条回答
霸刀☆藐视天下
2楼-- · 2020-02-02 08:43

Have you had a look at using Streaming Transfer?

Windows Communication Foundation (WCF) can send messages using either buffered or streamed transfers. In the default buffered-transfer mode, a message must be completely delivered before a receiver can read it. In streaming transfer mode, the receiver can begin to process the message before it is completely delivered. The streaming mode is useful when the information that is passed is lengthy and can be processed serially. Streaming mode is also useful when the message is too large to be entirely buffered.

http://msdn.microsoft.com/en-us/library/ms789010.aspx

查看更多
淡お忘
3楼-- · 2020-02-02 08:57

As pointed out, try using Streaming Transfer, here's some example code showing both sending and receiving (possibly) large amounts of data using streamed transfer.

Use a binding like this, notice the MaxReceivedMessageSize and TranferMode settings.

<binding name="Streaming_Binding" maxReceivedMessageSize="67108864"  
    messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed">
</binding>

Add some service code:

[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();
}

And some client code:

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));
}

Also, make sure you are not getting a timeout, a large file might take a while to transfer (the default receiveTimeout is 10 minutes though).

You can download Microsoft WCF/WF sample code here (top C# link is broken at the time of writing but other samples code seems ok).

查看更多
走好不送
4楼-- · 2020-02-02 08:58

(While I agree that streaming transfer would be preferrable, the below should make it work without any other changes)

You also need to increase the maximum message length in the Web.config:

<configuration>
  <system.web>
  <httpRuntime maxMessageLength="409600"
    executionTimeoutInSeconds="300"/>
  </system.web>
</configuration>

This will set the maximum message length to 400 MB (parameter is in kB). Check this MSDN page for more information.

查看更多
Fickle 薄情
5楼-- · 2020-02-02 08:58

I'll echo what others have said and say that using a Streaming Transfer is the way to go when using Windows Communication Foundation. Below is an excellent guide that explains all of the steps in order to stream files over WCF. It's quite comprehensive and very informative.

Here it is: Guide on Streaming Files over WCF.

查看更多
登录 后发表回答