IIS 网站上托管的 WCF 服务 TransferMode = Streamed 引发 w3wp.exe OutOfMemory 异常?

Posted

技术标签:

【中文标题】IIS 网站上托管的 WCF 服务 TransferMode = Streamed 引发 w3wp.exe OutOfMemory 异常?【英文标题】:WCF Service hosted on IIS website with TransferMode = Streamed throws w3wp.exe OutOfMemory exception? 【发布时间】:2011-08-19 17:07:05 【问题描述】:

我已经构建了一个 WCF 服务来上传和下载文件。

服务:托管在 IIS asp.net 网站上:

[ServiceContract]
public interface IFileTransferService

 [OperationContract(IsOneWay = true)]
 void Upload(FileTransferRequest request);


[MessageContract()]
public class FileTransferRequest

 [MessageHeader(MustUnderstand = true)]
 public string FileName;

 [MessageBodyMember(Order = 1)]
 public System.IO.Stream Data;



[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class FileTransferService : IFileTransferService

 public FileTransferService()
 
  HttpContext httpContext = HttpContext.Current;

  if (httpContext != null)
  
   httpContext.Response.BufferOutput = false;
  
 

 public void Upload(FileTransferRequest request)
 
  string fileName = System.Guid.NewGuid().ToString() + request.FileName;

  if (ConfigurationManager.AppSettings["UploadPath"] == null)
  
   throw new ApplicationException("Missing upload path");
  

  string uploadPath = "/OutputFeeds";
  string filePath = Path.Combine(Path.GetFullPath(HttpContext.Current.Server.MapPath(uploadPath)), fileName);

  FileStream fs = null;
  try
  
   fs = File.Create(filePath);
   byte[] buffer = new byte[1024];
   int read = 0;
   while ((read = request.Data.Read(buffer, 0, buffer.Length)) != 0)
   
    fs.Write(buffer, 0, read);
   
  
  finally
  
   if (fs != null)
   
    fs.Close();
    fs.Dispose();
   

   if (request.Data != null)
   
    request.Data.Close();
    request.Data.Dispose();
   
  
     

服务器配置:

<system.serviceModel>
 <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
  </serviceHostingEnvironment>
 <bindings>
  <basicHttpBinding>
  <binding name="HttpBinding_MTOM" messageEncoding="Mtom" transferMode="Streamed" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
   <security mode="None">
   <transport clientCredentialType="None" />
   </security>
  </binding>

 </bindings>
 <services>

  <service behaviorConfiguration="FileTransferServiceBehavior"
  name="FileTransferService">
  <endpoint address="" binding="basicHttpBinding" bindingConfiguration="HttpBinding_MTOM"
   contract="IFileTransferService">
   <identity>
   <dns value="localhost" />
   </identity>
  </endpoint>
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>

 </services>
 <behaviors>
  <serviceBehaviors>

  <behavior name="FileTransferServiceBehavior">
   <serviceMetadata httpGetEnabled="true" />
   <serviceDebug includeExceptionDetailInFaults="false" />
  </behavior>

  </serviceBehaviors>
 </behaviors>
 </system.serviceModel>

客户端:从控制台应用程序调用上述服务:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
  <bindings>
   <basicHttpBinding>
    <binding name="BasicHttpBinding_IFileTransferService" 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="2147483647" maxReceivedMessageSize="2147483647"
     messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed"
     useDefaultWebProxy="true">
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
      maxBytesPerRead="4096" maxNameTableCharCount="16384" />
     <security mode="None">
      <transport clientCredentialType="None" proxyCredentialType="None"
       realm="">
       <extendedProtectionPolicy policyEnforcement="Never" />
      </transport>
      <message clientCredentialType="UserName" algorithmSuite="Default" />
     </security>
    </binding>

   </basicHttpBinding>
  </bindings>
  <client>
   <endpoint address="http://ht/FileTransferService.svc" binding="basicHttpBinding"
    bindingConfiguration="BasicHttpBinding_IFileTransferService"
    contract="HobbyTown.IFileTransferService" name="BasicHttpBinding_IFileTransferService" />

  </client>
 </system.serviceModel>
</configuration>

客户端上传代码:

 string inputFile = @"C:\Client\InputFeeds\FullInventory.zip";
 using (FileStream fs = new FileStream(inputFile, FileMode.Open))
 
    FileTransferServiceClient proxy = new FileTransferServiceClient();
    proxy.Upload("Inventory.Zip", fs);
    //proxy.Upload(trIn);
 

注意:如果我在客户端将传输模式更改为缓冲它可以工作,但是如果将客户端上的传输模式设置为流式传输它不会并引发内存不足错误。

另一个post for same problem

【问题讨论】:

客户端的文件流不使用using会怎样? 【参考方案1】:

我想知道流是否没有被强制表现为在服务端缓冲。 FileTransferRequest 是什么——是第三方吗? WCF 中的流式处理通常要求流是您公开的服务方法中的唯一参数。

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

"请注意,将第二个参数添加到以下 Echo 或 ProvideInfo 操作会导致服务模型恢复为缓冲策略并使用流的运行时序列化表示。只有具有单个输入流参数的操作是兼容的具有端到端的请求流。

这条规则同样适用于消息合约。如以下消息协定所示,您的消息协定中只能有一个主体成员,即流。如果您想与流通信附加信息,则此信息必须是在消息头中携带的。消息正文专为流内容保留。”

【讨论】:

FileTransferRequest 是示例中显示的消息契约,并且定义正确。 @andrewbadera 就像 Ladislav 提到的......FilesTransferRequest 是消息合同,当客户端上的传输模式设置为“缓冲”并在服务器上设置为“流式”时,它确实有效。 @Ladislav Mrnka ...我希望双方都是流传输模式 对; msdn.microsoft.com/en-us/library/ms733742.aspx -- 现在在上面引用。 但是消息只有第二个参数。第二个参数是始终缓冲的自定义soap标头。这不会中断通过 http 的流式传输。 @andrewbadera 我根据您的建议更改了服务合同,但是它没有工作并且同样的例外。

以上是关于IIS 网站上托管的 WCF 服务 TransferMode = Streamed 引发 w3wp.exe OutOfMemory 异常?的主要内容,如果未能解决你的问题,请参考以下文章

WCF服务的IIS托管(网站托管)

WCF 托管在 IIS6 上

防火墙后面的 WCF WebService / IIS 托管和配置问题

WCF服务的IIS托管(应用程序)

在 IIS 中托管 WCF 服务时协议映射错误

如何从 IIS 托管的 WCF 服务启动进程?