2013-03-25 9 views
9

Bevor Sie dies als Duplikat betrachten, nehmen Sie sich bitte eine Sekunde Zeit. Wenn ich Web Api über die Versionierung recherchiere, ist alles um versionierte Controller und Best Practices zur Angabe der Version in URL vs. headern besorgt.Web Api Response Versionierungslösung?

Was ich versuche, herauszufinden, was der beste Weg, die Ausgangsantwort auf die Version ist, damit ich nicht die Version 1 Kunden brechen, wenn ich mit 2. Version kommen

Lets sagen, ich habe ein ständig wechselndes DAL für eine Website-Suite, die eine Website und andere Dienste bereitstellt. Ich arbeite an einem neuen Web-API-Projekt, das Antworten enthalten sollte, die versionierten Schemas entsprechen.

Meine Frage ist, was sind bewährte Lösungen/Best Practices für die Implementierung von Versionierung in Web Api-Projekte hinter versionierten Controllern und vor un-versionierten DALs?

Ich habe eine Lösung entwickelt, die eine zusätzliche Schicht versionierter Repositorys und eine zusätzliche Schicht versionierter Modelle enthält, sodass die versionierten Controller versionierte Repositorys verwenden, die versionierte Modelle verwenden. Und ich habe Automapper eingerichtet, um zwischen den nicht versionierten Domänenmodellen (von der DAL) zu den versionierten Modellen zu mappen. Aber der Fehler dieses Setup ist, ich muss alle Karten für jede neue Version aktualisieren; ein exponentiell wachsendes Problem.

Es muss einen besseren Weg geben. Vielen Dank!

+0

https://github.com/Sebazzz/Sdammann.WebApi.Versioning – adt

+0

Es ist eine großartige Lösung für die Versionsverwaltung Controller, aber wie ich schon sagte, ich bin nicht auf der Suche nach diesem – Levitikon

+0

Das einzige, was ich mir vorstellen konnte; wäre, ein eigenständiges Modell zu erstellen, das diese Daten enthält. Verwenden Sie dann einen Controller, um diese Informationen abzurufen. Oder Sie haben eine separate Datenbanktabelle, in der Sie diese Referenzen verwenden. Nicht sicher, dass das hilft, gute Frage, ich werde darüber nachdenken. – Greg

Antwort

1

In meiner Erfahrung ist die sauberste (aber nicht am einfachsten) Lösung, die wir kommt in 5 Teilen gefunden:

  1. ein maßgebliches Datenmodell und ein hinteres Ende, das immer auf dem neuesten Stand : DAL/Datenbank/Dienste.
  2. Mit versionsspezifischen Daten alle für das System verständlich: Multiple Data Model.
  3. Sicherstellen, dass Änderungen zwischen Versionen identifiziert und ordnungsgemäß nachverfolgt werden und dass Änderungen reversibel sind. Regeln müssen explizit definiert werden, um das zu handhaben (das könnte schwieriger sein): Konverter.
  4. Lassen Sie den Client explizit sagen, welche Version sie verwenden: Query Strings/Header.
  5. Verfügt über eine autoritative Geschäftslogik, die immer auf dem neuesten Stand ist, aber zwischen verschiedenen Datenversionen wechseln kann - abwärtskompatibel: Controller.

Das Datenmodell, das wir haben, ist Lieferant zum Beispiel.

(1) Das Backend (d. H. DAL/Datenbank) ist auf V5. Die Geschäftslogik (d. H. Dienste) befindet sich ebenfalls bei V5.

(2) Allerdings müssen wir Client Supplier auf V1, V2, V3, V4 und aktuellen Client auf V5 alle zur gleichen Zeit bedienen. Lassen Sie uns V1 zu V5 unseres Datenmodells machen: SupplierV1, SupplierV2 ... (Sie könnten Namespace oder andere Möglichkeiten verwenden, um sie zu unterscheiden)

(3) Sie müssen Konverter definieren und verwalten. Sie müssen sowohl Vorwärts- als auch Rückwärtskompatibilität zwischen Datenmodellversionen verarbeiten. Dies könnte mit einem Strategie-Pattern, Lambdas, einem Manager mit DI-Konvertern usw. erfolgen.Sie müßten mit V1-> V2-> V3-> V4-> V5 aber auch mit V5-> V4-> V3-> V2-> V1 umgehen.

Regeln in den Konvertern sind der schwierigste Teil. Manchmal ist es einfach - Standardwerte für neue Felder. Zu anderen Zeiten müssen Sie eine Geschäftslogik ausführen. Manchmal müssen Sie vorhandene Daten konvertieren/zusammenführen; Sie müssen sicherstellen, dass es reversibel ist! Wenn zum Beispiel die Werte in V1 gemischt sind und Sie sie in V2 in Großbuchstaben umwandeln, können Sie sie nicht auf V1 zurückversetzen, da Sie nicht wissen, welche Zeichen Groß- und Kleinbuchstaben sind. Sie können diese zwei Möglichkeiten behandeln:

  • Halten Sie es in Großbuchstaben für V1. Afterall, es ist nur V2, die es erfordert, V1 kann wahrscheinlich mit allen großen Fällen arbeiten (offensichtlich würde nicht auf Tasten arbeiten).
  • Behalten Sie den alten Wert in einem Feld in V2. Wenn Sie beispielsweise beschlossen haben, das Feld "State" in Großbuchstaben zu setzen, können Sie einen OriginalState beibehalten, der Groß- und Kleinschreibung enthält, und ihn in State kopieren, wenn Sie zu V1 zurückkehren.

Wie Sie sehen können, müssen Sie über diejenigen hart nachdenken und es ist oft nicht trivial.

(4) Dann müssen Sie in Controllern wissen, mit welcher Version der Client arbeitet, um bei Bedarf die Konvertierung in und aus dem Controller auszuführen. Dazu könnten Sie Abfragezeichenfolgen, Header (X-API-Version oder Accept zum Beispiel, aber Vorsicht einige Host/Proxy-Strips einige von ihnen), Post-Parameter, etc.

(5) Schließlich, wenn die Controller empfängt ein Datenmodell, Sie müssen überprüfen, welche Version der Client gesendet hat (sagen wir V2) und auf die neueste Version für das Back-End (V5) aktualisieren. Verwenden Sie es anschließend ordnungsgemäß. Wenn Sie anschließend Daten zurücksenden müssen, müssen Sie sie auf die Clientversion (V2) herabstufen. Um dies zu tun, könnten Sie tun benutzerdefinierte Bindung, individuelle Anfrage Aktionen, benutzerdefinierte Aktion Ergebnisse, etc. Zum Beispiel (bitte nicht automatisieren, dass):

public IHttpActionResult DoSomethingWithSupplier(JToken supplier) // Receiving Json Supplier 
{ 
    // TODO: Get the client version type, for example in the X-API-Version header/query strings 
    // (beware, some proxy/hosts strips some headers) 
    // Type clientType = ... 

    var clientSupplier = JsonConvert.DeserializeObject(supplier.ToString(), clientType); 

    // You should probably detect latest version automatically (instead of typeof) 
    var latestSupplier = VersionManager.Upgrade(clientSupplier, clientType, typeof(SupplierV5)); 

    outputSupplier = DoSomething(latestSupplier); 

    // You should probably detect latest version automatically (instead of typeof) 
    var clientOutputSupplier = VersionManager.Downgrade(outputSupplier, typeof(SupplierV5), clientType); 

    return Ok(clientOutputSupplier); 
} 

Dies ist eine sehr grobe Art und Weisen Ihnen die Idee zu zeigen. Das haben wir in einem unserer Systeme gemacht. Sie könnten Manager haben, die Typen und Versionen erkennen und die Konvertierung selbst durchführen, Sie könnten Assembly/Converter dynamisch mit Dependency-Injection laden, Sie könnten den Großteil der Conversion in benutzerdefinierten Bindungen/Request-Aktionen automatisieren und so weiter.

Hinweis: Es gibt auch einen Teil (6) müssen Sie möglicherweise prüfen. Um die Client-Daten in Ihrer Datenbank tatsächlich auf V5 zu aktualisieren, können Sie dies bei der Migration zu V5 (Stapelmigration von Daten) oder zur Laufzeit tun. Wenn Sie SupplierV1 erhalten, laden Sie dieses aus Ihrer Datenbank (noch V1-Daten), führen das Upgrade auf V5 durch und speichern die aktualisierten Daten im Converter. Das bedeutet, dass Sie Ihr Backend jetzt direkt migrieren können. Offensichtlich ist es nicht so einfach wie es klingt, da Sie beide Versionen in derselben Datenbank unterstützen müssen, aber je nach der Art der Änderungen oder Daten, die Sie haben, gut für Sie arbeiten können.