Nella mia esperienza, il più pulito (ma non più semplice) soluzione che abbiamo trovato è disponibile in 5 parti:
- Avere un modello di dati autorevole e un back-end che è sempre aggiornata : DAL/Database/Servizi.
- Avere dati specifici della versione tutti comprensibili per il sistema: Modello di dati multipli.
- Assicurarsi che le modifiche tra versione siano identificate e tracciate correttamente e che le modifiche siano reversibili. Le regole devono essere definite in modo esplicito per gestire quello (che potrebbe essere più difficile): Convertitori.
- Fare in modo che il client indichi in modo esplicito quale versione utilizzano: stringhe di query/intestazioni.
- Avere una logica aziendale autorevole che è sempre aggiornata ma sa come spostarsi tra le diverse versioni dei dati - compatibile con le versioni precedenti: Controller.
Il modello di dati che abbiamo è fornitore per esempio.
(1) Il back end (ovvero DAL/database) è in V5. La Business Logic (ovvero i servizi) è anche in V5.
(2) Tuttavia, dobbiamo servire il fornitore del cliente su V1, V2, V3, V4 e client aggiornato su V5 tutti allo stesso tempo. Facciamo V1 a V5 del nostro modello di dati: SupplierV1, SupplierV2 ... (si potrebbe usare namespace, o altri modi per differenziarli)
(3) è necessario definire convertitori e gestirli. Devono gestire sia la compatibilità in avanti che a ritroso tra le versioni del modello di dati. Questo potrebbe essere fatto con un modello di strategia, lambdas, un manager con convertitori DI, ecc.Dovresti gestire V1-> V2-> V3-> V4-> V5 ma anche V5-> V4-> V3-> V2-> V1.
Le regole nei convertitori sono la parte più difficile. A volte è facile: valori predefiniti per i nuovi campi. Altre volte è necessario eseguire alcune logiche di business. A volte è necessario convertire/unire i dati esistenti; devi assicurarti che sia reversibile! Ad esempio, se i valori sono in lettere maiuscole in V1 e lo converti in maiuscolo in V2 ... non potrai tornare a V1, dato che non hai idea di quali caratteri siano maiuscoli e minuscoli. È possibile gestire in due modi:
- Mantenerlo in maiuscolo per V1. Dopotutto, è solo V2 che lo richiede, probabilmente V1 può funzionare con tutti i casi superiori (ovviamente non funzionerebbe con le chiavi).
- Mantieni il vecchio valore in un campo in V2. Ad esempio, se si decide di digitare maiuscole nel campo Stato, è possibile mantenere uno stato originale misto a caso e copiarlo in stato quando si torna a V1.
Come potete vedere, è necessario pensare a quelli difficili ed è spesso non banale.
(4) Quindi, nei controller, è necessario conoscere la versione con cui il client lavora per eseguire la conversione dentro e fuori il controller quando necessario. Per questo è possibile utilizzare stringhe di query, intestazioni (X-API-Version o Accept per esempio, ma attenzione alcune strisce host/proxy alcune di esse), parametro post, ecc.
(5) Infine, quando il il controller riceve un modello di dati, è necessario verificare quale versione il client ha inviato (diciamo V2) e aggiornarlo alla versione più recente per il back-end (V5). Quindi usarlo correttamente, e in seguito, se è necessario inviare i dati, è necessario eseguirne il downgrade alla versione client (V2). Per fare questo, si potrebbe fare su misura vincolante, per richiedere azioni personalizzate, risultati d'azione personalizzati, ecc, ad esempio (si prega di automatizzare questo):
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);
}
Questo è un modo molto grezzo visualizzare l'idea. Questo è qualcosa che abbiamo fatto in uno dei nostri sistemi. Potresti avere Manager che rilevano tipi e versioni e gestire direttamente la conversione, puoi caricare dinamicamente assembly/converters con l'iniezione delle dipendenze, puoi automatizzare la maggior parte della conversione in associazioni personalizzate/azioni di richiesta e così via.
Nota: C'è anche una parte (6) potrebbe essere necessario prendere in considerazione. Per aggiornare effettivamente i dati del client nel database su V5, è possibile farlo durante la migrazione a V5 (migrazione batch di dati), OPPURE, farlo in fase di runtime. Quando si riceve SupplierV1, lo si carica dal database (ancora dati V1), si esegue l'aggiornamento a V5 e si salvano i dati aggiornati, il tutto nel convertitore. Ciò significa che ora hai la migrazione immediata del tuo back-end. Ovviamente, non è così facile come sembra, in quanto è necessario supportare entrambe le versioni nello stesso database, ma potrebbe funzionare bene a seconda del tipo di modifiche o dati che si hanno.
https://github.com/Sebazzz/SDammann.WebApi.Versioning – adt
È un'ottima soluzione per i controller di versioni, ma come ho detto, non sto cercando quello – Levitikon
L'unica cosa che potrei pensare; sarebbe quello di creare un modello autonomo che detiene tali dati. Quindi utilizzare un controller per estrarre tali informazioni. Oppure, per disporre di una tabella database separata in cui utilizzare tali riferimenti. Non sono sicuro che questo aiuti, buona domanda, ci rifletterò anche su questo. – Greg