Freigeben über


Einführung in Windows Communication Foundation 4 für Entwickler

Aaron Skonnard, Pluralsight

Original: November 2009

Aktualisiert auf RTM: April 2010

Überblick

.NET 4 enthält einige überzeugende neue Features und begrüßte Verbesserungen im Bereich von Windows Communication Foundation (WCF). Diese WCF-Verbesserungen konzentrieren sich in erster Linie auf die Vereinfachung der Entwicklererfahrung, die Aktivierung von mehr Kommunikationsszenarien und die umfassende Integration in Windows Workflow Foundation (WF), indem sie "Workflowdienste" zu einem erstklassigen Bürger machen.

Die gute Nachricht ist der Großteil der WCF 4-Änderungen, die sich darauf konzentrieren, die heutigen gängigen Szenarien zu vereinfachen und neue Kommunikationsszenarien und Entwicklungsstile zu ermöglichen. Daher ist das Verschieben Ihrer vorhandenen WCF-Lösungen auf .NET 4 relativ nahtlos in Bezug auf die Migration. Dann entscheiden Sie einfach, welche WCF 4-Features Sie in Ihren Lösungen nutzen möchten. Der Rest dieses Dokuments führt Sie in die einzelnen neuen WCF 4-Featurebereiche ein und zeigt, wie sie funktionieren.

Neuerungen in WCF 4

WCF 4 enthält eine breite Palette von spezifischen Features, aber Abbildung 1 beschreibt die wichtigsten Featurebereiche, auf die wir uns im gesamten folgenden Dokument konzentrieren werden. Diese Featurebereiche fassen die meisten Neuerungen in WCF 4 zusammen und heben die von dieser Version von .NET Framework gebotenen Möglichkeiten auf oberster Ebene hervor.

Abbildung 1: WCF 4-Featurebereiche

Featurebereich Beschreibung

Vereinfachte Konfiguration

Vereinfachung des WCF-Konfigurationsabschnitts durch Unterstützung für Standardendpunkte, Bindungs- und Verhaltenskonfigurationen. Diese Änderungen ermöglichen das Hosten von konfigurationsfreien Diensten, was die Entwicklerumgebung für die am häufigsten verwendeten WCF-Szenarien erheblich vereinfacht.

Entdeckung

Neue Framework-Unterstützung sowohl für Ad-hoc- als auch für verwaltete Dienstermittlungsverhalten, die dem Standardprotokoll WS-Discovery entsprechen.

Routingdienst

Neue Frameworkunterstützung für einen konfigurierbaren Routingdienst, den Sie in Ihren WCF-Lösungen verwenden können. Stellt Features für inhaltsbasiertes Routing, Protokollbrücken und Fehlerbehandlung bereit.

REST-Verbesserungen

Verbesserungen an WCF WebHttp Services mit einigen zusätzlichen Features und Tools, die die Entwicklung des REST-Diensts vereinfachen.

Workflowdienste

Umfassende Frameworkunterstützung für die Integration von WCF in WF zum Implementieren deklarativer lang ausgeführter Workflowdienste. Dieses neue Programmiermodell bietet Ihnen die besten beiden Frameworks (WCF & WF).

Sobald wir diese Hauptfeaturebereiche behandelt haben, besprechen wir kurz einige der fortschrittlicheren WCF-Features auf niedrigerer Ebene, die in .NET 4 enthalten sind, einschließlich verbesserter Funktionen zur Typauflösung, Unterstützung für Warteschlangen mit konkurrierenden Verbrauchern ("Empfangen von Kontext"), Unterstützung für entwrappte Binärdaten über einen Bytestream-Encoder und Unterstützung für eine leistungsfähige ETW-basierte Ablaufverfolgung.

Wenn wir fertig sind, werden Sie sehen, dass WCF 4 einfacher zu verwenden ist, und bietet mehr integrierte Unterstützung für einige der am häufigsten verwendeten Szenarien und Entwicklungsstile von heute.

Vereinfachte Konfiguration

Das von WCF in 3.x angebotene einheitliche Programmiermodell ist sowohl ein Segen als auch ein Fluch – es vereinfacht das Schreiben von Dienstlogik für eine Vielzahl verschiedener Kommunikationsszenarien, erhöht aber auch die Komplexität auf der Konfigurationsseite der Dinge, da es so viele verschiedene zugrunde liegende Kommunikationsoptionen bietet, die Sie verstehen müssen, bevor Sie loslegen können.

Die Realität ist DIE WCF-Konfiguration wird in der Regel zum kostspieligsten Bereich der Verwendung von WCF in der Praxis heute, und viele dieser Komplexität landen in den IT-/Betriebsmitarbeitern, die nicht darauf vorbereitet sind, sich damit zu befassen.

In Anbetracht dieser Realität kann man bei der Nettokomplexität der Verwendung von WCF 3.x zu dem Schluss kommen, dass es schwieriger ist, als sein Vorgänger ASP.NET Webdienste (ASMX) zu verwenden. Mit ASMX konnten Sie einen [WebMethod]-Vorgang definieren und die Laufzeit automatisch eine Standardkonfiguration für die zugrunde liegende Kommunikation bereitgestellt. Wenn Sie zu WCF 3.x wechseln, müssen Entwickler andererseits über die verschiedenen WCF-Konfigurationsoptionen genug wissen, um mindestens einen Endpunkt zu definieren. Und die entmutigende Anzahl von Konfigurationsoptionen schreckt einige Entwickler oft ab.

Um die allgemeine WCF-Erfahrung genauso einfach wie ASMX zu machen, bietet WCF 4 ein neues "Standardkonfigurationsmodell", das die Notwendigkeit für jede WCF-Konfiguration vollständig entfernt. Wenn Sie keine WCF-Konfiguration für einen bestimmten Dienst bereitstellen, konfiguriert die WCF 4-Laufzeit Ihren Dienst automatisch mit einigen Standardendpunkten und Standardbindungs-/Verhaltenskonfigurationen. Dies erleichtert das Einrichten und Ausführen eines WCF-Diensts, insbesondere für diejenigen, die nicht mit den verschiedenen WCF-Konfigurationsoptionen vertraut sind, und sind froh, die Standardwerte zu akzeptieren, zumindest für die ersten Schritte.

Standardendpunkte

Wenn Sie mit WCF 3.x versuchen, einen Dienst ohne konfigurierte Endpunkte zu hosten, löst die ServiceHost-Instanz eine Ausnahme aus, die Sie darüber informiert, dass Sie mindestens einen Endpunkt konfigurieren müssen. Bei WCF 4 ist dies nicht mehr der Fall, da die Laufzeit automatisch einen oder mehrere "Standardendpunkte" für Sie hinzufügt, wodurch der Dienst ohne Konfiguration verwendet werden kann.

Hier erfahren Sie, wie es funktioniert. Wenn die Hostanwendung "Open" auf der ServiceHost-Instanz aufruft, erstellt sie die interne Dienstbeschreibung aus der Anwendungskonfigurationsdatei zusammen mit allen Elementen, die die Hostanwendung möglicherweise explizit konfiguriert hat, und wenn die Anzahl der konfigurierten Endpunkte noch null ist, ruft sie AddDefaultEndpoints auf, eine neue öffentliche Methode, die in der ServiceHost-Klasse gefunden wurde. Diese Methode fügt der Dienstbeschreibung basierend auf den Basisadressen des Diensts einen oder mehrere Endpunkte hinzu (in IIS-Szenarien ist dies die SVC-Adresse). Da die Methode öffentlich ist, können Sie sie auch direkt in benutzerdefinierten Hostingszenarien aufrufen.

Um genau zu sein, fügt die Implementierung von AddDefaultEndpoints einen Standardendpunkt pro Basisadresse für jeden vom Dienst implementierten Dienstvertrag hinzu. Wenn der Dienst beispielsweise zwei Serviceverträge implementiert und Sie den Host mit einer einzigen Basisadresse konfigurieren, konfiguriert AddDefaultEndpoints den Dienst mit zwei Standardendpunkten (eine für jeden Servicevertrag). Wenn der Dienst jedoch zwei Dienstverträge implementiert und der Host mit zwei Basisadressen konfiguriert ist (eine für HTTP und eine für TCP), konfiguriert AddDefaultEndpoints den Dienst mit vier Standardendpunkten.

Sehen wir uns ein vollständiges Beispiel an, um diese Arbeiten zu veranschaulichen. Angenommen, Sie haben die folgenden WCF-Dienstverträge und die folgende Dienstimplementierung:

[ServiceContract]

Öffentliche Schnittstelle IHello

{

    [OperationContract]

    void SayHello(string name);

}

[ServiceContract]

öffentliche Schnittstelle IGoodbye

{

    [OperationContract]

    void SayGoodbye(string name);

}

public class GreetingService : IHello, IGoodbye // service implementiert beide Verträge

{

    public void SayHello(string name)

    {

        Console.WriteLine("Hello {0}", name);

    }

    public void SayGoodbye(string name)

    {

        Console.WriteLine("Goodbye {0}", Name);

    }

}

Mit WCF 4 können Sie jetzt ServiceHost verwenden, um den GreetingService-Dienst ohne Anwendungskonfiguration zu hosten. Wenn Sie ServiceHost in benutzerdefinierten Hostingszenarien verwenden, müssen Sie eine oder mehrere zu verwendende Basisadressen angeben. Im Folgenden wird gezeigt, wie Sie den GreetingService in einer Konsolenanwendung hosten, und erneut können Sie davon ausgehen, dass es keine app.config Datei gibt, die diesem Programm zugeordnet ist:

Klassenprogramm

{

    static void Main(string[] args)

    {

        Host ist mit zwei Basisadressen konfiguriert, eine für HTTP und eine für TCP

        ServiceHost host = new ServiceHost(typeof(GreetingService),

            neuer Uri("https://localhost:8080/greeting"),

            new Uri("net.tcp://localhost:8081/greeting"));

        Gastgeber. Open();

        foreach (ServiceEndpoint se in host. Description.Endpoints)

            Console.WriteLine("A: {0}, B: {1}, C: {2}",

                Se. Adresse, se.Binding.Name, se.Contract.Name);

        Console.WriteLine("Drücken Sie <EINGABETASTE>, um den Dienst zu beenden.");

        Console.ReadLine();

        Gastgeber. Close();

    }

}

In diesem Beispiel wird serviceHost mit zwei Basisadressen konfiguriert: eine für HTTP und eine andere für TCP. Wenn Sie dieses Programm ausführen, werden vier Endpunkte im Konsolenfenster gedruckt, wie in Abbildung 2 dargestellt. Sie erhalten zwei für die HTTP-Basisadresse, eine pro Vertrag und zwei für die TCP-Basisadresse, erneut eine pro Vertrag. Dies wird im Hintergrund von der ServiceHost-Instanz bereitgestellt.

Abbildung 2: Im Konsolenfenster angezeigte Standardendpunkte

Beachten Sie, wie WCF die Standard-HTTP-Endpunkte und netTcpBinding für die Standardmäßigen TCP-Endpunkte verwendet. Ich zeige Ihnen, wie Sie diese Standardwerte kurz ändern.

Denken Sie daran, dass dieses Standardendpunktverhalten nur gestartet wird, wenn der Dienst nicht mit Endpunkten konfiguriert wurde. Wenn ich die Konsolenanwendung so ändert, dass der Dienst mit mindestens einem Endpunkt konfiguriert wird, werden keine dieser Standardendpunkte mehr in der Ausgabe angezeigt. Um dies zu veranschaulichen, füge ich einfach die folgende Codezeile hinzu, die AddServiceEndpoint nach dem Erstellen der ServiceHost-Instanz aufruft:

...

ServiceHost host = new ServiceHost(typeof(GreetingService),

    neuer Uri("https://localhost:8080/greeting"),

    new Uri("net.tcp://localhost:8081/greeting"));

Gastgeber. AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");

...

Wenn Sie die Konsolenanwendung mit dieser eingefügten Codezeile ausführen, werden Sie feststellen, dass jetzt nur ein einzelner Endpunkt in der Ausgabe angezeigt wird – das, das wir manuell im obigen Code konfiguriert haben (siehe Abbildung 3).

Abbildung 3: Konsolenausgabe nach der Konfiguration des Hosts mit einem einzelnen Endpunkt

Sie können addDefaultEndpoints jedoch immer selbst aufrufen, wenn Sie den Satz von Standardendpunkten zusammen mit Ihren eigenen Endpunkten hinzufügen möchten. Im folgenden Codebeispiel wird veranschaulicht, wie Dies geschieht:

...

ServiceHost host = new ServiceHost(typeof(GreetingService),

    neuer Uri("https://localhost:8080/greeting"),

    new Uri("net.tcp://localhost:8081/greeting"));

Gastgeber. AddServiceEndpoint(typeof(IHello), new WSHttpBinding(), "myendpoint");

Gastgeber. AddDefaultEndpoints();

...

Wenn Sie die Konsolenanwendung mit dieser Änderung erneut ausführen, werden im Konsolenfenster fünf Endpunkte angezeigt – die, die ich manuell zusammen mit den vier Standardendpunkten konfiguriert habe (siehe Abbildung 4).

Abbildung 4: Konsolenausgabe nach dem manuellen Aufrufen von AddDefaultEndpoints

Da wir nun den Algorithmus und die Mechanik zum Hinzufügen von Standardendpunkten zu Diensten zur Laufzeit verstehen, ist die nächste Frage, wie WCF entscheidet, welche Bindung für eine bestimmte basierte Adresse verwendet werden soll?

Standardprotokollzuordnung

Die Antwort auf diese Frage ist einfach. WCF definiert eine Standardprotokollzuordnung zwischen Transportprotokollschemas (z. B. http, net.tcp, net.pipe usw.) und den integrierten WCF-Bindungen. Die Standardprotokollzuordnung befindet sich in der .NET 4-machine.config.comments-Datei und sieht wie folgt aus:

<system.serviceModel->

   <protocolMapping->

      <add scheme="http" binding="basicHttpBinding" bindingConfiguration="" />

      <add scheme="net.tcp" binding="netTcpBinding" bindingConfiguration=""/>

      <add scheme="net.pipe" binding="netNamedPipeBinding" bindingConfiguration=""/>

      <add scheme="net.msmq" binding="netMsmqBinding" bindingConfiguration=""/>

   </protocolMapping->

   ...

Sie können diese Zuordnungen auf Computerebene überschreiben, indem Sie diesen Abschnitt zu machine.config hinzufügen und die Zuordnung für jedes Protokollschema ändern. Oder wenn Sie ihn nur im Bereich einer Anwendung überschreiben möchten, können Sie diesen Abschnitt in Ihrer Anwendungs-/Webkonfigurationsdatei überschreiben.

Wenn Sich Ihre Organisation beispielsweise hauptsächlich auf das Erstellen von RESTful-Diensten mit WCF konzentriert, kann es sinnvoll sein, die Standardbindung für das "http"-Protokollschema in das WebHttpBinding zu ändern. Im folgenden Beispiel wird veranschaulicht, wie Sie dies in einer Anwendungskonfigurationsdatei erreichen:

<Konfiguration>

  <system.serviceModel->

    <protocolMapping->

      <add scheme="http" binding="webHttpBinding"/>

    </protocolMapping->

  </system.serviceModel>

</configuration>

Wenn ich nun die zuvor gezeigte Konsolenanwendung mit diesem app.config erneut ausführen würde, werden nun die beiden standardmäßigen HTTP-basierten Endpunkte angezeigt, die webHttpBinding verwenden (siehe Abbildung 5).

Abbildung 5: Konsolenausgabe nach außer Kraft setzen der standardmäßigen HTTP-Protokollzuordnung

Sobald WCF bestimmt, welche Bindung über die Protokollzuordnungstabelle verwendet werden soll, verwendet sie beim Konfigurieren des Standardendpunkts die Standardbindungskonfiguration. Wenn Sie nicht mit den integrierten Bindungsstandardeinstellungen zufrieden sind, können Sie auch die Standardkonfiguration für eine bestimmte Bindung außer Kraft setzen.

Standardbindungskonfigurationen

Jede WCF-Bindung enthält eine Standardkonfiguration, die verwendet wird, es sei denn, die Hostanwendung wird explizit von der Hostanwendung für einen bestimmten Endpunkt außer Kraft gesetzt. Jede von Ihnen verwendete Bindungsinstanz enthält immer die integrierten Standardwerte, es sei denn, Sie entscheiden sich, eine explizite Bindungskonfiguration außer Kraft zu setzen.

In WCF 3.x definieren Sie dazu eine benannte Bindungskonfiguration, die Sie über das BindingConfiguration-Attribut auf Endpunktdefinitionen anwenden können. Die Mechanik der ordnungsgemäßen Vorgehensweise ist mühsam und fehleranfällig.  Die folgende Konfigurationsdatei zeigt ein typisches Beispiel:

<Konfiguration>

  <system.serviceModel->

    <Bindungen>

      <basicHttpBinding->

        <Bindungsname="BasicWithMtom" messageEncoding="Mtom"/>

      </basicHttpBinding->

    </bindings>

    <Dienste>

      <Dienstname="GreetingService">

        <endpoint address="mtom" binding="basicHttpBinding"

                  bindingConfiguration="BasicWithMtom"

                  contract="IHello"/>

      </service>

    </services>

  </system.serviceModel>

</configuration>

Im obigen Beispiel überschreibt die Bindungskonfiguration "BasicWithMtom" die Standardwerte für "BasicHttpBinding", indem die Nachrichtencodierung in MTOM geändert wird. Diese Bindungskonfiguration wird jedoch nur wirksam, wenn Sie sie über das Attribut "bindingConfiguration" auf einen bestimmten Endpunkt anwenden . Dies ist der Schritt, der Entwickler und Betriebsmitarbeiter häufig entzieht, wodurch Konfigurationsprobleme verursacht werden.

Mit WCF 4 können Sie jetzt Standardbindungskonfigurationen definieren, indem Sie beim Definieren der neuen Konfiguration einfach den Bindungskonfigurationsnamen weglassen. Dann verwendet WCF diese Standardkonfiguration für alle Endpunkte, die diese Bindung verwenden, für die keine explizite Bindungskonfiguration festgelegt ist.

Wenn wir z. B. die folgende app.config Datei zur zuvor gezeigten Konsolenanwendung hinzufügen, übernehmen die beiden Standard-HTTP-Endpunkte diese Standardkonfiguration für BasicHttpBinding, die MTOM aktiviert:

<Konfiguration>

  <system.serviceModel->

    <Bindungen>

      <basicHttpBinding->

        <Binding messageEncoding="Mtom"/><!-- beachten Sie, dass kein Namensattribute vorhanden ist ->

      </basicHttpBinding->

    </bindings>

  </system.serviceModel>

</configuration>

Natürlich können Sie diese Standardbindungskonfigurationen auch zu machine.config hinzufügen, wenn sie für alle Dienste, die auf dem Computer ausgeführt werden, wirksam werden sollen, oder Sie können sie auf Anwendungsbasis definieren, indem Sie die Standardbindungskonfigurationen in der Anwendungskonfigurationsdatei hinzufügen.

Dieses Feature bietet Ihnen einen einfachen Mechanismus zum Definieren eines Standardsatzes von Bindungsstandardeinstellungen, den Sie für alle Ihre Dienste verwenden können, ohne die Komplexität der Bindungskonfigurationen für andere Entwickler oder die IT/Operations-Mitarbeiter zu erzwingen. Sie können einfach die entsprechende Bindung auswählen und sicher sein, dass die richtige Standardkonfiguration von der Hostingumgebung bereitgestellt wird.

Zusätzlich zu Standardbindungskonfigurationen sollten Sie für Ihre Dienste und Endpunkte die Standardverhaltenskonfiguration berücksichtigen.

Standardverhaltenskonfigurationen

WCF 4 ermöglicht auch das Definieren von Standardverhaltenskonfigurationen für Dienste und Endpunkte, was dies vereinfachen kann, wenn Sie eine Standardverhaltenskonfiguration für alle Dienste oder Endpunkte freigeben möchten, die auf einem Computer oder innerhalb einer Lösung ausgeführt werden.

In WCF 3.x müssen Sie benannte Verhaltenkonfigurationen definieren, die Sie explizit für Dienste und Endpunkte über das Attribut "behaviorConfiguration" anwenden. Mit WCF 4 können Sie Standardverhaltenskonfigurationen definieren, indem Sie den Namen in der Konfigurationsdefinition weglassen. Wenn Sie diese Standardverhaltensweisen zu machine.confighinzufügen, gelten diese für alle Dienste oder Endpunkte, die auf dem Computer gehostet werden. Wenn Sie sie zu app.confighinzufügen, werden sie nur innerhalb des Bereichs der Hostanwendung wirksam. Hier ist ein Beispiel:

<Konfiguration>

  <system.serviceModel->

    <Verhalten>

      <serviceBehaviors>

        <Verhalten><!-- kein Namensattribute bemerken ->

          <serviceMetadata httpGetEnabled="true"/>

        </behavior>

       </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

In diesem Beispiel werden Dienstmetadaten für alle Dienste aktiviert, die nicht mit einer expliziten Verhaltenskonfiguration enthalten sind. Wenn wir diese Standardverhaltenskonfiguration der app.config Datei für die Konsolenanwendung früher hinzufügen und die Anwendung erneut ausführen, können wir zur Basis-HTTP-Adresse navigieren, um die Diensthilfeseite und die WSDL-Definition des Diensts abzurufen (siehe Abbildung 6).

Abbildung 6: Navigieren zu den Dienstmetadaten, die durch die Standardverhaltenskonfiguration

Ein weiteres neues Feature in WCF 4 besteht darin, dass Verhaltenskonfigurationen jetzt ein Vererbungsmodell unterstützen. Wenn eine Anwendung eine Verhaltenskonfiguration definiert, die denselben Namen wie in machine.configbereits definiert hat, wird die anwendungsspezifische Verhaltenskonfiguration mit der computerweiten Konfiguration zusammengeführt und fügt der abgeleiteten Verbundverhaltenskonfiguration weitere Verhaltensweisen hinzu.

Standardendpunkte

Im Zusammenhang mit Standardendpunkten handelt es sich um ein weiteres neues WCF 4-Feature, das als "Standardendpunkte" bezeichnet wird. Sie können sich einen Standardendpunkt als eine gängige vorkonfigurierte Endpunktdefinition vorstellen, die in das WCF 4-Framework integriert ist, das Sie einfach verwenden können. Standardendpunkte definieren eine "Standard"-Endpunktkonfiguration, die Sie normalerweise nicht ändern, auch wenn Sie kurz sehen müssen.

Abbildung 7 beschreibt die Standardendpunkte, die mit WCF 4 ausgeliefert werden. Diese stellen Standardendpunktdefinitionen für einige der am häufigsten verwendeten WCF 4-Features und Kommunikationsszenarien bereit. Bei einem MEX-Endpunkt müssen Sie z. B. immer IMetadataExchange für den Dienstvertrag angeben und wahrscheinlich HTTP auswählen. Anstatt sie also immer manuell zu erledigen, stellt WCF eine Standardendpunktdefinition für den metdata-Austausch namens "mexEndpoint" bereit, der einfach zu verwenden ist.

Abbildung 7: Standardendpunkte in WCF 4

Standardendpunktname Beschreibung

mexEndpoint

Definiert einen Standardendpunkt für MEX, der mit IMetadataExchange für den Dienstvertrag konfiguriert ist, mexHttpBinding als Standardbindung (Sie können dies ändern) und eine leere Adresse.

dynamicEndpoint

Definiert einen Standardendpunkt, der für die Verwendung von WCF Discovery in einer WCF-Clientanwendung konfiguriert ist. Bei Verwendung dieses Standardendpunkts ist keine Adresse erforderlich, da der Client während des ersten Aufrufs nach einem Dienstendpunkt fragt, der dem angegebenen Vertrag entspricht, und stellt automatisch eine Verbindung mit diesem für Sie her. Standardmäßig wird die Ermittlungsabfrage über Multicast UDP gesendet, Sie können jedoch die Ermittlungsbindung und Suchkriterien angeben, die bei Bedarf verwendet werden sollen.

discoveryEndpoint

Definiert einen Standardendpunkt, der für Ermittlungsvorgänge innerhalb einer Clientanwendung vorkonfiguriert ist. Der Benutzer muss die Adresse und die Bindung angeben, wenn dieser Standardendpunkt verwendet wird.

udpDiscoveryEndpoint

Definiert einen Standardendpunkt, der für Ermittlungsvorgänge innerhalb einer Clientanwendung mithilfe der UDP-Bindung an einer Multicastadresse vorkonfiguriert ist. Abgeleitet von DiscoveryEndpoint.

announcementEndpoint

Definiert einen Standardendpunkt, der für die Ankündigungsfunktionalität der Ermittlung vorkonfiguriert ist. Der Benutzer muss die Adresse und die Bindung angeben, wenn dieser Standardendpunkt verwendet wird.

udpAnnouncementEndpoint

Definiert einen Standardendpunkt, der für die Ankündigungsfunktion über eine UDP-Bindung an einer Multicastadresse vorkonfiguriert ist. Dieser Endpunkt wird von announcementEndpoint abgeleitet.

workflowControlEndpoint

Definiert einen Standardendpunkt zum Steuern der Ausführung von Workflowinstanzen (Erstellen, Ausführen, Anhalten, Beenden usw.).

webHttpEndpoint

Definiert einen Standardendpunkt, der mit dem WebHttpBinding und dem WebHttpBehavior konfiguriert ist. Wird verwendet, um REST-Dienste verfügbar zu machen.

webScriptEndpoint

Definiert einen Standardendpunkt, der mit webHttpBinding und WebScriptEnablingBehavior konfiguriert ist. Wird verwendet, um Ajax-Dienste verfügbar zu machen.

Sie können jeden dieser Standardendpunkte in Ihren eigenen Dienstkonfigurationen nutzen, indem Sie einfach nach Namen darauf verweisen. Der <Endpunkt> Elements enthält jetzt ein "kind"-Attribut, mit dem Sie den Namen eines Standardendpunkts angeben können. Im folgenden Beispiel wird beispielsweise der GreetingService mit einem MEX-Endpunkt konfiguriert, indem die Standarddefinition "mexEndpoint" verwendet wird:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <Dienstname="GreetingService">

        <endpoint kind="basicHttpBinding" contract="IHello"/>

        <endpoint kind="mexEndpoint" address="mex" />

      </service>

    </services>

  </system.serviceModel>

</configuration>

Obwohl die Standardendpunkte Sie vor den meisten Konfigurationsdetails abschirmen (z. B. mit dem mexEndpoint musste ich die Bindung oder den Vertrag nicht angeben), gibt es möglicherweise immer noch Zeiten, in denen Sie sie verwenden möchten, aber die Standardendpunktdefinitionen etwas anders konfigurieren müssen. 

Wenn Sie dies tun müssen, können Sie den Abschnitt <standardEndpoints> verwenden und die Endpunktkonfiguration für den Standardendpunkt außer Kraft setzen. Anschließend können Sie beim Definieren eines neuen <> Endpunkts über das endpointConfiguration-Attribut auf diese Konfiguration verweisen, wie hier dargestellt:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <Dienstname="GreetingService">

        <endpoint binding="basicHttpBinding" contract="IHello"/>

        <endpunkt kind="udpDiscoveryEndpoint" endpointConfiguration="D11"/>

      </service>

    </services>

    <standardEndpoints->

      <udpDiscoveryEndpoint->

        <standardEndpoint name="D11" discoveryVersion="WSDiscovery11"/>

      </udpDiscoveryEndpoint>

    </standardEndpoints->

    <Verhalten>

      <serviceBehaviors>

        <Verhalten>

          <serviceDiscovery/>

          <serviceMetadata httpGetEnabled="true"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

In diesem Beispiel wird die Standardversion WS-Discovery Version für den Standardendpunkt "udpDiscoveryEndpoint" geändert (wir werden kurz über die Dienstermittlung sprechen).

Vereinfachen des IIS/ASP.NET-Hostings

Angesichts dieser neuen Features für Standardendpunkte, Standardbindungskonfigurationen und Standardverhaltenskonfigurationen wird das Hosting in IIS/ASP.NET in WCF 4 wesentlich einfacher. ASP.NET Entwickler, die mit ASMX-Diensten arbeiten, können jetzt WCF-Dienste definieren, die in der Natur genauso einfach sind.

Sehen Sie sich tatsächlich an, wie einfach die folgende WCF-Dienstdefinition ist:

<!-- HelloWorld.svc -->

<%@ ServiceHost Language="C#" Debug="true" Service="HelloWorldService"

    CodeBehind="~/App_Code/HelloWorldService.cs" %>

[ServiceContract]

öffentliche Klasse HelloWorldService

{

    [OperationContract]

    öffentliche Zeichenfolge HelloWorld()

    {

        "Hallo, Welt" zurückgeben;

    }

}

Dies ist die einfachste Form der WCF-Dienstdefinition, da wir keine separate Schnittstellendefinition verwenden, um den Dienstvertrag zu definieren und alles in einer Datei definiert ist, HelloWorld.svc (Hinweis: Ich empfehle diesen Ansatz nicht, und es ist nicht möglich, einen Vergleich mit ASMX zu erstellen). Dies sollte ähnlich wie typische ASMX-Dienste sein, wobei der Hauptunterschied die Attributnamen ist, die Sie für die Dienstklasse verwenden (z. B. [WebService] und [WebMethod]). Es gibt definitiv weniger bewegliche Teile.

Mit den im vorherigen Abschnitt beschriebenen neuen WCF 4-Features können Sie jetzt ohne zusätzliche WCF-Konfiguration zu HelloWorld.svc navigieren, und die WCF-Aktivierungslogik erstellt hinter den Kulissen die ServiceHost-Instanz und konfiguriert sie mit einem einzigen Standard-HTTP-Endpunkt. Und wenn Sie Ihrem machine.config Datei, das Dienstmetadaten aktiviert, ein Standarddienstverhalten hinzugefügt haben, wird die WCF-Hilfeseite und der Link zur WSDL-Definition angezeigt, wenn Sie zu HelloWorld.svc navigieren (siehe Abbildung 8).

Abbildung 8: Hilfeseite "HelloWorldService"

Wenn Sie die Dienstmetadaten nicht computerweit aktiviert haben, können Sie sie in Ihrer Webanwendung aktivieren, indem Sie der web.config Datei die folgende Standardverhaltenskonfiguration hinzufügen:

...

<system.serviceModel->

  <Verhalten>

    <serviceBehaviors>

      <Verhalten><!-- beachten, dass kein Namensattribute vorhanden ist ->

         <serviceMetadata httpGetEnabled="true"/>

      </behavior>

    </serviceBehaviors>

  </behaviors>

</system.serviceModel>

...

Sie können auch andere Standardeinstellungen ändern, indem Sie die in den vorherigen Abschnitten beschriebenen Verfahren befolgen. Sie können z. B. die Standardprotokollzuordnung ändern, Standardbindungskonfigurationen oder zusätzliche Standardverhaltenskonfigurationen hinzufügen. Wenn der Dienst mehr als einen Dienstvertrag implementiert, wird die resultierende ServiceHost-Instanz mit einem HTTP-Endpunkt pro Vertrag konfiguriert.

Angenommen, wir hosten unsere GreetingService (von früher) über die hier gezeigte SVC-Datei:

<!-- GreetingService.svc -->

<%@ServiceHost Service="GreetingService"%>

Angesichts unserer Definition für GreetingService erstellt die WCF-Aktivierungslogik beim ersten Navigieren zu GreetingService.svc die ServiceHost-Instanz und fügt zwei Standard-HTTP-Endpunkte für den GreetingService-Typ hinzu (eine für jeden Dienstvertrag). Sie können dies überprüfen, indem Sie zur WSDL-Definition navigieren und zwei <Portieren> Elemente innerhalb des <Dienst->-Elements finden.

Insgesamt sollten diese WCF-Konfigurationserleichterungen es ASP.NET Entwicklern viel einfacher machen, WCF-Dienste in ihren Webanwendungen auszuführen, und es bringt den einfachsten Fall wesentlich näher an die Erfahrung, die Entwickler mit ASP.NET Webdiensten verwendet haben.

Dateilose Aktivierung

Obwohl SVC-Dateien das Verfügbarmachen von WCF-Diensten vereinfachen, wäre ein noch einfacherer Ansatz das Definieren virtueller Aktivierungsendpunkte innerhalb Web.config, wodurch die Notwendigkeit von SVC-Dateien vollständig entfernt wird.

In WCF 4 können Sie virtuelle Dienstaktivierungsendpunkte definieren, die Ihren Diensttypen in Web.configzugeordnet sind. Dadurch können WCF-Dienste aktiviert werden, ohne physische SVC-Dateien (z. B. "Dateilose Aktivierung") beibehalten zu müssen. Das folgende Beispiel zeigt, wie Sie einen Aktivierungsendpunkt konfigurieren:

<Konfiguration>

  <system.serviceModel->

    <serviceHostingEnvironment->

      <serviceActivations->

        <"relativeAddress="Greeting.svc" service="GreetingService"/>

      </serviceActivations->

    </serviceHostingEnvironment>

  </system.serviceModel>

</configuration>

Damit ist es jetzt möglich, den GreetingService mithilfe eines relativen Pfads von "Greeting.svc" (relativ zur Basisadresse der Webanwendung) zu aktivieren. Um dies zu veranschaulichen, habe ich eine IIS-Anwendung auf meinem Computer namens "GreetingSite" erstellt, die ich dem Anwendungspool "ASP.NET v4.0" zugewiesen habe, und es dem GreetingService-Projektverzeichnis zugeordnet, das die oben gezeigte web.config enthält. Jetzt kann ich einfach zu https://localhost/GreetingSite/Greeting.svc navigieren, ohne tatsächlich eine physische SVC-Datei auf dem Datenträger zu haben. Abbildung 9 zeigt, wie dies im Browser aussieht.

Abbildung 9: Beispiel für eine dateilose Aktivierung

Entdeckung

Das nächste wichtige WCF 4-Feature, das wir besprechen werden, ist die Dienstermittlung. In einigen speziellen dienstorientierten Umgebungen gibt es Dienste, deren Laufzeitspeicherort dynamisch und sich ständig ändert. Betrachten Sie beispielsweise Umgebungen, in denen verschiedene Arten von dienstfähigen Geräten ständig beitreten und das Netzwerk als Teil der gesamten Geschäftslösung verlassen. Der Umgang mit dieser Realität erfordert, dass Clients den Laufzeitspeicherort von Dienstendpunkten dynamisch ermitteln.

WS-Discovery ist eine OASIS-Spezifikation, die ein SOAP-basiertes Protokoll definiert, um den Standort von Dienstendpunkten zur Laufzeit dynamisch zu ermitteln. Das Protokoll ermöglicht Clients die Überprüfung auf Dienstendpunkte, die bestimmten Kriterien entsprechen, um eine Liste der geeigneten Kandidaten abzurufen. Ein Client kann dann einen bestimmten Endpunkt aus der ermittelten Liste auswählen und seine aktuelle Laufzeitendpunktadresse verwenden.

WS-Discovery definiert zwei primäre Betriebsmodi: Ad-hoc-Modus und verwalteter Modus. Im Ad-hoc-Modus werden Clients auf Dienste durch Senden von Multicastnachrichten durchstellen. Das Framework stellt einen UDP-Multicastmechanismus für diesen Ad-hoc-Modus bereit. Dienste, die mit dem Prüfpunkt übereinstimmen, reagieren direkt auf den Client. Um die Notwendigkeit der Clientabfragung zu minimieren, können Dienste sich auch "ankündigen", wenn sie dem Netzwerk beitreten oder das Netzwerk verlassen, indem sie eine Multicastnachricht an Clients senden, die möglicherweise "lauschen" sind. Die Ad-hoc-Ermittlung ist durch das Protokoll beschränkt, das für Multicasting-Nachrichten verwendet wird, falls für UDP nur die Dienste verwendet werden, die im lokalen Subnetz lauschen, die Nachrichten empfangen können.

Bei der Ermittlung verwalteter Dienste stellen Sie einen Ermittlungsproxy im Netzwerk bereit, der die auffindbaren Dienstendpunkte "verwaltet". Clients sprechen direkt mit dem Discoveryproxy, um Dienste basierend auf Denbingkriterien zu finden. Der Ermittlungsproxy benötigt ein Repository von Diensten, das mit der Abfrage abgeglichen werden kann. Wie der Proxy mit diesen Informationen gefüllt wird, ist ein Implementierungsdetails. Discoveryproxys können problemlos mit einem exisiting-Dienst-Repository verbunden werden, sie können mit einer Liste von Endpunkten vorkonfiguriert werden, oder ein Discoveryproxy kann sogar auf Ankündigungen lauschen, um den Cache zu aktualisieren. Im verwalteten Modus können Ankündigungen direkt an einen Empfänger gesendet werden, möglicherweise durch einen Ermittlungsproxy.

Das .NET 4.0 Framework stellt die Basisklassen bereit, die Sie zum Implementieren Ihres eigenen Discoveryproxys benötigen. Die Basisklassen abstrahieren die Details des Discoveryprotokolls, sodass Sie sich einfach auf die Logik konzentrieren können, die der Ermittlungsproxy enthalten soll. Beispielsweise müssen Sie nur definieren, was der Ermittlungsproxy als Reaktion auf eine Probenachricht, Ankündigungsnachrichten und Auflösen von Nachrichten bewirkt.

WCF 4 bietet eine vollständige Implementierung des WS-Discovery-Protokolls und bietet Unterstützung für die Ad-hoc- und verwalteten Ermittlungsmodi. Wir sehen uns die einzelnen unten aufgeführten Informationen kurz an.

Simple Service Discovery

Die einfachste Möglichkeit zum Aktivieren der Dienstermittlung ist der Ad-hoc-Modus. WCF erleichtert die Aktivierung der Dienstermittlung in Ihren Diensthostanwendungen, indem einige Standardmäßige Ermittlungsendpunkte und ein Dienstermittlungsverhalten bereitgestellt werden. Um Ihren Dienst für die Ermittlung zu konfigurieren, fügen Sie einfach den standardmäßigen "udpDiscoveryEndpoint"-Endpunkt hinzu, und aktivieren Sie dann das <serviceDiscovery-> Verhalten für den Dienst.

Hier ist ein vollständiges Beispiel, das zeigt, wie Dies geschieht:

<Konfiguration>

    <system.serviceModel->

      <Dienste>

        <Dienstname="CalculatorService">

          <endpoint binding="wsHttpBinding" contract="ICalculatorService" />

          <!-- einen standardmäßigen UDP-Ermittlungsendpunkt hinzufügen –>

          <Endpunktname="udpDiscovery" kind="udpDiscoveryEndpoint"/>

        </service>

      </services>

      <Verhalten>

        <serviceBehaviors>

          <Verhalten>

            <serviceDiscovery/><!-- das Verhalten der Dienstermittlung aktivieren –>

          </behavior>

        </serviceBehaviors>

      </behaviors>

    </system.serviceModel>

</configuration>

Dadurch wird Ihr Dienst über UDP im lokalen Subnetz auffindbar. Clients können dann WS-Discovery zur Laufzeit nutzen, um die tatsächliche Adresse des ausgeführten Diensts zu ermitteln. WCF 4 erleichtert Clients dies über den dynamicEndpoint-Standardendpunkt.

Verwenden Sie einfach Ihren vorhandenen Clientendpunkt, den Sie zum Herstellen einer Verbindung mit dem Dienst verwendet haben, entfernen Sie die Adresse, und fügen Sie ein "kind="dynamicEndpoint"-Tag hinzu.

<Konfiguration>

    <system.serviceModel->

        <Client->

          <Endpunkt

              name="calculatorEndpoint"

              kind="dynamicEndpoint"

              binding="wsHttpBinding"

              contract="ICalculatorService">

          </endpoint>

        </client->

    </system.serviceModel>

</configuration>

Wenn der erste Dienstaufruf erfolgt, sendet der Client eine Multicastabfrage, die nach Diensten sucht, die dem ICalculatorService-Vertrag entsprechen, und versucht, eine Verbindung mit einem Dienst herzustellen. Mit verschiedenen Einstellungen können Sie Ihre Serach optimieren, die Ermittlungsbindungen anpassen und den Ermittlungsprozess steuern. Sie können dies auch programmgesteuert mithilfe der DiscoveryClient-Klasse ausführen.

Das folgende Beispiel geht einen Schritt weiter, indem gezeigt wird, wie UdpDiscoveryEndpoint programmgesteuert verwendet wird, um einen ICalculatorService-Endpunkt zu ermitteln und dann aufzurufen:

DiscoveryClient erstellen

DiscoveryClient discoveryClient =

    new DiscoveryClient(new UdpDiscoveryEndpoint());

Suchen von ICalculatorService-Endpunkten im angegebenen Bereich

FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));

FindResponse findResponse = discoveryClient.Find(findCriteria);

Wählen Sie einfach den ersten ermittelten Endpunkt aus.

EndpointAddress address = findResponse.Endpoints[0]. Adresse;

Erstellen des Zieldienstclients

CalculatorServiceClient-Client =

    new CalculatorServiceClient("calculatorEndpoint");

Herstellen einer Verbindung mit dem ermittelten Dienstendpunkt

Kunde. Endpoint.Address = address;

Console.WriteLine("Aufrufen von CalculatorService bei {0}", Adresse);

Rufen Sie den Vorgang "Dienst hinzufügen" auf.

double result = client. Add(100, 15.99);

Console.WriteLine("Add({0},{1}) = {2}", 100, 15.99, result);

Nachdem das Clientprogramm die Sammlung der ermittelten Endpunkte abgerufen hat, kann es einen davon verwenden, um den Zieldienst tatsächlich aufzurufen. Abbildung 10 zeigt die Ausgabe der Ausführung des oben gezeigten Clientcodes, vorausgesetzt, der Dienst wird ebenfalls gleichzeitig ausgeführt. Hinweis: In diesem Beispiel ist der Suchvorgang auf dem Ermittlungsclient synchron; Discovery bietet auch Unterstützung für asynchrone Suchvorgänge.

Abbildung 10: Ausgabe der Ausführung des Ermittlungsclientcodes

Verwenden von Bereichen beim Ermitteln von Endpunkten

Im vorherigen Beispiel wurde der Client einfach auf Dienste basierend auf dem Dienstvertragstyp untersucht. Clients können die Ermittlungsergebnisse einschränken, indem beim Senden der Ermittlungssonden zusätzliche Bereichsinformationen bereitgestellt werden. Sehen wir uns ein einfaches Beispiel an, um zu sehen, wie "Bereiche" während der Ermittlung verwendet werden können.

Zunächst muss der Dienst einen oder mehrere Bereiche jedem Endpunkt zuordnen, der für die Ermittlung veröffentlicht wird. WCF 4 enthält ein <EndpointDiscovery-> Verhalten, das Sie zum Definieren einer Gruppe von Bereichen verwenden können, die Sie einer Endpunktdefinition zuordnen können. Das folgende Beispiel veranschaulicht, wie zwei Bereiche dem einzelnen Endpunkt zugeordnet werden, der für den Dienst definiert ist:

<Konfiguration>

    <system.serviceModel->

      <Dienste>

        <Dienstname="CalculatorService"

                 behaviorConfiguration="calculatorServiceBehavior">

          <endpoint binding="wsHttpBinding"

                    contract="ICalculatorService"

                    behaviorConfiguration="ep1Behavior" />

          <Endpunktname="udpDiscovery" kind="udpDiscoveryEndpoint"/>

        </service>

      </services>

      <Verhalten>

        <serviceBehaviors>

          <Verhaltensname="calculatorServiceBehavior">

            <serviceDiscovery/>

          </behavior>

        </serviceBehaviors>

        <endpointBehaviors>

          <Verhaltensname="ep1Behavior">

            <endpointDiscovery->

               <!-- Bereiche, die diesem Endpunktverhalten zugeordnet sind –>

              <Bereiche>

                <bereich="http://www.example.org/calculator"/> hinzufügen

                <"scope="ldap:///ou=engineering,o=exampleorg,c=us"/>

              </scopes>

            </endpointDiscovery->

          </behavior>

         </endpointBehaviors>

      </behaviors>

    </system.serviceModel>

</configuration>

Clients können auf Dienstendpunkten basierend auf bestimmten Bereichen zur Laufzeit einen Prüfpunkt ausführen. Dazu können sie eine Liste von Zielbereichen zur FindCriteria-Instanz hinzufügen, die Sie für den Suchvorgang bereitstellen. Der folgende Code veranschaulicht, wie ICalculatorService-Endpunkte ermittelt werden, die einem bestimmten LDAP-Bereich entsprechen:

...

DiscoveryClient erstellen

DiscoveryClient discoveryClient = new DiscoveryClient("udpDiscoveryEndpoint");

Suchen von ICalculatorService-Endpunkten im angegebenen Bereich

URI-Bereich = neuer Uri("ldap:///ou=engineering,o=exampleorg,c=us");

FindCriteria findCriteria = new FindCriteria(typeof(ICalculatorService));

findCriteria.Scopes.Add(scope);

FindResponse findResponse = discoveryClient.Find(findCriteria);

...

Durch die Nutzung von Bereichen können Sie Ihre Discoveryimplementierung optimieren, sodass Clients die spezifischen Dienstendpunkte leichter ermitteln können, die für sie von Interesse sind. Discovery ermöglicht auch weitere Anpassungen. Dienste können z. B. einem Endpunkt benutzerdefinierte XML-Metadaten hinzufügen. Diese Informationen werden als Reaktion auf die Abfrage des Clients an den Client gesendet.

Dienstankündigungen

WCF 4 erleichtert auch die Konfiguration von Diensten, um ihre Endpunkte beim Start "anzukündigen". Auf diese Weise können Clients, die sich "anhören", über neue Dienstendpunkte direkt beim Beitritt zum Netzwerk informieren, wodurch die Von Clients durchgeführte Probingmenge (und Multicast-Messaging) reduziert wird.

Sie können einen Dienst mit einem Ankündigungsendpunkt konfigurieren, indem Sie das <serviceDiscovery-> Verhalten verwenden. Mit dem <serviceDiscovery-> Verhalten können Sie eine Sammlung von Ankündigungsendpunkten definieren, die vom Dienst verfügbar gemacht werden. In den meisten Fällen können Sie den Standard "udpAnnouncementEndpoint" verwenden.

Sie müssen den Dienst auch weiterhin mit einem standardmäßigen "udpDiscoveryEndpoint" konfigurieren, wenn er auf von Clients initiierte Discovery-Probe reagieren soll. Das folgende Beispiel zeigt eine typische Konfiguration:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <Dienstname="CalculatorService">

        <endpoint binding="wsHttpBinding" contract="ICalculatorService"/>

        <endpoint kind="udpDiscoveryEndpoint"/>

      </service>

    </services>

    <Verhalten>

      <serviceBehaviors>

        <Verhalten>

          <serviceDiscovery->

            <announcementEndpoints>

              <endpoint kind="udpAnnouncementEndpoint"/>

            </announcementEndpoints>

          </serviceDiscovery->

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Wenn diese Konfiguration eingerichtet ist, liest sich der Dienst an, wenn er online ist, und er gibt auch an, wann er offline ist. Um diese Ankündigungen nutzen zu können, müssen Sie Ihre Kunden speziell so gestalten, dass sie zur Laufzeit auf sie lauschen. Dazu hosten Sie einen Ankündigungsdienst in der Clientanwendung, der das WS-Discovery Ankündigungsprotokoll implementiert.

WCF 4 enthält eine Klasse namens AnnouncementService, die speziell für diesen Zweck entwickelt wurde. Der AnnouncementService stellt zwei Ereignishandler bereit: OnlineAnnouncementReceived und OfflineAnnouncementReceived. Clientanwendungen können einfach eine Instanz des AnnouncementService mithilfe von ServiceHost hosten und Ereignishandler für diese beiden Ereignisse registrieren.

Wenn ein Dienst online ist und sich ankündigt, erhält der vom Client gehostete AnnouncementService die "Online"-Ankündigung, und OnlineAnnouncementReceived wird im Client ausgelöst. Wenn der Dienst offline ist, sendet er eine "Offline"-Ankündigung, und OfflineAnnouncementReceived wird im Client ausgelöst. Im Folgenden wird eine Beispielclientanwendung veranschaulicht, die den AnnouncementService hostet und Handler für die beiden Ankündigungsereignisse implementiert:

Klassenclient

{

    public static void Main()

    {

        Erstellen einer AnnouncementService-Instanz

        AnnouncementService announcementService = new AnnouncementService();

        Abonnieren der Ankündigungsereignisse

        announcementService.OnlineAnnouncementReceived += OnOnlineEvent;

        announcementService.OfflineAnnouncementReceived += OnOfflineEvent;

        Erstellen von ServiceHost für den AnnouncementService

        using (ServiceHost announcementServiceHost =

            new ServiceHost(announcementService))

        {

            Überwachen der Über UDP-Multicast gesendeten Ankündigungen

            announcementServiceHost.AddServiceEndpoint(

                new UdpAnnouncementEndpoint());

            announcementServiceHost.Open();

            Console.WriteLine("Überwachen von Dienstankündigungen.");

            Console.WriteLine();

            Console.WriteLine("Drücken Sie <EINGABETASTE,> beendet werden soll.");

            Console.ReadLine();

        }

    }

    static void OnOnlineEvent(object sender, AnnouncementEventArgs e)

    {

        Console.WriteLine();

        Console.WriteLine("Empfangen einer Onlineankündigung von {0}:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    static void OnOfflineEvent(object sender, AnnouncementEventArgs e)

    {

        Console.WriteLine();

        Console.WriteLine("Empfangen einer Offlineankündigung von {0}:",

            e.EndpointDiscoveryMetadata.Address);

        PrintEndpointDiscoveryMetadata(e.EndpointDiscoveryMetadata);

    }

    ...

}

Abbildung 11: Überwachen von Erkennungsankündigungsmeldungen

Angenommen, ich führe dieses Clientprogramm aus und verlasse es für eine Weile. Später habe ich einige Instanzen der Diensthostanwendung ausgeführt. Bei jedem Start wird im Clientkonsolenfenster eine "Online"-Meldung angezeigt. Wenn ich jede der Diensthostanwendungen schließt, wird im Clientkonsolenfenster eine Meldung "offline" angezeigt. Abbildung 11 zeigt das resultierende Clientkonsolenfenster, nachdem ich gerade beschrieben habe.

Denken Sie daran, dass der Ad-hoc-Ermittlungsmodus nur in einem lokalen Subnetz funktioniert. Wenn Sie WS-Discovery über die Grenzen Ihres lokalen Netzwerks hinaus verwenden möchten, müssen Sie den verwalteten Ermittlungsmodus aktivieren. WCF 4 bietet Unterstützung für die Erstellung der erforderlichen verwalteten Ermittlungskomponenten.

Managed Service Discovery

Die Implementierung des verwalteten Ermittlungsmodus ist etwas mehr beteiligt als der Ad-hoc-Modus, da Sie einen Ermittlungsproxydienst implementieren müssen. Der Ermittlungsproxydienst ist die Komponente, die alle verfügbaren Dienstendpunkte nachverfolgt. In diesem Beispiel wird die Ankündigungsfunktion verwendet, um den Discoveryproxy zu aktualisieren. Es gibt viele andere Möglichkeiten, einen Discoveryproxy mit den relevanten Ermittlungsinformationen bereitzustellen, z. B. sie können eine vorhandene Datenbank mit Endpunkten verbinden und Daten von dort erfassen. Wie implementieren Sie also einen Ermittlungsproxydienst?

WCF 4 enthält eine Basisklasse namens DiscoveryProxy, von der Sie ableiten können, um einen Ermittlungsproxydienst zu implementieren. Abbildung 12 zeigt den Start einer implementierung eines benutzerdefinierten Ermittlungsproxydiensts. Die .NET 4 SDK-Beispiele enthalten eine vollständige Beispielimplementierung für Ihre Referenz. Nachdem Sie die Implementierung des Ermittlungsproxydiensts abgeschlossen haben, müssen Sie ihn an einer beliebigen Stelle hosten.

Abbildung 12: Implementieren eines benutzerdefinierten Discoveryproxydiensts

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,

    ConcurrencyMode = ConcurrencyMode.Multiple)]

öffentliche Klasse MyDiscoveryProxy : DiscoveryProxyBase

{

    Repository zum Speichern von EndpointDiscoveryMetadata.

    Stattdessen kann eine Datenbank oder eine Flat-Datei verwendet werden.

    Dictionary<EndpointAddress, EndpointDiscoveryMetadata> onlineServices;

    public MyDiscoveryProxy()

    {

        this.onlineServices =

            neues Wörterbuch<EndpointAddress, EndpointDiscoveryMetadata>();

    }

    OnBeginOnlineAnnouncement wird aufgerufen, wenn eine Hello-Nachricht von Proxy empfangen wird

    protected override IAsyncResult OnBeginOnlineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, AsyncCallback-Rückruf, Objektstatus)

    {

        das. AddOnlineService(endpointDiscoveryMetadata);

        neue OnOnlineAnnouncementAsyncResult(callback, state);

    }

    protected override void OnEndOnlineAnnouncement(IAsyncResult result)

    {

        OnOnlineAnnouncementAsyncResult.End(result);

    }

    OnBeginOfflineAnnouncement wird aufgerufen, wenn eine Bye-Nachricht von Proxy empfangen wird

    protected override IAsyncResult OnBeginOfflineAnnouncement(

        DiscoveryMessageSequence messageSequence, EndpointDiscoveryMetadata

        endpointDiscoveryMetadata, AsyncCallback-Rückruf, Objektstatus)

    {

        das. RemoveOnlineService(endpointDiscoveryMetadata);

        neue OnOfflineAnnouncementAsyncResult(callback, state);

    }

    protected override void OnEndOfflineAnnouncement(IAsyncResult result)

    {

        OnOfflineAnnouncementAsyncResult.End(result);

    }

    OnBeginFind wird aufgerufen, wenn eine Probeanforderungsnachricht von Proxy empfangen wird

    protected override IAsyncResult OnBeginFind(

        FindRequestContext findRequestContext, AsyncCallback-Rückruf, Objektstatus)

    {

        das. MatchFromOnlineService(findRequestContext);

        neue OnFindAsyncResult(callback, state);

    }

    protected override void OnEndFind(IAsyncResult result)

    {

        OnFindAsyncResult.End(result);

    }

    ...

In diesem Beispiel hoste ich einfach den MyDiscoveryProxy-Dienst in einer Konsolenanwendung.  Ich werde den Host mit zwei Endpunkten konfigurieren: einen Ermittlungsendpunkt und einen Ankündigungsendpunkt. Das folgende Beispiel veranschaulicht, wie der MyDiscoveryProxy-Dienst ordnungsgemäß mit beiden Endpunkten gehostet wird:

Klassenprogramm

{

    public static void Main()

    {

        Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");

        Uri announcementEndpointAddress =

            new Uri("net.tcp://localhost:9021/Announcement");

        ServiceHost proxyServiceHost = new ServiceHost(new MyDiscoveryProxy());

        DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(

            new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));

        discoveryEndpoint.IsSystemEndpoint = false;

        AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(

            new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));

        proxyServiceHost.AddServiceEndpoint(discoveryEndpoint);

        proxyServiceHost.AddServiceEndpoint(announcementEndpoint);

        proxyServiceHost.Open();

        Console.WriteLine("Proxy service started.");

        Console.WriteLine();

        Console.WriteLine("Drücken Sie <EINGABETASTE>, um den Dienst zu beenden.");

        Console.WriteLine();

        Console.ReadLine();

        proxyServiceHost.Close();

    }

}

Sobald Sie über einen Ermittlungsproxydienst verfügen und ausgeführt werden, können Sie Ihre Dienste so konfigurieren, dass sie sich direkt an den Ermittlungsproxydienst ankündigen. Ebenso können Sie Ihre Clientanwendungen so konfigurieren, dass der Ermittlungsproxydienst direkt untersucht wird (kein Multicast-Messaging mehr).

Sie konfigurieren den Dienst so, dass er sich direkt an den Ermittlungsproxydienst meldet, indem Sie die Ankündigungsadresse des Discoveryproxys angeben, wenn Sie den AnnouncementEndpoint innerhalb der Diensthostanwendung erstellen. Das folgende Beispiel zeigt, wie Sie dies erreichen:

...

Uri baseAddress = new Uri("net.tcp://localhost:9002/CalculatorService/" +

    Guid.NewGuid(). ToString());

Uri announcementEndpointAddress = new Uri("net.tcp://localhost:9021/Announcement");

ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService), baseAddress);

ServiceEndpoint netTcpEndpoint = serviceHost.AddServiceEndpoint(

    typeof(ICalculatorService), new NetTcpBinding(), string. Leer);

Erstellen eines Ankündigungsendpunkts, der auf den gehosteten Proxydienst verweist

AnnouncementEndpoint announcementEndpoint = new AnnouncementEndpoint(

    new NetTcpBinding(), new EndpointAddress(announcementEndpointAddress));

ServiceDiscoveryBehavior serviceDiscoveryBehavior = new ServiceDiscoveryBehavior();

serviceDiscoveryBehavior.AnnouncementEndpoints.Add(announcementEndpoint);

serviceHost.Description.Behaviors.Add(serviceDiscoveryBehavior);

serviceHost.Open();

...

Anschließend können Sie Ihre Clientanwendungen so konfigurieren, dass sie direkt mit dem Ermittlungsproxydienst kommunizieren, indem Sie die Prüfadresse des Discoveryproxys angeben, wenn Sie den DiscoveryEndpoint innerhalb der Clientanwendung erstellen. Das folgende Beispiel veranschaulicht eine Möglichkeit, dies zu tun:

...

Erstellen Sie einen Ermittlungsendpunkt, der auf den Proxydienst verweist.

Uri probeEndpointAddress = new Uri("net.tcp://localhost:8001/Probe");

DiscoveryEndpoint discoveryEndpoint = new DiscoveryEndpoint(

    new NetTcpBinding(), new EndpointAddress(probeEndpointAddress));

Erstellen von DiscoveryClient mit dem zuvor erstellten discoveryEndpoint

DiscoveryClient discoveryClient = new DiscoveryClient(discoveryEndpoint);

Suchen von ICalculatorService-Endpunkten

FindResponse findResponse = discoveryClient.Find(

    neue FindCriteria(typeof(ICalculatorService)););

...

Sehen wir uns nun ein vollständiges Beispiel an. Zuerst werde ich die Discoveryproxyanwendung ausführen, damit der Ermittlungsproxydienst zur Verwendung verfügbar ist. Anschließend führt ich eine Instanz der Diensthostanwendung aus, die sich mit dem Ermittlungsproxy ankündigen wird. Sobald dies geschieht, wird eine Meldung im Konsolenfenster der Ermittlungsproxyanwendung gedruckt (siehe Abbildung 13). Dies veranschaulicht, dass sich der Dienst erfolgreich an den Discoveryproxy angekündigt hat und der Discoveryproxy die Informationen zum neuen "Online"-Dienstendpunkt gespeichert hat. Wenn wir nun den oben gezeigten Clientcode ausführen, wird der Ermittlungsproxy direkt untersucht und die Endpunktadresse des derzeit ausgeführten Zieldiensts abgerufen.

Abbildung 13: Ausgabe des Ermittlungsproxydiensts zur Laufzeit

Die Schönheit der Verwalteten Dienstermittlung besteht darin, dass sie über Netzwerkgrenzen hinweg funktioniert (sie basiert auf herkömmlichen Dienstaufrufen), und die Notwendigkeit von Multicastnachrichten in Ihrer Discoverylösung wird reduziert. Da die Clients einen Ermittlungsproxy durchlaufen, um nach Diensten zu suchen, müssen die Dienste selbst nicht ständig ausgeführt werden, um ermittelt zu werden.

Erweiterte Ermittlungsproxyverwendung

Das WCF-Programmiermodell bietet Ihnen viel Flexibilität bei der Implementierung eines Discoveryproxys. Das Empfangen von Ankündigungen ist eine Möglichkeit, Ihre Liste der Dienste aufzufüllen; Es ist jedoch nicht die einzige Methode. Wenn Ihre Umgebung z. B. bereits ein Dienst-Repository enthält, können Sie ganz einfach eine Discovery-Proxy-Fassade über diesem Speicher erstellen, um das Repository zur Laufzeit auffindbar zu machen.

Ein Ermittlungsproxy kann entweder im Ad-hoc- oder Verwaltungsmodus eingerichtet werden. Wenn Sie im verwalteten Modus arbeiten, kommunizieren Clients mit dem Proxy direkt auf Unicast-Weise mithilfe von Ankündigungen, Probes und Auflösungen. Der Proxy überträgt die Antwort auch auf unicast-Weise zurück an den Absender.

Wenn ein Proxy im Ad-hoc-Modus ausgeführt wird, kann er auf Multicast-Erkennungsmeldungen lauschen und direkt auf den Absender reagieren. In diesem Ad-hoc-Modus kann ein Proxy auch so konfiguriert werden, dass Multicastnachrichten unterdrückt werden. Das heißt, wenn ein Proxy eine Multicastnachricht empfängt, informiert er den Absender über seine Anwesenheit und informiert den Absender, weitere Abfragen an den Proxy zu leiten, wodurch weitere Multicastnachrichten vermieden werden.

Weitere Informationen zu diesen erweiterten Ermittlungsszenarien finden Sie im WS-Discovery Primer unter http://www.oasis-open.org/committees/download.php/32184/WS-D-primer-wd-04.docx.

Routingdienst

In einigen dienstorientierten Umgebungen ist es häufig nützlich, zentralisierte Routingdienste zu nutzen, die als Broker oder Gateways zu den tatsächlichen Geschäftsdiensten in der Organisation verteilt sind. Dies entkoppelt Die Verbraucher von den realen Geschäftsdiensten und ermöglicht es, eine Vielzahl verschiedener Arten von Zwischenverarbeitung innerhalb des Routingknotens durchzuführen.

Beispielsweise verwenden einige Umgebungen Routing, um eine zentrale Sicherheitsgrenze zu implementieren, die alle eingehenden Nachrichten durchlaufen müssen. Einige verwenden inhaltsbasierte Routingtechniken, um zu bestimmen, welcher Zieldienst basierend auf dem Inhalt einer bestimmten eingehenden Nachricht verwendet werden soll. Andere verwenden Routing zum Implementieren von Protokollüberbrückung, wodurch Verbraucher eine Gruppe von Protokollen für die Kommunikation verwenden können, während der Router eine andere Gruppe von Protokollen für die Kommunikation mit dem Zieldienst verwendet. Es ist auch nicht ungewöhnlich, Routing für verschiedene Lastenausgleichs- oder sogar Dienstversionsverwaltungstechniken zu verwenden.

Unabhängig vom Grund ist das "Zwischenrouting"-Muster eine häufige Anforderung beim heutigen Erstellen umfangreicher SOA-Lösungen. In WCF 3.x gab es keine offizielle Unterstützung für das Routing. Obwohl das Framework die erforderlichen APIs zum Implementieren Ihrer eigenen Routingdienste bereitstellte, war dies sehr viel Arbeit. Es wurden mehrere Artikel im MSDN Magazine veröffentlicht, die zeigen, wie dies erreicht werden kann.

Da routing heutzutage eine solche häufige Anforderung ist, enthält WCF 4 jetzt einen offiziellen "Routingdienst" im Framework, den Sie einfach in Ihren eigenen Lösungen hosten und konfigurieren können.

Grundlegendes zum RoutingService

WCF 4 enthält eine neue Klasse namens RoutingService, die eine generische WCF-Routingimplementierung für die Verwendung in Ihren Anwendungen bereitstellt. Der RoutingService kann das Routing von Nachrichten über ein beliebiges WCF-unterstütztes Protokoll verarbeiten, indem verschiedene Messagingmuster verwendet werden, z. B. Unidirektionale, Anforderungsantwort und Duplexnachrichten). Im Folgenden wird die RoutingService-Klassendefinition gezeigt:

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,

    InstanceContextMode = InstanceContextMode.PerSession,

    UseSynchronizationContext = false, ValidateMustUnderstand = false),

 AspNetCompatibilityRequirements(RequirementsMode =

    AspNetCompatibilityRequirementsMode.Allowed)]

Öffentliche versiegelte Klasse RoutingService : // Verträge ermöglichen verschiedene Kommunikationsmuster

    ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter,

    IDuplexSessionRouter, IDisposable

{

    ... // Implementierung nicht angegeben

}

Wie Sie sehen können, leitet sich die RoutingService-Klasse von mehreren Serviceverträgen ab, um mehrere Messagingmuster zu unterstützen. Jeder Dienstvertrag bietet Unterstützung für ein anderes Messagingmuster, einschließlich Unterstützung für sitzungsbasierte Kommunikation bei Bedarf.

Der gesamte Zweck des RoutingService besteht darin, eingehende Nachrichten von Verbrauchern zu empfangen und sie an einen entsprechenden nachgeschalteten Dienst weiterzuleiten. Der RouterService bestimmt, welcher Zieldienst verwendet werden soll, indem jede eingehende Nachricht anhand einer Reihe von Nachrichtenfiltern ausgewertet wird. Daher steuern Sie als Entwickler das Routingverhalten, indem Sie die Nachrichtenfilter definieren, in der Regel in einer Konfigurationsdatei. Die Zieldienste befinden sich möglicherweise auf demselben Computer wie der RouterService, müssen aber nicht – sie könnten auch über das Netzwerk verteilt werden und erfordern möglicherweise eine Vielzahl von verschiedenen Protokollen.

Hosten des RoutingService

Sie können den RoutingService wie jeden anderen WCF-Dienst in Ihrer Anwendung hosten. Sie erstellen einfach eine ServiceHost-Instanz und geben RoutingService für den Diensttyp an. Sobald Sie "Open" auf der ServiceHost-Instanz aufrufen, können Sie Ihre RoutingService-Nachrichten wie hier gezeigt "weiterleiten":

System verwenden;

mit System.ServiceModel;

mit System.ServiceModel.Routing;

public static void Main()

{

    Erstellen Sie einen ServiceHost für den RoutingService-Typ.

    using (ServiceHost serviceHost =

        new ServiceHost(typeof(RoutingService)))

    {

        versuchen

        {

            serviceHost.Open();

            Console.WriteLine("Der Routingdienst wird jetzt ausgeführt.");

            Console.WriteLine("Drücken Sie <EINGABETASTE>, um den Router zu beenden.");

            Auf den Dienst kann jetzt zugegriffen werden.

            Console.ReadLine();

            serviceHost.Close();

        }

        catch (CommunicationException)

        {

            serviceHost.Abort();

        }

    }

}

Außerdem konfigurieren Sie routingService wie jeder andere Dienst, und hier definieren Sie die Routingfilter. Zunächst müssen Sie sie mit einem oder mehreren Endpunkten konfigurieren. Beim Definieren eines Routingendpunkts wählen Sie eine WCF-Bindung und einen der Routingdienstverträge aus, die von dem oben gezeigten RoutingService implementiert werden (z. B. ISimplexDatagramRouter, IRequestReplyRouter usw.). Sie können mehrere Endpunkte in Ihrem RoutingService verfügbar machen, wenn Sie mehrere Messagingmuster oder WCF-Bindungen unterstützen möchten.

Im folgenden Beispiel wird veranschaulicht, wie Der RoutingService mit vier Routingendpunkten konfiguriert wird: zwei, die das BasicHttpBinding (Unidirektionale und Anforderungsantwort) und zwei verwenden, die WSHttpBinding (Unidirektionale und Anforderungsantwort) verwenden. Beachten Sie, wie es genau wie beim Konfigurieren eines anderen WCF-Diensts ist:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <!--ROUTING SERVICE ->

      <DienstverhaltenConfiguration="routingData"

          name="System.ServiceModel.Routing.RoutingService">

        <Host->

          <baseAddresses->

            <baseAddress="https://localhost:8000/routingservice/router"/>

          </baseAddresses->

        </host>

        <!--

          Definieren und Konfigurieren des Endpunkts, auf den der Router lauschen soll, und die

          Vertrag, den wir verwenden möchten. Router bereitgestellte Verträge sind:

          ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter und

          IDuplexSessionRouter.

         -->

        <Endpunktadresse="oneway-basic"

                  binding="basicHttpBinding"

                  name="onewayEndpointBasic"

                  contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />

        <endpoint address="oneway-ws"

                  binding="wsHttpBinding"

                  name="onewayEndpointWS"

                  contract="System.ServiceModel.Routing.ISimplexDatagramRouter" />

        <Endpunktadresse="twoway-basic"

                  binding="basicHttpBinding"

                  name="reqReplyEndpointBasic"

                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />

        <endpoint address="twoway-ws"

                  binding="wsHttpBinding"

                  name="reqReplyEndpointWS"

                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />

      </service>

    </services>

    ...

Die ISimplexDatagramRouter- und IRequestReplyRouter-Schnittstellen definieren generische Unidirektionale und Anforderungsantwort-Servicevertragsdefinitionen, die in Verbindung mit geschäftsspezifischen Serviceverträgen verwendet werden können. Im Folgenden wird gezeigt, wie diese Schnittstellen in WCF definiert wurden:

[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",

    SessionMode = SessionMode.Allowed)]

öffentliche Schnittstelle ISimplexDatagramRouter

{

    [OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]

    IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback,

        Objektzustand);

    void EndProcessMessage(IAsyncResult result);

}

[ServiceContract(Namespace="https://schemas.microsoft.com/netfx/2009/05/routing",

    SessionMode = SessionMode.Allowed)]

öffentliche Schnittstelle IRequestReplyRouter

{

    [OperationContract(AsyncPattern = true, IsOneWay= false, Action = "*",

        ReplyAction = "*")]

    [GenericTransactionFlow(TransactionFlowOption.Allowed)]

    IAsyncResult BeginProcessRequest(Message message, AsyncCallback callback,

        Objektzustand);

    Message EndProcessRequest(IAsyncResult result);

}

Die oben beschriebene Endpunktkonfiguration macht die Routingendpunkte für Verbraucher verfügbar.  Clientanwendungen wählen einen dieser Endpunkte aus, die in ihrem Clientcode verwendet werden sollen, und leiten alle Dienstaufrufe direkt an den RoutingService weiter. Wenn der RoutingService eine Nachricht über einen dieser Endpunkte empfängt, wertet er die Routingnachrichtenfilter aus, um zu bestimmen, wo die Nachricht weitergeleitet werden soll.

Konfigurieren des RoutingService mit Nachrichtenfiltern

Sie können routingService mit Nachrichtenfiltern entweder über Code oder Konfiguration konfigurieren (wie alles andere in WCF). WCF 4 stellt ein RoutingBehavior zum Verwalten der Routingnachrichtenfilter bereit. Zuerst müssen Sie routingBehavior für routerService aktivieren und dann den Namen der Filtertabelle angeben, die Sie mit dieser bestimmten Instanz des RoutingService verwenden möchten:

<Konfiguration>

  <system.serviceModel->

    ...

    <Verhalten>

      <serviceBehaviors>

        <Verhaltensname="routingData">

          <serviceMetadata httpGetEnabled="True"/>

          <!-- Definieren des Routingverhaltens und Angeben des Namen der Filtertabelle –>

          <routing filterTableName="filterTable1" />

        </behavior>

      </serviceBehaviors>

    </behaviors>

    ...

Wenn Sie im vorherigen Beispiel sehen, in dem wir den RoutingService mit Endpunkten konfiguriert haben, sehen Sie, dass wir das Verhalten "routingData" über das Attribut "behaviorConfiguration" auf den Dienst angewendet haben. Als Nächstes müssen wir eine Filtertabelle mit dem Namen "filterTable1" definieren.

Bevor wir jedoch eine Filtertabelle definieren können, benötigen wir Endpunktdefinitionen für die Zieldienste, an die wir weiterleiten möchten. Sie definieren diese Zielendpunkte innerhalb des WCF-<-Clients> Konfigurationsabschnitt, da RoutingService im Wesentlichen der "Client" ist, wenn er Nachrichten an einen Zieldienst weiterleitet. Das folgende Beispiel zeigt, wie sie zwei Zielendpunkte definieren, an die wir weiterleiten können:

<Konfiguration>

    ...

    <!-- Definieren sie die Clientendpunkte, mit denen der Router kommunizieren soll.

         Dies sind die Ziele, an die der Router Nachrichten sendet. -->

    <Client->

      <Endpunktname="CalculatorService1"

       address="https://localhost:8000/servicemodelsamples/calcservice1"

       binding="wsHttpBinding" contract="*" />

      <Endpunktname="CalculatorService2"

       address="https://localhost:8001/servicemodelsamples/calcservice2"

       binding="wsHttpBinding" contract="*" />

    </client->

    ...

Jetzt können wir die tatsächliche Filtertabelle definieren, die die Routinglogik zur Laufzeit bestimmt. Sie definieren die Filtertabelleneinträge innerhalb des <filterTables>-Elements. Jeder Eintrag innerhalb der <filterTable> definiert eine Zuordnung zwischen einem Routingfilter und einem Zielendpunkt. Sie definieren die "Filter", die Sie in den <Filtern> Element verwenden möchten – jeder <Filter> Eintrag gibt an, welchen Filtertyp Sie zusammen mit den filterspezifischen Daten verwenden möchten (z. B. einen Aktionswert, einen XPath-Ausdruck usw.).

Im folgenden Beispiel wird veranschaulicht, wie Eine Filtertabelle mit einem einzelnen Filter konfiguriert wird, der dem RechnerService1-Endpunkt zugeordnet ist. In diesem Fall stimmt der Filter "MatchAll" mit allen eingehenden Nachrichten überein:

<Konfiguration>

    ...

    ABSCHNITT <!--ROUTING -->

    <Routing->

      <!-- Definieren Sie die Filter, die der Router verwenden soll. -->

      <Filter>

        <Filtername="MatchAllFilter1" filterType="MatchAll" />

      </filters>

      <!-- Definieren der Filtertabelle, die den MatchAll-Filter enthält –>

      <filterTables>

        <filterTable name="filterTable1">

            <!-- Ordnen Sie den Filter einem zuvor definierten Clientendpunkt zu.

                 Nachrichten, die diesem Filter entsprechen, werden an dieses Ziel gesendet. -->

          <add filterName="MatchAllFilter1" endpointName="CalculatorService1" />

        </filterTable->

      </filterTables->

    </routing>

  </system.serviceModel>

</configuration>

Wir können überprüfen, ob das Routing ordnungsgemäß funktioniert, indem die Routingdiensthostanwendung, die RechnerService1-Hostanwendung und ein Client ausgeführt werden, der zum Senden von Nachrichten an einen der Routerendpunkte konzipiert ist. Wenn wir den Client ausführen, sollten die Nachrichten bei CalculatorService 1 angezeigt werden, nachdem sie vom Zwischenroutingservice "weitergeleitet" wurden (siehe Abbildung 14, Abbildung 15 und Abbildung 16).

Abbildung 14: Die RoutingService-Hostanwendung

Abbildung 15: Client für RoutingService bei https://localhost:8000/routingservice/router

Abbildung 16: Der Zieldienst (CalculatorService1)

Nachrichtenfilter und inhaltsbasiertes Routing

WCF enthält mehrere integrierte MessageFilter-Klassen, die Sie in Verbindung mit Ihren Routingnachrichtenfiltern verwenden können, um den Inhalt der eingehenden Nachrichten zu prüfen.

Beispielsweise stellt WCF einen ActionMessageFilter bereit, mit dem Sie bestimmte WS-Addressing "Action"-Werte abgleichen können. WCF stellt auch EndpointAddressMessageFilter, EndpointNameMessageFilter und PrefixEndpointAddressMessageFilter bereit, mit denen Sie bestimmte Endpunktdetails abgleichen können. Einer der flexibelsten ist der XPathMessageFilter, mit dem Sie XPath-Ausdrücke für die eingehenden Nachrichten auswerten können. Mit allen diesen Filtern können Sie inhaltsbasiertes Routing innerhalb Ihrer Lösung durchführen.

Zusätzlich zu diesen integrierten MessageFilter-Typen ermöglicht WCF 4 auch das Definieren von benutzerdefinierten Nachrichtenfiltern, was zu einem der primären Erweiterbarkeitspunkte für routingService gehört.

Sehen wir uns ein Beispiel für das Ausführen von inhaltsbasiertem Routing basierend auf Aktionswerten an. Angenommen, wir möchten die Hälfte der RechnerService-Vorgänge an CalculatorService1 und die andere Hälfte an CalculatorService2 weiterleiten. Sie können dies erreichen, indem Sie Filter für jeden der verschiedenen RechnerService-Aktionswerte definieren und die Hälfte davon jedem Zieldienstendpunkt zuordnen, wie hier dargestellt:

<Konfiguration>

    ...

    ABSCHNITT <!--ROUTING -->

    <Routing->

      <!-- Definieren Sie die Filter, die der Router verwenden soll. -->

     <Filter>

        <filter name="addFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Add"/>

         <filter name="subFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Subtract"/>

        <Filtername="mulFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Multiply"/>

        <filter name="divFilter" filterType="Action"

         filterData="http://Microsoft.Samples.ServiceModel/ICalculator/Divide"/>

      </filters>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"/>

          <add filterName="subFilter" endpointName="CalculatorService2"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"/>

          <add filterName="divFilter" endpointName="CalculatorService2"/>

        </filterTable->

      </filterTables->

    </routing>

  </system.serviceModel>

</configuration>

Wenn wir nun die Lösung ausführen und den Client ausführen, der alle vier Vorgänge aufruft, werden die Hälfte der Vorgänge in jedem Dienstkonsolenfenster angezeigt (siehe Abbildung 17 und Abbildung 18).

Abbildung 17: Ausgabe von CalculatorService1

Abbildung 18: Ausgabe von CalculatorService2-

Der XPathMessageFilter bietet Ihnen noch mehr Flexibilität, da Sie eine Vielzahl verschiedener XPath-Ausdrücke bereitstellen können, die für die eingehenden Nachrichten ausgewertet werden sollen. Ihre XPath-Ausdrücke können jeden Teil der eingehenden Nachricht auswerten, einschließlich SOAP-Headern oder SOAP-Textkörper. Dies bietet Ihnen beim Erstellen inhaltsbasierter Nachrichtenfilter eine große Flexibilität. Um die Mechanik von XPathMessageFilter zu verstehen, wird im folgenden Beispiel das letzte Beispiel mithilfe von XPath-Ausdrücken neu geschrieben:

<Konfiguration>

    ...

    ABSCHNITT <!--ROUTING -->

    <Routing->

      <!-- Definieren Sie die Filter, die der Router verwenden soll. -->

     <Filter>

        <filter name="addFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Add'"/>

        <filter name="subFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Subtract'"/>

        <Filtername="mulFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Multiply'"/>

        <filter name="divFilter" filterType="XPath"

                filterData="/s:Envelope/s:Header/wsa:Action =

                'http://Microsoft.Samples.ServiceModel/ICalculator/Divide'"/>

      </filters>

      <namespaceTable->

        <präfix="s" namespace="http://www.w3.org/2003/05/soap-envelope"hinzufügen; />

        <präfix="wsa" namespace="http://www.w3.org/2005/08/addressing"hinzufügen; />

      </namespaceTable->

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"/>

          <add filterName="subFilter" endpointName="CalculatorService2"/>

           <add filterName="mulFilter" endpointName="CalculatorService1"/>

          <add filterName="divFilter" endpointName="CalculatorService2"/>

        </filterTable->

      </filterTables->

    </routing>

  </system.serviceModel>

</configuration>

Beachten Sie, dass das FilterData-Attribut einen XPath-Ausdruck enthält, der für die eingehende Nachricht ausgewertet wird (die Ausdrücke überprüfen einfach die Aktionswerte in diesem Beispiel). Beachten Sie, wie ich auch eine Reihe von Namespacepräfixbindungen mithilfe des <namespaceTable->-Elements definiert habe. Dies ist erforderlich, wenn Sie Namespacepräfixe in Ihren XPath-Ausdrücken wie oben beschrieben verwenden möchten. Die erneute Ausführung der Lösung mit dieser Konfiguration erzeugt dieselben Ergebnisse wie zuvor (siehe Abbildung 17 und Abbildung 18).

Sie müssen diese XPath-Filtertechnik jedes Mal verwenden, wenn Sie Nachrichten basierend auf benutzerdefinierten SOAP-Headern oder basierend auf dem Inhalt im Textkörper der SOAP-Nachricht weiterleiten müssen.

Protokollüberbrückung

In den vorherigen Beispielen haben wir dieselbe WCF-Bindung (WSHttpBinding) verwendet, um zwischen dem Client und dem Router und zwischen dem Router und den Zieldiensten zu sprechen. Der RoutingService kann die Kommunikation über die meisten WCF-Bindungen hinweg überbrücken. Beispielsweise können Sie den Router so konfigurieren, dass die Clients mit dem Router über WSHttpBinding kommunizieren, aber dann kommuniziert der Router mit den nachgeschalteten Zieldiensten mithilfe von NetTcpBinding oder netNamedPipeBinding.

Sehen wir uns an, wie Sie den RoutingService so konfigurieren, dass es dieses Szenario behandelt. Wir behalten die RoutingService-Endpunktkonfiguration wie oben bei, sodass Verbraucher mit dem RoutingService über BasicHttpBinding oder WSHttpBinding kommunizieren können. Jetzt ändern wir jedoch die Clientendpunktdefinitionen für die Zieldienste so, dass netTcpBinding und NetNamedPipeBinding verwendet werden, wie hier gezeigt:

<Konfiguration>

    ...

    <!-- Definieren sie die Clientendpunkte, mit denen der Router kommunizieren soll.

         Dies sind die Ziele, an die der Router Nachrichten sendet. -->

    <Client->

      <Endpunktname="CalculatorService1"

       address="net.tcp://localhost:8001/servicemodelsamples/calcservice1"

       binding="netTcpBinding" contract="*" />

      <Endpunktname="CalculatorService2"

       address="net.pipe://localhost/servicemodelsamples/calcservice2"

       binding="netNamedPipeBinding" contract="*" />

    </client->

    ...

Und natürlich müssen wir die CalculatorService1- und CalculatorService2-Anwendungen aktualisieren, um kompatible NetTcpBinding- bzw. NetNamedPipeBinding-Endpunkte zu unterstützen. Mit dieser Konfiguration können Verbraucher mithilfe von BasicHttpBinding/WSHttpBinding mit dem RoutingService kommunizieren, und der Router kommuniziert mit den Zieldiensten, je nachdem, an welchen Dienst die Nachricht weitergeleitet wird.

Fehlerbehandlung und Fehlertoleranz

Der RoutingService bietet auch einen integrierten Mechanismus zur Behandlung von Laufzeitkommunikationsfehlern und zur Unterstützung einer grundlegenden Fehlertoleranz. Beim Definieren der Filtertabelle können Sie verschiedene Listen alternativer Endpunkte definieren, die vom RoutingService verwendet werden, wenn die Kommunikation mit dem ursprünglichen Zielendpunkt zu einem Fehler führt. Dies ermöglicht es im Wesentlichen, Listen mit "Sicherungsendpunkten" zu haben.

Im folgenden Beispiel wird veranschaulicht, wie eine Liste von Sicherungsendpunkten innerhalb des <backupLists> Element definiert wird, das wir unseren Filtertabelleneinträgen zuordnen können:

<Konfiguration>

    ...

    ABSCHNITT <!--ROUTING -->

    <Routing->

      ... <!-- Definieren Sie die Filter, die der Router verwenden soll. -->

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="addFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="subFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="mulFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

          <add filterName="divFilter" endpointName="CalculatorService1"

               alternateEndpoints="backupEndpoints"/>

        </filterTable->

      </filterTables->

      <backupLists>

        <backupList name="backupEndpoints">

          <"endpointName="CalculatorService2"/>

        </backupList->

      </backupLists>

    </routing>

  </system.serviceModel>

</configuration>

Beachten Sie, wie wir alle Filtertabelleneinträge so konfiguriert haben, dass sie in diesem Beispiel an CalculatorService1 weitergeleitet werden, da CalculatorService2 jetzt unser "Backup"-Endpunkt ist, der nur verwendet wird, wenn CalculatorService1 zu einer TimeoutException, einer CommunicationException oder einem abgeleiteten Ausnahmetyp führt. Wenn ich die Lösung z. B. erneut ausführt und CalculatorService1 schließt und dann das Clientprogramm ausführt, werden alle Nachrichten in CalculatorService2 angezeigt. Es ist wichtig zu beachten, dass alle diese Routingkonfiguration dynamisch im Hostanwendungscode ausgeführt werden können.

Multicast-Routingverhalten

Der RoutingService unterstützt auch das automatische Weiterleiten einer bestimmten eingehenden Nachricht an mehrere Ziele in einer "Multicast"-Art. Wenn die eingehende Nachricht mit mehreren Filtern übereinstimmt, die in der konfigurierten Filtertabelle gefunden wurden, leitet RoutingService die Nachricht automatisch an jeden der Zielendpunkte weiter, die den "übereinstimmenden" Filtern zugeordnet sind.

Das folgende Beispiel zeigt zwei Routingeinträge, die mit demselben Wildcardfilter konfiguriert sind, der mit allen eingehenden Nachrichten übereinstimmt:

<Konfiguration>

    ...

    ABSCHNITT <!--ROUTING -->

    <Routing->

      <!-- Definieren Sie die Filter, die der Router verwenden soll. -->

     <Filter>

        <filter name="wildcardFilter" filterType="MatchAll" />

      </filters>

      <filterTables>

        <filterTable name="filterTable1">

          <add filterName="wildcardFilter" endpointName="CalculatorService1"/>

          <add filterName="wildcardFilter" endpointName="CalculatorService2"/>

          <add filterName="wildcardFilter" endpointName="CalculatorService3"/>

        </filterTable->

      </filterTables->

    </routing>

  </system.serviceModel>

</configuration>

Mit dieser Konfiguration wird jede eingehende SOAP-Nachricht automatisch an alle Zielendpunkte weitergeleitet, unabhängig davon, was in den Nachrichten zu finden ist.

Dieses Multicast-Verhalten erstellt die Protokollüberbrückungs- und Fehlerbehandlungsfunktionen, die in den vorherigen Abschnitten erläutert werden. Das einzige Problem ist Multicast nur für unidirektionale oder Duplexkommunikation, aber nicht für die Anforderungsantwortkommunikation, da das zugrunde liegende System ein 1:1-Verhältnis zwischen ausgehenden Anforderungen und eingehenden Antworten beibehalten muss.

Verbesserte REST-Unterstützung

WCF 4 bietet mehrere neue Features, die beim Erstellen von RESTful-Diensten mit WCF nützlich sind.  Dieser Satz von Features wird jetzt als WCF WebHttp Services bezeichnet. Sie umfassen Unterstützung für eine automatische Hilfeseite, die den RESTful-Dienst für Verbraucher beschreibt, vereinfachte HTTP-Zwischenspeicherung, Nachrichtenformatauswahl, REST-freundliche Ausnahmen, ASP.NET Routingintegration, einige neue Visual Studio-Projektvorlagen und vieles mehr. Wir haben keinen Platz, um alle diese Features hier ausführlich abzudecken, aber ich gebe Ihnen eine kurze Einführung in einige meiner Favoriten unten, zusammen mit Links zu weiteren Informationen über den Rest.

Viele dieser Features wurden im letzten Jahr vom WCF REST Starter Kit eingeführt und machen es nun zum offiziellen Framework. Möglicherweise sehen Sie in Zukunft weitere WCF REST Starter Kit-Features.

Seite "Automatische Hilfe"

Wenn Sie die WebServiceHost-Klasse in WCF 4 verwenden, profitieren Ihre RESTful-Dienste automatisch von den Vorteilen der automatischen Hilfeseitenfunktionalität. Dies ist eine dringend benötigte Ergänzung bei der Verwendung von REST aufgrund des Mangels an WSDL-Metadaten und clientseitiger Codegenerierung – es erleichtert es Den Verbrauchern, herauszufinden, wie Sie mit Ihrem Dienst beginnen können – daher empfiehlt es sich in der Regel, dieses neue Feature zu aktivieren.

Wenn Sie die WebServiceHost-Klasse zum Hosten Ihres Diensts verwenden, konfiguriert sie Ihren Dienst automatisch mit dem WebHttpBehavior und fügt einen standardmäßigen HTTP-Endpunkt hinzu, der mit webHttpBinding (an der Basis-HTTP-Adresse) konfiguriert ist. Ab WCF 4 enthält die WebHttpBehavior-Klasse eine HelpEnabled-Eigenschaft, die steuert, ob die neue Hilfeseite innerhalb des Hosts aktiviert ist. Das folgende Konfigurationsbeispiel zeigt, wie Sie das Feature für die automatische Hilfeseite für einen bestimmten REST-Endpunkt aktivieren:

<Konfiguration>

  <system.serviceModel->

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    <Verhalten>

      <endpointBehaviors>

        <Verhaltensname="HelpBehavior">

          <webHttp helpEnabled="true" />

        </behavior>

      </endpointBehaviors>

    </behaviors>

    <Dienste>

      <Dienstname="CounterResource">

        <EndpunktverhaltenConfiguration="HelpBehavior"

                  binding="webHttpBinding"

                  contract="CounterResource" />

      </service>

    </services>

  </system.serviceModel>

</configuration>

Sie können die Hilfeseite anzeigen, indem Sie zur Basisadresse des Diensts navigieren, wobei "Hilfe" am Ende der URL angefügt ist (siehe Abbildung 19).

Abbildung 19: Seite "Automatische Hilfe" für RESTFul-Dienste

Die Hilfeseite stellt eine lesbare Beschreibung der einzelnen Vorgänge bereit, die mit [WebGet] oder [WebInvoke] versehen sind, und für jeden, der die URI-Vorlage, den unterstützten HTTP-Vorgang und die unterstützten Nachrichtenformate beschreibt, ist im Grunde alles, was ein Verbraucher wissen muss (siehe Abbildung 20). Sie können auch eine benutzerfreundlichere Beschreibung bereitstellen, indem Sie für jeden Vorgang ein [Description]-Attribut anwenden.

Für jede Anforderung/Antwort stellt die Hilfeseite auch ein XML-Schema und eine entsprechende XML-Beispielinstanz bereit, die Consumer für die Integration in den Dienst verwenden können. Consumer können das Schema verwenden, um geeignete clientseitige serialisierbare Typen zu generieren, oder sie können einfach das XML-Beispieldokument überprüfen, um manuell zu bestimmen, wie der entsprechende XML-Verarbeitungscode geschrieben wird. Beide Ansätze sind nützlich.

Abbildung 20: Seite "Automatische Hilfe" für einen bestimmten Vorgang

Dieses neue Hilfeseitenfeature macht Ihre RESTful-Dienste automatisch leichter auffindbar, wodurch sie letztendlich für andere Benutzer leichter zu nutzen sind. Ihre Verbraucher können den URI-Entwurf des Diensts, die unterstützten HTTP-Vorgänge und die Anforderungs-/Antwortformate ermitteln, und Ihre Beschreibung bleibt immer synchron mit Ihrem WCF-Code – ähnlich wie die Funktionsweise mit ASP.NET Webdiensten.

Unterstützung für HTTP-Zwischenspeicherung

Einer der haupt potenziellen Vorteile von REST ist die HTTP-Zwischenspeicherung. Um diesen Vorteil zu erkennen, müssen Sie jedoch die verschiedenen HTTP-Cacheheader in Ihren Anforderungs- und Antwortnachrichten nutzen. Sie können dies in Ihren WCF-Dienstvorgängen erreichen, indem Sie manuell über die WebOperationContext-Instanz auf die Anforderungs-/Antwortheader zugreifen, aber es ist nicht trivial, ordnungsgemäß zu arbeiten.

Wcf 4 verfügt daher über ein einfacheres Modell zum Steuern der Zwischenspeicherung über das [AspNetCacheProfile]-Attribut, das Sie deklarativ auf Ihre GET-Vorgänge anwenden können. Mit diesem Attribut können Sie einen ASP.NET Zwischenspeicherungsprofilnamen für jeden Vorgang und hinter den Kulissen angeben, dass ein Cacheinspektor (CachingParameterInspector) vorhanden ist, der alle zugrunde liegenden HTTP-Zwischenspeicherungsdetails behandelt.

Die [AspNetCacheProfile]-Implementierung basiert auf dem Standardmäßigen ASP.NET Ausgabezwischenspeicherungsmechanismus. Das folgende Beispiel zeigt, wie das [AspNetCacheProfile]-Attribut auf einen [WebGet]-Vorgang angewendet wird:

...

[AspNetCacheProfile("CacheFor60Seconds")]

[WebGet(UriTemplate=XmlItemTemplate)]

[OperationContract]

public Counter GetItemInXml()

{

    return HandleGet();

}

...

Damit müssen Sie in Ihrer web.config Datei ein ASP.NET Ausgabezwischenspeicherungsprofil namens "CacheFor60Seconds" definieren. Die folgende web.config zeigt, wie dies möglich ist:

<Konfiguration>

  <system.web>

    <zwischenspeichern>

      <outputCacheSettings->

        <outputCacheProfiles->

          <add name="CacheFor60Seconds" duration="60" varyByParam="format" />

        </outputCacheProfiles>

      </outputCacheSettings>

    </caching>

  </system.web>

  <system.serviceModel->

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

  </system.serviceModel>

</configuration>

Beachten Sie, dass das ASP.NET Zwischenspeicherungsprofils so festgelegt ist, dass die Ausgabe 60 Sekunden lang zwischengespeichert wird und der Cache durch die Abfragezeichenfolgenvariable "format" variiert. Dies ist wichtig, da der betreffende Dienst sowohl XML als auch JSON unterstützt, das Sie über die Formatvariable steuern (z. B. "?format=json"). Der Dienst muss XML- und JSON-Antworten unabhängig voneinander zwischenspeichern.

In dieser Konfigurationsdatei wird auch veranschaulicht, wie Sie den ASP.NET Kompatibilitätsmodus aktivieren, der erforderlich ist, wenn Sie verschiedene ASP.NET Features wie ausgabezwischenspeichern nutzen möchten.

Das Attribut [AspNetCacheProfile] erleichtert die Nutzung der HTTP-Zwischenspeicherung, ohne dass Sie direkt mit den HTTP-Cacheheadern arbeiten müssen. Das zugrunde liegende WCF-Verhalten kümmert sich um das Einfügen der HTTP-Cache-Control-, Date-, Expires- und Vary-HTTP-Header in der Antwort, die Clients auch nutzen können, um die richtige Zwischenspeicherungsemantik für zukünftige Roundtrips zu ermitteln.

Nachrichtenformatauswahl

Wenn Sie auf Abbildung 19 zurückschauen, werden Sie feststellen, dass der CounterResource-Dienst sowohl XML- als auch JSON-Formate für die GET-, POST- und PUT-Vorgänge unterstützt. Dies ist seit WCF 3.5 über die Eigenschaften RequestFormat und ResponseFormat möglich, die in den Attributen [WebGet] und [WebInvoke] gefunden wurden.

Ich habe dies im CounterResource-Dienst erreicht, indem ich einen separaten Vorgangsvertrag für jede Version definiert – eine für die XML-Version und eine für die JSON-Version – wie hier dargestellt:

...

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItemInXml()

{

    return HandleGet();

}

[WebGet(UriTemplate = "?format=json", ResponseFormat=WebMessageFormat.Json)]

[OperationContract]

public Counter GetItemInJson()

{

    return HandleGet();

}

...

Dies bedeutet leider, dass Sie für jeden logischen Vorgang zwei Vorgangsverträge benötigen, wenn Sie sowohl XML- als auch JSON-Formate unterstützen möchten. Im Falle des CounterResource-Diensts musste ich sechs Vorgangsverträge haben, um SOWOHL XML als auch JSON für die GET-, POST- und PUT-Vorgänge zu unterstützen.

WCF 4 erleichtert die Handhabung dieses Szenarios erheblich, indem unterstützung für die automatische Formatauswahl basierend auf HTTP-Headern "Accept" bereitgestellt wird. Dies ist eine bessere Möglichkeit, dies zu tun. Lassen Sie mich erklären, wie das funktioniert.

Zunächst benötigen wir nur einen einzigen Vorgangsvertrag für jeden logischen Vorgang:

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItem()

{

    return HandleGet();

}

Anschließend wird die automatische Formatauswahl im StandardwebHttpEndpoint wie hier veranschaulicht:

<Konfiguration>

  <system.serviceModel->

    <standardEndpoints->

      <webHttpEndpoint->

        <!-- der Standardendpunkt "" zum automatischen Erstellen eines Webendpunkts verwendet wird. -->

        <standardEndpoint name="" helpEnabled="true"

            automaticFormatSelectionEnabled="true"/>

      </webHttpEndpoint->

    </standardEndpoints->

  </system.serviceModel>

</configuration>

Damit ist der Dienst nun in der Lage, XML- oder JSON-Nachrichten zu verarbeiten und zurückzugeben. Es ermittelt, welches Format verwendet werden soll, indem zuerst der HTTP Accept-Header in der Anforderungsnachricht überprüft wird. Wenn dies nicht funktioniert, wird das gleiche Nachrichtenformat wie die Anforderungsnachricht verwendet, vorausgesetzt, es ist ENTWEDER XML oder JSON, andernfalls wird das Standardformat für den jeweiligen Vorgang verwendet.

Es liegt nun an dem Client, zu bestimmen, welches Format über die HTTP-Inhaltstyp- und Accept-Header verwendet werden soll. Der Inhaltstypheader gibt das Format in der Anforderungsnachricht an, während der Accept-Header angibt, welches Format der Client vom Dienst zurücknimmt. Wenn der Client beispielsweise JSON zurück vom Dienst empfangen möchte, sollte er den folgenden HTTP Accept-Header in der Anforderung angeben:

Accept: application/json

Dies ist einfach in jedem HTTP-Clientprogrammiermodell zu erreichen, und es ist auch einfach, Tools wie Fiddler zu verwenden. Abbildung 21 zeigt, wie Sie Fiddler verwenden, um JSON von unserem neuen und verbesserten Dienst zurückzuholen.

Abbildung 21: Verwenden des HTTP Accept-Headers zum Abrufen von JSON-

WCF 4 stellt auch neue APIs bereit, die das Explizite Angeben des Nachrichtenformats zur Laufzeit vereinfachen. Der folgende Code zeigt, wie wir den GetItem-Vorgang erweitern können, indem Code geschrieben wird, der zuerst nach einem "format"-Abfragezeichenfolgenparameter sucht und explizit das Antwortformat entsprechend festlegt. Wenn kein "format"-Parameter gefunden wird, basiert er einfach wie zuvor auf der Accept-Kopfzeile.

[WebGet(UriTemplate="")]

[OperationContract]

public Counter GetItem()

{

    wenn ein Formatabfragezeichenfolgenparameter angegeben wurde,

    legen Sie das Antwortformat auf dieses Format fest. Wenn keine solche

    Der Abfragezeichenfolgenparameter ist vorhanden, der Accept-Header wird verwendet.

    string formatQueryStringValue =

       WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters[

       "format"];

    if (!string. IsNullOrEmpty(formatQueryStringValue))

    {

        if (formatQueryStringValue.Equals("xml",

           System.StringComparison.OrdinalIgnoreCase))

        {

            WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;

        }

        else if (formatQueryStringValue.Equals("json",

           System.StringComparison.OrdinalIgnoreCase))

        {

            WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;

        }

        oder

        {

            neue WebFaultException-<Zeichenfolge>auslösen (Zeichenfolge). Format("Nicht unterstütztes Format '{0}'",

               formatQueryStringValue), HttpStatusCode.BadRequest);

        }

    }

    return HandleGet();

}

Am Ende machen diese neuen Features es so, dass Sie keinen Nachrichtenformattyp mehr in Ihre [WebGet]- und [WebInvoke]-Vorgangsverträge wie in WCF 3.5 hartcodieren müssen.

RESTful Error Handling

Da RESTful-Dienste KEINE SOAP verwenden, verfügen Sie nicht mehr über den standardmäßigen SOAP-Fehlermechanismus, der es ermöglicht, zwischen .NET-Ausnahmen und SOAP-Fehlermeldungen automatisch zuzuordnen. Beim Erstellen von REST-Diensten in WCF 3.5 mussten Sie die HTTP-Antwortnachricht manuell erstellen, wenn Sie die HTTP-Fehlermeldung anpassen möchten, die an den Client zurückgesendet wird.

In WCF 4 finden Sie eine neue Klasse namens "WebFaultException"<T>, die es viel einfacher macht, "Webfehler" (z. B. HTTP-Fehler) an Ihre Verbraucher zu übertragen. Es funktioniert sehr ähnlich wie FaultException<T> in WCF, Sie können jedoch einen HTTP-Statuscode und einen Detailtyp angeben, um weitere Details bereitzustellen.

Das folgende Beispiel zeigt, wie ein HTTP 400 -Fehler (ungültige Anforderung) zurückgegeben wird, wenn der Benutzer einen nicht unterstützten Formattyp angibt – ich verwende einfach eine Zeichenfolge für den Detailtyp:

if (!string. IsNullOrEmpty(format))

{

    wenn (Format. Equals("xml", System.StringComparison.OrdinalIgnoreCase))

    {

        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;

    }

    else if (format. Equals("json", System.StringComparison.OrdinalIgnoreCase))

    {

        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;

    }

    oder

    {

        neue WebFaultException-<Zeichenfolge>auslösen (Zeichenfolge). Format("Nicht unterstütztes Format '{0}'",

           format), HttpStatusCode.BadRequest);

    }

}

Dieses neue Feature macht es wesentlich natürlicher, Standard-HTTP-Fehlermeldungen zurückzugeben, indem sie einfach Ausnahmen wie in Ihren SOAP-basierten Diensten auslösen.

Integrieren von WCF mit ASP.NET Routen

Es gibt viele Ähnlichkeiten zwischen den URL-basierten Routingfunktionen in WCF 4 und ASP.NET 4. Beide ermöglichen es Ihnen, dasselbe zu tun – im Wesentlichen ordnen Sie URL-Vorlagen Methoden für Klassen zu. Es gibt jedoch einen signifikanten Unterschied zwischen den beiden Modellen.

Der WCF 4-Ansatz verknüpft das URL-Vorlagendesign mit einer einzelnen Klasse über die Attribute [WebGet] und [WebInvoke], die während der Entwicklung auf die Klassendefinition angewendet werden. Da der Dienst im Laufe der Zeit wächst und sich weiterentwickelt, kann dies zu einem großen monolithischen Design führen, das nicht in kleinere Blöcke aufgeteilt werden kann. Der ASP.NET 4-Ansatz entkoppelt dagegen die Routinglogik von der Zielklassendefinition, sodass Sie Ihre Dienstrouten bei Bedarf über zahlreiche Klassendefinitionen hinweg zuordnen können.

WCF 4 bietet jetzt die Möglichkeit, das ASP.NET Routingmodul in Ihre WCF 4-Dienste zu integrieren, sodass es möglich ist, vom ASP.NET Routingmodell über Ihre WCF-Dienste zu profitieren.

Dies erreichen Sie in Ihrer Global.asax RegisterRoutes-Methode, indem Sie die neue ServiceRoute-Klasse nutzen, mit der Sie eine ASP.NET Route zu einer WCF-Dienstklasse zuordnen können:

private void RegisterRoutes()

{

   WebServiceHostFactory factory = new WebServiceHostFactory();

   RouteTable.Routes.Add(new ServiceRoute("Bookmarks", factory,

      typeof(BookmarkService)););

   RouteTable.Routes.Add(new ServiceRoute("Users", factory,

      typeof(UserService)););

}

Ich rufe RouteTable.Routes.Add zweimal auf, um neue Routen für zwei verschiedene WCF-Dienstklassen hinzuzufügen. Die erste Route ordnet "/Bookmarks" der BookmarkService-Klasse zu, während die zweite Route "/Users" der UserService-Klasse zuordnet. Beachten Sie, wie beide Routen für die Verwendung von WebServiceHostFactory konfiguriert sind.

Wenn wir nun die Attribute [WebGet] und [WebInvoke] für die WCF-Dienstklassendefinitionen verwenden, verwenden wir relative Pfade – und sie sind relativ zur hier angegebenen ASP.NET Route.

REST-Projektvorlagen

Eines der ordentlichen Features in Visual Studio 2010 ist der Erweiterungs-Manager, auf den Sie über Tools zugreifen können | Erweiterungs-Manager. Der Erweiterungs-Manager ermöglicht Es Microsoft und anderen Drittanbietern, neue Projektvorlagen, Steuerelemente und Tools in Ihre Visual Studio 2010-Oberfläche mit einem einfachen Klick auf eine Schaltfläche zu integrieren. Für Microsoft-Produktteams ist dies großartig, da es möglich ist, Dinge nach RTM zu versenden und weiterhin offizielle Erweiterungen von Microsoft zur Verfügung zu stellen.

Wenn Sie den Erweiterungs-Manager aufrufen und den Knoten "Vorlagen" erweitern, finden Sie einen untergeordneten Knoten namens "WCF". Klicken Sie auf "WCF", und sie sollten vier neue WCF REST-Dienstvorlagen sehen – eine für jede .NET-Version (3.5 vs 4.0) und eine pro Sprache (C# vs. VB.NET), wie in Abbildung 22 dargestellt.

Abbildung 22: Neue WCF-REST-Projektvorlagen im Erweiterungs-Manager-

Sie können diese neuen Projektvorlagen auswählen und sie in Ihre lokale Visual Studio 2010-Installation herunterladen und wie jeden anderen Projekttyp verwenden. Sie finden den neuen REST-Projekttyp unter Visual C# | Web | WCF REST-Dienstanwendung (vorausgesetzt, Sie haben die C#-Version installiert).

Wenn Sie es zum Erstellen eines neuen Projekts verwenden, werden Sie feststellen, dass die von ihr generierte WCF REST-Dienstanwendung die meisten der neuen WCF 4-Features verwendet, die ich in diesem Abschnitt hervorgehoben habe.

Weitere Informationen

Zusätzlich zu den hier erläuterten Themen enthält WCF 4 mehrere erweiterte REST-Funktionen und neue WCF-API-Erweiterungen, die das Behandeln von benutzerdefinierten Nachrichtenformaten (nicht XML oder JSON), das Zurückgeben von vorlagenbasierten "Ansichten" mithilfe der neuen T4-Funktionalität, die Implementierung der Unterstützung für bedingte GET und ETag, die Implementierung optimistischer Parallelität und das Generieren ausgehender Links vereinfachen.

Weitere Informationen zu all diesen neuen WCF 4-Features, einschließlich der Features, die wir hier nicht behandelt haben, finden Sie im .NET-Endpunktblog, und suchen Sie den Eintrag "Einführung in WCF WebHttp Services" in .NET 4. Das Team hat eine gründliche 12-teilige Blogreihe bereitgestellt, die jeden neuen Feature-Blogeintrag einzeln durchläuft, zusammen mit vielen Beispielcode und schrittweisen Anleitungen.

Workflowdienste

Einer der Featurebereiche, die in .NET 4 die größte Aufmerksamkeit erhielten, war die der "Workflowdienste". Microsoft investierte stark in die Verbesserung der Integration zwischen WCF und WF, um ein umfangreiches und deklaratives Programmiermodell für die Erstellung einer Vielzahl von Anwendungen bereitzustellen.

Grundlegendes zu Workflowdiensten

WF bietet Ihnen ein deklaratives Programmiermodell, das die Abstraktionsebene für diejenigen erhöht, die die Logik schreiben. Das WF bietet Ihnen letztendlich ein Framework zum Schreiben eigener Sprachen, indem Sie Ihre eigene Bibliothek der Geschäftsdomänenaktivitäten definieren. Anschließend erhalten Sie einen visuellen Designer zum Verfassen dieser Aktivitäten in Programmen und eine Laufzeit, die weiß, wie die Ausführung dieser Programme verwaltet wird.

WF bietet ein besonders gutes Modell für die Implementierung langer Anwendungen, die warten müssen, bis verschiedene Arten externer Ereignisse auftreten, z. B. das Empfangen einer Nachricht von einem anderen System. Das Persistenzmodell ermöglicht es, Systemressourcen effizient zu nutzen, indem das Programm nur im Arbeitsspeicher gespeichert wird, wenn es tatsächlich ausgeführt wird. Wenn das Programm auf ein externes Ereignis wartet, kann es in der Datenbank beibehalten werden, wodurch die verwendeten Systemressourcen freigegeben werden.

Abbildung 23: Workflowdienste

Das Ding, das WF von anderen Entwicklungsframeworks unterscheidet, besteht darin, dass sie Ihnen diese Features bietet, während Sie dennoch mit einer sequenziellen Ablaufsteuerungsprogrammierlogik programmieren können, was in der Regel für Entwickler viel einfacher ist, den Code zu lesen und zu verstehen.

Wenn Sie WCF-Dienste erstellen, die langfristig ausgeführt werden oder von einigen der anderen Vorteile profitieren könnten, die ich gerade beschrieben habe, können Sie Ihre WCF-Dienste mithilfe eines WF-Workflows implementieren. Und Sie können WF verwenden, um die Logik der Nutzung anderer externer Dienste zu koordinieren.

Abbildung 23 veranschaulicht diese Konzepte.

Obwohl dies seit .NET 3.5 möglich ist, hat .NET 4 erhebliche Fortschritte bei der Verbesserung der Entwicklererfahrung gemacht und einige der erforderlichen Features bereitgestellt, die in .NET 3.5 fehlen.

Durch die Kombination der Welten von WCF und WF erhalten Sie das Beste aus beiden Welten. Sie erhalten ein deklaratives Programmiermodell, eine entwicklerfreundliche Erfahrung dank der WF-Designer, einer leistungsstarken Laufzeit für die Verwaltung langer Dienste und der umfassenden Kommunikationsflexibilität, die von WCF geboten wird.

Erstellen Ihres ersten Workflowdiensts

Um Ihnen ein Gefühl für die neue Entwicklerumgebung für Workflowdienste zu geben, werde ich Sie durch ein vollständiges Beispiel für die Erstellung eines Workflows mit .NET 4 und dem neuen Visual Studio 2010-Designer führen.

Wenn Sie Visual Studio 2010 öffnen und "Datei" auswählen | Neues Projekt finden Sie unter den WCF-Vorlagen ein neues Workflowprojekt – es heißt "WCF-Workflowdienstanwendung". Ich wähle diese Projektvorlage aus, gebe ihm den Namen "HelloWorldWorkflowService", und erstelle das neue Projekt.

Abbildung 24: Visual Studio 2010 Workflow Services Project Templates

Nach der Erstellung enthält das neue Projekt einfach zwei Dateien: eine Datei "Service1.xamlx", die die deklarative Workflowdienstdefinition und eine Web.config Datei enthält, die die Dienstkonfiguration enthält.

Eines der überzeugendsten Dinge des neuen Workflowdienstemodells in .NET 4 besteht darin, dass die gesamte Dienstdefinition in XAML definiert werden kann.   In unserem neuen Projekt enthält die Datei Service1.xamlx die Dienstdefinition, und die Implementierung ist einfach ein XAML-basierter Workflow. Die Web.config Datei enthält die WCF-Dienstkonfiguration – hier definieren Sie die Workflowdienstendpunkte und -verhaltensweisen.

Abbildung 25 zeigt, wie der Visual Studio 2010-Designer für die Datei "Service1.xamlx" aussieht. Beachten Sie, dass es sich nur um den Standardmäßigen Workflow-Designer handelt, nur in diesem Fall wird der workflow, den wir entwerfen, als WCF-Dienstimplementierung dienen. Der Schlüssel zum Integrieren dieser Workflowdefinition in WCF ist der neue WorkflowServiceHost und der Satz von WCF-"Messaging"-Aktivitäten (siehe Toolbox in Abbildung 25).

Abbildung 25: Entwerfen eines Workflowdiensts in Visual Studio 2010

Der mit dieser Projektvorlage bereitgestellte Skelettworkflowdienst enthält eine Empfangsaktivität gefolgt von einer Sendeaktivität. Beachten Sie, dass die Empfangsaktivität eine OperationName-Eigenschaft enthält und zurzeit auf "GetData" festgelegt ist. Außerdem verfügt sie über eine Inhaltseigenschaft zum Binden der eingehenden Nachricht an eine lokale Variable, die innerhalb der Sequenzaktivität definiert ist . In diesem Fall wird die Variable als "Daten" bezeichnet und ist vom Typ "Int32" (siehe fenster "Variablen" unter dem Workflowentwurfsdienst in Abbildung 25).

Die Empfangsaktivität ist auch für die Aktivierung des Diensts konfiguriert, was bedeutet, dass in eingehenden Nachrichten eine neue Instanz des Workflows erstellt werden kann. Beachten Sie, dass die CanCreateInstance-Eigenschaft im Eigenschaftenfenster rechts in Abbildung 25 aktiviert ist.

Lassen Sie uns diesen Workflowdienst ein wenig anpassen. Zuerst ändere ich den Dienstdateinamen von "Service1.xamlx" in "HelloWorld.xamlx". Als Nächstes ändere ich den Namen des Diensts in "HelloWorldService" im ordnungsgemäßen Fenster. Als Nächstes ändere ich die OperationName-Eigenschaft der Empfangsaktivität in "SayHello". Und schließlich definiere ich eine neue Variable namens "personName" vom Typ "String" innerhalb der Sequence.

Dann bindet ich die Content-Eigenschaft der Empfangen-Aktivität an die Variable "personName", wie in Abbildung 26 dargestellt. Als Nächstes bindet ich die Content-Eigenschaft der Senden-Aktivität an eine Zeichenfolge im Format "hello {0}!" Einfügen der PersonName-Variablen in den Platzhalter. Anschließend speichere ich die resultierende Datei "Service1.xamlx".

Abbildung 26: Definieren der Inhaltseigenschaft für die Empfangen-Aktivität

Fahren Sie an diesem Punkt fort, und öffnen Sie die Datei "HelloWorld.xamlx", und prüfen Sie deren Inhalt. Dazu können Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Datei klicken und "Öffnen mit..." auswählen. gefolgt von "XML-Editor". Auf diese Weise können Sie die unformatierte XAML-Definition für den Dienst betrachten. Beachten Sie, dass die XAML-Definition die vollständige Dienstimplementierung darstellt. Es gibt überhaupt keinen C#-Code.

Für dieses Beispiel setzen wir auf den standardmäßigen HTTP-Endpunkt und gehen davon aus, dass ein Standarddienstverhalten vorhanden ist, das automatisch Dienstmetadaten aktiviert, sodass keine WCF-Konfiguration erforderlich ist.

Jetzt können wir unseren XAML-basierten Workflowdienst testen. Dies ist so einfach wie das Drücken von F5 in Visual Studio 2010. Wenn Sie F5 drücken, wird der Workflowdienst in den ASP.NET Development Server geladen und bewirkt, dass der WCF-Testclient angezeigt wird. Der WCF-Testclient stellt automatisch eine Verbindung mit dem Workflowdienst her, lädt die WSDL-Metadaten herunter und ermöglicht das Testen der Workflowdienstlogik (siehe Abbildung 27).

Abbildung 27: Testen des workflowdienst-

Dies veranschaulicht, dass die Workflowdiensteinfrastruktur dynamisch eine WSDL-Definition für den Dienst erstellen kann, indem die in der Workflowdefinition verwendeten Sende- und Empfangsaktivitäten sowie die Typen von Nachrichten überprüft werden, die gesendet und empfangen werden.

Dies schließt die einfache exemplarische Vorgehensweise zum Erstellen Ihres ersten deklarativen Workflowdiensts in .NET 4 ab. Wir haben gesehen, dass die Dienstimplementierung vollständig in XAML definiert ist und dass Sie die Senden-Empfangen-Aktivitäten verwenden, um die Messaginginteraktionen innerhalb des Workflows zu modellieren. Wir haben auch gesehen, dass .NET 4 mit Hostingunterstützung für XAMLX-Dateien enthalten ist, wodurch die Notwendigkeit zusätzlicher SVC-Dateien entfernt wird. In den folgenden Abschnitten werden wir jeden dieser Bereiche ausführlicher einarbeiten.

Hosten von Workflowdiensten

.NET 4 verfügt über eine neue und verbesserte Hostinginfrastruktur für Workflowdienste. Sie können Workflowdienste in IIS/WAS oder in Ihren eigenen Anwendungen mit WorkflowServiceHost hosten. Die .NET 4-Hostinginfrastruktur stellt die erforderlichen Komponenten für die Verwaltung langer Workflowinstanzen und zum Korrelieren von Nachrichten bereit, wenn mehrere Dienstinstanzen gleichzeitig ausgeführt werden. .NET 4 stellt außerdem einen standardmäßigen Workflowsteuerungsendpunkt für die Remoteverwaltung von Workflowinstanzen bereit.

Hosting in IIS/ASP.NET

Das einfache HelloWorldWorkflowService-Beispiel wurde im vorherigen Abschnitt erläutert, wie Workflowdienste in IIS/ASP.NET gehostet werden. Obwohl wir den Dienst mit dem ASP.NET Development Server getestet haben, hätte er in IIS mit einem ASP.NET 4-Anwendungspool identisch funktioniert. .NET 4 installiert den erforderlichen Handler für XAMLX-Anforderungen, der die Erstellung von WorkflowServiceHost hinter den Kulissen und die Aktivierung der einzelnen Workflowinstanzen behandelt.

Obwohl wir den Ansatz "zero config" in unserem ersten Beispiel verwendet haben, können Sie Workflowdienste innerhalb Web.config wie jeder andere WCF-Dienst konfigurieren. Hier konfigurieren Sie alle WCF-Endpunkte und -Verhaltensweisen, die Sie verwenden möchten. Sie können beliebig viele Endpunkte für Ihre Workflowdienste verfügbar machen, aber Sie sollten eine der neuen Kontextbindungen (z. B. BasicHttpContextBinding, WSHttpContextBinding oder NetTcpContextBinding) verwenden, die instanzspezifische Kommunikation verwalten.

Im folgenden Beispiel wird veranschaulicht, wie ein Workflowdienst mit zwei HTTP-Endpunkten konfiguriert wird:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <Dienstname="HelloWorldWorkflowService">

        <endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding"

                  contract="IHelloWorld"/>

      </service>

      ...

Sie können den Workflowdienst auch mit WCF-Verhalten konfigurieren. Im folgenden Beispiel wird veranschaulicht, wie Sie diesen Workflowdienst mit einigen der standardmäßigen WCF-Verhaltensweisen konfigurieren:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <Dienstname="HelloWorldWorkflowService"

        behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

        <endpoint binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding"

                  contract="IHelloWorld"/>

      </service>

     </services>

    <Verhalten>

      <serviceBehaviors>

        <Verhaltensname="HelloWorldWorkflowService.Service1Behavior">

          <serviceDebug includeExceptionDetailInFaults="False" />

          <serviceMetadata httpGetEnabled="True"/>

        </behavior>

      </serviceBehaviors>

      ...

Zusätzlich zu diesen standardmäßigen WCF-Verhaltensweisen enthält .NET 4 einige neue WF-spezifische Verhaltensweisen zum Steuern der Workflowpersistenz, der Workflownachverfolgung und anderer Workflowlaufzeitverhalten in Verbindung mit Ihren Workflowdiensten. Weitere Informationen finden Sie in den .NET 4 SDK-Beispielen.

Self-Hosting mit WorkflowServiceHost

Obwohl .NET 3.5 mit einer WorkflowServiceHost-Klasse für das Hosten von Workflowdiensten ausgeliefert wurde, musste sie neu gestaltet werden, wenn alle Änderungen an der WF-Laufzeit und des Programmiermodells in .NET 4 vorgenommen wurden. Daher enthält .NET 4 eine neue WorkflowServiceHost-Klasse, die in der Assembly "System.ServiceModel.Activities" enthalten ist.

Die WorkflowServiceHost-Klasse erleichtert das Hosten von Workflowdiensten in Ihrer eigenen Anwendung, sei es eine Konsolenanwendung, eine WPF-Anwendung oder ein Windows-Dienst. Das folgende Codefragment veranschaulicht, wie WorkflowServiceHost in Ihrem eigenen Anwendungscode verwendet wird:

...

WorkflowServiceHost-Host = new WorkflowServiceHost("HelloWorld.xamlx",

    neuer Uri("https://localhost:8080/helloworld"));

Gastgeber. AddDefaultEndpoints();

Gastgeber. Description.Behaviors.Add(

    new ServiceMetadataBehavior { HttpGetEnabled = true });

Gastgeber. Open();

Console.WriteLine("Host ist geöffnet");

Console.ReadLine();

...

Wie Sie sehen können, ob Sie Ihre Workflowdienste in IIS/ASP.NET oder in Ihren eigenen Anwendungen hosten möchten, sind sie genauso einfach wie jeder WCF-Dienst zu hosten.

WorkflowControlEndpoint

Beim Hosten eines Workflowdiensts wird die WF-Laufzeit initialisiert und neue Workflowinstanzen aktiviert, wenn Nachrichten über einen der verfügbar gemachten Endpunkte aktiviert werden. Zusätzlich zu dieser grundlegenden Hostingfunktionalität ist es auch wichtig, die Konfiguration und Ausführung dieser ausgeführten Workflowinstanzen remote verwalten zu können. .NET 4 erleichtert dies, indem Sie einen standardmäßigen WorkflowControlEndpoint bereitstellen, den Sie für Ihre Workflowdienste verfügbar machen können.

Im folgenden Beispiel wird veranschaulicht, wie Sie Ihrem Dienst den standardmäßigen Workflowsteuerungsendpunkt in einem benutzerdefinierten Hostingszenario hinzufügen:

...

WorkflowServiceHost-Host = new WorkflowServiceHost("HelloWorld.xamlx",

    neuer Uri("https://localhost:8080/helloworld"));

Gastgeber. AddDefaultEndpoints();

WorkflowControlEndpoint wce = new WorkflowControlEndpoint(

    new NetNamedPipeBinding(),

    neue EndpointAddress("net.pipe://localhost/helloworld/WCE"));

Gastgeber. AddServiceEndpoint(wce);

Gastgeber. Open();

...

Wenn Sie in IIS/ASP.NET hosten, können Sie den Standardmäßigen WorkflowControlEndpoint wie folgt hinzufügen:

<Konfiguration>

  <system.serviceModel->

    <Dienste>

      <Dienstname="HelloWorldWorkflowService"

          behaviorConfiguration="HelloWorldWorkflowService.Service1Behavior" >

        <endpoint address="" binding="basicHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="ws" binding="wsHttpContextBinding" contract="IHelloWorld"/>

        <endpoint address="wce" binding="wsHttpBinding" kind="workflowControlEndpoint"/>

      </service>

      ...

Der WorkflowControlEndpoint ermöglicht es Ihrem Workflowdienst, innerhalb verschiedener Hostingumgebungen verwaltet zu werden. Eine solche Umgebung wird von der Windows Server AppFabric ermöglicht, die in einer zukünftigen Version von Windows Server verfügbar sein wird.

Senden/Empfangen-Aktivitäten

.NET 3.5 umfasste zwei Messagingaktivitäten – Senden und Empfangen – zum Senden und Empfangen von Nachrichten mithilfe von WCF, waren aber hinsichtlich ihrer Funktionalität ziemlich eingeschränkt. .NET 4 verbessert die Sende- und Empfangsaktivitäten mit einigen zusätzlichen Features (z. B. Korrelation) und fügt einige weitere Messagingaktivitäten hinzu – SendReply und ReceiveReply –, die die Modellierung von Anforderungsantwortvorgängen vereinfachen.

Wenn Sie die Sende-/Empfangsaktivitäten innerhalb eines Workflowdiensts verwenden, verwenden Sie sie im Wesentlichen, um den Dienstvertrag zu modellieren, der über die WSDL-Definition für Clients verfügbar gemacht wird. Wenn Sie die Empfangsaktivität verwenden, geben Sie ihm einen Vorgangsnamen und ordnen die eingehende Nachricht einem .NET-Typ zu. Obwohl wir bisher einfache Zeichenfolgen verwendet haben, können Sie auch komplexe benutzerdefinierte Datenverträge verwenden. Aktualisieren wir den HelloWorldWorkflowService so, dass der folgende Datentyp verwendet wird:

[DataContract(Namespace="")]

Öffentliche Kursperson

{

    [DataMember]

    öffentliche Zeichenfolgen-ID;

    [DataMember]

    public string FirstName;

    [DataMember]

    Öffentliche Zeichenfolge Nachname;

}

Wenn wir diese Klassendefinition zum Webprojekt hinzufügen und zu HelloWorld.xamlx zurückkehren, können wir dann eine neue Variable namens "personMsg" vom Typ "PersonMsg" (der oben definierte Datenvertrag) definieren. Anschließend können wir die Aktivitäten "ReceiveRequest" und "SendResponse" der Variablen "personMsg" über die Eigenschaft "Content" zuordnen. Um dies zu tun, wählen Sie einfach jede Aktivität aus, und drücken Sie die Schaltfläche "Inhalt", um das Fenster "Inhaltsdefinition" anzuzeigen. Geben Sie dann "personMsg" in das Textfeld "Nachrichtendaten" und "Person" im Textfeld "Nachrichtentyp" ein. Sie müssen dies für beide Aktivitäten tun.

Mit den Sende-/Empfangsaktivitäten können auch andere Aspekte des WCF-Diensts konfiguriert werden, z. B. der Name des Vorgangs, der Dienstvertragsname, die Aktion, die Sammlung bekannter Typen, die Schutzebene und der Serialisierer, die zur Laufzeit verwendet werden sollen (z. B. DataContractSerializer vs. XmlSerializer). In der Sendeaktivität geben Sie auch die Zielendpunktdetails an. Alle diese Einstellungen können über das Eigenschaftenfenster konfiguriert werden, wenn die Aktivität "Senden/Empfangen" ausgewählt ist.

Mit diesen Änderungen können Sie HelloWorld.xamlx erneut testen, um zu sehen, dass der SayHello-Vorgang jetzt definiert ist, um Nachrichten vom Typ "Person" zu empfangen und zurückzugeben.

Definieren von Request-Reply Vorgängen

Um das Modellieren von Anforderungsantwortvorgängen zu vereinfachen, führt .NET 4 einige neue Aktivitäten zum Modellieren dieser Arten von Interaktionen ein. Eine ist die SendReply-Aktivität, die Sie mit einer Empfangsaktivität kombinieren können, um einen Anforderungsantwortvorgang innerhalb des Diensts zu implementieren. Es gibt auch eine ReceiveReply-Aktivität, die Sie mit einer Sendeaktivität kombinieren können, wenn Sie einen externen Dienst innerhalb eines Workflows aufrufen.

.NET 4 enthält auch einige Aktivitäten auf höherer Ebene namens ReceiveAndSendReply und SendAndReceiveReply, die Sie in der Visual Studio 2010-Toolbox sehen. Diese Aktivitäten verfassen einfach "Receive/Send" mit SendReply/ReceiveReply bzw. machen sie einfach zu bedienen. Wenn Sie sie auf die Workflowentwurfsoberfläche ziehen, sehen Sie, dass sie auf eine Sequenz erweitert werden, die eine Senden- oder Empfangen-Aktivität enthält, gefolgt von der entsprechenden "Antwort"-Aktivität.

Dienstreferenz hinzufügen

Um die Verwendung externer Dienste noch einfacher zu machen, bietet Visual Studio 2010 auch ein Feature "Dienstverweis hinzufügen", das wie erwartet funktioniert, außer dass eine Clientproxyklassendefinition generiert wird, die eine Reihe clientseitiger Aktivitäten generiert. Nachdem Sie "Dienstverweis hinzufügen" ausgewählt und die Adresse der WSDL-Definition angegeben haben, lädt Visual Studio die WSDL herunter und generiert eine benutzerdefinierte Aktivität für jeden Vorgang in der WSDL-Definition.

Sehen wir uns ein einfaches Beispiel an. Angenommen, es gibt einen CalculatorService mit Add-, Subtrahieren-, Multiplizier- und Dividieren-Vorgängen, die wir von unserem Workflowdienst verwenden möchten. Wir können einfach "Dienstverweis hinzufügen" auswählen und den Speicherort der RechnerService-WSDL-Definition angeben, wie in Abbildung 28 dargestellt.

Abbildung 28: Hinzufügen eines Dienstverweises

Sobald wir OK drücken, um den Dienstverweis hinzuzufügen, lädt Visual Studio die WSDL-Definition herunter und generiert vier benutzerdefinierte Aktivitäten, die in der Toolbox angezeigt werden. Sie verfügen jetzt über Add-, Subtrahieren-, Multiplizier- und Dividieren-Aktivitäten, die in Workflows einfach zum Aufrufen des externen Diensts verwendet werden können.

Korrelation

Beim Erstellen von Systemen, die aus lang ausgeführten Workflowdiensten bestehen, ist es üblich, dass zahlreiche Instanzen eines einzelnen Workflowdiensts gleichzeitig ausgeführt werden, bis dasselbe Ereignis auftritt (z. B. warten, bis eine bestimmte Nachricht eingeht, bevor sie fortgesetzt wird). Die Herausforderung bei diesem Szenario besteht darin, dass Sie eine Möglichkeit benötigen, die eingehende Nachricht mit der richtigen Workflowinstanz zu korrelieren. In der Regel bestimmen Sie die richtige Workflowinstanz, indem Sie den Inhalt der eingehenden Nachricht prüfen.

.NET 4 verfügt über ein komplexes inhaltsbasiertes Nachrichtenkorrelationsfeature, das Sie in Verbindung mit den soeben besprochenen Sende- und Empfangsaktivitäten verwenden können. Die Implementierung dieses Features dreht sich um das sogenannte "Korrelationshandles", ein weiteres neues Konzept in .NET 4.

Um mit der Verwendung der Korrelation zu beginnen, müssen Sie zuerst eine Workflowvariable vom Typ CorrelationHandle definieren. Sie können sich diese Variable als rendezvous-Punkt vorstellen, um eine Datenmenge aus (potenziell) zwei verschiedenen Nachrichten (die von zwei verschiedenen Messagingaktivitäten verarbeitet werden) zu verbinden. Sowohl die Sende- als auch die Empfangsaktivitäten stellen eine CorrelationsWith-Eigenschaft bereit, um eine CorrelationHandle-Variable anzugeben.

Um Nachrichten zu korrelieren, die von mehreren Sende-/Empfangsaktivitäten gesendet werden, müssen Sie den gleichen Korrelationshandle für alle Aktivitäten angeben, die an der Korrelation teilnehmen möchten. Anschließend konfigurieren Sie für jede Aktivität den Korrelationsschlüssel, der der von dieser bestimmten Aktivität verarbeiteten Nachricht zugeordnet wird (z. B. das SSN-Element in einer Nachricht könnte mit dem CustomerId-Element in einer anderen Nachricht korrelieren). Sie definieren Korrelationsschlüssel mithilfe von XPath-Ausdrücken, die für die Nachrichten ausgewertet werden.

Lassen Sie uns unser HelloWorldWorkflowService erweitern, um ein Beispiel dafür zu sehen, wie das funktioniert. Derzeit empfängt das Beispiel, mit dem wir gearbeitet haben, eine Person-Nachricht und gibt es zurück an den Client. Fügen wir nun eine weitere ReceiveAndSendReply-Aktivität direkt unterhalb der SendResponse-Aktivität am unteren Rand des Workflows hinzu. Dadurch wird Sequence hinzugefügt, die einen weiteren Empfang gefolgt von einem anderen SendReply enthält. Ich gebe der Empfangen-Aktivität den Namen "Finish", und wir fordern den Client auf, eine Anrede in der Nachricht "Ende" anzugeben, mit der die endgültige Begrüßungsantwort erstellt wird.

Mit anderen Worten, Clients rufen zuerst SayHello auf, und geben ihren vollständigen Namen an, um eine neue Workflowdienstinstanz zu starten. Dann wartet die Workflowinstanz, bis der Client "Finish" aufruft, um eine Anrede zu liefern (und dies kann möglicherweise Minuten, Stunden oder Tage dauern, in denen der Workflow beibehalten werden kann). Sobald der Client "Finish" aufgerufen hat, um die Anrede anzugeben, erstellt der Workflow eine Begrüßung mit der Anrede und dem ursprünglichen Namen und gibt ihn zurück. In diesem Szenario können wir problemlos mehrere ausgeführte Workflowinstanzen haben, die darauf warten, dass der Ende-Vorgang aufgerufen wird, sodass wir definitiv die Nachricht "Fertig stellen" mit der vorherigen SayHello-Nachricht korrelieren müssen. Da dies der Fall ist, muss ich die Empfangsaktivität für "Finish" mit dem gleichen Korrelationshandle verknüpfen, das wir für die Aktivität "SayHello" (NameHandle) angegeben haben.

Sehen wir uns nun den Nachrichteninhalt an, den wir in diesen beiden Aktivitäten korrelieren werden. In diesem Beispiel verwende ich die folgenden beiden Datentypen, um die Nachrichten zu modellieren:

[DataContract(Namespace="")]

Öffentliche Kursperson

{

    [DataMember]

    public string FirstName { get; set; }

    [DataMember]

    public string LastName { get; set; }

}

[DataContract(Namespace = "")]

Öffentliche Klassengruß

{

    [DataMember]

    öffentliche Zeichenfolge Anrede { get; set; }

    [DataMember]

    public string NameKey { get; set; }

}

Die Empfangsaktivität für "SayHello" ist so konfiguriert, dass die Person-Nachricht verwendet wird und die Empfangsaktivität für "Fertig stellen" für die Verwendung der Begrüßungsnachricht konfiguriert ist. Wir gehen davon aus, dass der Wert "LastName" immer eindeutig ist, damit wir ihn als eindeutigen Wert für die Korrelation verwenden können. Wenn der Client die Nachricht "Fertig stellen" sendet, muss er daher denselben Nachnamenwert angeben, der in der vorherigen "SayHello"-Nachricht verwendet wird.

Sehen wir uns nun an, wie Sie den Korrelationshandle so konfigurieren, dass dies eingerichtet wird. Ich habe bereits eine CorrelationHandle-Variable innerhalb der Sequenz namens "handle" definiert. Als Erstes müssen wir den Korrelationshandle innerhalb der Empfangsaktivität "SayHello" initialisieren. Wählen Sie also die "SayHello"-Empfangsaktivität aus, und drücken Sie die Schaltfläche neben dem Textfeld "CorrelationInitializers".

Hier müssen Sie im Dropdownfeld "Abfragekorrelationsinitialisierung" auswählen, und dann sollten Sie die Eigenschaft "LastName" für das Abfragefeld auswählen können (dies sollte einen XPath-Ausdruck von "sm:body()/xg0:Person/xg0:LastName" erzeugen, wie in Abbildung 29 dargestellt).

Anschließend müssen wir angeben, dass die "Ende"-Empfangsaktivität mit demselben Handle korreliert. Wählen Sie die "Ende"-Empfangsaktivität aus, und drücken Sie die Schaltfläche "KorrelierenOn". Geben Sie dann "handle" für das Handle "CorrelatesWith" an, und wählen Sie dann "NameKey" für das Abfragefeld aus (siehe Abbildung 30).

Abbildung 29: Definieren eines Korrelationsschlüssels für "SayHello"

Abbildung 30: Definieren eines Korrelationsschlüssels für "Fertig stellen"

Dies bedeutet letztendlich, dass das LastName-Element in der Person-Nachricht mit dem NameKey-Element in der Begrüßungsnachricht über die beiden separaten Anforderungen hinweg übereinstimmen muss. Damit kann die Workflowinfrastruktur die Nachrichten für uns automatisch korrelieren und die eingehenden "Finish"-Nachrichten an die richtige Workflowinstanz weiterleiten (basierend auf "LastName/NameKey").

Die letzte SendReply-Aktivität gibt die folgende formatierte Zeichenfolge an den Aufrufer zurück, einschließlich Informationen aus dem ursprünglichen "personMsg" und dem neuen "greetingMsg":

String.Format("{0}{1}{2}!",

   greetingMsg.Salutation, personMsg.FirstName, personMsg.LastName)

Ich werde das Korrelationsfeature mithilfe des WCF-Testclients testen, um mehrere Workflowinstanzen zu starten, indem SayHello mehrmals mit unterschiedlichen FirstName- und LastName-Werten aufgerufen wird. Danach sollten mehrere ausgeführte Instanzen des Workflowdiensts vorhanden sein. Nun können wir den Finish-Vorgang aufrufen, der einen der gleichen LastName-Werte angibt, die in einer der SayHello-Nachrichten verwendet werden, und wir sollten den entsprechenden FirstName-Wert sehen, der in der endgültigen Begrüßung an den Client zurückgegeben wird (siehe Abbildung 31).

Dies veranschaulicht die inhaltsbasierte Korrelation in Aktion, ein überzeugendes Feature für Workflowdienste, das im Lieferumfang von .NET 4 enthalten ist. Es ist wichtig zu beachten, dass Sie auch korrelationsbasierte Daten auf Kanal- und Protokollebene durchführen können, z. B. in .NET 3.5 (z. B. mithilfe der Kanal- oder Workflowinstanz-ID). Inhaltsbasierte Korrelation ist ein flexiblerer und anspruchsvollerer Ansatz, um dasselbe zu tun.

Abbildung 31: Testen des inhaltsbasierten Korrelationsbeispiels

Das bringt uns zum Ende unserer Workflowdienste-Abdeckung. Wir konnten die Oberfläche von Workflowdiensten in diesem Dokument nur noch kratzen, aber Sie können zusätzliche Informationen in den .NET 4 SDK-Beispielen und in der wachsenden MSDN-Dokumentation online finden. Wie Sie sehen können, öffnet die Kombination aus WCF und WF 4 die Türen zu einem völlig neuen Entwicklungsmodell zum Erstellen deklarativer, lang ausgeführter und asynchroner Dienste, die die besten Features beider Frameworks bieten können.

Verschiedene erweiterte Features

Zusätzlich zu allen anderen Themen, über die wir in diesem Dokument gesprochen haben, enthält WCF 4 einige erweiterte Features, die Sie möglicherweise hilfreich finden können. Diese erweiterten Features umfassen verbesserte Unterstützung der Typauflösung über DataContractResolver, die Möglichkeit, konkurrierende Kunden mit ReceiveContext, einem neuen Bytestream-Encoder und einer leistungsfähigen ETW-basierten Ablaufverfolgung zu verarbeiten.

Typauflösung mit DataContractResolver

In WCF 3.x gibt es ein Feature zur Typauflösung, das als "bekannte Typen" bezeichnet wird. Wenn während der Deserialisierung eine Instanz gefunden wird, die nicht vom selben Typ wie der deklarierte Typ ist, prüft er die Liste der deklarierten "bekannten Typen", um herauszufinden, welcher Typ verwendet werden soll. Als Autor des Diensts können Sie Ihre Typen/Methoden mit den Attributen [KnownType] oder [ServiceKnownType] kommentieren, um die Liste der möglichen Ersetzungen zu definieren. Dieses Feature wird häufig verwendet, um Vererbung und Polymorphismus zu unterstützen.

Leider bietet WCF 3.x keine einfache Möglichkeit, den von DataContractSerializer verwendeten Typzuordnungsalgorithmus zu überschreiben, wenn diese Art von dynamischer Typauflösung zur Laufzeit ausgeführt wird. Um dieses Problem zu beheben, stellt WCF 4 die abstrakte DataContractResolver-Klasse bereit, von der Sie ableiten können, um Ihren eigenen benutzerdefinierten Typauflösungsalgorithmus zu implementieren.  Im Folgenden wird gezeigt, wie Sie beginnen:

class MyDataContractResolver : DataContractResolver

{

    Assemblyassembly;

    public MyDataContractResolver(Assembly assembly)

    {

        this.assembly = assembly;

    }

    Wird bei der Deserialisierung verwendet

    Ermöglicht Benutzern das Zuordnen des xsi:type-Namens zu einem beliebigen Typ

    public override Type ResolveName(string typeName, string typeNamespace,

        Type declaredType, DataContractResolver knownTypeResolver)

    {

        ... // Implementieren Ihrer Zuordnung

    }

    Wird bei der Serialisierung verwendet

    Ordnet einen beliebigen Typ einer neuen xsi:type-Darstellung zu

    public override bool TryResolveType(Type type, Type declaredType,

        DataContractResolver knownTypeResolver, out XmlDictionaryString typeName,

        out XmlDictionaryString typeNamespace)

    {

        ... // Implementieren Ihrer Zuordnung

    }

}

Nachdem Sie Ihren benutzerdefinierten DataContractResolver implementiert haben, können Sie ihn wie hier gezeigt an DataContractSerializer bereitstellen:

DataContractSerializer dcs = new DataContractSerializer(

    typeof(Object), null, int. MaxValue, false, true, null,

    neue MyDataContractResolver(assembly));

Wenn Sie nun diese DataContractSerializer-Instanz zum Serialisieren/Deserialisieren von Objekten verwenden, wird Ihr benutzerdefinierter DataContractResolver aufgerufen, um die auflösung des benutzerdefinierten Typs auszuführen.

Um Ihren benutzerdefinierten DataContractResolver in die WCF-Runtime hinter den Kulissen einzufügen, müssen Sie ein WCF-Vertragsverhalten schreiben, das in dataContractSerializerOperationBehavior eingebunden wird und den Standardlöser überschreibt. Das .NET 4 SDK enthält ein vollständiges Beispiel, das veranschaulicht, wie dies durch ein Vertragsverhalten und ein benutzerdefiniertes Attribut mit dem Namen [KnownAssembly] erreicht werden kann.

Benutzerdefinierte Typauflösung kann nützlich sein, wenn Sie die Standardwerte für DataContractSerializer außer Kraft setzen möchten, genau steuern, welche Typen für die Serialisierung verwendet werden, oder um bekannte Typen dynamisch zu verwalten.

Verarbeiten von nachrichten in der Warteschlange mit ReceiveContext

Mit WCF 3.x können Sie die genau einmalige Zustellung von Nachrichten garantieren, wenn Sie netMsmqBinding verwenden, indem Sie Transaktionswarteschlangen verwenden und den WCF-Dienstvorgang in der MSMQ-Transaktion auflisten. Wenn Ausnahmen während der Verarbeitung einer Nachricht ausgelöst werden, stellt WCF sicher, dass die Nachricht nicht verloren geht, indem sie die Nachricht in eine Warteschlange zurückgibt (es kann je nach Konfiguration an die ursprungsende Warteschlange, eine Giftnachrichtwarteschlange oder eine Warteschlange mit toten Buchstaben zurückgegeben werden).

Obwohl diese Funktionalität wichtig ist, gibt es ein paar Probleme, die häufig auftreten. Eine ist, dass die Transaktionen teuer sind und viel Lese-/Schreibzugriff mit den Warteschlangen erzeugt, was mehr Aufwand und Komplexität bringt. Ein weiteres Problem besteht darin, dass es keine Möglichkeit gibt, sicherzustellen, dass derselbe Dienst die Nachricht beim nächsten Abrufen aus der Warteschlange verarbeitet (z. B. gibt es keine Möglichkeit, dass ein bestimmter Dienst eine Nachricht "sperren" kann), was eine Garantie darstellt, die Sie in bestimmten Szenarien vornehmen möchten.

Um diese Probleme zu beheben, führt WCF 4 eine neue API namens ReceiveContext zum Verarbeiten von nachrichten in die Warteschlange ein. Mit ReceiveContext kann ein Dienst eine Nachricht in der Warteschlange "ins Blick werfen", um mit der Verarbeitung zu beginnen, und wenn etwas schief geht und eine Ausnahme ausgelöst wird, verbleibt er in der Warteschlange. Dienste können nachrichten auch "sperren", um die Verarbeitung zu einem späteren Zeitpunkt erneut zu wiederholen. ReceiveContext bietet einen Mechanismus zum "Abschließen" der Nachricht, sobald sie verarbeitet wurde, damit sie aus der Warteschlange entfernt werden kann.

Dieser Ansatz vereinfacht dinge an mehreren Fronten, da Nachrichten nicht mehr gelesen und in Warteschlangen über das Netzwerk neu geschrieben werden, und einzelne Nachrichten werden während der Verarbeitung nicht über verschiedene Dienstinstanzen verteilt. Sehen wir uns ein einfaches Beispiel an, um zu veranschaulichen, wie es funktioniert.

Das folgende Beispiel zeigt, wie EmpfangenContext verwendet wird, um Nachrichten zu verarbeiten, die in einer Warteschlange ankommen:

...

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

[ReceiveContextEnabled(ManualControl = true)]

public void CalculateProduct(int firstNumber, int secondNumber)

{

    ReceiveContext receiveContext;

    wenn (! ReceiveContext.TryGet(OperationContext.Current.IncomingMessageProperties,

         out receiveContext))

    {

        Console.WriteLine("ReceiveContext auf diesem Computer nicht installiert/gefunden.");

        Rückgabe;

    }

    if ((firstNumber * secondNumber) % 2 == (receiveCount % 2))

    {

        receiveContext.Complete(TimeSpan.MaxValue);

        Console.WriteLine("{0} x {1} = {2}", firstNumber, secondNumber,

            firstNumber * secondNumber);

    }

    oder

    {

        receiveContext.Abandon(TimeSpan.MaxValue);

        Console.WriteLine("{0} & {1} nicht verarbeitet", firstNumber, secondNumber);

    }

    receiveCount++;

}

...

Bei erfolgreicher Übergabe rufen wir ReceiveContext.Complete auf, um die Verarbeitung der Nachricht abzuschließen, sodass sie aus der zugrunde liegenden Warteschlange entfernt wird. Andernfalls rufen wir "Abandon" auf, wodurch die Nachricht für zukünftige Wiederholungen in der Warteschlange verbleibt. Das .NET 4 SDK enthält ein vollständiges Beispiel, mit dem Sie dieses neue Feature genauer untersuchen können.

Optimieren der Codierung mit ByteStreamMessageEncodingBindingElement

In einigen Messaging-Szenarien möchten Sie einfach "Blobs" von Binärdaten ohne Umbruch oder zusätzliche Verarbeitung übertragen. Um dieses Szenario zu vereinfachen, enthält WCF 4 ein neues ByteStreamMessageEncodingBindingElement, das genau das tut. Leider enthält .NET 4 keine neue Bindung für diesen Encoder, sodass Sie eine benutzerdefinierte Bindung erstellen müssen, um sie zu nutzen.

Das .NET 4 SDK enthält ein vollständiges Beispiel, das veranschaulicht, wie eine benutzerdefinierte Bindung definiert wird, die das ByteStreamMessageEncodingBindingElement über eine benutzerdefinierte Bindungsklasse verwendet. Sobald Sie die neue Bindungsklasse eingerichtet haben, wird der Bytedatenstrom-Encoder sehr einfach mit Ihren Diensten verwendet.

Hochleistungs-ETW-basierte Ablaufverfolgung

WCF 4 verbessert auch die Ablaufverfolgung und Diagnose im Vordergrund. WCF 4 verwendet nun ETW für die Ablaufverfolgung, was die Ablaufverfolgungsleistung erheblich verbessert und eine bessere Integration mit anderen verwandten Technologien wie Windows Workflow Foundation, Windows Server AppFabric und den verschiedenen Verwaltungstechnologien in Windows Server bietet, die ein besseres Modell für die Plattform bieten.

Mit ETW können Ereignisanbieter Ereignisse in Sitzungen und Sitzungen schreiben, die diese Ereignisse optional in einem Protokoll speichern können. Verbraucher können Echtzeitsitzungsereignisse abhören oder diese Ereignisse aus einem Protokoll nach der Tatsache lesen. ETW-Controller sind für das Aktivieren/Deaktivieren von Sitzungen und das Zuordnen von Anbietern zu Sitzungen verantwortlich.

Das .NET 4 SDK bietet ein einfaches Beispiel, das veranschaulicht, wie Sie diese neue Hochleistungsablaufverfolgungsarchitektur in Verbindung mit Ihren WCF-Diensten nutzen können.

Schlussfolgerung

WCF 4 bietet zahlreiche Verbesserungen und mehrere völlig neue Features, die sich auf einige der am häufigsten verwendeten Kommunikationsszenarien von heute beziehen. In erster Linie wird WCF 4 durch das vereinfachte Konfigurationsmodell einfacher zu verwenden und die Unterstützung für allgemeine Standardwerte zu verbessern.

Darüber hinaus bietet WCF 4 erstklassige Unterstützung für die Dienstermittlung und das Routing, die in den meisten Unternehmensumgebungen und großen SOA-Initiativen gängige Anforderungen sind – diese Features setzen WCF allein von vielen konkurrierenden Frameworks ab. WCF 4 vereinfacht auch die REST-basierte Dienstentwicklung und bietet mehrere weitere erweiterte WCF-Features, die sich heute auf bestimmte Schmerzpunkte beziehen.

Darüber hinaus bietet WCF 4 eine anspruchsvolle Integration in WF, um ein neues Modell für die Entwicklung deklarativer Workflowdienste bereitzustellen. Workflowdienste ermöglichen die Entwicklung lang ausgeführter und asynchroner Dienste, die vom WF-Programmiermodell und der zugrunde liegenden Laufzeit profitieren. Dank der neuen WCF-basierten Aktivitäten und der Designerunterstützung in Visual Studio 2010 wird dieses neue Programmiermodell zu einer erstklassigen Option für Erstellungsdienste.

In .NET 4 werden die Welten von WCF und WF zusammengeführt, um ein einheitliches Programmiermodell zu bieten, das Ihnen die besten beiden Welten bietet. Weitere Informationen zu den Neuerungen in WF 4 finden Sie in der Einführung eines Entwicklers in Windows Workflow Foundation in .NET 4.

Informationen zum Autor

Aaron Skonnard ist ein Mitbegründer von Pluralsight, einem Microsoft-Schulungsanbieter, der sowohl kursleitergeführte als auch on-demand .NET-Entwicklerkurse anbietet. In diesen Tagen verbringt Aaron die meiste Zeit mit der Aufzeichnung von Pluralsight On-Demand! Kurse, die sich auf Cloud Computing, Windows Azure, WCF und REST konzentrierten. Aaron hat Jahre damit verbracht, professionelle Entwickler auf der ganzen Welt zu schreiben, zu sprechen und zu unterrichten. Sie können ihn bei http://pluralsight.com/aaron und http://twitter.com/skonnarderreichen.

Zusätzliche Ressourcen