Schnelleinstieg zur Problembehandlung in WCF

Dieses Thema beschreibt im Frage-und-Antwort-Format einige der häufigsten Probleme, wie Sie diese Probleme beheben können und wo sie weitere Informationen zu dem Thema finden.

Fragen

Frage: 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 zur Verwendung eines Tokens für den Sicherheitszustandskontext in einer Sicherheitssitzung finden Sie unter Gewusst wie: Erstellen eines Tokens für den Sicherheitszustandkontext 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 Gewusst wie: Erstellen einer benutzerdefinierten Bindung mit dem SecurityBindingElement. Bevor Sie eine dieser Optionen anwenden, müssen Sie die Sicherheitsanforderungen der Anwendung kennen.

Frage: Der Dienst startet und 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.

Frage: 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;
  }
}

Frage: 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 Instructions in den SDK-Beispielen.
  • Weitere mögliche Fragen finden Sie im Thema mit den Beispielen, 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 zum Kerberos-Protokoll finden Sie unter In WCF verwendete Sicherheitsbegriffe und:

Frage: Beim Auslösen einer FaultException<Exception>, deren Typ eine Ausnahme ist, erhalte ich immer einen allgemeinen FaultException-Typ für den Client und 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.

Frage: 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, die unidirektionalen Vorgänge ebenso wie die Anforderung-Antwort-Vorgänge. Weitere Informationen finden Sie unter Unidirektionale Dienste und Zugreifen auf Dienste mithilfe eines Clients.

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

Das Problem tritt in der Regel nach einer Änderung des Benutzerkontos auf, unter dem der IIS-Workerprozess 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-Workerprozess 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 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 Gewusst wie: Zugänglichmachen von X.509-Zertifikaten für WCF.

Frage: 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, die den Vorgang für Clientanwendungen beschreiben, unterschieden werden muss.

Frage: 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 Via-Adressierungsheader und gibt die nächste Netzwerkadresse unabhängig vom endgültigen Empfänger an, der mit dem To-Adressierungsheader 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>

Frage: 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.

Frage: Wie mache ich mehrere Endpunkte für einen Dienst verfügbar?

Fügen Sie dazu dem <service>-Element in einer Anwendungskonfigurationsdatei <endpoint>-Elemente hinzu, oder führen Sie die entsprechenden Schritte programmgesteuert aus. Weitere Informationen finden Sie unter Angeben einer Endpunktadresse, Gewusst wie: Erstellen eines Dienstendpunkts in einer Konfiguration und Gewusst wie: Erstellen eines Dienstendpunkts im Code.

Frage: Woher weiß ich, welche Bindungen verschiedene Verhalten unterstützen?

Weitere Informationen zu den vom System bereitgestellten Bindungen und von ihnen unterstützten Features finden Sie unter Vom System bereitgestellte Bindungen.

Frage: Wie wird eine Standardbindung mit unterschiedlichen Werten für ein Attribut konfiguriert?

Weitere Informationen finden Sie unter Konfigurieren von Bindungen für Windows Communication Foundation-Dienste.

Frage: Muss ich den Dienst für einen HTTP-Server bereitstellen, wenn ich HTTP als Transport verwenden möchte?

Nein. Unter den vom System bereitgestellten Bindungen unterstützen einige HTTP-Transporte, wenn sie in einem Hostanwendungstyp verwendet werden. Weitere Informationen zu den vom System bereitgestellten Bindungen und den von ihnen unterstützten Features finden Sie unter Vom System bereitgestellte Bindungen.

Frage: Welches Standardverhalten zeigt ein Dienst, der Standardbindungen verwendet?

Dies hängt von der gewählten Standardbindung ab. Bindungen, die Sitzungen verwenden, zeigen im Allgemeinen folgendes Standardverhalten: Für jeden neuen Client wird eine neue Dienstinstanz erstellt, und anschließende Aufrufe von einem bestimmten Client werden an eine zugehörige Dienstinstanz weitergeleitet. Weitere Informationen zu den vom System bereitgestellten Bindungen und den von ihnen unterstützte Features finden Sie unter Vom System bereitgestellte Bindungen.

Frage: Gibt es eine einfache Möglichkeit, die den Bindungen zugeordneten Features festzustellen? (Wie sehe ich beispielsweise, welche Bindungen Transaktionen, Sicherheit usw. unterstützen?)

Ja. Siehe Vom System bereitgestellte Bindungen.

Frage: Wie übergebe ich benutzerdefinierte Datentypen von einem Dienst an einen Client?

Zwischen zwei Endpunkten übergebene Datentypen müssen serialisierbar sein. Der einfachste Serialisierungsmechanismus mit der höchsten Interoperabilität für Dienste besteht in der Verwendung der Klassen DataContractAttribute und DataMemberAttribute. Weitere Informationen zu diesem Mechanismus und anderen unterstützten Serialisierungsmechanismen finden Sie unter Angeben von Datenübertragung in Dienstverträgen.

Frage: Wann sollte zum Konfigurieren eine Konfigurationsdatei und wann Code verwendet werden?

Eine Anwendungskonfigurationsdatei ermöglicht es dem Entwickler, die Entscheidungen der Laufzeitkonfiguration in die Hände des Bereitstellers zu legen. Deshalb empfiehlt es sich, Entscheidungen, die ein Bereitsteller niemals treffen sollte, im Produktcode zu konfigurieren. Bei Bereitstellern kann es sich um Personen handeln, die Programme auf ihrem eigenen Computer installieren, oder um Unternehmensadministratoren, die anhand von Unternehmensgruppenrichtlinien die Konfigurationsdateien von Computern ändern und diese Dateien sperren, um lokale Änderungen zu verhindern. Ein Beispiel für Letzteres finden Sie unter Gewusst wie: Endpunkte im Unternehmen sperren.

Frage: Was muss ich wissen, um einen gut konzipierten Dienst zu entwerfen?

Siehe Entwerfen und Implementieren von Diensten.

Frage: Was ist dieses ganze Zeug im generierten Clientcode?

Erklärungen und Hinweise zum generierten Clientcode finden Sie unter Grundlagen des generierten Clientcodes. Weitere Informationen zur Clientarchitektur finden Sie unter Clientarchitektur.

Frage: Warum soll ich die Close-Methode für das WCF-Clientobjekt aufrufen?

Wenn Close für das WCF-Clientobjekt aufgerufen wird, können der Client und der Dienst die Kommunikation ordnungsgemäß beenden und zugeordnete Ressourcen wiederverwenden. Außerdem kann bei der Verwendung von Sitzungen mit dem Aufrufen von Close am schnellsten festgestellt werden, ob eine Sitzung seit dem letzten Aufruf einen Fehler verursachte. Dieses Szenario ist möglicherweise für die Clientanwendung relevant. Weitere Informationen finden Sie unter Zugreifen auf Dienste mithilfe eines WCF-Clients und den Beispielen zu Expected Exceptions.

Frage: Warum wird der Dienst nicht erwartungsgemäß ausgeführt, obwohl der Code in Ordnung zu sein scheint?

Wenn die Dienstanwendung für die Verwendung einer Anwendungskonfigurationsdatei konfiguriert ist, überprüfen Sie diese Datei. Stellen Sie fest, ob ein Konfigurationselement oder Attribut darin das Ausführungsverhalten unerwünscht ändert. Insbesondere das Laufzeitverhalten hängt erheblich von der Bindung ab, die den Vertrag in einem Endpunkt implementiert. Überprüfen Sie, ob die Bindung in der Konfigurationsdatei die von Ihnen gewünschten Feature auf die von Ihnen beabsichtigte Weise unterstützt.

Wenn die Konfigurationsdatei in Ordnung ist, können Sie anschließend mithilfe von Diagnosefeatures, wie Protokollierung und Ablaufverfolgung, das Laufzeitverhalten der Anwendung überprüfen. Weitere Informationen finden Sie unter Verwaltung und Diagnose.

Frage: Wie kann einem Client am besten vermittelt werden, dass der Dienst Fehler aufwies?

Fügen Sie hierzu am besten dem Vorgang eine FaultContractAttribute-Klasse mit einem serialisierbaren Fehlerdatentyp hinzu. Wenn der Vorgang dann auf eine Fehlerbedingung trifft, die er erkennen kann, löst er eine neue FaultException aus, bei der der Typparameter ein serialisierbarer Fehlertyp ist. Weitere Informationen finden Sie unter Angeben und Behandeln von Fehlern in Verträgen und Diensten.

Frage: Welche Informationen dürfen an den Client zurückgegeben werden?

Geben Sie nur die Informationen zurück, die Clients des Dienstes benötigt. Stellen Sie als Designer des Dienstes Informationen nur in diesem Umfang bereit und nicht mehr, um die Offenlegung interner Implementierungsdetails für unbefugte Clients so gering wie möglich zu halten. Geben Sie deshalb keinesfalls Exception-Objekte in den SOAP-Fehlern zurück. Weitere Informationen finden Sie unter Angeben und Behandeln von Fehlern in Verträgen und Diensten.

Frage: Wie erkennt die Clientanwendung, dass eine Verbindung mit einem Dienst geschlossen wurde?

Sie können die CommunicationObject-Statusänderungsereignisse des Clientkanals behandeln. Wann Sie jedoch über das Schließen oder Fehlschlagen eines Kanals benachrichtigt werden, hängt von der Kanalimplementierung ab. Beispielsweise kann eine NetTcpBinding-Klasse Sie sehr schnell benachrichtigen, dass der Kanal geschlossen wurde oder fehlerhaft ist, da die Lebensdauer ihrer Sitzung mit der Lebensdauer des zugrunde liegenden Sockets verknüpft ist.

Von einer sitzungsbasierten Bindung jedoch, die die Anwendung vor leichten Netzwerkstörungen schützen soll, wie z. B. die von der ReliableSessionBindingElement-Klasse bereitgestellte Sitzung, werden Sie vielleicht eine gewisse Zeit nicht benachrichtigt, während versucht wird, die Sitzung wiederherstellen. Aus diesem Grund sollten Sie nicht versuchen, die Verbindungstrennung direkt zu ermitteln.

Behandeln Sie die Sitzung stattdessen als Kommunikation. Nehmen Sie beim Öffnen des Kanals verschiedene Vorgangsaufrufe vor, und schließen Sie den Kanal ordnungsgemäß. Dann können Sie davon ausgehen, dass der Kanal nicht unerwartet geschlossen wurde. Weitere Informationen zu Clients und Sitzungen finden Sie unter Verwenden von Sitzungen. Weitere Informationen zur Behandlung kanalbezogener Ausnahmen finden Sie unter Zugreifen auf Dienste mithilfe eines Clients. Informationen zur allgemeinen Behandlung von Ausnahmen finden Sie unter Angeben und Behandeln von Fehlern in Verträgen und Diensten.

Frage: Wie konfiguriere ich ein SSL-Zertifikat (Secure Sockets Layer) für die WCF-Dienstsicherheit?

Siehe Gewusst wie: Konfigurieren eines Anschlusses mit einem SSL-Zertifikat.

Frage: Wie verwende ich Nachrichteninspektoren zum Protokollieren oder Ändern einer Nachricht?

Informationen hierzu finden Sie in den folgenden Themen:

Frage: Wie füge ich eine Endpunktadresse mit zusätzlichen Informationen hinzu?

Wenn Sie programmgesteuert komplexe Endpunktadressen hinzufügen möchten (z. B., falls Sie programmgesteuert eine EndpointAddress-Klasse angeben müssen, die einen bestimmten Header oder eine bestimmte Identität enthält), gehen Sie wie unten dargestellt vor. Dabei ist relativeOrAbsoluteAddress ein relativer oder absoluter URI (Uniform Resource Identifier):

// Do this:
ServiceEndpoint e = myServiceHost.AddServiceEndpoint(c,b,"relativeOrAbsoluteAddress");
e.Address = new EndpointAddress(e.Address.Uri, /*other info like headers */);

Frage: Ich versuche, ein im Web gehostetes Beispiel zu erstellen, was jedoch nicht gelingt, weil ein Befehl zum Erstellen eines Verzeichnisses oder ein Kopier- oder Löschbefehl fehlschlägt. Warum geschieht das?

Beim Erstellen wird bei einigen im Web gehosteten Beispielen versucht, die kompilierten Binärdateien des WCD-Diensts in den Ordner %SystemDrive%\inetpub\wwwroot\ServiceModelSamples zu kopieren. Dadurch soll der Dienst in IIS bereitgestellt werden. Hat das Konto, unter dem die SDK-Eingabeaufforderung oder Visual Studio ausgeführt werden, nicht die Berechtigung, den Ordner zu ändern, wird die Erstellung abgebrochen. Sie haben folgende Möglichkeiten, dies zu korrigieren:

  • Erteilen Sie dem Konto, unter dem Sie die Beispiele erstellen, die Berechtigung zum Ändern des Ordners %SystemDrive%\inetpub\wwwroot
    oder
  • Führen Sie die SDK-Eingabeaufforderung oder Visual Studio als Administrator aus.

Siehe auch

Konzepte

Debuggen von Windows-Authentifizierungsfehlern