現在、WCF セルフホスト サービス (IIS なし) を使用して大容量データを送信しようとしているときに問題が発生しています。ストリーミングを使用して 500 MB を転送すると、System.OutOfMemoryException が発生してサービスがクラッシュします。このような量のデータを転送することは可能ですか?
私の WCF 構成は次のとおりです。
<system.serviceModel>
<services>
<service name="CIService" behaviorConfiguration="CIBehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:6547/CIService/CIService.svc" />
</baseAddresses>
</host>
<endpoint binding="netTcpBinding"
bindingConfiguration="netTcpBindingConfig"
behaviorConfiguration="CIBehavior.EndpointBehavior"
contract="CIService.ICreatable" />
<endpoint address="mex"
binding="mexHttpBinding"
name="mexTcpBinding"
contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment multippleSiteBindingEnabled="True" />
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfig" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="01:00:00" sendTimeout="00:10:00"
hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxConnections="10"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
transferMode="Streamed">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CIBehavior">
<serviceMetadata httpGetEnabled="False" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling maxConcurrentCalls="200" maxConcurrentInstances="2147483647" maxConcurrentSessions="100" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehavior>
<behavior name="CIBehavior.EndpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehavior>
</behaviors>
</system.serviceModel>
私のクライアント構成:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ICreatable"
closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="01:00:00" sendTimeout="00:10:00"
transactionFlow="false"
transferMode="Streamed"
transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard"
listenBacklog="10"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647"
maxConnections="10"
maxReceivedMessageSize ="2147483647">
<readerQuotas
maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" anabled="false" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint name="NetTcpBinding_ICreatable"
address="net.tcp://localhost:6547/CIService/CIService.svc"
binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_ICreatable"
behaviorConfiguration="CIBehavior.EndpointBehavior"
contract="ICreatable" />
</client>
<behaviors>
<endpointBehavior>
<behavior name="CIBehavior.EndpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehavior>
</behaviors>
</system.serviceModel>
ベストアンサー1
必要ありません最大バッファサイズまたは最大バッファプールサイズ高く設定しすぎると、メモリ不足例外が発生する可能性があります。 デフォルトのままで問題ありません。
チェックアウト大規模データとストリーミングMSDNのセクション大規模データに関する特別なセキュリティ上の考慮事項このテキスト部分は重要です
MaxBufferSize プロパティは、WCF がバッファリングするメモリを制限するために必要です。ストリーミング時には、このプロパティを安全な値に設定する (または既定値のままにする) ことが重要です。たとえば、サービスが最大 4 GB のサイズのファイルを受信してローカル ディスクに保存する必要があるとします。また、メモリが制限されており、一度にバッファリングできるのは 64 KB のデータだけであるとします。その場合、MaxReceivedMessageSize を 4 GB に、MaxBufferSize を 64 KB に設定します。また、サービス実装では、受信ストリームから 64 KB のチャンクのみを読み取り、前のチャンクがディスクに書き込まれてメモリから破棄されるまで次のチャンクを読み取らないようにする必要があります。
自己ホスト型サービスからコンソール クライアントにデータをストリーミングする非常にシンプルな例をまとめました。投稿を短くするために、サーバー コードとクライアントの一部のみを追加しました。
サービス契約
using System.IO;
using System.ServiceModel;
namespace Service
{
[ServiceContract]
public interface IStream
{
[OperationContract]
Stream GetLargeObject();
}
}
サービスの実装
using System;
using System.IO;
using System.ServiceModel;
namespace Service
{
[ServiceBehavior]
public class StreamService : IStream
{
public Stream GetLargeObject()
{
// Add path to a big file, this one is 2.5 gb
string filePath = Path.Combine(Environment.CurrentDirectory, "C:\\Temp\\BFBC2_PC_Client_R11_795745_Patch.exe");
try
{
FileStream imageFile = File.OpenRead(filePath);
return imageFile;
}
catch (IOException ex)
{
Console.WriteLine(String.Format("An exception was thrown while trying to open file {0}", filePath));
Console.WriteLine("Exception is: ");
Console.WriteLine(ex.ToString());
throw;
}
}
}
}
サービスメイン
using System;
using System.ServiceModel;
namespace Service
{
class Program
{
static void Main(string[] args)
{
try
{
using (var serviceHost = new ServiceHost(typeof(StreamService)))
{
serviceHost.Open();
Console.WriteLine("Press Any Key to end");
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
サービス app.config
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="StreamServiceBehavior">
<serviceMetadata httpGetEnabled="True" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="NewBinding0" transferMode="Streamed"/>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="StreamServiceBehavior" name="Service.StreamService">
<endpoint address="net.tcp://localhost:9000/streamserver" binding="netTcpBinding"
bindingConfiguration="NewBinding0" bindingName="" contract="Service.IStream" />
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/StreamService" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
サービスを起動します。ソケットを開くには、管理者アカウントで実行する必要がある場合があります。クライアント コンソール アプリケーションを作成し、URL http:// localhost:8080 / StreamService を使用してサービス参照を追加します。生成されたクライアントの名前空間として Service を使用します。
クライアントのメイン
using System;
using System.IO;
using Client.Service;
namespace Client
{
class Program
{
static void Main(string[] args)
{
try
{
using (StreamClient streamClient = new StreamClient())
{
streamClient.Open();
using (FileStream fileStream = new FileStream("c:\\temp\\bigfile.exe",FileMode.Create))
{
streamClient.GetLargeObject().CopyTo(fileStream);
}
}
Console.WriteLine("Press any key to end");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
生成されたクライアント設定ファイルを少し変更する必要があります。受信タイムアウトそして設定最大受信メッセージサイズ = "4294967295"
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IStream" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:30:00" sendTimeout="00:01:00"
transactionFlow="false" transferMode="Streamed" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
maxReceivedMessageSize="4294967295">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:9000/streamserver" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IStream" contract="Service.IStream"
name="NetTcpBinding_IStream">
</endpoint>
</client>
</system.serviceModel>
サービスを起動してからクライアントを起動します。問題なく大きなファイルをストリーミングできます。