通过wcf将大文件流式传输到azure失败

时间:2016-02-16 22:32:00

标签: c# wcf azure

我需要将一个大文件上传到Azure存储。作为第一步,我试图通过wcf服务将文件上传到web服务文件夹。我按照此链接Streaming files over WCF中的步骤进行操作。我的服务代码:

namespace MilkboxGames.Services
{    
    [ServiceContract]
    public interface IFileUploadService
    {
        [OperationContract]
        UploadResponse Upload(UploadRequest request);
    }

    [MessageContract]
    public class UploadRequest
    {
        [MessageHeader(MustUnderstand = true)]
        public string BlobUrl { get; set; }

        [MessageBodyMember(Order = 1)]
        public Stream data { get; set; }
    }

    [MessageContract]
    public class UploadResponse
    {
        [MessageBodyMember(Order = 1)]
        public bool UploadSucceeded { get; set; }
    }
}

namespace MilkboxGames.Services
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]


    public class FileUploadService : IFileUploadService
    {
        #region IFileUploadService Members

        public UploadResponse Upload(UploadRequest request)
        {                                    
            try
            {                                                                                                        

                string uploadDirectory = System.AppDomain.CurrentDomain.BaseDirectory;

                string path = Path.Combine(uploadDirectory, "zacharyxu1234567890.txt");
                if (File.Exists(path))
                {
                    File.Delete(path);
                }

                const int bufferSize = 2048;
                byte[] buffer = new byte[bufferSize];
                using (FileStream outputStream = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    int bytesRead = request.data.Read(buffer, 0, bufferSize);
                    while (bytesRead > 0)
                    {
                        outputStream.Write(buffer, 0, bytesRead);
                        bytesRead = request.data.Read(buffer, 0, bufferSize);
                    }
                    outputStream.Close();
                }

                return new UploadResponse
                {
                    UploadSucceeded = true
                };
            }
            catch (Exception ex)
            {
                return new UploadResponse
                {
                    UploadSucceeded = false
                };
            }
        }

        #endregion
    }
}

的Web.config:

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>

  <system.web>
    <compilation debug="false" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" executionTimeout="600"    
    maxRequestLength="2097152" />
    <customErrors mode="Off"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="FileUploadServiceBinding" messageEncoding="Mtom" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="00:15:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00" transferMode="Streamed">
          <security mode="None">
            <transport clientCredentialType="None" />
          </security>  
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="MilkboxGames.Services.FileUploadService" behaviorConfiguration="FileUploadServiceBehavior">
        <endpoint address="" 
            binding="basicHttpBinding" contract="MilkboxGames.Services.IFileUploadService" bindingConfiguration="FileUploadServiceBinding">
        </endpoint>          
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="FileUploadServiceBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>

    <directoryBrowse enabled="true"/>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="2147483648" />
      </requestFiltering>
    </security>
  </system.webServer>

</configuration>

要使用此服务,我创建了一个控制台应用程序并将wcf服务添加到服务引用。我注意到服务方法变成了公共bool上传(字符串BlobUrl,System.IO.Stream数据)&#39;而不是公共UploadResponse上传(UploadRequest请求)&#39;。有人可以向我解释原因吗?

客户代码:

        string blobUrl = "assassinscreedrevelationsandroid/GT-I9100G/assassinscreedrevelationsandroid.apk";

        string fileName = "C:\\ws_new\\XuConsoleApplication\\XuConsoleApplication\\bin\\Debug\\motutcimac.myar"; 

        bool bUploadBlobResult;

        byte[] buffer = File.ReadAllBytes(fileName);

        Console.WriteLine("Size = " + buffer.Length);

        Stream fileStream = System.IO.File.OpenRead(fileName);

        FileUploadServiceClient objFileUploadServiceClient = new FileUploadServiceClient();

        bUploadBlobResult = objFileUploadServiceClient.Upload(blobUrl, fileStream);

我设法上传了一个123.8MB的文件。当我尝试上传354.6MB的文件时,我得到以下异常:

Unhandled Exception: System.InsufficientMemoryException: Failed to allocate
 a managed memory buffer of 371848965 bytes. The amount of available memory   
may be low. ---> System.OutOfMemoryException: Exception of type 
'System.OutOfMemoryException' was thrown.
    at System.Runtime.Fx.AllocateByteArray(Int32 size)
    --- End of inner exception stack trace ---

我无法弄清楚为什么会这样。任何帮助或建议都表示赞赏。

1 个答案:

答案 0 :(得分:0)

  

未处理的异常:System.InsufficientMemoryException:失败   分配371848965字节的托管内存缓冲区。大量的   可用内存可能很低。

以上消息表明您的应用正在耗尽允许的所有内存,为了增加限制,我认为您需要更大的属性值&#34; maxReceivedMessageSize&#34;

也来自另一个线程(Failed to allocate a managed memory buffer of 134217728 bytes. The amount of available memory may be low),它建议使用流传输模式进行大文件上传。

  

在WCF操作的消息合约中使用Stream属性进行传输   大物件。

[MessageContract]
public class DocumentDescription
{
    [MessageBodyMember(Namespace = "http://example.com/App")]
    public Stream Stream { get; set; }
}
Configure your binding this way

<binding name="Binding_DocumentService" receiveTimeout="03:00:00"
        sendTimeout="02:00:00" transferMode="Streamed" maxReceivedMessageSize="2000000">
    <security mode="Transport" />
</binding>