Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Large Binary (byte[]) File transfer through WCF

Tags:

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> 
like image 726
user402186 Avatar asked May 17 '11 11:05

user402186


2 Answers

(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.

like image 140
Thorarin Avatar answered Nov 01 '22 21:11

Thorarin


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).

like image 34
Jakob Möllås Avatar answered Nov 01 '22 23:11

Jakob Möllås