Ursprünglich:
Szenario:
Code:
[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 ; }
}
Gedanken:
Elternteil:
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;
}
}
Kind:
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;
}
}
diese Ausnahme bezieht sich nicht auf Circular Reference. Es wird lediglich ein Timeout ausgeführt, wenn Sie versuchen, Tonnen von Daten über das Kabel zu pumpen.
Die mit WCF gelieferten Standardwerte sind sehr niedrig (diese Werte wurden meiner Meinung nach in WCF 4 geändert). Lesen Sie sich diese beiden Blogeinträge durch und sie sollten Ihnen eine Vorstellung davon geben, wie Sie Ihren Dienst drosseln können:
Hochleistungs-WCF-Dienste erstellen
Wie man einen Wcf-Dienst drosselt, DoS-Angriffe verhindert und die Wcf-Skalierbarkeit aufrechterhält
Update: Auch in der WCF-Konfiguration gibt es verschiedene Timeouts. Abhängig davon, ob Sie über den Client oder Server sprechen, müssen Sie eine andere Timeout-Klausel aktualisieren ... lesen Sie dies Thread was jedes davon bedeutet und Sie sollten herausfinden können, welches Sie aufstocken müssen. Oder, Sie könnten einfach jedes Timeout auf int.max setzen, wenn Sie sich nicht wirklich darum kümmern, ob ein Anruf längere Zeit in Anspruch nehmen kann.
Dieser Fehler kann verschiedene Ursachen haben. Während es in diesem Fall ein Timing-Problem war, hat es normalerweise nichts mit Timings zu tun, insbesondere wenn der Fehler sofort empfangen wird. Mögliche Gründe sind:
Hatte dieses Problem mit einem langen Initialisierungsprozess, der vom OnStart-Ereignis eines Windows Service Host-Installationsprogramms aufgerufen wurde. Festgelegt durch Festlegen des Sicherheitsmodus und der Zeitüberschreitung für die TCP - Bindung.
// 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);
Dieses Problem kann auch darauf zurückzuführen sein, dass der WCF-Client nicht bereinigt wird, wenn Sie ihn nicht mehr verwenden. In unserem System verwenden wir das Einwegmuster und wickeln alle Funktionsaufrufe in das System ein, um eine ordnungsgemäße Bereinigung und Protokollierung zu ermöglichen. Wir verwenden eine Version der folgenden Klasse:
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;
}
}
}
}
Jeder WCF-Aufruf, den wir in unseren Service aufnehmen, erfolgt über eine definierte Schnittstellenklasse wie die folgende:
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));
}
}
}
Unter Verwendung dieses Musters werden alle WCF-Aufrufe in das System entweder mit der Function- oder der Procedure-Methode umschlossen. Dadurch können sie zunächst sicherstellen, dass die Protokollierung aller Fehler erfolgt, und zweitens, um sicherzustellen, dass der Kanal geschlossen wird, wenn keine Fehler auftreten, aber bei einer Ausnahme abgebrochen wird . Schließlich, da es sich in einer using-Anweisung befindet, wird die endgültige Verfügung des Kanals aufgerufen. Auf diese Weise werden Fehler, die durch nicht ordnungsgemäß bereinigte Kanäle entstehen, die wie dieser Fehler aussehen, vermieden.
Diese Ausnahmebedingung trat für mich auf, als ich ein Objekt mit IEnumerable-Auflistungen zurückgegeben habe und eine Ausnahmebedingung aufgetreten ist, während eines der Auflistungsmitglieder abgerufen wurde. Zu diesem Zeitpunkt ist es zu spät, um es in Ihrem Code einzufangen, und WCF ist vermutlich dafür ausgelegt, den Socket in diesem Fall zu trennen, da es auch zu spät ist, dem Client eine Ausnahme zu melden, da bereits mit dem Streaming der Ergebnisse begonnen wurde.
Der WCF-Fehler:
Die Socket-Verbindung wurde abgebrochen. Dies kann durch einen Fehler verursacht werden Verarbeitung Ihrer Nachricht oder ein Empfangszeitlimit, das von der .__ überschritten wird. Remote-Host oder ein zugrunde liegendes Problem mit der Netzwerkressource. Lokaler Socket Timeout war ...
die angegebenen Timeouts liegen sehr nahe an 1 Minute (z. B. 00:00:59.9680000
) oder genau 1 Minute (d. h. 00:01:00
), weil die Nachricht zu groß ist und die Einstellungen für die Bindung überschreitet .
Dies kann durch Erhöhen der Werte in der Konfigurationsdatei behoben werden, z.
<binding name="MyWcfBinding"
maxReceivedMessageSize="10000000"
maxBufferSize="10000000"
maxBufferPoolSize="10000000" />
(Nur für Beispielwerte, möchten Sie sie möglicherweise anpassen).
In meinem Fall habe ich versucht, eine Wcf mit net tcp zu instanziieren. Wenn Sie also im Bindungsbereich Ihrer web.config das "netTcpBinding" so konfiguriert haben
<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>
Anschließend müssen Sie den Serviceabschnitt konfigurieren, der die Endpunkte mit ihrem Vertragsattribut über den Namespace Ihrer Serviceschnittstelle definiert, und auch die baseAddres in etwa so einfügen
<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>
Ich habe zwei Tage mit diesem Problem verbracht, aber das war das Einzige, was mir geholfen hat.