Verfasst von: bletra | 2. Juni 2010

WCF: Schnellstart (Teil 1 von 3)

SOA, WebServices sind in aller Munde, die zugehörige Microsofttechnologie heißt Windows Communication Foundation (WCF).
Mit den zugehörigen Templates und Klassenbibliotheken kann man relativ einfach eine Schnittstelle als Dienst für andere
Applikationen zur Verfügung stellen. Prinzipiell haben sich zwei Standards als zugrundeliegende Technologie etabliert: REST und SOAP.
Auf beide und wie diese mit .Net implementiert werden, möchte ich in diesem Artikel eingehen.

Wann immer eine Applikationen auf eine andere Applikation zugreifen möchte, sind drei Fragen wichtig:

  • Wo: Wo finde ich den Service? (Adresse, .Net: Address)
  • Wie: Wie kann ich mich verbinden? (Protokoll, Verbindung, .Net: Binding)
  • Was: Was wird übertragen? Welche Methoden kann ich wie anfragen, wie werden die Parameter (Daten) übertragen, welches Format hat die Antwort? (Schnittstelle, Daten, .Net: Contract)

In der .Net-Sprache sind diese drei zusammen ein Endpunkt (Endpoint) eines Dienstes. Einfach zu merken als ABC:
Adress, Binding, Contract, siehe folgende Graphik (Quelle: Microsoft).

WCF: Endpoint

Einfacher Dienst mit SOAP

SOAP steht für Simple Object Access Protocol und ist die Technologie, die von .Net schon länger gut unterstützt wird.
Bei SOAP handelt es sich jedoch nicht wirklich um ein Protokoll und es ist nicht simpel und dient auch nicht nur für den
Zugriff auf Objekten. Als Transportprotokoll kann TCP verwendet werden, verbreitet ist jedoch das Aufsetzen auf HTTP. Mit WSDL
existiert eine auf XML basierende Beschreibungssprache für den Dienst. Dazu gibt es modulare Ergänzungen, die sogenannten
WS*-Sprachen, die Sicherheit, Transaktionen oder Betriebssicherheit (Reliability) eines Dienstes definieren.

In VS2010 kann auf der Vorlage von WCF->WCF Service Library ein einfacher Dienst auf Basis von SOAP erstellt werden. Als Basis wird ein Interface definiert, das mit dem Attribut [ServiceContract] als Dienst markiert wird. Die einzelnen Methoden werden mit den Attributen [OperationContract] durchgereicht. Um zusammengesetzte Datentypen als Parameter im Dienst zu ermöglichen, werden die zugehörigen Klassen mit [DataContract] und die Properties dieser Klasse mit [DataMember] markiert. Nun wird noch eine Klasse benötigt, die das definierte Interface implementiert und der Dienst ist in der App.config entsprechend zu konfigurieren:

<service name="WCFLecture.SimpleSOAP">
 <endpoint address="" binding="wsHttpBinding" contract="WCFLecture.ITestService">...
 <host>
 <baseAddresses>
 <add baseAddress="http://localhost:8732/Design_Time_Addresses/WCFLecture/PublicServiceSOAP/" />
 </baseAddresses>
 </host>
</service>

Hier wird also das ABC eines Dienstes definiert:

Mit einem Rechtsklick auf die App.config und Edit WCF-Configuration existiert eine benutzerfreundlichere Oberfläche
zur Definition des Dienstes. Wir erweitern das vorgegebene Interface noch um einen schreibenden Zugriff, sowie einen weiteren Datentyp so dass der Quellcode insgesamt wie folgt aussieht:

[ServiceContract]
 public interface ITestService
 {
   [OperationContract]
   string GetData(int value);

   [OperationContract]
   Person GetDataUsingDataContract(CompositeType composite, int id);

   [OperationContract]
   string PutDataUsingDataContract(Person composite);
 }

 [DataContract]
 public class CompositeType
 {
   bool boolValue = true;
   string stringValue = "Hello ";

   [DataMember]
   public bool BoolValue
   {
     get { return boolValue; }
     set { boolValue = value; }
   }

   [DataMember]
   public string StringValue
   {
     get { return stringValue; }
     set { stringValue = value; }
   }
 }

 [DataContract]
 public struct Person
 {
   [DataMember]
   public int Id;
   [DataMember]
   public string Name;
   public Person(int id, string name)
   {
     this.Id = id;
     this.Name = name;
   }
 }
 public class SimpleSOAP : ITestService
 {
   public string GetData(int value)
   {
     return string.Format("You entered: {0}", value);
   }

   public Person GetDataUsingDataContract(CompositeType composite, int id)
   {
     if (composite == null)
     {
       throw new ArgumentNullException("composite");
     }
     return new Person(id, composite.StringValue);
   }
   public string PutDataUsingDataContract(Person p)
   {
     return "hello " + p.Name;
   }
 }

VS2010 stellt auch einen zugehörigen Debug-Client zur Verfügung. Die Applikation ist also direkt zu debuggen. Im Client können die zu übergebenden Parameter einfach editiert werden. Ein Blick auf die XML-Ansicht zeigt, welche Daten dabei wirklich ausgetauscht werden:
Anfrage (Request) von string PutDataUsingDataContract(Person composite):

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
 <s:Header>
 <a:Action s:mustUnderstand="1">http://tempuri.org/ITestService/PutDataUsingDataContract</a:Action>
 <a:MessageID>urn:uuid:2cf0bda1-49f4-4bf2-b05c-df1529db1c93</a:MessageID>
 <a:ReplyTo>
 <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
 </a:ReplyTo>
 </s:Header>
 <s:Body>
 <PutDataUsingDataContract xmlns="http://tempuri.org/">
 <composite xmlns:d4p1="http://schemas.datacontract.org/2004/07/WCFLecture" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
 <d4p1:Id>1</d4p1:Id>
 <d4p1:Name>Berta</d4p1:Name>
 </composite>
 </PutDataUsingDataContract>
 </s:Body>
</s:Envelope>

Zugehörige Antwort (Response):

<pre><s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
 <s:Header>
 <a:Action s:mustUnderstand="1" u:Id="_2">http://tempuri.org/ITestService/PutDataUsingDataContractResponse</a:Action>
 <a:RelatesTo u:Id="_3">urn:uuid:daaf536a-abae-4abf-89cf-8af96768ec33</a:RelatesTo>
 <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
 <u:Timestamp u:Id="uuid-43de11fc-4760-4068-87ff-be99fafbaf3f-11">
 <u:Created>2010-06-02T14:01:51.803Z</u:Created>
 <u:Expires>2010-06-02T14:06:51.803Z</u:Expires>
 </u:Timestamp>
 <c:DerivedKeyToken u:Id="uuid-43de11fc-4760-4068-87ff-be99fafbaf3f-7" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
 <o:SecurityTokenReference>
 <o:Reference URI="urn:uuid:a73939ec-ed4c-4b76-b337-12bbd3927521" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
 </o:SecurityTokenReference>
 <c:Offset>0</c:Offset>
 <c:Length>24</c:Length>
 <c:Nonce>nRSWEkBdK+B0QJJzTkkw8Q==</c:Nonce>
 </c:DerivedKeyToken>
 <c:DerivedKeyToken u:Id="uuid-43de11fc-4760-4068-87ff-be99fafbaf3f-8" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
 <o:SecurityTokenReference>
 <o:Reference URI="urn:uuid:a73939ec-ed4c-4b76-b337-12bbd3927521" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct" />
 </o:SecurityTokenReference>
 <c:Nonce>0HBcrgKzul80wIBpBU1Cmw==</c:Nonce>
 </c:DerivedKeyToken>
 <e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
 <e:DataReference URI="#_1" />
 <e:DataReference URI="#_4" />
 </e:ReferenceList>
 <e:EncryptedData Id="_4" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
 <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
 <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
 <o:SecurityTokenReference>
 <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" URI="#uuid-43de11fc-4760-4068-87ff-be99fafbaf3f-8" />
 </o:SecurityTokenReference>
 </KeyInfo>
 <e:CipherData>
 <e:CipherValue>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</e:CipherValue>
 </e:CipherData>
 </e:EncryptedData>
 </o:Security>
 </s:Header>
 <s:Body u:Id="_0">
 <PutDataUsingDataContractResponse xmlns="http://tempuri.org/">
 <PutDataUsingDataContractResult>hello Berta</PutDataUsingDataContractResult>
 </PutDataUsingDataContractResponse>
 </s:Body>
</s:Envelope>

Um jede Anfrage wird also ein umfangreiches XML als Umschlag gebastelt. Für einen häufig genutzten Dienst mit kurzen Antworten,
wie z.B. einen Aktienticker, ist dies eine Menge „unnötigen“ Daten, die das Netz belasten. Eine zu SOAP alternative
Technologie adressiert dieses Problem: REST.

Teil 2 von 3: Einfacher Dienst mit REST

Teil 3 von 3: Datenbankanbindung mit REST

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

Kategorien

%d Bloggern gefällt das: