title: Serialization error when calling a MTOM streamed file upload asynchronously
body: <p>I'm calling a WCF (non-REST) based asynchronous (async) binary file upload service, which I built using "MTOM" and "Streamed" web.config parameters. The environment is ASP.NET MVC 3, .NET 4, IIS 7.5, VS2010.</p>
  
  <p>The service tries to upload a binary file e.g. zip, pdf or doc. With non-async approach all works fine. But when I'm calling this async service I got this error message on client-side:</p>
  
  <blockquote>
    <p>There was an error while trying to serialize parameter <a href="http://tempuri.org/:dataStream" rel="nofollow">http://tempuri.org/:dataStream</a>. The InnerException message was 'Type 'System.IO.FileStream' with data contract name 'FileStream:http://schemas.datacontract.org/2004/07/System.IO' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.</p>
  </blockquote>
  
  <p>Because of the async approach I have to override the WCF constraint concerning streams: either a single param of type Stream or a single param of type MessageContract would be accepted as type within a service method. This approach works fine when working in non-async manner.</p>
  
  <p>To get the whole picture en detail I'm presenting all (relevant) parts of code so far:</p>
  
  <p><strong>Server:</strong></p>
  
  <p>Service contract interface, IUploadService:</p>
  
  <pre><code>[ServiceContract]
  public interface IUploadService
  {
     [OperationContract(AsyncPattern = true)]
     IAsyncResult BeginUpload(CompletedAsyncUploadResult dataStream, AsyncCallback callback, object state);
  
     int EndUpload(IAsyncResult result);  
  }
  </code></pre>
  
  <p>Container class that wraps the stream and a meta data field, e.g. fileName:</p>
  
  <pre><code>[DataContract]
  [KnownType(typeof(Stream))]   
  public class StreamUploadContainer
  {
          [DataMember]
          public string fileName;
          [DataMember]    
          public Stream content;   
  }
  </code></pre>
  
  <p>IAsyncResult derived class that embeds StreamUploadContainer as Data member:</p>
  
  <pre><code>// Simple async result implementation.
  public  class CompletedAsyncUploadResult : IAsyncResult
  {
      private StreamUploadContainer data;
      public StreamUploadContainer Data
      {
          get { return data; }
          set { data = value; }
      }
  
      public object AsyncState
      { get { return (object)data; } }
  
      public WaitHandle AsyncWaitHandle
      { get { throw new Exception("The method or operation is not implemented."); } }
  
      public bool CompletedSynchronously
      { get { return true; } }
  
      public bool IsCompleted
      { get { return true; } }
  }
  </code></pre>
  
  <p>Service class UploadService.svc:</p>
  
  <pre><code>[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] 
  public class UploadService : IUploadService
  {
      public IAsyncResult BeginUpload(CompletedAsyncUploadResult dataStream, AsyncCallback callback, object state)
      {
          string retVal = "All went ok.";
          try
          {
              string docFolderPath = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, @"App_Data/Scanning/");
              using (FileStream outputStream = File.Create(Path.Combine(docFolderPath, dataStream.Data.fileName)))
              {
                  dataStream.Data.content.CopyTo(outputStream);
              }
              dataStream.Data.content.Close();
          }
          catch (Exception)
          {
              dataStream.Data.content.Close();
              retVal = "Somethin went wrong.";
          }
          CompletedAsyncUploadResult retValContract = new CompletedAsyncUploadResult();
          retValContract.Data = new StreamUploadContainer();
          retValContract.Data.fileName = retVal;
          retValContract.Data.content = Stream.Null;
          return retValContract;
      }
  
      public int EndUpload(IAsyncResult result)
      {
          return 0;
      }
  }
  </code></pre>
  
  <p>WCF service markup file:</p>
  
     
  
  <p>Web.config:</p>
  
  <pre><code>&lt;system.serviceModel&gt;
      &lt;bindings&gt;
      &lt;basicHttpBinding&gt;
        &lt;binding name="BasicHttpBinding_IUploadService" messageEncoding="Mtom" transferMode="Streamed" maxReceivedMessageSize="2147483647"&gt;
         &lt;security mode="None"&gt;
           &lt;transport clientCredentialType="None" /&gt;
         &lt;/security&gt;
        &lt;/binding&gt;
      &lt;/basicHttpBinding&gt;
      &lt;/bindings&gt;
      &lt;services&gt;
        &lt;service name="WcfUploadServiceProject.WcfServices.FileStreamUpload.UploadService" behaviorConfiguration="defaultBehaviour"&gt;
          &lt;endpoint binding="basicHttpBinding" contract="WcfUploadServiceProject.WcfServices.FileStreamUpload.IUploadService" bindingConfiguration="BasicHttpBinding_IUploadService"&gt;&lt;/endpoint&gt;
        &lt;/service&gt;
      &lt;/services&gt;
      &lt;behaviors&gt;
        &lt;serviceBehaviors&gt;
          &lt;behavior name="defaultBehaviour"&gt;
            &lt;serviceMetadata httpGetEnabled="true" /&gt;
            &lt;serviceDebug includeExceptionDetailInFaults="true"/&gt;
          &lt;/behavior&gt;
        &lt;/serviceBehaviors&gt;
      &lt;/behaviors&gt;
  &lt;/system.serviceModel&gt;
  </code></pre>
  
  <p><strong>Client:</strong></p>
  
  <p>Calling the service asynchronously</p>
  
  <pre><code>private void Upload()
  {
      UploadBinaryService.IUploadService client = new UploadBinaryService.UploadServiceClient();
      UploadBinaryService.StreamUploadContainer contract = new UploadBinaryService.StreamUploadContainer();
      contract.content = this.GetStreamSample(@"c:\temp\balloon.zip");
      contract.fileName = "balloon.zip";
  
      UploadBinaryService.CompletedAsyncUploadResult result = new UploadBinaryService.CompletedAsyncUploadResult();
      result.Data = contract;
      client.BeginUpload(result, FileStreamBinaryUploadAsyncServiceCallback, client);
  }
  
  public void FileStreamBinaryUploadAsyncServiceCallback(IAsyncResult result)
  {
      var proxy = result.AsyncState as UploadBinaryService.IUploadService;
      if (proxy != null)
      {
          var value = proxy.EndUpload(result);
      }
  }
  </code></pre>
  
  <p>App.config:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
  &lt;configuration&gt;
      &lt;system.serviceModel&gt;
          &lt;bindings&gt;
              &lt;basicHttpBinding&gt;
                &lt;binding name="BasicHttpBinding_IUploadService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed" useDefaultWebProxy="true"&gt;
                      &lt;readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /&gt;
                      &lt;security mode="None"&gt;
                          &lt;transport clientCredentialType="None" proxyCredentialType="None" realm="" /&gt;
                          &lt;message clientCredentialType="UserName" algorithmSuite="Default" /&gt;
                      &lt;/security&gt;
                  &lt;/binding&gt;
              &lt;/basicHttpBinding&gt;
          &lt;/bindings&gt;
          &lt;endpoint address="http://example.com/WcfServices/FileStreamUpload/UploadService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUploadService" contract="UploadBinaryService.IUploadService" name="BasicHttpBinding_IUploadService" /&gt;
          &lt;/client&gt;
      &lt;/system.serviceModel&gt;
  &lt;/configuration&gt;
  </code></pre>