Dieser Artikel wurde maschinell übersetzt.

Service Station

Erstellen von RESTful-Clients

Jon Flanders

In dieser Ausgabe der Service der Rest an werden erstellen-Clients für REST-Dienste erläutert. Erstellen von Clients als schwierig wahrgenommen wird (hauptsächlich aufgrund der fehlenden automatische Client Generierung von Metadaten À la SOAP und WSDL), aber in Wirklichkeit wie jeder andere Typ von Code ist es, den Sie schreiben: Zunächst wird einige Rampe-Up-Zeit, Sie zu einer bestimmten Programmierparadigma verwendet erhalten. Dann, wenn Sie die hängt das Paradigma haben, Code dafür schreiben wird einfacher und leichter. Ich habe festgestellt dazu zum Schreiben von Clients für REST-Dienste erfüllt sein, wie viele Entwickler haben, denen ich mit interagiert haben.

Client-Grundlagen

Ich werde die Grundlagen der Interaktion zwischen einem Client und einen Dienst, die Verwendung von REST anzeigen. Nur eine schnelle Zusammenfassung zu REST, bevor wir in untersuchen. REST ist ein Architekturstil, die auf den gleichen Prinzipien aufbaut, die die Grundlage für das Internet bereitstellen. Clients interagieren mit Diensten indem HTTP-Anforderungen, und Dienste mit HTTP-Antworten, die häufig eine Darstellung einer Ressource enthalten, mit dem Client-Code eine Anwendung Laufwerk Antworten.

Genommen Sie an, besteht einen Dienst, der Informationen und Funktionen im Zusammenhang mit Hyper-V (die Virtualisierungstechnologie in Windows Server 2008 integriert) verfügbar macht. Wenn "Eintrag"URI dieses Dienstes ist http://localhost/HyperVServices/VMs.svc/, als Client, den ich eine HTTP GET-Anforderung zum Abrufen einer Darstellung der durch dieses URI identifizierte Ressource machen würden. In diesem Fall wird die Ressource wird als XML formatiert und stellt eine Liste aller virtuellen Computer (VM) s auf einem bestimmten Computer installiert.


Abbildung 1 eine einfache HTTP GET-Anforderung

Wie ich in der ersten Meine Service Station-Artikel über REST, in der Januar 2009 Ausgabe des MSDN Magazine (msdn.microsoft.com/magazine/2009.01.servicestation.aspx) einer der Vorteile der Verwendung von kleinen gezeigt REST ist können HTTP-Anforderung Tools Sie Ihre erste Test Anforderungen gegen einen Dienst. (Mit diesen Tools zum Debuggen von Problemen ist auch sehr hilfreich.) Ich verwende in diesem Fall ein kostenloses Tool namens „ Fiddler (fiddlertool.com) verwenden, zum Erstellen eine HTTP GET-Anforderung für die Ressource, die eigene virtuelle Computer darstellt. Finden Sie unter Abbildung 1. Natürlich Tools wie Fiddler sind nützlich, aber zum Erstellen einer Anwendung müssen Sie Code für den Dienst zu schreiben. Ich werde beginnen mit die Grundlagen für eine HTTP-anfordern und dann in der Ausgabe des tatsächlich beim Lesen der Ressource vornehmen.

.NET Framework hat immer einen grundlegenden HTTP-API angeboten, die Interaktion mit Rest-Diensten verwendet werden können. Sind Sie in der Mitte dieser API die HttpWebRequest "und" HttpWebResponse-Typen. Damit eine HTTP-Anforderung, Sie erstellen und konfigurieren Sie eine HttpWebRequest-Instanz und Fragen Sie nach der HttpWebResponse. Abbildung 2 zeigt ein Beispiel. Die eine Anforderung an eines REST-Diensts wird eine einfache Schritte festgelegt:

  1. Stellen Sie sicher Sie den entsprechenden URI verwenden.
  2. Stellen Sie sicher Sie die richtige Methode (HTTP-Verb) verwenden.
  3. Verarbeiten der Antwort, wenn der Statuscode 200 OK ist.
  4. Umgang mit anderen Statuscodes als entsprechenden (mehr dazu später).

Da die Schritte 1 und 2 ziemlich einfach, landen allgemeinen Schritt 3 (und manchmal Schritt 4) wird schwieriger die Schritte.

Der Großteil der Arbeit von Schritt 3 wird die Darstellung der Ressource auf angemessene Weise verarbeitet. Da XML weiterhin die häufigste Antwort der Ressource ist, werde ich, die in diesem Artikel behandelt. (Der wahrscheinlichste Medientyp wäre JSON.) Wenn die Ressource XML ist, müssen Sie die Ressource zu analysieren und Schreiben des Codes, die die benötigten Daten extrahieren können, aus der resource.Using .NET, einige Optionen für die XML-Analyse. Es gibt versucht true XmlReader-Klasse. XmlDocument-Klasse besteht auch die Möglichkeit und mithilfe dieser Typen Sie manuell analysieren oder XPath Ihren Weg, um die XML-Daten navigieren verwenden können. Mit der Einführung von .NET 3.0 erhalten Sie auch das XDocument-Klasse, die zusammen mit LINQ to XML für XML-Verarbeitung die de facto Wahl geworden. Abbildung 3 zeigt ein Beispiel von Code verarbeitet die Liste der VMs XDocument verwenden.

Abbildung 2 Simple HttpWebRequest Code

string uri = "http://localhost/HyperVServices/VMs.svc/";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
//this is the default method/verb, but it's here for clarity
webRequest.Method = "GET";
var webResponse = (HttpWebResponse)webRequest.GetResponse();
Console.WriteLine("Response returned with status code of 0}",
webResponse.StatusCode);
if (webResponse.StatusCode == HttpStatusCode.OK)
ProcessOKResponse(webResponse);
else
ProcessNotOKResponse(webResponse);

LINQ to XML, zusammen mit anonymer Typen bietet eine gute und einfache Möglichkeit zum Umgang mit XML in Objekte, die von eine Anwendung verarbeitet werden können und, selbstverständlich können Sie auch einen vordefinierten Typ anstelle eines anonymen Typs.

Ein anderer Ansatz beliebte ist, wenn Programmieren mit SOAP-basierte und REST-basierte Dienste führen die Antworten automatisch in .NET Typen deserialisiert werden. Im Fall von SOAP geschieht dies im Allgemeinen in der generierten WSDL-Proxy. Mit Windows Communication Foundation (WCF) und REST kann dies in einigen Arten erreicht werden. Eine Möglichkeit (die nicht wirklich empfohlen, jedoch wird der Vollständigkeit halber erwähnen) ist die Verwendung die symmetrische Natur der WCF auf dem Client eine Vertragsdefinition WCF-Dienst verwenden. Tatsächlich umfasst die WCF-Unterstützung für REST einen Typ mit dem Namen WebChannelFactory, die zum Erstellen eines Client-Kanals gegen eine Dienstdefinition Vertrag verwendet werden können. Diese Art der Programmierung für zwei Gründe Client wird nicht empfohlen. Erstellen des Clients wird zunächst ein sehr manuelle und fehleranfälliger Vorgang. Zweitens erstellt die mithilfe eines stark typisierten Servicevertrags eine enge Kopplung zwischen dem Client und dem Dienst. Enge Kopplung zu vermeiden ist einer der Hauptgründe, die das Web wurde erfolgreich abgeschlossen, und wir möchten, dass Trend fortgesetzt, wenn im Web programmgesteuert mithilfe.

Eine andere Möglichkeit mit XML-Serialisierung besteht darin, verwenden Sie die HttpWebResponse.GetResponseStream-Methode und die XML-Daten manuell in das Objekt deserialisieren. Hierzu können Sie mithilfe der XmlSerializer oder das WCF-DataContract-Serialisierungsprogramm. In den meisten Fällen ist XmlSerializer der vorzuziehen Ansatz, da es mit Weitere Varianten in XML-Dokumenten (z. B. Attribute und nicht gekennzeichnete Elemente), behandelt als das Serialisierungsprogramm DataContract.

Abbildung 3 Verarbeitung einer Rest Antwort mit XDocument

var stream = webResponse.GetResponseStream();
var xr = XmlReader.Create(stream);
var xdoc = XDocument.Load(xr);
var vms = from v in xdoc.Root.Elements("VM")
select new { Name = v.Element("Name").Value};
foreach (var item in vms)
{
Console.WriteLine(item.Name);
}

Das Problem scheint noch an die Tatsache Kreis verfügbar, Rest-Dienste im Allgemeinen Metadaten machen nicht, kann die auf Autogenerate einige oder alle dieser Code verwendet. Obwohl viele in Rest Ferienlager dies als Problem (wieder etwas, Autogenerates gegen Dienst) sehen Definitionen als gefährlich Agent enge Kopplung gesehen werden können, sicherlich sind gibt es Zeiten Wenn eine erschwert, die Akzeptanz der REST nicht über diese Tools ist.

Darin, dass ein interessanter Ansatz durch das WCF REST Starter Kit, ist eine Erweiterung von Microsoft den Rest Programmiermodell in .NET 3.5 bereitzustellen, die eine partielle Autogeneration-Funktion. Wenn Sie das Starter Kit installieren, müssen ein neues Menüelement in Visual Studio 2008 unter dem Menü Bearbeiten Sie wie im Abbildung 4 sehen.


Abbildung 4 einfügen XML als Menüelement Typen

Das Modell Syntax dieses Befehls ist ziemlich einfach. Sie kopieren die XML-Ressource Darstellung in die Zwischenablage (entweder über einige Menschen lesbaren Dokumentation des Dienstes verfügbar macht oder durch eine Anforderung mit einem Tool wie Fiddler). Sobald Sie dies tun, wird eine Reihe von XmlSerializable Typen erstellt dem können Sie den Stream aus der HttpWebResponse in ein Objekt umwandeln. Finden Sie unter Abbildung 5 (der Hauptteil der generierten Typen ist nicht für der Kürze halber dargestellt).

Abbildung 5 Code generierte von Einfügen verwenden XML als Typen

var stream = webResponse.GetResponseStream();
//in a real app you'd want to cache this object
var xs = new XmlSerializer(typeof(VMs));
var vms = xs.Deserialize(stream) as VMs;
foreach (VMsVM vm in vms.VM)
{
Console.WriteLine(vm.Name);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "",
IsNullable = false)]
public partial class VMs
{
private VMsVM[] vmField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("VM")]
public VMsVM[] VM
{
get
{
return this.vmField;
}
set
{
this.vmField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.4918")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class VMsVM
{
//omitted
}

Auch bietet eine sehr gute API über der HttpWebRequest-WebResponse-API, jedoch REST Starter Kit vereinfacht nicht nur die Verwendung von XmlSerializer. Der folgende Code zeigt die einfache GET-Anforderung aus Abbildung 1 umgeschrieben REST Starter Kit HttpClient-API verwenden:

 

string uri = "http://localhost/HyperVServices/VMs.svc/";
var client = new HttpClient();
var message = client.Get(uri);
ProcessOKResponse(message.Content.ReadAsStream());

HttpClient-Klasse erheblich vereinfacht (und stellt explizite welche Verben, die Sie verwenden) die Verwendung der .NET HTTP-API. Wie Sie in den folgenden Code sehen können auch vereinfacht die Verwendung der Funktion einfügen XML als Datentypen generiert:

var vms = XmlSerializerContent.ReadAsXmlSerializable<VMs>(
message.Content);

Obwohl das REST Starter Kit offiziell noch von Microsoft unterstützt nicht ist, es ein sehr wichtiger Punkt veranschaulichen: Die REST-Client Programmieren kann vereinfacht werden und teilweise automatisierte ohne einen REST-Diensts müssen vollständige Metadaten à la eine WSDL-Datei.

Mithilfe von HTTP

Eine Möglichkeit, dass ein Client und einem Dienst HTTP nutzen können ist ordnungsgemäß Statuscodes und Header verwenden. Weitere Informationen über Statuscodes finden Sie unter w3.org/Protocols/rfc2616/rfc2616-sec10.html.

Wie ich der ganzen Welt sprechen über REST überschritten haben, ist einer der Vorteile von REST-Dienste, die ich oft hinweisen darauf, dass GET-Anforderungen zwischengespeichert werden können. Nehmen Sie keine Fehler, die Skalierbarkeit und der Erfolg des Webs ist größtenteils aufgrund der HTTP-Zwischenspeicherung.

Eine Möglichkeit, um HTTP zu nutzen ist die Zwischenspeicherung mit bedingte GET. Bedingte GET ermöglicht dem Client ("User Agent"in HTTP Zweitsprache Lingo) eine GET-Anforderung für eine Ressource zu erstellen, die der Benutzer-Agent bereits eine Kopie verfügt. Wenn die Ressource nicht geändert hat, weist den Server dem Benutzer-Agent, dass die Ressource genau gehalten bereits vom Benutzer-Agent-Version identisch ist. Der Vorteil Effizienz bedingte GET ist eine Reduzierung Bandbreitenauslastung des Netzwerks zwischen dem Server und Benutzer-Agent, schaffen Sie die Bandbreite von Anforderungen für neu erstellte oder geänderte Ressourcen verwendet werden. Außerdem werden die zusätzliche Verarbeitungszeit erforderlich, um die Ressource serialisieren zwar nicht die Verarbeitung zu generieren oder die Ressource abgerufen werden (da Sie eine Kopie der aktuellen Ressource mit den vom Benutzer-Agent mit der bedingten GET gesendeten Informationen vergleichen benötigen) Zeit gespeichert.

Abbildung 6 serverseitige Implementierung von bedingte GET

[OperationContract]
[WebGet(UriTemplate = "/{name}")]
public VMData GetOne(string name)
{
VMManager.Connect();
var v = VMManager.GetVirtualMachine(name);
var newVM = FromVM(v);
string etag = GenerateETag(newVM);
if (CheckETag(etag))
return null;
if (newVM == null)
{
OutgoingWebResponseContext ctx =
WebOperationContext.Current.OutgoingResponse;
ctx.SetStatusAsNotFound();
ctx.SuppressEntityBody = true;
}
SetETag(etag);
return newVM;
}
private bool CheckETag(string currentETag)
{
IncomingWebRequestContext ctx =
WebOperationContext.Current.IncomingRequest;
string incomingEtag =
ctx.Headers[HttpRequestHeader.IfNoneMatch];
if (incomingEtag != null)
{
if (currentETag == incomingEtag)
{
SetNotModified();
return true;
}
}
return false;
}
string GenerateETag(VMData vm)
{
byte[] bytes = Encoding.UTF8.GetBytes(vm.ID +
vm.LastChanged.ToString());
byte[] hash = MD5.Create().ComputeHash(bytes);
string etag = Convert.ToBase64String(hash);
return string.Format("\"{0}\"", etag);
}
void SetETag(string etag)
{
OutgoingWebResponseContext ctx =
WebOperationContext.Current.OutgoingResponse;
ctx.ETag = etag;
}

Wie die meisten anderen "Erweiterte"HTTP-Konzepte nicht WCF bedingte GET automatisch unterstützen, da die Implementierung von bedingte GET dringend Variable zwischen Implementierungen des Dienstes ist. Jedoch wie für erweiterte"andere"HTTP-Konzepte, WCF bietet Tools zum Implementieren, bedingte GET. Es gibt zwei Ansätze dazu: mit die Uhrzeit, zu die Ressource zuletzt geändert wurde oder mit einem eindeutigen Bezeichner als ein ETag bezeichnet.

ETags geworden beliebter Möglichkeit, Bedingung GET zu implementieren. In Abbildung 6 sehen Sie den Code ein ETag-basierten bedingte GET auf der VM-Dienst implementieren. Beachten Sie, dass dies die serverseitige Implementierung; istIch erhalten in Kürze an den Client.

Der grundlegende Ablauf ist für den Server nach ETag im If-None-Match HTTP-Header vom Client gesendet, und versuchen, Sie gegen die aktuelle ETag für die Ressource generiert übereinstimmen. Ich bin in diesem Fall durch Verwendung der eindeutige ID jede VM sowie der letzten Änderung Zeitstempel (in Bytes konvertiert und dann in MD5-Hash, die eine recht häufige Implementierung durchgeführt). Wenn zwei Werte übereinstimmen, sendet der Server wieder 304 nicht geänderten HTTP-Header mit einen leeren Text speichern Serialisierung als auch Bandbreite. Der Client Ruft eine viel schnellere Antwort und weiß, dass es dieselbe Ressource verwenden können, bereits vorhanden ist.


Abbildung 7 A Simple WPF VM-Client

Genommen Sie an, eine Clientanwendung wie dargestellt in Abbildung 7. Anwendung den Namen der jedem virtuellen Computer sowie das Bild der den aktuellen Status der VM zeigt. Stellen Sie sich jetzt vor, dass Sie diese Anwendung entsprechend den aktuellen Zustand der jede VM zu aktualisieren. Um dies zu erreichen, müssten Sie Code schreiben, in einen Zeitgeber und jeden Datensatz aktualisieren, wenn Ihre lokale Datensatz unterscheidet. Und es ist aber wahrscheinlich das würden Sie aktualisieren, alles, was bei jeder Iteration um die Anwendung zu vereinfachen, wäre dies eine Verschwendung von Ressourcen.

Wenn Sie bedingte GET stattdessen auf dem Client verwendet, konnte Sie den Dienst für Änderungen abrufen, durch Senden einer bedingten GET-Anforderung, dem einen If-None-Match HTTP-Header ETag der Ressource angegeben würde. Für die VM-Auflistung kann des Dienstes am zuletzt geänderte VM zum Generieren der ETag und der Client wird aktualisiert, nur wenn eine oder mehrere die VMs haben Ihren Zustand geändert. (Wenn Sie eine Vielzahl von VMs haben, sollten Sie dies für jede VM tun. Aber da wir Datenbindung an die Auflistung in dieser Anwendung sind, bin OK mit dem die gesamte Auflistung aktualisieren).

Nun implementieren diese Logik ist nicht allzu schwierig, aber es ist eines der Features, die den REST Starter Kit für Sie implementiert. In den Codebeispielen enthalten ist eine Datei namens PollingAgent.cs, über einen automatischen bedingte GET-Client die Abstimmung einen REST-Endpunkt auf ein Intervall, die Sie definieren. Wenn die PollingAgent feststellt, dass die Ressource geändert hat, (da der Dienst nicht mehr eine 302 Rückgabe ist), wird einen Rückruf ausgelöst.

So in meine einfache WPF-Anwendung ich einfach das Ergebnis der Rückruf (Dies ist das HttpResponseMessage-Objekt) in Anspruch nehmen und binden Ihre Steuerelemente an den neuen Daten. Abbildung 8 zeigt den Code zum Implementieren dieser Anwendung mit der PollingAgent.

Folgende Hypertext

Vor dem Verlassen des Betreff der Clients, möchten auf einem anderen der wichtigen Einschränkungen von REST berühren werden: Verwenden Hypermedia als das Datenbankmodul des Anwendungszustands (bekannt als HATEOAS).

Ich feststellen, dass HATEOAS leichter verständlich im Kontext des menschlichen Webs. Wenn Sie das menschliche Web verwenden, müssen manchmal wir Lesezeichen zu Sites, die wir wissen wir besuchen möchten. Innerhalb dieser Websites jedoch folgen wir in der Regel Hyperlinks basierend auf unsere Anforderungen des Tages. Möglicherweise besteht eine Textmarke zu www.amazon.com, aber wenn ich etwas kaufen möchten, folgen ich die Hyperlinks auf jeder Seite (Ressource), um meinen Warenkorb ein Element hinzuzufügen. Und ich Befolgen der Hyperlinks (und manchmal Formulare) auf jedem nachfolgenden Seite meiner Bestellung zu verarbeiten. In jeder Phase der Bestellungsabwicklung die Verknüpfungen in der Seite den aktuellen Zustand der Anwendung darstellen (mit anderen Worten, was kann ich, als User-Agent?).

Ein wichtiger Aspekt beim Erstellen von Rest-Clients (Obwohl Teil dieses etablierten auf REST-Diensts Implementierer sowie ist) ist "Lesezeichen" beibehaltenauf ein Minimum. Praktisch bedeutet dies ist, dass Clients sollten als wenig Kenntnisse wie möglich über die URI-Struktur der Ihre Darstellungen verfügen, aber so weit wie möglich Sie wissen sollten, wie "navigieren""Hyperlinks"innerhalb dieser Ressourcen. "Hyperlinks" abgelegtin Anführungszeichen da beliebige Daten in die Ressource ein relativer URI sein kann, für die nächste "Verknüpfung" erstellenfür den Client.

Abbildung 8 bedingte GET die REST-Starterkit abrufen Agent verwenden

public Window1()
{
InitializeComponent();
string uri = "http://localhost/HyperVServices/VMs.svc/";
var client = new HttpClient();
var message = client.Get(uri);
var vms = XmlSerializerContent.ReadAsXmlSerializable<VMs>(
message.Content);
_vmList.DataContext = vms.VM;
var pa = new PollingAgent();
pa.HttpClient = client;
pa.ResourceChanged += new EventHandler<ConditionalGetEventArgs>(
pa_ResourceChanged);
pa.PollingInterval = new TimeSpan(0, 0, 5);
pa.StartPolling(new Uri(uri), message.Headers.ETag, null);
}
void pa_ResourceChanged(object sender, ConditionalGetEventArgs e)
{
var vms = XmlSerializerContent.ReadAsXmlSerializable<VMs>(
e.Response.Content);
_vmList.DataContext = vms.VM;
}

In meinem Beispiel ist jede VM Namen tatsächlich eine Verknüpfung, da ein Client für einen bestimmten VM Daten bitten kann, indem für den Namen als Teil des URIS. Http://localhost/HyperVServices/VMs.svc/MyDesktop (wobei MyDesktop den Wert des Name-Elements in der VM-Element innerhalb der Auflistung ist) ist also der URI für die MyDesktop VM-Ressource.

Genommen Sie an, dass dieser REST Dienst für Bereitstellung und VMs starten ermöglicht. Es wäre sinnvoll, die innerhalb des jede VM Ressource Hyperlinks zu verschiedenen Statusangaben einbetten eine VM konnte zu einem bestimmten Zeitpunkt platziert werden, anstatt darauf der Client eine VM, die noch ordnungsgemäß bereitgestellt wurde noch nicht gestartet.

Mithilfe von HATEOAS hilft bei der den aktuellen Status der Anwendung überprüfen, und es fördert auch mehr lose gekoppelte Clients, (da die Clients nicht wissen, so viel über die URI-Struktur des Dienstes müssen).

Einfacher als Sie Think

Es gibt keine Zweifel, das Erstellen von Rest Clients schwieriger, dies als das Erstellen von WSDL-Metadaten unterstützten SOAP-basierten Clients zu starten ist. Wie ich in meinem letzten Artikel geschrieben habe, "REST ist einfach, aber einfach nicht zwangsläufig einfach. SOAP ist einfach (aufgrund der WSDL), aber einfach nicht immer bedeuten einfache. "gute Programmierpraktiken und Tools wie der REST Starter Kit erstellen Rest Clients sein können einfacher, als Sie denken. Und am Ende Meiner Meinung nach Sie feststellen, dass die Vorteile, die Sie erhalten von der Verwendung der Architekturstil, für temporäre Verzögerungen beim Erstellen von Clients mehr als bilden werden.

Jon Flanders ist unabhängiger Berater, Referent und Trainer für Pluralsight. Er spezialisiert BizTalk Server, Windows Workflow Foundation und Windows Communication Foundation.