MSDN Magazin > Home > Ausgaben > 2008 > January >  WCF-Syndikation: HTTP-Programmierung mit WCF un...
WCF-Syndikation
HTTP-Programmierung mit WCF und .NET Framework 3.5
Justin Smith

Dieser Artikel basiert auf einer Vorabversion von Visual Studio 2008. Änderungen an allen Informationen in diesem Artikel sind vorbehalten.
Themen in diesem Artikel:
  • Grundlagen von HTTP-Nachrichten
  • Hinzufügen von Informationen zu URIs
  • WCF und HTTP
  • RSS und ATOM mit WCF
In diesem Artikel werden folgende Technologien verwendet:
Windows Communication Foundation
Bei der ersten Veröffentlichung als Teil von Microsoft® .NET Framework 3.0 umfasste Windows® Communication Foundation (WCF) ein universelles Objektmodell für ganz gewöhnliches XML (Plain Old XML, POX) und SOAP-Messaging über eine Vielzahl von Transporten. Da WCF auch intensive Unterstützung für WS-*-Webdienststandards enthält, kann es auf verhältnismäßig einfache Weise mit anderen modernen Dienstplattformen zusammenarbeiten. WCF in .NET Framework 3.0 ist äußerst erweiterbar und enthält stabile Verwaltbarkeitsfeatures wie Nachrichtenprotokollierung, Aktivitätsüberwachung, Diensteinschränkung, Instanzverwaltung und Threadingsteuerelemente.
WCF in .NET Framework 3.5 baut so auf den Erweiterbarkeitspunkten in .NET Framework 3.0 auf, dass das Erstellen von Diensten, die die Prinzipien des Webs einhalten, in erstklassiger Weise unterstützt wird. Hierzu gehören ein benutzerfreundliches HTTP-Programmiermodell, JavaScript Object Notation (JSON)-Messagingfunktionen sowie eine neue Syndikations-API, mit der sich syndizierter Inhalt leicht erstellen und nutzen lässt. Mit diesen Features ist WCF jetzt die beliebteste Dienstplattform für die Verbindung von Diensten mit Webclients, unabhängig davon, ob diese ASP.NET AJAX-Steuerelemente, SilverlightTM-Clients oder sogar Browser sind. Diese Features funktionieren auch in Szenarios mit teilweiser Vertrauenswürdigkeit (wie ASP.NET mit mittlerer Vertrauenswürdigkeit), sodass Sie WCF-Dienste in allgemein verfügbaren Hostumgebungen hosten können. Zur Abrundung gibt es noch neue, in Visual Studio® 2008 integrierte Tools, die den Zeitaufwand für Aufbau und Ausführung eines Diensts erheblich verringern.
Die Kombination von webzentrierter Kommunikation mit SOAP- und WS-*-Standards zu einem Dienststapel und Objektmodell ist eines der Features, die WCF in .NET Framework 3.5 so leistungsfähig machen. Dies bedeutet, dass Sie mithilfe von SOAP und WS-* einen Dienst für die unternehmensinterne oder -übergreifende Kommunikation erstellen können, und denselben Dienst so konfigurieren können, dass die Kommunikation nach außen mithilfe der Webprotokolle erfolgt. Letztlich kümmert sich WCF um die Grundstruktur Ihres Diensts, sodass Sie sich besser auf die dadurch verfügbar gemachte Funktionalität konzentrieren können.
In diesem Artikel werden einige der neuen webzentrierten Features von WCF in .NET Framework 3.5 erläutert. Zunächst wird die Ebeneneinstellung bezüglich einiger der wichtigen architektonischen Prinzipien in HTTP und Web behandelt. Anschließend geht es um das neue HTTP-Programmiermodell in WCF und schließlich um die neue Syndikations-API.

Grundlagen von HTTP-Nachrichten
Sie verwenden das Web wahrscheinlich fast jeden Tag, aber wie oft denken Sie über die grundlegenden Konzepte nach, dank derer das Web funktionieren kann? Es ist nicht meine Art, mich über architektonische Konzepte auszulassen, aber einige der Grundideen des Webs sind möglicherweise nicht auf den ersten Blick offensichtlich. Meiner Meinung nach sind gute Kenntnisse dieser Prinzipien ein notwendiger erster Schritt, wenn Sie Dienste erstellen wollen, die die Webprotokolle erfüllen. Beachten Sie, dass diesem Thema ganze Bücher gewidmet wurden, weshalb in diesem Artikel nur die wichtigsten Punkte angesprochen werden.
Die Webübertragung erfolgt mit HTTP. HTTP erfordert ein Anforderungs-/Antwort-Nachrichtenaustauschmuster (Message Exchange Pattern, MEP). Dies findet jedes Mal statt, wenn Sie mithilfe Ihres Browsers zu einer Webseite navigieren: Sie fordern eine Ressource an und erhalten genau eine Antwort, die diese Ressource enthält. Der HTTP-Transport definiert mehrere Verben (auch Methoden genannt), die dem Anforderungs-/Antwort-MEP Features wie GET, POST, PUT und DELETE hinzufügen. Um einige der Unterschiede zwischen HTTP-Verben zu verdeutlichen, sehen Sie sich eine HTTP POST-Nachricht näher an. Hier ist eine verkürzte Version:
POST /myservice/PostAlbum HTTP 1.1
HOST: www.cloudsample.net
<albumInfo>
  <albumId>15</albumId>
</albumInfo>
Es handelt sich einfach nur um eine Nachricht, die an eine wartende Anwendung gesendet wird. Im vorliegenden Fall wird die Nachricht an http://www.cloudsamples.net/myservice/PostAlbum gesendet. Die Nachricht hat auch eine Nutzlast, die für das Feld „albumId“ einen Wert enthält. Im Endeffekt können Sie sich eine HTTP POST-Nachricht als eine Möglichkeit vorstellen, eine Nutzlast an eine wartende Anwendung zu senden.
Die Nutzlast in diesem Beispiel ist so einfach, dass die gesamte Nutzlast mit der Zahl 15 dargestellt werden könnte. Damit dies funktioniert, müsste die empfangende Anwendung wissen, dass die Zahl 15 dem Wert eines Felds „albumId“ zugeordnet ist. Dies ist unter anderem eines der Hauptfeatures, die in einer HTTP GET-Nachricht enthalten sind. So erhalten Sie zum Beispiel beim Übergang von der vorherigen HTTP POST-Nachricht zu einer HTTP GET-Nachricht Folgendes:
GET /myservice/GetAlbum/15 HTTP 1.1
HOST: www.cloudsamples.net
Eine HTTP GET-Nachricht ist eine optimierte HTTP POST-Nachricht und kann eine Nutzlast überflüssig machen. Letztlich ist der URI die Nutzlast. Dies führt zu geringeren Nachrichtengrößen, und kleinere Nachrichten führen zu kürzeren Übertragungszeiten. Kleinere Nachrichten und die Verbindung zum URI haben noch eine weitere positive Folge: Andere Anwendungen (wie Proxys oder Browser) können die Ergebnisse vorheriger HTTP GET-Anforderungen derselben Ressource leichter zwischenspeichern. Es sollte darauf hingewiesen werden, dass HTTP GET viel öfter als jedes andere HTTP-Verb verwendet wird.
Im Prinzip ist eine HTTP GET-Nachricht die Anforderung einer Ressource. Stellen Sie sich zur Verdeutlichung vor, dass Sie im Web eine interessante Ressource finden (z. B. http://www.cloudsamples.net/pictureservices) und diese per E-Mail an einen Freund schicken wollen. Wenn Ihr Freund die E-Mail erhält, erwarten Sie, dass er auf den Link klicken und dieselbe Seite anzeigen kann, die Sie auch gesehen haben. Sie wären sicher überrascht, wenn als Ressource unter http://www.cloudsamples.net/pictureservices plötzlich die neuesten Nachrichten von MSNBC angezeigt würden. Schließlich ist der in HTTP GET verwendete URI doch die Darstellung einer Ressource, und diese Ressource dürfte sich in der Regel nicht ändern.
Zwar gibt es eine klare Übereinstimmung darüber, was eine HTTP GET-Nachricht darstellt, doch gilt dies nicht für die anderen HTTP-Verben. Bedenken Sie die Folge des Versendens einer HTTP DELETE-Nachricht an eine empfangende Anwendung. Muss die empfangende Anwendung ihren Zustand ändern oder eine Aktion durchführen? Gewöhnlich ist eine HTTP DELETE-Nachricht einer subtraktiven Zustandsänderung oder Aktion verbunden, aber die Einzelheiten dieser Zustandsänderung sind nicht definiert. Dasselbe gilt für eine HTTP PUT-Nachricht. In der Regel ist eine HTTP PUT-Nachricht einer beliebigen additiven Zustandsänderung oder Aktion verbunden, aber die genaue Form der Änderung ist von Anwendung zu Anwendung verschieden.

Ausdrücken zusätzlicher Informationen
Anwendungen, die eine HTTP GET-Nachricht erhalten, verwenden die im URI eingebetteten Informationen, um die als Antwort zu sendende Ressource zu bestimmen. Betrachten Sie zur Veranschaulichung folgenden Satz von URIs:
contoso.com/artists/Flaming+Hammer/HitMe
contoso.com/artists/Northwind/Overdone
Im vorliegenden Fall verfügt Contoso Corporation über eine Anwendung, die Ressourcen im Bereich Musik liefert. Sie können aus diesen Beispielen wahrscheinlich entnehmen, wie sich der Name des Interpreten und der Name des Albums einem URI zuordnen lassen:
contoso.com/artists/[artist]/[album]
Wenn die Anwendung eine HTTP GET-Nachricht für http://contoso.com/artists/Northwind/Overdone erhält, muss sie eine Ressource im Zusammenhang mit Northwinds Overdone-Album zurückgeben. Es gibt ein eindeutiges Muster für den URI. Dieses besteht aus einigen Basisinformationen (contoso.com/artists) und einigen URI-Segmenten (oder „Löchern“), die die Werte für den Interpreten und das Album enthalten.
Es ist auch üblich, derartige Informationen in die Parameter der Abfragezeichenfolge einzubetten. Obwohl sich das Format von den vorstehenden Beispielen unterscheidet, ist das Endergebnis gleich. Nachfolgend sehen Sie einen Satz von URI-Löchern mit einem Abfragezeichenfolgen-Parameter:
contoso.com/artists/Flaming+Hammer?album=HitMe
contoso.com/artists/Northwind?album=Overdone
In diesem Fall verwenden URI und Abfragezeichenfolge die folgende Syntax:
contoso.com/artists/[artist]?album=[album]
Der HTTP-Transport verwendet darüber hinaus einen erweiterbaren Satz von Kopfzeilen, um zusätzliche Informationen auszudrücken. Diese Informationen können sich auf die Zwischenspeicherung, den Datentyp in der Nachricht, den Namen der sendenden Anwendung, die Länge des Inhalts, das Hostbetriebssystem und vieles mehr beziehen. Abbildung 1 zeigt eine HTTP GET-Nachricht (Zeilen 1-8) und die Antwortnachricht (Zeilen 9-14) mit mehreren typischen Kopfzeilen.
1    GET /PictureServices/Feed.svc/picture/Pictures;Bridge.jpg HTTP/1.1
2    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, 
       application/x-ms-application, application/vnd.ms-xpsdocument, 
       application/xaml+xml, application/x-ms-xbap, 
       application/vnd.ms-excel, application/vnd.ms-powerpoint, 
       application/msword, application/x-shockwave-flash, 
       application/x-silverlight, */*
3    Accept-Language: en-us
4    UA-CPU: x86
5    Accept-Encoding: gzip, deflate
6    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; 
       .NET CLR 2.0.50727; InfoPath.2; .NET CLR 1.1.4322; 
       .NET CLR 3.5.20706; .NET CLR 3.0.590; MS-RTC LM 8)
7    Host: www.cloudsamples.net
8    Proxy-Connection: Keep-Alive

9    HTTP/1.1 200 OK
10   Content-Type: image/jpeg
11   Server: Microsoft-IIS/7.0
12   X-Powered-By: ASP.NET
13   Date: Sat, 15 Sep 2007 18:57:11 GMT
14   Content-Length: 106333

Der Accept-Header in der HTTP GET-Anforderung zeigt an, welche Datenformate der Client empfangen möchte. Wie Sie der langen Liste der Werte entnehmen können, kann der Client mehrere Arten von Daten empfangen (Bilder, Office-Dokumente, Silverlight-Anwendungen usw.). Die Antwort auf die HTTP GET-Nachricht enthält Daten, deren Format durch den Wert des Inhaltstypheaders (image/jpeg wie in Zeile 10 gezeigt) beschrieben wird. Mit dieser einfachen Methode kann die sendende und empfangende Anwendung die Datenformate koordinieren. Die Verwendung von Kopfzeilen zur Koordination der Datenformate ist nicht so aussagekräftig wie die Grammatik von SOAP-Webdiensten für Web Services Description Language (WSDL) und XML Schema Definition (XSD), aber sie ist für das Web ausreichend.

REST und das Web
Bei der Betrachtung der Hauptbestandteile des HTTP-Transports sehen Sie gleichzeitig eine Reihe der wichtigen Prinzipien, die das Web locker zusammenhalten. Im Jahr 2000 schrieb ein Doktorand namens Roy Fielding eine Dissertation, in der er unter anderem diese Prinzipien in einem als Representational State Transfer (REST) bekannten architektonischen Stil kodierte. (Sie finden Roy Fieldings Dissertation unter ics.uci.edu/~fielding/pubs/dissertation/top.htm.)
Der architektonische REST-Stil wurde in Büchern, auf Softwarekonferenzen und in einer schier unüberschaubaren Sammlung von Blogs detailliert erörtert. Es ist unmöglich, hier alle Facetten abzudecken, aber meiner Meinung nach lässt er sich auf drei wesentliche Punkte reduzieren:
  • Integration des URI
  • HTTP GET ist etwas Besonderes
  • Datenmodell ist Inhaltstyp
Für den Zweck dieses Artikels werden diese Aspekte als Prinzipien des Webs betrachtet. Durch Integration dieser Prinzipien in Ihre Anwendungen erhöhen Sie die Interoperabilität und Reichweite der Funktionalität dieser Anwendung erheblich. Interoperabilität und Reichweite sind die wesentlichen Gründe für den Erfolg der meisten Webdienste. Schließlich ist ein Webdienst eigentlich eine Möglichkeit, Funktionalität über ein strukturiertes Messagingschema verfügbar zu machen. Die Prinzipien des Webs (HTTP-Anforderung/-Antwort) beschreiben eigentlich eine Teilmenge möglicher Messagingschemas. Praktisch verstehen alle Plattformen, Anwendungen, Betriebssysteme und Benutzer die Prinzipien des Webs. Wenn Sie diese also in Ihre Webdienstanwendung integrieren, gewinnen Sie verbesserte Reichweite und Interoperabilität.
Es sollte unbedingt angemerkt werden, dass die Prinzipien des Webs WS-* nicht ausblenden, da sich REST und WS-* nicht gegenseitig ausschließen. Keines von beiden kann alle Arten von Kommunikationsanforderungen abdecken. Deshalb wird nachdrücklich empfohlen, nicht eines von beiden universell auf alle Dienste anzuwenden. So eignet sich REST beispielsweise nicht sehr gut zum Senden von Nachrichten an einen Vermittler, während WS-* hierfür hervorragend geeignet ist. Andererseits eignen sich WS-*-Anwendungen nicht besonders gut zur Interaktion mit einfachen Clients wie Browsern, während sich REST-Anwendungen auf diesem Gebiet durch besondere Stärke auszeichnen.

HTTP-Programmierung mit WCF
Ausgehend von den Grundlagen des Webs soll im Folgenden betrachtet werden, wie sich mithilfe von WCF in .NET Framework 3.5 Anwendungen erstellen lassen, die die Prinzipien des Webs erfüllen. An erster Stelle steht die Untersuchung einiger der neuen Bausteine des HTTP-Programmiermodells. Anschließend bewege ich mich durch das System hindurch nach oben.
Wenn Sie den URI in Ihre Anwendungen integrieren möchten, müssen Sie sich wahrscheinlich daran gewöhnen, URIs zu erstellen und zu analysieren. Diese Aufgabe von Hand vorzunehmen, ist fehleranfällig und mühsam. Allerdings erledigen die neuen Typen „System.UriTemplate“ und „System.UriTemplateMatch“ jetzt die Schwerstarbeit bei der Erstellung und Analyse von URIs. Sie gehören zu den grundlegenden Bausteinen für die neuen HTTP-Funktionen von WCF.
Der UriTemplate-Typ ist der grundlegende Baustein für die Definition der bereits erläuterten URI-Löcher. Der Konstruktor des UriTemplate-Typs akzeptiert eine Zeichenfolge, die die Löcher in einem URI darstellt. Nach der Instanziierung macht ein UriTemplate-Objekt zwei Instanzmethoden verfügbar, um Textwerte an die bei der Instanziierung definierten Löcher zu binden. Diese Methoden geben einen URI zurück, dessen Löcher mit Werten gefüllt sind.
Ein UriTemplate-Objekt macht auch eine Instanzmethode mit dem Namen „Match“ verfügbar, um die Werte der Löcher eines System.Uri-Objekts zu extrahieren. Die Match-Instanzmethode akzeptiert zwei System.Uri-Objekte. Der erste URI ist eine Basisadresse, der zweite dient zum Vergleich. Ein System.UriTemplateMatch-Objekt wird von der Match-Methode zurückgegeben. Das UriTemplateMatch-Objekt enthält eine Sammlung von Werten für die Löcher, die zum Zeitpunkt der Instanziierung von UriTemplate definiert werden.
Der Code in Abbildung 2 veranschaulicht, wie die Typen UriTemplate und UriTemplateMatch für den Roundtrip eines URI zu verwenden sind. Als Ergebnis dieses Codes erhalten Sie folgende Ausgabe:
// create a URI bound to the template
Uri baseAddress = new Uri(@"http://localhost:2000");
UriTemplate template = new UriTemplate("{artist}?album={album}");
Uri boundUri = template.BindByPosition(baseAddress, "Northwind", 
    "Overdone");
Console.WriteLine(boundUri.ToString());
            
// retrieve the value of the artist segment
UriTemplateMatch match = template.Match(baseAddress, boundUri);
String bandName = match.BoundVariables["artist"];
Console.WriteLine("the name of the artist is  {0}", bandName);

http://localhost:2000/Northwind?album=Overdone
the name of the artist is  Northwind
Bei den Typen „System.UriTemplate“ und „System.UriTemplateMatch“ fehlt der übliche WCF-System.ServiceModel-Moniker im Namespace. Ihre Funktionalität ist nämlich so gestaltet, dass Sie sie innerhalb einer WCF-Anwendung nicht verwenden müssen. Sie sind immer dann recht praktisch, wenn Sie einen URI erstellen oder analysieren müssen.
Obwohl die Typen „UriTemplate“ und „UriTemplateMatch“ ziemlich einfach zu verwenden sind, wollte das WCF-Team die Anwendung dieser beiden Typen in einem WCF-Dienst sogar noch leichter machen. Ziel war es, eine einfache und intuitive Möglichkeit anzubieten, URI-Segmente und Abfragezeichenfolgen-Parameter in Anwendungsfunktionalität abzubilden. Das im folgenden Code gezeigte Modell ist meiner Meinung nach hierfür geeignet:
[ServiceContract]
public interface IPictureService
{
  [OperationContract]
  [WebGet(UriTemplate = "picture/{pictureId}")]
  Stream GetPicture(String pictureId);

  [OperationContract]
  [WebGet(UriTemplate = "picture/t/{pictureId}")]
  Stream GetPictureThumbnail(String pictureId);
}
UriTemplate wird als Instanzeigenschaft auf „WebGetAttribute“ angezeigt, das seinerseits auf einen Dienstvertrag angewendet wird. Beachten Sie, dass das Token zwischen den geschweiften Klammern dem Namen des Methodenparameters zugeordnet ist. Obwohl dieses Beispiel nur einen Parameter zeigt, können Sie viele Parameter hinzufügen, diese in beliebiger Reihenfolge anordnen, sie als Abfragezeichenfolgen-Parameter hinzufügen und sogar Platzhalter verwenden.
Zur Laufzeit wird der Wert der UriTemplate-Eigenschaft zum UriTemplate-Konstruktor weitergeleitet. Sowohl die Client-Laufzeit als auch der Verteiler verwenden den UriTemplate-Eigenschaftswert in dieser Weise. Der Verteiler verwendet ihn, um einem Vorgang eingehende Nachrichten zuzuordnen, und der Client verwendet ihn, um sicherzustellen, dass eine Methode auf einem Proxy zum richtigen URI gesendet wird. Dies ist eine leicht anwendbare, einfache und effektive Möglichkeit, den URI in Ihre Dienste zu integrieren.

HTTP-Verben in WCF-Verträgen
HTTP-Programmierung mit WCF in .NET Framework 3.5 macht es leicht, Vorgänge in einem Dienstvertrag HTTP-Verben zuzuordnen. Wie Sie wahrscheinlich am Namen erkennen können, macht die Anwendung von WebGetAttribute auf einen Vorgang diesen Vorgang über eine HTTP GET-Nachricht verfügbar. Im obigen Codeausschnitt haben Sie gesehen, dass WebGetAttribute eine Instanzeigenschaft mit dem Namen „UriTemplate“ definiert.
Es gibt auf dem WebGetAttribute-Typ noch weitere Instanzeigenschaften. Die wichtigsten sind RequestFormat und ResponseFormat. Wie ihre Namen bereits andeuten, geben die Werte dieser Eigenschaften das Nachrichtenformat für den Vorgang vor. Die RequestFormat- und ResponseFormat-Eigenschaften sind vom Typ „WebMessageFormat“, einem enumerierten Typ mit zwei Werten: Xml und JSON. Die WCF-Infrastruktur verwendet die Werte dieser Eigenschaften, um den Kanalstapel mit dem passenden Nachrichtencodierer einzurichten. Ein Eigenschaftswert von „WebMessageFormat.Xml“ führt zu einem Kanalstapel, der den XML-Codierer verwendet. Die Einstellung des Werts auf „WebMessageFormat.JSON“ führt zu einem Kanalstapel, der den in .NET Framework 3.5 enthaltenen JSON-Codierer verwendet. Da es für beide Seiten des HTTP-Nachrichtenaustauschs Eigenschaften gibt, ist es möglich, dass eine Anwendung eine XML-Nachricht empfängt und eine JSON-Nachricht zurückgibt (oder umgekehrt).
Das andere Attribut im Zusammenhang mit HTTP-Verben ist „WebInvokeAttribute“. Die Anwendung dieses Attributs auf einen Vorgang macht diesen Vorgang durch jedes HTTP-Verb außer HTTP GET verfügbar. Die Trennung im Objektmodell zwischen HTTP GET und allen anderen Verben weist auf die Häufigkeit hin, mit der HTTP GET im Vergleich zu den anderen HTTP-Verben verwendet wird. Das WebInvokeAttribute-Objektmodell ähnelt WebGetAttribute, aber es umfasst eine Instanzeigenschaft mit der Bezeichnung „Method“. Der Wert dieser Eigenschaft ordnet dem Vorgang ein bestimmtes HTTP-Verb zu. Die Methodeneigenschaft ist vom Typ Zeichenfolge, daher können Sie den Wert auf alle HTTP-Standardverben und sogar auf solche HTTP-Verben festlegen, die nicht dem Standard entsprechen. Abbildung 3 stellt dar, wie WebInvokeAttribute in einem Dienstvertrag verwendet wird.
[ServiceContract]
public interface IPictureService
{
  [OperationContract]
  [WebGet(UriTemplate = "picture/{pictureId}")]
  Stream GetPicture(String pictureId);

  [OperationContract]
  [WebGet(UriTemplate = "picture/t/{pictureId}")]
  Stream GetPictureThumbnail(String pictureId);
  
  [OperationContract]
  [WebInvoke(UriTemplate="update", Method="POST")]
  void UpdatePictureInfo(PictureInfo info);
}

Die UpdatePictureInfo-Methode verfügt über einen Parameter des Typs „PictureInfo“. Zur Laufzeit ist eine serialisierte Version eines PictureInfo-Objekts die Nutzlast einer HTTP POST-Nachricht. Wenn Anwendungen Daten auf diese Weise übergeben, können sie komplexe Datentypen liefern, die ansonsten nicht in einem URI ausdrückbar sind.
WCF in .NET Framework 3.5 macht es auch leicht, mit HTTP-Headern zu interagieren. HTTP-Anforderungs- und -Antwortheader werden über den System.ServiceModel.Web.WebOperationContext-Typ verfügbar gemacht. Der WebOperationContext-Typ ist eine Erweiterung des System.ServiceModel.OperationContext-Typs, der in WCF in .NET Framework 3.0 eingeführt wurde, und sein Verwendungsmuster ist ähnlich. Beide sind zur Verwendung im Rahmen der Implementierung eines Dienstobjekts vorgesehen. Der WebOperationContext-Typ macht Member verfügbar, die das Lesen oder Einstellen von HTTP-Headerwerten sowie das Abrufen von Informationen zum URI vereinfachen, der für den Zugriff auf das Dienstobjekt verwendet wird. Die HTTP-Header werden als Sammlung gespeichert, und die häufigsten werden als einzelne Eigenschaften verfügbar gemacht. Dieses Beispiel zeigt, wie Sie den WebOperationContext-Typ so verwenden können, dass dem Datenmodell des Webs durch Festlegen des Inhaltstypheaders für eine HTTP-Antwort entsprochen wird:
public Stream GetPicture(string pictureId)
{
  // retrieve the Stream (omitted)
  Stream stream;

  // set the Content-Type to image/jpeg
  WebOperationContext.Current.OutgoingResponse.ContentType = 
    "image/jpeg";

  return stream;
}

Bindung und Hosting
Bis jetzt wurde erläutert, wie Sie der Anwendungsfunktionalität URI-Segmente und den HTTP-Verben Vorgänge zuordnen können, und wie Sie mit HTTP-Headern interagieren. Im Folgenden wird untersucht, wie sich diese Features in einem funktionierenden Dienst zusammenführen lassen. Hierzu müssen Sie sich ein noch paar weitere Typen anschauen, die in WCF neu sind.
WCF in .NET Framework 3.0 hat das Konzept einer Bindung eingeführt, die Abstraktion des Transports und die Protokolle eines Endpunkts. .NET Framework 3.0 wurde mit mehreren Bindungen geliefert, die auch die Unterstützung für eine umfangreiche Auswahl von Transporten und Protokollen umfassten.
Zu WCF in .NET Framework 3.5 gehört eine neue Bindung mit dem Namen System.ServiceModel.WebHttpBinding. Diese Bindung ist die Abstraktion der Prinzipien des Webs und folgt demselben Nutzungsmodell wie die Bindungstypen in .NET Framework 3.0. Deshalb können Sie sie wie jede andere Bindung einem Endpunkt hinzufügen.
In WCF in .NET Framework 3.0 wurde ebenfalls das Konzept eines Endpunktverhaltens eingeführt. Ein Verhalten ist eine Möglichkeit, den Ausführungspfad der Messaginginfrastruktur zu erweitern. Es gibt mehrere Verhaltensweisen, die mit .NET Framework geliefert werden, und Sie können auch leicht Ihr eigenes Verhalten erstellen.
WCF in .NET Framework 3.5 umfasst ein neues Endpunktverhalten mit dem Namen „System.ServiceModel.Description.WebHttpBehavior“. Dieses Verhalten führt mehrere Aufgaben durch. Für empfangende Anwendungen richtet es die Filterinfrastruktur ein, um unter anderem sicherzustellen, dass empfangene Nachrichten an die entsprechende Methode für das Dienstobjekt gesendet werden. In .NET Framework 3.0 verwendete WCF eine Kombination von SOAP-Aktion und Zieladresse als Versandschlüssel. Das Setup des Filtermechanismus durch WebHttpBehavior erweitert die vorhandenen Filtermechanismen so, dass sie UriTemplate-Treffer und HTTP-Verben erfassen.
Abbildung 4 zeigt, wie Sie mithilfe von WebHttpBinding und WebHttpBehavior eine empfangende Anwendung erstellen können, die die Prinzipien des Webs erfüllt. Der Vorteil dieses Ansatzes besteht darin, dass Sie einen dieser Endpunkte einem vorhandenen ServiceHost hinzufügen können und auf diese Weise ein einziges ServiceHost erhalten, das sowohl über SOAP/WS-*-Endpunkte als auch über REST-Endpunkte verfügt.
ServiceHost host = new ServiceHost(typeof(IPictureContract), 
    new Uri("http://localhost:5000"));
// instantiate a WebHttpBinding
WebHttpBinding binding = new WebHttpBinding();

// add an endpoint, using the WebHttpBinding
ServiceEndpoint ep = host.AddServiceEndpoint(
    typeof(IPictureContract),  binding, String.Empty);

// add the WebHttpBehavior to the endpoint
ep.Behaviors.Add(new WebHttpBehavior());

// open the ServiceHost to start listening
host.Open(); 

Sendende Anwendungen folgen demselben Nutzungsmodell, aber es muss der Sammlung von Endpunktverhaltensweisen auf dem ChannelFactory<T>-Objekt WebHttpBehavior hinzugefügt werden. Gemäß der typischen WCF-Methoden sind diese Optionen auch in Konfigurationsdateien verfügbar.
WCF in .NET Framework 3.5 entwickelt dieses einfach zu bedienende Modell sogar noch weiter, sodass Sie in einigen Fällen weder WebHttpBinding noch WebHttpBehavior hinzufügen müssen. Die neue API umfasst zwei Typen, die diesem Zweck dienen: System.ServiceModel.Web.WebServiceHost und System.ServiceModel.Web.WebServiceHostFactory. Der WebServiceHost-Typ fügt allen Endpunkten automatisch WebHttpBehavior hinzu und führt eine zusätzliche Prüfung zur Laufzeit durch, um sicherzustellen, dass alle Endpunkte mit dem Verhalten kompatibel sind. Dies erspart Ihnen den Arbeitsschritt, einem Endpunkt WebHttpBehavior hinzuzufügen.
Der WebServiceHostFactory-Typ wurde zur Verwendung in IIS-gehosteten Szenarios entworfen, um die Notwendigkeit unbedingt erforderlicher Informationen oder Konfigurationsdatei-Hostformationen zu vermeiden. WCF in .NET Framework 3.0 führte die .svc-Datei als Aktivierungsziel zum Hosten von WCF-Diensten in IIS ein. Diese Dateien enthalten Direktiven, die Seitendirektiven in ASP.NET ähnlich sehen. Das Hinzufügen von WebServiceHostFactory zur Factory-Eigenschaft der .svc-Dateidirektive erstellt einen ServiceHost, fügt einen Endpunkt hinzu, der den passenden Vertrag mit WebHttpBinding verwendet, fügt diesem Endpunkt WebHttpBehavior hinzu und öffnet den ServiceHost:
<%@ ServiceHost 
  Language="C#" 
  Service="PictureService" 
  Factory="System.ServiceModel.Web.WebServiceHostFactory" %>
Die web.config-Datei für den Dienst enthält keine WCF-bezogenen Einträge.

Die neue Syndikations-API
Stellen Sie sich einen RSS-Feed vor. Vielleicht denken Sie wie ich dabei sofort an einen Nachrichtenfeed oder einen Blog. Syndikationen (RSS und ATOM sind Syndikationsformate) können viel mehr ausdrücken. Abstrakt ausgedrückt ist syndizierter Inhalt einfach eine Möglichkeit, einen Datensatz darzustellen. Dieser Datensatz könnte in der Praxis etwas ganz Beliebiges sein: die Population der Beutelhörnchen innerhalb eines 50-Meilen-Radius um Sydney, die letzten 10 Bestellungen von über 100 Dollar oder die Anzahl der von Contoso im letzten Monat hergestellten Bumerangs.
.NET Framework 3.5 bietet umfangreiche Unterstützung für die Erstellung und Nutzung von syndiziertem Inhalt. Es unterstützt Erstellung und Nutzung sowohl des RSS 2.0- als auch des ATOM 1.0-Formats, verschiedene Mechanismen zum Hinzufügen von Syndikationserweiterungen und sogar die Funktion, zusätzliche Formate zu implementieren. Das Programmiermodell erspart dem Entwickler die Einzelheiten des Syndikationsformats und macht es dadurch leichter verwendbar.
Bis hin zu Version 3.5 gab es keine Standardmöglichkeit, syndizierten Inhalt mit .NET Framework zu erstellen oder zu nutzen. Obwohl die neue Syndikationsfunktionalität vom WCF-Team geschrieben wurde, ist sie nicht von WCF abhängig. Eigentlich sind alle zur Syndikation gehörigen Typen Teil des System.Syndication-Namespace, obwohl sie sich in der System.ServiceModel.Web.dll-Assembly befinden. Sie können die Syndikationsfunktionen von .NET Framework 3.5 von jedem Prozess aus verwenden, der eine AppDomain (ASP.NET, WPF-Anwendungen, NT-Dienste usw.) hostet. Diese Funktion impliziert, dass Sie syndizierten Inhalt über jeden Transport liefern oder nutzen können, nicht nur über HTTP. In Verbindung mit dem HTTP-Programmiermodell in WCF können Sie Syndikation jedoch auch vorhandenen SOAP-/WS-*-Diensten hinzufügen.
Die neue Syndikations-API umfasst Typen, die einen einzelnen Syndikationsfeed und die Elemente in einem Feed zusammenfassen, sowie Typen, die diesen Feed in ein bestimmtes Format umwandeln können. Der System.Syndication.SyndicationFeed-Typ ist eine formatunabhängige Darstellung eines Syndikationsfeeds. Ein SyndicationFeed enthält eine Liste von SyndicationItem-Objekten. Ein SyndicationFeed ohne einen Satz von SyndicationItem-Objekten ist wie ein Garten ohne Blumen, da ein SyndicationItem-Objekt nur die Darstellung für ein Element in einem Feed ist.
Sobald ein SyndicationFeed einen Satz von SyndicationItem-Objekten enthält, kann ein SyndicationFeedFormatter<T> diesen Feed in ein bestimmtes Format umwandeln. Es gibt zwei Typen, die von SyndicationFeedFormatter<T> abgeleitet werden: Rss20FeedFormatter und Atom10FeedFormatter. Wie die Namen bereits andeuten, wandeln diese Typen eine SyndicationFeed-Instanz in das RSS 2.0-Format bzw. das ATOM 1.0-Format um.

Erstellen eines SyndicationFeed
Es gibt zwei Möglichkeiten, ein SyndicationFeed-Objekt zu erstellen. Sie können ein solches Objekt instanziieren und seine Member manuell auffüllen, oder Sie können das gesamte SyndicationFeed-Objekt von einem vorhandenen Feed aus auffüllen. Beide Möglichkeiten sind leicht durchzuführen und ersparen dem Entwickler die mit einem bestimmten Wire-Format verbundenen Probleme. Dieser Code zeigt, wie ein SyndicationFeed-Objekt manuell erstellt wird.
SyndicationFeed feed = new SyndicationFeed();
feed.Title.Text = "The Cybertopian Chronicle";
Title ist nur eine von vielen Eigenschaften, die Sie festlegen können. Weitere Möglichkeiten finden Sie in der Dokumentation.
Es kommt oft vor, dass Sie einen vorhandenen Feed lesen und aufgrund seines Inhalts etwas veranlassen wollen. In der neuen Syndikations-API können Sie ein SyndicationFeed instanziieren und seinen Zustand automatisch von einem vorhandenen Feed aus auffüllen. Dazu benötigen Sie lediglich den URI des vorhandenen Feeds oder ein XmlReader-Objekt, das in der Lage ist, ihn zu lesen. Dieser Code zeigt, wie sich eine Verbindung zu einem vorhandenen Feed im Web herstellen lässt und Informationen daraus extrahiert werden können:
Uri feedUri = new Uri("http://blogs.msdn.com/justinjsmith/atom.xml");
SyndicationFeed feed = SyndicationFeed.Load(feedUri);
Console.WriteLine(feed.Title.Text);

// outputs "The Cybertopian Chronicle"
Der SyndicationItem-Typ enthält über 35 Member. Viele sind zu Einstellungs- oder Abruffeldern gehörige Eigenschaften wie Element-ID, Zeitpunkt der letzten Aktualisierung, Veröffentlichungsdatum, Titel oder der eigentliche Inhalt. Es gibt auch mehrere Member, die das Erweitern des in einem SyndicationItem gespeicherten Inhalts erleichtern. Es gibt viele Erweiterungen zu RSS und ATOM (darunter Microsoft Simple List Extensions, Yahoo Media RSS und GeoRSS), und sowohl SyndicationFeed als auch SyndicationItem können so erweitert werden, dass sie jede vorhandene RSS- oder ATOM-Erweiterung umfassen.
Feeds können viele Elemente haben, und es ist bei großen Feeds nicht möglich, sie alle auf einmal zu laden. SyndicationFeed behandelt diese Situation so, dass sein Satz von SyndicationItem-Objekten als IEnumerable<SyndicationItem> verfügbar gemacht wird. Diese Implementierung macht die Behandlung großer Mengen von SyndicationItem-Objekten leichter, da die Iteratorfunktion von .NET Framework 2.0 genutzt wird. Es ist auch möglich, mithilfe von LINQ einen Satz von SyndicationItem-Objekten zu durchlaufen. Dies kann den Umfang an Code erheblich verringern, der zum Extrahieren von Informationen aus einem Feed erforderlich ist.
Die Syndikations-API definiert mehrere Typen, die ein SyndicationFeed-Objekt in das RSS 2.0- und das ATOM 1.0-Format umwandeln. Sie können sogar ein SyndicationFeed erstellen, ihn es SyndicationItem-Objekten auffüllen und dann diesen Feed sowohl als RSS als auch als ATOM verfügbar machen. Abbildung 5 zeigt, wie Sie einen ATOM 1.0-Feed abrufen, ihn in RSS 2.0 umwandeln und die neue RSS-Darstellung auf der Konsole ausgeben.
// read an ATOM feed
Uri feedUri = new Uri("http://blogs.msdn.com/justinjsmith/atom.xml");
SyndicationFeed feed = SyndicationFeed.Load(feedUri);

// transform it to RSS
Rss20FeedFormatter formatter = new Rss20FeedFormatter(feed);
XmlWriter writer = XmlWriter.Create(Console.Out, null);

// write it to the Console
formatter.WriteTo(writer);
writer.Flush();

Wenn Sie die Syndikations-API mit dem HTTP-Programmiermodell in WCF kombinieren, können Sie einen Feed von einem benutzerdefinierten URI aus verfügbar machen und RSS oder ATOM zurückgeben, je nach Zusammenstellung des URI. Abbildung 6 zeigt, wie Sie einen Vorgang in einem Dienstvertrag, der einen Abfragezeichenfolgen-Parameter von einer empfangenen HTTP GET-Nachricht verwendet, so definieren, dass entweder ein RSS- oder ein ATOM-Feed zurückgegeben wird. Beachten Sie die Verwendung von SyndicationFeedFormatter<SyndicationFeed> im Vorgangsvertrag. Sowohl Rss20FeedFormatter als auch Atom10FeedFormatter werden von SyndicationFeedFormatter<TSyndicationFeed> abgeleitet.
[ServiceKnownType(typeof(Atom10FeedFormatter))]
[ServiceKnownType(typeof(Rss20FeedFormatter))]
[ServiceContract]
interface IPictureService {
  [OperationContract]
  [WebGet(UriTemplate="Pictures?format={format}")]
  SyndicationFeedFormatter<SyndicationFeed> Feed(String format);
}

class PictureService : IPictureService {

  public SyndicationFeedFormatter<SyndicationFeed> Feed(String format){
    // create the syndication feed 
    SyndicationFeed feed = new SyndicationFeed();

    // add the items to the feed (omitted)

    // check the argument & return the right format
    if(format.ToLower() == "rss"){
      return new Rss20FeedFormatter(feed);
    }
    return new Atom10FeedFormatter(feed);

  }

}


Letzte Schritte
Zusammenfassend lässt sich sagen, dass Sie in diesem Artikel einige der Grundlagen des HTTP-Transports kennengelernt haben. Sie haben erfahren, wie dieser mit den Prinzipien des Webs zusammenhängt, wie Sie WCF zur Integration dieser Prinzipien in Ihre Anwendungen einsetzen können, und wie Sie die neue Syndikations-API verwenden können, um RSS- und ATOM-Feeds zu liefern und zu nutzen. Um die Funktionen dieser neuen Features weitergehend vorzuführen, sehen Sie sich eine Beispielanwendung namens „PictureServices“ unter www.cloudsamples.net/pictureservices an. Sie können das Beispiel online ausführen, den Quellcode durchsuchen und das ganze Beispiel herunterladen. Abbildung 7 zeigt PictureServices in Aktion.
Abbildung 7 Der PictureServices-Feed (Klicken Sie zum Vergrößern auf das Bild)
PictureServices kann Bilder entweder von einem lokalen Computer oder von einem Flickr-Feed abrufen. Die Anwendung verwendet ein einfaches Anbietermodell, und es gibt derzeit drei Anbieter: Windows-Desktopsuche, ein Ordner auf Ihrem Dateisystem und Flickr. Sobald PictureServices die Dateien von einem Anbieter abruft, werden die Bilder zusammengeführt und lokal bereitgestellt. Von einem Browser aus können Sie sich durch einen Feed durchklicken und einzelne Bilder abrufen. Es gibt für Sie noch einiges andere in diesem Beispiel zu entdecken. Weitere Links mit Informationen zu den hier erörterten Technologien finden Sie in der Randleiste „Zusätzliche Ressourcen“ in diesem Artikel.

Justin Smith arbeitet bei Microsoft im Bereich Technologieförderung und befasst sich mit Webdiensten. Seine Hauptgebiete sind WCF und BizTalk-Dienste. Justin ist außerdem Autor von „Inside Windows Communication Foundation“ (Microsoft Press, 2007) und tritt häufig als Referent bei Softwareentwicklungskonferenzen auf. Lesen Sie seinen Blog unter blogs.msdn.com/justinjsmith.

Page view tracker