元々:
シナリオ:
コード:
[DataContract(IsReference=true)]
public class Message
{
[DataMember]
public string TopicName { get; set; }
[DataMember]
public string EventData { get; set; }
[DataMember]
public SerializableDictionary<string, FuturesLineAsset> FuturesLineDictionary { get; set ; }
}
思考:
親:
public class FuturesAsset
{
public string AssetName { get; set; }
public BindableDictionary<string, FuturesLineAsset> AssetLines { get; private set; }
public FuturesAsset()
{
AssetLines = new BindableDictionary<string, FuturesLineAsset>();
}
public FuturesAsset(string assetName)
{
AssetLines = new BindableDictionary<string, FuturesLineAsset>();
AssetName = assetName;
}
}
子:
public class FuturesLineAsset
{
public string ReferenceAsset { get; set; }
public string MID { get; set; }
public double LivePrice { get; set; }
public DateTime UpdateTime { get; set; }
public DateTime LastContributedTime { get; set; }
public double Spread { get; set; }
public double Correlation { get; set; }
public DateTime Maturity { get; set; }
public double ReferenceCurve { get; set; }
public FuturesLineAsset(string mID, string referenceAsset, double livePrice)
{
MID = mID;
ReferenceAsset = referenceAsset;
ReutersLivePrice = livePrice;
}
}
この例外は、循環参照とは関係ありません。大量のデータをネットワーク経由で送信しようとすると、純粋にタイムアウトします。
WCFに付属するデフォルト値は非常に低い(これらはWCF 4で変更されたと思う)。次の2つのブログ投稿を読んでください。サービスのスロットルを解除する方法についてのアイデアが得られるはずです。
Wcfサービスを調整し、DoS攻撃を防ぎ、Wcfのスケーラビリティを維持する方法
Update:また、WCF構成には多数の異なるタイムアウトがあり、それがあなたが話しているクライアントまたはサーバーであるかどうかに応じて、更新する必要があります別のタイムアウト句...これを読んでください thread それぞれが何を意味するかについて、あなたはあなたがどれを上げる必要があるかを理解できるはずです。 または、呼び出しが完了するまでに長い時間がかかるかどうかを本当に気にしない場合は、すべてのタイムアウトをint.maxに設定することができます。
このエラーは、さまざまな原因で発生する可能性があります。この場合はタイミングの問題でしたが、通常はタイミングとは関係ありません特にエラーがすぐに受信された場合。考えられる理由は次のとおりです。
Windows Service HostインストーラーのOnStartイベントから呼び出されていた長い初期化プロセスでこの問題が発生しました。 TCPバインディングのセキュリティモードとタイムアウトを設定することにより修正されました。
// Create a channel factory.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Transport;
b.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
b.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
b.MaxReceivedMessageSize = 1000000;
b.OpenTimeout = TimeSpan.FromMinutes(2);
b.SendTimeout = TimeSpan.FromMinutes(2);
b.ReceiveTimeout = TimeSpan.FromMinutes(10);
この問題は、WCFクライアントを使用した後、WCFクライアントをクリーンアップしないことが原因の場合もあります。このシステムでは、すべての関数呼び出しをシステムにラップするとともに、使い捨てパターンを使用して、適切なクリーンアップとログ記録を可能にします。次のクラスのバージョンを使用します。
public class WcfWrapper : IDisposable
{
private readonly OperationContextScope _operationContextScope;
private readonly IClientChannel _clientChannel;
public WcfWrapper(IClientChannel clientChannel)
{
_clientChannel = clientChannel;
_operationContextScope = new OperationContextScope(_clientChannel);
}
public void Dispose()
{
_operationContextScope.Dispose();
}
public T Function<T>(Func<T> func)
{
try
{
var result = func();
_clientChannel.Close();
return result;
}
catch (Exception ex)
{
KTrace.Error(ex);
_clientChannel.Abort();
throw;
}
}
public void Procedure(Action action)
{
try
{
action();
_clientChannel.Close();
}
catch (Exception ex)
{
KTrace.Error(ex);
_clientChannel.Abort();
throw;
}
}
}
}
サービスに対して行うWCF呼び出しはすべて、次のような定義済みのインターフェイスクラスを介して行われます。
public sealed class WcfLoginManager : ILoginManager
{
private static LoginManagerClient GetWcfClient()
{
return
new LoginManagerClient(
WcfBindingHelper.GetBinding(),
WcfBindingHelper.GetEndpointAddress(ServiceUrls.LoginManagerUri));
}
public LoginResponse Login(LoginRequest request)
{
using(var loginManagerClient = GetWcfClient())
using (var slice = new WcfWrapper(loginManagerClient.InnerChannel))
{
DSTicket ticket;
DSAccount account;
return slice.Function(() => new LoginResponse(loginManagerClient.Login(request.accountName, request.credentials, out ticket, out account), ticket, account));
}
}
}
このパターンを使用して、システムへのすべてのWCF呼び出しはFunctionメソッドまたはProcedureメソッドでラップされ、最初にすべてのエラーでログが記録されることを確認し、次にエラーが発生しない場合にチャネルが閉じられ、例外が発生すると中止されるようにします。最後に、usingステートメントにあるように、チャネルの最終処分が呼び出されます。このようにして、チャネルが適切にクリーンアップされないために発生するエラー(このエラーのように見える)は防止されます。
この例外は、IEnumerableコレクションを含むオブジェクトを返しているときに発生し、コレクションメンバーの1つが取得されているときに例外が発生しました。その時点で、コードでキャッチするのは遅すぎます。おそらく、WCFは、結果をストリーミングし始めているため、クライアントに例外を報告するには遅すぎるため、その場合はソケットを切断するように設計されています。
WCFエラー:
ソケット接続は中止されました。これは、メッセージの処理エラー、リモートホストによる受信タイムアウトの超過、または基になるネットワークリソースの問題が原因である可能性があります。ローカルソケットタイムアウトは...
報告されるタイムアウトが1分に非常に近い場合(例:00:00:59.9680000
)または正確に1分(つまり00:01:00
)は、メッセージが大きすぎて バインディングの設定を超えている が原因である可能性があります。
これは、設定ファイルの値を増やすことで修正できます。例:
<binding name="MyWcfBinding"
maxReceivedMessageSize="10000000"
maxBufferSize="10000000"
maxBufferPoolSize="10000000" />
(例の値のみ、調整することができます)。
私の場合、net tcpでWcfをインスタンス化しようとしていました。したがって、web.configのバインディングセクションに、「netTcpBinding」がこのように構成されている場合
<bindings>
<netTcpBinding>
<binding name="bindingName" closeTimeout="01:10:00" openTimeout="01:10:00" receiveTimeout="01:10:00" sendTimeout="01:10:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="10" maxReceivedMessageSize="2147483647" portSharingEnabled="true">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="01:10:00" enabled="false"/>
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
次に、サービスインターフェイスの名前空間を使用して、コントラクト属性でエンドポイントを定義するサービスセクションを構成し、baseAddresも配置する必要があります。
<services>
<service behaviorConfiguration="sgiBehavior" name="Enterprise.Tecnic.SGI.OP.Wcf.OP">
<endpoint address="" behaviorConfiguration="endPointBehavior" binding="webHttpBinding" bindingConfiguration="BindingWebHttp" name="endPointHttp" contract="Enterprise.Tecnic.SGI.OP.Interface.IOP"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<endpoint address="" binding="netTcpBinding" bindingConfiguration="bindingName"
name="EndpointNetTcp" contract="Enterprise.Tecnic.SGI.OP.Interface.IOP" />
<Host>
<baseAddresses>
<!-- <add baseAddress="http://localhost:61217/OP.svc"/> -->
<add baseAddress="http://www.Enterprise.com/Tecnic/SGI/OP/" />
<add baseAddress="net.tcp://www.Enterprise.com/Tecnic/SGI/OP/" />
</baseAddresses>
</Host>
</service>
</services>
私はこの問題に2日間を費やしましたが、これが私のために働いた唯一のことでした。