Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Nach der ersten Bereitstellung und möglicherweise mehrmals während ihrer Lebensdauer müssen Dienste (und die von ihnen verfügbaren Endpunkte) aus verschiedenen Gründen geändert werden, z. B. ändern sich geschäftliche Anforderungen, Anforderungen an die Informationstechnologie oder um andere Probleme zu beheben. Jede Änderung führt eine neue Version des Diensts ein. In diesem Thema wird erläutert, wie Sie die Versionsverwaltung in Windows Communication Foundation (WCF) berücksichtigen.
Vier Kategorien von Dienständerungen
Die Änderungen an Diensten, die erforderlich sein können, können in vier Kategorien unterteilt werden:
Vertragsänderungen: Beispielsweise kann ein Vorgang hinzugefügt oder ein Datenelement in einer Nachricht hinzugefügt oder geändert werden.
Adressänderungen: Beispielsweise wechselt ein Dienst an einen anderen Ort, an dem Endpunkte neue Adressen haben.
Bindungsänderungen: Beispielsweise ändert sich ein Sicherheitsmechanismus oder seine Einstellungen.
Implementierungsänderungen: Wenn sich beispielsweise eine interne Methodenimplementierung ändert.
Einige dieser Änderungen werden als "brechend" bezeichnet, andere als "nicht-brechend". Eine Änderung ist nicht-brechend, wenn alle Nachrichten, die erfolgreich in der vorherigen Version verarbeitet wurden, auch in der neuen Version erfolgreich verarbeitet werden. Jede Änderung, die dieses Kriterium nicht erfüllt, ist eine wichtige Änderung.
Dienstausrichtung und Versionsverwaltung
Einer der Grundsätze der Dienstleistungsorientierung ist, dass Dienste und Kunden autonom (oder unabhängig) sind. Dies bedeutet unter anderem, dass Dienstentwickler nicht davon ausgehen können, dass sie alle Dienstclients steuern oder sogar kennen. Dadurch wird die Option zum Neuerstellen und erneuten Bereitstellen aller Clients beim Ändern der Versionen eines Diensts entfernt. In diesem Thema wird davon ausgegangen, dass der Dienst diesem Tenet entspricht und daher unabhängig von seinen Clients geändert oder "versioniert" werden muss.
In Fällen, in denen eine umfassende Änderung unerwartet ist und nicht vermieden werden kann, kann eine Anwendung dieses Prinzip ignorieren und erfordern, dass Clients neu erstellt und mit einer neuen Version des Diensts erneut bereitgestellt werden.
Vertragsversionsverwaltung
Verträge, die von einem Kunden verwendet werden, müssen nicht mit dem vertrag übereinstimmen, der vom Dienst verwendet wird; sie müssen nur kompatibel sein.
Bei Serviceverträgen bedeutet kompatibilität, dass neue Vorgänge, die vom Dienst verfügbar gemacht werden, hinzugefügt werden können, vorhandene Vorgänge können jedoch nicht entfernt oder semantisch geändert werden.
Bei Datenverträgen bedeutet die Kompatibilität, dass neue Schematypdefinitionen hinzugefügt werden können, vorhandene Schematypdefinitionen können jedoch nicht auf unterbrechende Weise geändert werden. Kritische Änderungen könnten das Entfernen von Datenmitgliedern oder das Ändern des Datentyps auf inkompatible Weise umfassen. Dieses Feature gibt dem Dienst einige Freiheiten, die Version seiner Verträge zu ändern, ohne die Client-Software zu stören. In den nächsten beiden Abschnitten werden Non-Breaking Changes und Breaking Changes erläutert, die an WCF-Daten und -Dienstverträgen vorgenommen werden können.
Datenvertragsversionierung
In diesem Abschnitt wird die Datenversionsverwaltung behandelt, wenn Sie die Klassen DataContractSerializer und DataContractAttribute verwenden.
Strenge Versionsverwaltung
In vielen Szenarien, in denen das Ändern von Versionen ein Problem ist, hat der Dienstentwickler keine Kontrolle über die Clients und kann daher keine Annahmen darüber treffen, wie sie auf Änderungen im Nachrichten-XML oder -Schema reagieren würden. In diesen Fällen müssen Sie sicherstellen, dass die neuen Nachrichten aus zwei Gründen anhand des alten Schemas überprüft werden:
Die alten Kunden wurden mit der Annahme entwickelt, dass sich das Schema nicht ändert. Möglicherweise werden nachrichten, für die sie nie entwickelt wurden, nicht verarbeitet.
Die alten Clients können eine tatsächliche Schemaüberprüfung für das alte Schema durchführen, bevor sie sogar versuchen, die Nachrichten zu verarbeiten.
Der empfohlene Ansatz in solchen Szenarien besteht darin, vorhandene Datenverträge als unveränderlich zu behandeln und neue mit eindeutigen XML-qualifizierten Namen zu erstellen. Der Dienstentwickler würde dann entweder neue Methoden zu einem vorhandenen Dienstvertrag hinzufügen oder einen neuen Dienstvertrag mit Methoden erstellen, die den neuen Datenvertrag verwenden.
Es ist häufig der Fall, dass ein Dienstentwickler einige Geschäftslogik schreiben muss, die in allen Versionen eines Datenvertrags und versionsspezifischem Geschäftscode für jede Version des Datenvertrags ausgeführt werden soll. Im Anhang am Ende dieses Themas wird erläutert, wie Schnittstellen verwendet werden können, um diesen Bedarf zu erfüllen.
Nachlässige Versionsverwaltung
In vielen anderen Szenarien kann der Dienstentwickler davon ausgehen, dass das Hinzufügen eines neuen, optionalen Mitglieds zum Datenvertrag vorhandene Clients nicht unterbrechen wird. Dazu muss der Dienstentwickler untersuchen, ob vorhandene Clients keine Schemaüberprüfung durchführen und unbekannte Datenmmber ignorieren. In diesen Szenarien ist es möglich, Datenvertragsmerkmale zum Hinzufügen neuer Mitglieder ohne Unterbrechung zu nutzen. Der Dienstentwickler kann diese Annahme mit Vertrauen machen, wenn die Datenvertragsfeatures für die Versionsverwaltung bereits für die erste Version des Diensts verwendet wurden.
WCF, ASP.NET Webdienste und viele andere Webservice-Technologien unterstützen laxe Versionsverwaltung: d. h., sie lösen keine Ausnahmen für neue unbekannte Datenmember in empfangenen Daten aus.
Es ist leicht fälschlicherweise anzunehmen, dass das Hinzufügen eines neuen Mitglieds bestehende Clients nicht beeinträchtigen wird. Wenn Sie nicht sicher sind, dass alle Clients die lockere Versionierung verarbeiten können, wird empfohlen, die Anwendung strenger Versionsrichtlinien in Betracht zu ziehen und Datenverträge als unveränderlich zu betrachten.
Ausführliche Richtlinien für laxe und strenge Versionsverwaltung von Datenverträgen finden Sie unter Best Practices: Data Contract Versionsing.
Unterscheidung zwischen Datenvertrags- und .NET-Typen
Eine .NET-Klasse oder -Struktur kann als Datenvertrag projiziert werden, indem das DataContractAttribute Attribut auf die Klasse angewendet wird. Der .NET-Typ und die zugehörigen Datenkontraktprojektionen sind zwei unterschiedliche Aspekte. Es ist möglich, mehrere .NET-Typen mit derselben Datenvertragsprojektion zu haben. Diese Unterscheidung ist besonders nützlich, um es Ihnen zu ermöglichen, den .NET-Typ zu ändern, während der Vertrag für projizierte Daten beibehalten wird, wodurch die Kompatibilität mit vorhandenen Clients auch im strengen Sinne des Wortes beibehalten wird. Es gibt zwei Dinge, die Sie immer tun sollten, um diesen Unterschied zwischen .NET-Typ und Datenvertrag beizubehalten:
Geben Sie einen Name und einen Namespace an. Sie sollten immer den Namen und den Namespace Ihres Datenvertrags angeben, um zu verhindern, dass der Name und der Namespace Ihres .NET-Typs im Vertrag verfügbar gemacht werden. Auf diese Weise bleibt Ihr Datenvertrag unverändert, wenn Sie später den .NET-Namespace oder den Typnamen ändern möchten.
Geben Sie Name an. Sie sollten immer den Namen Ihrer Datenmitglieder angeben, um zu verhindern, dass Ihr .NET-Mitgliedsname im Vertrag verfügbar gemacht wird. Wenn Sie später beschließen, den .NET-Namen des Mitglieds zu ändern, bleibt Ihr Datenvertrag gleich.
Ändern oder Entfernen von Mitgliedern
Wenn Sie den Namen oder Datentyp eines Members ändern oder Datenmember entfernen, ist dies eine unterbrechende Änderung, auch wenn die weniger strenge Versionsverwaltung zulässig ist. Wenn dies erforderlich ist, erstellen Sie einen neuen Datenvertrag.
Wenn die Dienstkompatibilität von hoher Bedeutung ist, können Sie erwägen, nicht verwendete Datenmember in Ihrem Code zu ignorieren und sie an Ort und Stelle zu lassen. Falls Sie einen Datenmember in mehrere Member aufteilen, sollten Sie erwägen, den vorhandenen Member als eine Eigenschaft unverändert zu lassen, mit der die erforderliche Aufteilung und erneute Aggregation für Clients auf niedrigeren Ebenen (Clients ohne Upgrade auf die neueste Version) durchgeführt werden.
Ähnlich verhält es sich mit Änderungen des Namens oder Namespace eines Datenvertrags, bei denen es sich ebenfalls um unterbrechende Änderungen handelt.
Round-Trips von unbekannten Daten
In einigen Szenarien muss ein "Round-Trip" von unbekannten Daten stattfinden, die aus Membern stammen, die einer neuen Version hinzugefügt wurden. Beispielsweise sendet ein "versionNew"-Dienst Daten mit einigen neu hinzugefügten Mitgliedern an einen "versionOld"-Client. Der Client ignoriert die neu hinzugefügten Mitglieder bei der Verarbeitung der Nachricht, sendet jedoch denselben Daten, einschließlich der neu hinzugefügten Mitglieder, zurück an den VersionNew-Dienst. Das typische Szenario hierfür sind Datenaktualisierungen, bei denen Daten aus dem Dienst abgerufen, geändert und zurückgegeben werden.
Um Roundtripping für einen bestimmten Typ zu aktivieren, muss der Typ die IExtensibleDataObject Schnittstelle implementieren. Die Schnittstelle enthält eine Eigenschaft, ExtensionData die den ExtensionDataObject Typ zurückgibt. Die Eigenschaft wird verwendet, um beliebige Daten aus zukünftigen Versionen des Datenvertrags zu speichern, die der aktuellen Version unbekannt sind. Diese Daten sind für den Client undurchsichtig, aber wenn die Instanz serialisiert wird, wird der Inhalt der ExtensionData-Eigenschaft zusammen mit den Daten der restlichen Datenvertragsmitglieder geschrieben.
Es wird empfohlen, dass alle Typen diese Schnittstelle implementieren, um neue und unbekannte zukünftige Member aufzunehmen.
Datenvertragsbibliotheken
Es können Bibliotheken mit Datenverträgen vorhanden sein, bei denen ein Vertrag in einem zentralen Repository veröffentlicht wird, und Dienst- und Typimplementierer Datenverträge aus diesem Repository implementieren und verfügbar machen. In diesem Fall haben Sie beim Veröffentlichen eines Datenvertrags im Repository keine Kontrolle darüber, wer Typen erstellt, die ihn implementieren. Daher können Sie den Vertrag nach der Veröffentlichung nicht mehr ändern, wodurch er effektiv unveränderlich dargestellt wird.
Verwenden des XmlSerializer
Die gleichen Versionsverwaltungsprinzipien gelten bei Verwendung der XmlSerializer Klasse. Wenn eine strenge Versionsverwaltung erforderlich ist, behandeln Sie Datenverträge als unveränderlich, und erstellen Sie neue Datenverträge mit eindeutigen, qualifizierten Namen für die neuen Versionen. Wenn Sie sicher sind, dass eine lockere Versionsverwaltung verwendet werden kann, können Sie in neuen Versionen neue serialisierbare Member hinzufügen, aber vorhandene Member nicht ändern oder entfernen.
Hinweis
Das XmlSerializer nutzt die Attribute XmlAnyElementAttribute und XmlAnyAttributeAttribute, um das Roundtripping unbekannter Daten zu unterstützen.
Versionsverwaltung für Nachrichtenverträge
Die Richtlinien für die Versionsverwaltung von Nachrichtenverträgen ähneln den Versionsverwaltungsdatenverträgen. Wenn eine strenge Versionsverwaltung erforderlich ist, sollten Sie ihren Nachrichtentext nicht ändern, sondern stattdessen einen neuen Nachrichtenvertrag mit einem eindeutigen qualifizierten Namen erstellen. Wenn Sie wissen, dass Sie eine laxe Versionsverwaltung verwenden können, können Sie neue Nachrichtentextteile hinzufügen, vorhandene jedoch nicht ändern oder entfernen. Diese Richtlinie gilt sowohl für reine als auch für eingeschlossene Nachrichtenverträge.
Nachrichtenkopfzeilen können immer hinzugefügt werden, auch wenn strenge Versionsverwaltung verwendet wird. Die MustUnderstand-Kennzeichnung kann sich auf die Versionsverwaltung auswirken. Im Allgemeinen wird das Versionsverwaltungsmodell für Header in WCF wie in der SOAP-Spezifikation beschrieben.
Dienstvertragsversionsverwaltung
Ähnlich wie bei der Datenvertragsversionsverwaltung umfasst die Versionsverwaltung des Dienstvertrags auch das Hinzufügen, Ändern und Entfernen von Vorgängen.
Angeben von Name, Namespace und Aktion
Standardmäßig ist der Name eines Dienstvertrags der Name der Schnittstelle. Der Standardnamespace ist http://tempuri.org, und die Aktion jeder Operation ist http://tempuri.org/contractname/methodname. Es wird empfohlen, explizit einen Namen und einen Namespace für den Dienstvertrag sowie eine Aktion für jeden Vorgang anzugeben, um die Verwendung von http://tempuri.org zu vermeiden und die Schnittstellen- und Methodennamen im Vertrag des Dienstes nicht offenzulegen.
Hinzufügen von Parametern und Vorgängen
Das Hinzufügen von Dienstvorgängen, die vom Dienst verfügbar gemacht werden, ist eine nicht-unterbrechende Änderung, da vorhandene Clients sich keine Gedanken über diese neuen Vorgänge machen müssen.
Hinweis
Beim Hinzufügen von Vorgängen zu einem Duplexrückrufvertrag handelt es sich um eine unterbrechende Änderung.
Ändern des Vorgangsparameters oder Rückgabetypen
Das Ändern von Parameter- oder Rückgabetypen ist in der Regel eine bahnbrechende Änderung, es sei denn, der neue Typ implementiert denselben Datenvertrag, der vom alten Typ implementiert wird. Um eine solche Änderung vorzunehmen, fügen Sie dem Servicevertrag einen neuen Vorgang hinzu, oder definieren Sie einen neuen Servicevertrag.
Entfernen von Vorgängen
Beim Entfernen von Vorgängen handelt es sich ebenfalls um eine unterbrechende Änderung. Um eine solche Änderung vorzunehmen, definieren Sie einen neuen Dienstvertrag, und machen Sie ihn auf einem neuen Endpunkt verfügbar.
Fehlerverträge
Mit dem FaultContractAttribute Attribut kann ein Dienstvertragsentwickler Informationen zu Fehlern angeben, die aus den Vorgängen des Vertrags zurückgegeben werden können.
Die Liste der fehler, die im Vertrag eines Dienstes beschrieben sind, gilt nicht als erschöpfend. Zu jedem Zeitpunkt kann ein Vorgang Fehler zurückgeben, die in seinem Vertrag nicht beschrieben sind. Daher gilt die Änderung der im Vertrag beschriebenen Fehlermenge nicht als Bruch. Fügen Sie zum Beispiel mithilfe von FaultContractAttribute dem Vertrag einen neuen Fehler hinzu oder entfernen Sie einen vorhandenen Fehler aus dem Vertrag.
Dienstvertragsbibliotheken
Organisationen verfügen möglicherweise über Bibliotheken von Verträgen, bei denen ein Vertrag in einem zentralen Repository veröffentlicht wird, und Dienstimplementierer implementieren Verträge aus diesem Repository. Wenn Sie in diesem Fall einen Dienstvertrag für das Repository veröffentlichen, haben Sie keine Kontrolle darüber, wer Dienste erstellt, die ihn implementieren. Daher können Sie den Dienstvertrag nicht mehr ändern, nachdem er veröffentlicht wurde, wodurch er effektiv unveränderlich dargestellt wird. WCF unterstützt die Vertragsvererbung, die zum Erstellen eines neuen Vertrags verwendet werden kann, der vorhandene Verträge erweitert. Um dieses Feature zu verwenden, definieren Sie eine neue Dienstvertragsschnittstelle, die von der alten Dienstvertragsschnittstelle erbt, und fügen Sie der neuen Schnittstelle Methoden hinzu. Anschließend ändern Sie den Dienst, der den alten Vertrag implementiert, um den neuen Vertrag zu implementieren und die Endpunktdefinition "versionOld" so zu ändern, dass er den neuen Vertrag verwendet. Für "versionOld"-Clients erscheint der Endpunkt weiterhin als "versionOld"-Vertrag; für "versionNew"-Clients erscheint der Endpunkt als "versionNew"-Vertrag.
Versionsverwaltung von Adressen und Bindungen
Bei Änderungen an der Endpunktadresse und -bindung handelt es sich um unterbrechende Änderungen, solange die Clients die neue Endpunktadresse oder -bindung nicht dynamisch erkennen können. Ein Mechanismus für die Implementierung dieser Funktion ist die Verwendung einer Universal Discovery Description and Integration (UDDI)-Registrierung und des UDDI-Aufrufmusters, bei dem ein Client versucht, mit einem Endpunkt zu kommunizieren, und bei Fehlern eine bekannte UDDI-Registrierung für die aktuellen Endpunktmetadaten abfragt. Der Client verwendet dann die Adresse und Bindung aus diesen Metadaten, um mit dem Endpunkt zu kommunizieren. Wenn diese Kommunikation erfolgreich ist, speichert der Client die Adress- und Bindungsinformationen für zukünftige Verwendung.
Routingdienst und Versionsverwaltung
Wenn die Änderungen, die an einem Dienst vorgenommen wurden, wesentliche Änderungen darstellen, die Kompatibilitätsbrüche verursachen und zwei oder mehr verschiedene Versionen eines Dienstes gleichzeitig betrieben werden müssen, können Sie den WCF-Routingdienst verwenden, um Nachrichten an die jeweilige Dienstinstanz weiterzuleiten. Der WCF-Routingdienst verwendet inhaltsbasiertes Routing, d. h., er verwendet Informationen innerhalb der Nachricht, um zu bestimmen, wo die Nachricht weitergeleitet werden soll. Weitere Informationen zum WCF-Routingdienst finden Sie unter Routingdienst. Ein Beispiel für die Verwendung des WCF-Routingdiensts für die Dienstversionsverwaltung finden Sie unter How To: Service Versioning.
Anhang
Die allgemeinen Richtlinien für die Datenvertragsversionsverwaltung, wenn eine strenge Versionsverwaltung erforderlich ist, besteht darin, Datenverträge als unveränderlich zu behandeln und neue zu erstellen, wenn Änderungen erforderlich sind. Für jeden neuen Datenvertrag muss eine neue Klasse erstellt werden. Daher ist ein Mechanismus erforderlich, um zu vermeiden, dass vorhandener Code in Bezug auf die alte Datenvertragsklasse geschrieben und in Bezug auf die neue Datenvertragsklasse neu geschrieben wurde.
Ein solcher Mechanismus besteht darin, Schnittstellen zu verwenden, um die Member der einzelnen Datenkontrakte zu definieren und internen Implementierungscode in Bezug auf die Schnittstellen und nicht die Datenvertragsklassen zu schreiben, die die Schnittstellen implementieren. Der folgende Code für Version 1 eines Diensts zeigt eine IPurchaseOrderV1 Schnittstelle und eine PurchaseOrderV1:
public interface IPurchaseOrderV1
{
string OrderId { get; set; }
string CustomerId { get; set; }
}
[DataContract(
Name = "PurchaseOrder",
Namespace = "http://examples.microsoft.com/WCF/2005/10/PurchaseOrder")]
public class PurchaseOrderV1 : IPurchaseOrderV1
{
[DataMember(...)]
public string OrderId {...}
[DataMember(...)]
public string CustomerId {...}
}
Während die Vorgänge des Dienstleistungsvertrags in Hinblick auf PurchaseOrderV1 formuliert würden, würde die tatsächliche Geschäftslogik in Hinblick auf IPurchaseOrderV1 stehen. Dann wäre in Version 2 eine neue IPurchaseOrderV2 Schnittstelle und eine neue PurchaseOrderV2 Klasse vorhanden, wie im folgenden Code gezeigt:
public interface IPurchaseOrderV2
{
DateTime OrderDate { get; set; }
}
[DataContract(
Name = "PurchaseOrder",
Namespace = "http://examples.microsoft.com/WCF/2006/02/PurchaseOrder")]
public class PurchaseOrderV2 : IPurchaseOrderV1, IPurchaseOrderV2
{
[DataMember(...)]
public string OrderId {...}
[DataMember(...)]
public string CustomerId {...}
[DataMember(...)]
public DateTime OrderDate { ... }
}
Der Dienstvertrag würde aktualisiert werden, um neue Vorgänge für PurchaseOrderV2 zu berücksichtigen. Bestehende Geschäftslogik, die im Rahmen von IPurchaseOrderV1 geschrieben wurde, würde weiterhin für PurchaseOrderV2 funktionieren, und neue Geschäftslogik, die die OrderDate-Eigenschaft benötigt, würde im Rahmen von IPurchaseOrderV2 geschrieben.