RESTful Web Service mit .NET und ExtJs: Service-Interface

Dieser Artikel ist Teil 2 einer mehrteiligen Serie, die sich mit dem Erstellen und Nutzen eines RESTful Web Service mit Hilfe von .NET und ExtJs beschäftigt.

WCF unterstützt seit der .NET-Frameworkversion 3.5 das Erstellen von RESTful Webservices durch das WebInvokeAttribute. Auf die Properties dieses Attributs möchte ich kurz anhand von Beispielen eingehen.

UriTemplate

Dieses Property legt die Adresse für die Schnittstelle (also die URI) fest. Dabei können Platzhalter für Zeichenketten-Parameter hinterlegt werden.

[OperationContract]
[WebInvoke(RequestUri = "Message/{messageId}";)]
ChatMessage GetMessageDetails(string messageId); 

Wenn der Service unter der Adresse

http://service.example.com/MessageService/

veröffentlicht wird, wäre der Endpunkt für die Methode GetMessageDetails demnach

http://service.example.com/MessageService/Message/{messageId},

wobei {messageId} lediglich ein Platzhalter für eine Zeichenkette ist, die der Methode GetMessageDetails() als Parameter übergeben wird.

Method

RESTful Webservices veröffentlichen ihre Schnittstellen durch Uri und das HTTP-Verb. WCF stellt den Zugriff auf das HTTP-Verb, mit dem der Zugriff auf die Schnittstelle erfolgte, durch die Property "Method" des WebInvokeAttribute zur Verfügung. Deshalb stellt folgende Deklaration eine Schnittstelle bereit, die über "PUT" angesprochen wird:

[OperationContract] 
[WebInvoke(
    RequestUri = "Message/{messageId}",
    Method = "PUT")] 
ChatMessage ModifyMessage(
	string messageId, 
	ChatMessage messageToModify);

RequestFormat / ResponseFormat

Diese Properties legen fest, wie die zu übertragenden Objekte serialisiert werden. Die möglichen Werte sind vom Typ WebMessageFormat, also XML oder Javascript Object Notation. Für ersteres wird für die Serialisierung die Klasse DataContractSerializer verwendet, für JSON folgerichtig DataContractJsonSerializer. Das Ergebnis der Serialisierung – und damit der Inhalt der Antwort einer Serviceanfrage – würde zum Beispiel so aussehen:

<chatmessage>
  <messageid>
    f1fe94db-f859-404e-bada-213f296b13a6
  </messageid>
  <time>21.04.2009 12:00:00.0000</time>
  <author>LaTino</author>
  <text>Beispieltext der Nachricht</text>
</chatmessage>

Oder für WebMessageFormat.Json:

{ 
  "Author":"LaTino", 
  "MessageId":"f1fe94db-f859-404e-bada-213f296b13a6", 
  "Text":"Beispieltext der Nachricht", 
  "Time":"\/Date(1240320060000+0200)\/" 
} 

Erwähnenswert ist dabei vielleicht, dass durch die Einteilung in RequestFormat und ResponseFormat für die Deserialisierung von eingehenden Objekten durchaus andere Regeln gelten können als für die Serialisierung ausgehender Objekte.

BodyStyle

Dieses Property ist vom Typ WebMessageBodyStyle und legt fest, ob die serialisierten Daten noch einmal als Kindknoten (im Fall von XML) oder als Subobjekt (im Fall von Json) serialisiert werden.

WebMessageBodyStyle.Bare steht dabei für die oben angeführten Serialisierungen, Wrapped für das Wrappen – Bare ist die Voreinstellung, durch Auswahl der WrappedRequest und WrappedResponse-Werte kann diese Eigenschaft also einzeln für Anfragen und Antworten festgelegt werden.

Für eine ChatMessage, die wrapped nach JSON serialisiert wird, ergibt sich im Gegensatz dazu folgender Output:

{ 
  "GetMessageResult": { 
    "Author":"LaTino", 
    "MessageId":"f1fe94db-f859-404e-bada-213f296b13a6", 
    "Text":"Beispieltext der Nachricht", 
    "Time":"\/Date(1240320060000+0200)\/"
  } 
} 

Ein möglicher Nachteil dieses Formats ist, wie schon zu sehen ist, das mögliche Offenlegen der hinter dem Request stehenden Schnittstelle (hier: GetMessage). Im Beispiel werden wir daher auf das BodyStyle-Attribut verzichten und Nachrichten grundsätzlich unwrapped serialisieren.

Es ist an der Zeit, zu definieren, was für Nachrichten wir eigentlich hin- und herschicken möchten. Dafür benötigen wir eine (sehr einfache) Klasse ChatMessage, die wir mit Hilfe des DataContractAttribute und des DataMemberAttribute so markieren, dass der gewählte DataContractJsonSerializer seine Arbeit tun kann:

[DataContract]
public class ChatMessage
{
    [DataMember] public Guid MessageId { get; set; }
    [DataMember] public DateTime Time { get; set; }
    [DataMember] public string Author { get; set; }
    [DataMember] public string Text { get; set; }
}

Die fertige Schnittstelle unseres Beispieldienstes wird Json für die Kommunikation verwenden und stellt für die Ressource "Message" alle notwendigen Endpunkte mit den im ersten Teil erwähnten vier HTTP-Verben „GET“, „POST“, „PUT“ und „DELETE“ bereit.

[ServiceContract] 
public interface IMessageService 
{
  [OperationContract] 
  [WebInvoke(
	UriTemplate = "Message", 
	Method = "GET", 
	RequestFormat = WebMessageFormat.Json, 
	ResponseFormat = WebMessageFormat.Json)] 
  List ListMessages(); 

  [OperationContract]
  [WebInvoke(
	UriTemplate = "Message/{messageId}", 
	Method = "GET", 
	RequestFormat = WebMessageFormat.Json, 
	ResponseFormat = WebMessageFormat.Json)] 
  ChatMessage GetMessage(string messageId); 

  [OperationContract] 
  [WebInvoke(
	UriTemplate = "Message", 
	Method = "POST", 
	RequestFormat = WebMessageFormat.Json, 
	ResponseFormat = WebMessageFormat.Json)] 
  ChatMessage CreateMessage(ChatMessage message); 

  [OperationContract] 
  [WebInvoke(
	UriTemplate = "Message/{messageId}", 
	Method = "DELETE", 
	RequestFormat = WebMessageFormat.Json, 
	ResponseFormat = WebMessageFormat.Json)] 
  ChatMessage DeleteMessage(string messageId); 

  [OperationContract] 
  [WebInvoke(
	UriTemplate = "Message/{messageId}", 
	Method = "PUT", 
	RequestFormat = WebMessageFormat.Json, 
	ResponseFormat = WebMessageFormat.Json)] 
  ChatMessage ModifyMessage(
	string messageId, 
	ChatMessage messageToModify);
} 

Im nächsten Teil schauen wir uns die Implementierung des Service an, und überlegen, wie er am besten veröffentlicht wird.

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

%d Bloggern gefällt das: