Freigeben über


Schnelleinstieg zur Problembehandlung in WCF

In diesem Thema wird eine Reihe bekannter Probleme aufgeführt, denen Kunden beim Entwickeln von WCF-Clients und -Diensten begegnet sind. Wenn Ihr spezifisches Problem nicht in dieser Liste enthalten ist, sollten Sie die Ablaufverfolgung für den Dienst konfigurieren. Dadurch wird eine Ablaufverfolgungsdatei generiert, die Sie im Ablaufverfolgungsdatei-Viewer anzeigen können, um detaillierte Informationen zu Ausnahmen im Dienst zu erhalten. Weitere Informationen zum Konfigurieren der Ablaufverfolgung finden Sie unter Konfigurieren der Ablaufverfolgung. Weitere Informationen zum Ablaufverfolgungsdatei-Viewer finden Sie unter Service Trace Viewer-Tool (SvcTraceViewer.exe).

  1. Manchmal wird eine MessageSecurityException bei der zweiten Anforderung ausgelöst, wenn sich der Client nach der ersten Anforderung eine Weile im Leerlauf befunden hat. Woran liegt das?

  2. Der Dienst lehnt nach einer Interaktion mit ungefähr 10 Clients weitere Clients ab. Woran liegt das?

  3. Kann ich die Dienstkonfiguration aus einer anderen Quelle laden als der Konfigurationsdatei der WCF-Anwendung?

  4. Dienst und Client funktionieren hervorragend, nicht jedoch, wenn sich der Client auf einem anderen Computer befindet. Woran liegt das?

  5. Beim Auslösen einer FaultException<Exception>, deren Typ eine Ausnahme ist, erhalte ich immer einen allgemeinen FaultException-Typ auf dem Client, nicht den generischen Typ. Woran liegt das?

  6. Unidirektionale und Anforderung-Antwort-Vorgänge scheinen nahezu mit der gleichen Geschwindigkeit zurückgegeben zu werden, wenn die Antwort keine Daten enthält. Woran liegt das?

  7. Ich verwende ein X.509-Zertifikat mit dem Dienst und erhalte eine System.Security.Cryptography.CryptographicException. Woran liegt das?

  8. Ich habe den ersten Parameter eines Vorgangs von Groß- in Kleinbuchstaben geändert, und der Client löst nun eine Ausnahme aus. Woran liegt das?

  9. Bei der Verwendung eines meiner Ablaufverfolgungstools wird EndpointNotFoundException ausgelöst. Woran liegt das?

What is the base address? How does it relate to an endpoint address?

Manchmal wird eine MessageSecurityException bei der zweiten Anforderung ausgelöst, wenn sich der Client nach der ersten Anforderung eine Weile im Leerlauf befunden hat. Woran liegt das?

Die zweite Anforderung kann in erster Linie aus zwei Gründen fehlschlagen: (1) Das Timeout der Sitzung wurde überschritten. (2) Der Webserver, der diesen Dienst hostet, wird wiederverwendet. Im ersten Fall ist die Sitzung so lange gültig, bis das Timeout des Dienstes überschrietten wird. Wenn der Dienst innerhalb des Zeitrahmens, der in der Bindung des Dienstes angegeben ist (ReceiveTimeout) keine Anforderung vom Client erhält, beendet der Dienst die Sicherheitssitzung. Nachfolgende Clientnachrichten führen zu MessageSecurityException. Der Code muss erneut eine Sicherheitssitzung mit dem Dienst herstellen, um weitere Nachrichten senden oder ein Token für den Sicherheitszustandskontext verwenden zu können. Token für den Sicherheitszustandskontext sorgen auch dafür, dass eine Sicherheitssitzung das Wiederverwenden eines Webservers überdauert. Weitere Informationen über zur Verwendung eines Tokens für den Sicherheitszustandskontext in einer Sicherheitssitzung finden Sie unter Vorgehensweise: Erstellen eines Tokens für den Sicherheitskontext einer sicheren Sitzung. Stattdessen können Sie Sicherheitssitzungen auch deaktivieren. Wenn Sie die <wsHttpBinding>-Bindung verwenden, können Sie die establishSecurityContext-Eigenschaft auf false festlegen, um Sicherheitssitzungen zu deaktivieren. Wenn Sie Sicherheitssitzungen für andere Bindungen deaktivieren möchten, müssen Sie eine benutzerdefinierte Bindung erstellen. Ausführliche Informationen zum Erstellen einer benutzerdefinierten Bindung finden Sie unter Vorgehensweise: Erstellen einer benutzerdefinierten Bindung mit dem SecurityBindingElement. Bevor Sie eine dieser Optionen anwenden, müssen Sie die Sicherheitsanforderungen der Anwendung kennen.

Der Dienst lehnt nach einer Interaktion mit ungefähr 10 Clients weitere Clients ab. Woran liegt das?

Standardmäßig können Dienste nur 10 Sitzungen gleichzeitig verarbeiten. Wenn die Dienstbindungen Sitzungen verwenden, akzeptiert der Dienst neue Clientverbindungen folglich, bis diese Zahl erreicht ist. Anschließend lehnt er neue Clientverbindungen ab, bis eine der aktuellen Sitzungen beendet wird. Es gibt verschiedene Möglichkeiten, mehr Clients zu unterstützen. Wenn der Dienst keine Sitzungen erfordert, verwenden Sie keine sitzungsbasierte Bindung. (Weitere Informationen finden Sie unter Verwenden von Sitzungen.) Sie können auch das Sitzungslimit erhöhen, indem Sie den Wert der MaxConcurrentSessions-Eigenschaft auf eine Zahl festlegen, die Ihren Anforderungen entspricht.

Kann ich die Dienstkonfiguration aus einer anderen Quelle laden als der Konfigurationsdatei der WCF-Anwendung?

Ja. Sie müssen jedoch eine benutzerdefinierte ServiceHost-Klasse erstellen, die die ApplyConfiguration-Methode überschreibt. In dieser Methode können Sie die Basisklasse aufrufen und zuerst die Konfiguration laden (wenn Sie die Standardkonfigurationsinformationen ebenfalls laden möchten). Sie können jedoch auch das gesamte Konfigurationsladesystem ersetzen. Falls Sie eine Konfiguration aus einer anderen Konfigurationsdatei als der Anwendungskonfigurationsdatei laden möchten, müssen Sie die Konfigurationsdatei selbst analysieren und die Konfiguration laden.

Im folgenden Codebeispiel wird veranschaulicht, wie die ApplyConfiguration-Methode überschrieben und ein Endpunkt direkt konfiguriert wird.

public class MyServiceHost : ServiceHost
{
  public MyServiceHost(Type serviceType, params Uri[] baseAddresses)  
    : base(serviceType, baseAddresses)
  { Console.WriteLine("MyServiceHost Constructor"); }

  protected override void ApplyConfiguration()
  {
    string straddress = GetAddress();
    Uri address = new Uri(straddress);
    Binding binding = GetBinding();
    base.AddServiceEndpoint(typeof(IData), binding, address);
  }

  string GetAddress()
  { return "http://MyMachine:7777/MyEndpointAddress/"; }

  Binding GetBinding()
  {
    WSHttpBinding binding = new WSHttpBinding();
    binding.Security.Mode = SecurityMode.None;
    return binding;
  }
}

Dienst und Client funktionieren hervorragend, nicht jedoch, wenn sich der Client auf einem anderen Computer befindet. Woran liegt das?

Je nach Ausnahme können verschiedene Probleme vorliegen:

  • Möglicherweise müssen Sie die Clientendpunktadressen von localhost auf den Hostnamen ändern.

  • Sie müssen gegebenenfalls den Anschluss zur Anwendung öffnen. Weitere Informationen finden Sie unter Firewall-Anweisungen in den SDK-Beispielen.

  • Weitere mögliche Fragen finden Sie im Thema mit den Beispielen unter Running the Samples in a Workgroup and Across Machines.

  • Wenn der Client Windows-Anmeldeinformationen verwendet und es sich bei der Ausnahme um SecurityNegotiationException handelt, konfigurieren Sie Kerberos wie folgt.

    1. Fügen Sie die Anmeldeinformationen für die Identität dem Endpunktelement in der Datei App.config des Clients hinzu:

      <endpoint 
        address="http://MyServer:8000/MyService/" 
        binding="wsHttpBinding" 
        bindingConfiguration="WSHttpBinding_IServiceExample" 
        contract="IServiceExample" 
        behaviorConfiguration="ClientCredBehavior" 
        name="WSHttpBinding_IServiceExample">
        <identity>
          <userPrincipalName value="name@corp.contoso.com"/>
        </identity>
      </endpoint>
      
    2. Führen Sie den selbst gehosteten Dienst unter dem System- oder dem Netzwerkdienstkonto aus. Sie können diesen Befehl ausführen, um unter dem Systemkonto ein Befehlsfenster zu erstellen:

      at 12:36  /interactive "cmd.exe"
      
    3. Hosten Sie den Dienst unter Internetinformationsdienste (IIS). Standardmäßig wird hier das Dienstprinzipalnamenkonto verwendet.

    4. Registrieren Sie mit SetSPN einen neuen Dienstprinzipalnamen bei der Domäne. Sie müssen dazu ein Domänenadministrator sein.

Weitere Informationen über zum Kerberos-Protokoll finden Sie unter In WCF verwendete Sicherheitsbegriffe und:

Beim Auslösen einer FaultException<Exception>, deren Typ eine Ausnahme ist, erhalte ich immer einen allgemeinen FaultException-Typ auf dem Client, nicht den generischen Typ. Woran liegt das?

Erstellen Sie unbedingt einen eigenen benutzerdefinierten Fehlerdatentyp und deklarieren Sie ihn als Detailtyp in ihrem Fehlervertrag. Das Problem entsteht, weil Folgendes geschieht, wenn vom System bereitgestellter Ausnahmetypen verwendet werden:

  • Eine Typabhängigkeit wird erstellt, die eine der größten Stärken dienstorientierter Anwendungen entfernt.

  • Ausnahmen werden nicht notwendigerweise standardmäßig serialisiert. Einige – wie SecurityException – sind vielleicht überhaupt nicht serialisierbar.

  • Interne Implementierungsdetails werden für Clients verfügbar gemacht. Weitere Informationen finden Sie unter Angeben und Behandeln von Fehlern in Verträgen und Diensten.

Wenn Sie eine Anwendung debuggen, können Sie jedoch mit der ServiceDebugBehavior-Klasse Ausnahmeinformationen serialisieren und an den Client zurückgeben.

Unidirektionale und Anforderung-Antwort-Vorgänge scheinen nahezu mit der gleichen Geschwindigkeit zurückgegeben zu werden, wenn die Antwort keine Daten enthält. Woran liegt das?

Einen Vorgang als unidirektional anzugeben, bedeutet, dass der Vorgangsvertrag lediglich eine Eingabenachricht akzeptiert und keine Ausgabenachricht zurückgibt. In WCF werden allen Clientaufrufe zurückgegeben, wenn die ausgehenden Daten zur Übertragung geschrieben wurden oder eine Ausnahme ausgelöst wurde. Unidirektionale Vorgänge funktionieren genauso. Außerdem können sie eine Ausnahme auslösen, falls der Dienst nicht gefunden wird, oder sie können blockiert werden, falls der Dienst nicht zur Annahme der Daten aus dem Netzwerk bereit ist. In der Regel führt das in WCF zu unidirektionalen Aufrufen, die schneller an den Client zurückgegeben werden als Anforderung-Antwort-Vorgänge. Doch verlangsamt jede Bedingung, die das Senden der ausgehenden Daten über das Netzwerk verlangsamt, unidirektionale Vorgänge ebenso wie Anforderung-Antwort-Vorgänge. Weitere Informationen finden Sie unter One-Way Services und Zugreifen auf Dienste mithilfe eines Clients.

Ich verwende ein X.509-Zertifikat mit dem Dienst und erhalte eine System.Security.Cryptography.CryptographicException. Woran liegt das?

Das Problem tritt in der Regel nach einer Änderung des Benutzerkontos auf, unter dem der IIS-Arbeitsprozess ausgeführt wird. Wenn Sie in Windows XP z. B. das Standardbenutzerkonto, unter dem die Datei Aspnet_wp.exe ausgeführt wird, von ASPNET in ein benutzerdefiniertes Konto ändern, wird dieser Fehler vermutlich angezeigt. Bei der Verwendung eines privaten Schlüssels benötigt der entsprechende Prozess die Berechtigungen für den Zugriff auf die Datei, in der der Schlüssel gespeichert ist.

In diesem Fall müssen Sie dem Konto des Prozesses Leseberechtigungen für die Datei mit dem Schlüssel erteilen. Wenn z. B. der IIS-Arbeitsprozess unter dem Konto Bob ausgeführt wird, müssen Sie Bob den Lesezugriff auf die Datei erteilen, die den privaten Schlüssel enthält.

Weitere Informationen über zur Vorgehensweise beim Erteilen der richtigen Zugriffsrechte für das Benutzerkonto auf die Datei, die den privaten Schlüssel für ein bestimmtes X.509-Zertifikat enthält, finden Sie unter Vorgehensweise: Zugänglichmachen von X.509-Zertifikaten für WCF.

Ich habe den ersten Parameter eines Vorgangs von Groß- in Kleinbuchstaben geändert, und der Client löst nun eine Ausnahme aus. Woran liegt das?

Die Werte der Parameternamen in der Vorgangssignatur sind Teil des Vertrags und werden nach Groß- und Kleinschreibung unterschieden. Verwenden Sie das System.ServiceModel.MessageParameterAttribute-Attribut, wenn der lokale Parametername von den Metadaten unterschieden werden muss, die den Vorgang für Clientanwendungen beschreiben.

Bei der Verwendung eines meiner Ablaufverfolgungstools wird EndpointNotFoundException ausgelöst. Woran liegt das?

Wenn Sie ein anderes Ablaufverfolgungstool als den vom System bereitgestellten WCF-Ablaufverfolgungsmechanismus verwenden und EndpointNotFoundException ausgelöst wird, ist ein Adressfilterkonflikt aufgetreten. Verweisen Sie die Nachrichten in diesem Fall mithilfe der ClientViaBehavior-Klasse auf das Ablaufverfolgungstool, und lassen Sie das Tool diese Nachrichten an die Dienstadresse weiterleiten. Die ClientViaBehavior-Klasse ändert den Adressierungsheader Via und gibt die nächste Netzwerkadresse unabhängig vom endgültigen Empfänger an, der mit dem Adressierungsheader To angegeben wird. Ändern Sie dabei jedoch nicht die Endpunktadresse, die den To-Wert festlegt.

Das folgende Codebeispiel zeigt eine standardmäßige Konfigurationsdatei für einen Beispielclient.

<endpoint 
  address=https://localhost:8000/MyServer/
  binding="wsHttpBinding"
  bindingConfiguration="WSHttpBinding_IMyContract"
  behaviorConfiguration="MyClient" 
  contract="IMyContract" 
  name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
  <endpointBehaviors>
    <behavior name="MyClient">
      <clientVia viaUri="https://localhost:8001/MyServer/"/>
    </behavior>
  </endpointBehaviors>
</behaviors>

Was ist die Basisadresse? Worin besteht die Beziehung zu einer Endpunktadresse?

Eine Basisadresse ist die Stammadresse für eine ServiceHost-Klasse. Wenn Sie der Dienstkonfiguration eine ServiceMetadataBehavior-Klasse hinzufügen, werden standardmäßig die WSDL (Web Services Description Language) für alle vom Host veröffentlichten Endpunkte aus der HTTP-Basisadresse und alle relativen Adressen, die für das Metadatenverhalten bereitgestellt werden, sowie "?wsdl" abgerufen. Wenn Sie mit ASP.NET und IIS vertraut sind, ist die Basisadresse mit dem virtuellen Verzeichnis vergleichbar.

Gemeinsames Verwenden eines Ports durch einen Dienstendpunkt und einen mex-Endpunkt mithilfe der NetTcpBinding

Wenn Sie die Basisadresse für einen Dienst als net.tcp://MyServer:8080/MyService angeben und die folgenden Endpunkte hinzufügen:

<services>
      <service name="Microsoft.Samples.NetTcp.CalculatorService">
        <endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
      </service>
    </services>

Und wenn Sie eine der NetTcpBinding-Einstellungen wie im folgenden Konfigurationsausschnitt veranschaulicht ändern:

<bindings>
      <netTcpBinding>
        <binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="11" maxReceivedMessageSize="65536">
          <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"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>

Ein Fehler ähnlich dem folgenden wird angezeigt: Unbehandelte Ausnahme: System.ServiceModel.AddressAlreadyInUseException: Für den IP-Endpunkt 0.0.0.0:9000 ist bereits ein Listener vorhanden. Sie können diesen Fehler beheben, indem Sie eine vollqualifizierte URL mit einem anderen Port für den MEX-Endpunkt angeben. Dies wird im folgenden Konfigurationsausschnitt veranschaulicht:

<services>
      <service name="Microsoft.Samples.NetTcp.CalculatorService">
        <endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
        <endpoint address="net.tcp://localhost:9001/servicemodelsamples/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
      </service>
    </services>

Siehe auch

Konzepte

Debuggen von Windows-Authentifizierungsfehlern