Udostępnij za pośrednictwem


Najlepsze rozwiązania: przechowywanie wersji kontraktów danych

W tym temacie wymieniono najlepsze rozwiązania dotyczące tworzenia kontraktów danych, które mogą łatwo ewoluować w miarę upływu czasu. Aby uzyskać więcej informacji na temat kontraktów danych, zobacz tematy w temacie Using Data Contracts (Korzystanie z kontraktów danych).

Uwaga dotycząca sprawdzania poprawności schematu

Omawiając przechowywanie wersji kontraktu danych, należy pamiętać, że schemat kontraktu danych wyeksportowany przez program Windows Communication Foundation (WCF) nie ma żadnej obsługi wersji, poza faktem, że elementy są domyślnie oznaczone jako opcjonalne.

Oznacza to, że nawet najbardziej typowy scenariusz przechowywania wersji, taki jak dodanie nowego elementu członkowskiego danych, nie może być zaimplementowany w sposób bezproblemowy w odniesieniu do danego schematu. Nowsze wersje kontraktu danych (na przykład z nowym elementem członkowskim danych) nie są weryfikowane przy użyciu starego schematu.

Istnieje jednak wiele scenariuszy, w których nie jest wymagana ścisła zgodność schematu. Wiele platform usług sieci Web, w tym usług sieci Web WCF i XML utworzonych przy użyciu ASP.NET, domyślnie nie przeprowadza weryfikacji schematu i dlatego toleruje dodatkowe elementy, które nie są opisane przez schemat. Podczas pracy z takimi platformami wiele scenariuszy przechowywania wersji jest łatwiejszych do zaimplementowania.

W związku z tym istnieją dwa zestawy wytycznych dotyczących przechowywania wersji kontraktów danych: jeden zestaw dla scenariuszy, w których ważna jest ścisła ważność schematu, a drugi zestaw dla scenariuszy, gdy nie jest.

Przechowywanie wersji, gdy wymagana jest weryfikacja schematu

Jeśli wymagana jest ścisła ważność schematu we wszystkich kierunkach (nowe i stare i stare), kontrakty danych powinny być uznawane za niezmienne. Jeśli wymagane jest przechowywanie wersji, należy utworzyć nowy kontrakt danych z inną nazwą lub przestrzenią nazw, a kontrakt usługi używający typu danych powinien być odpowiednio wersjonowany.

Na przykład kontrakt usługi przetwarzania zamówień zakupu o nazwie PoProcessing z operacją przyjmuje parametr zgodny z PostPurchaseOrder kontraktem PurchaseOrder danych. PurchaseOrder Jeśli kontrakt musi ulec zmianie, musisz utworzyć nowy kontrakt danych, PurchaseOrder2czyli , który zawiera zmiany. Następnie należy obsługiwać przechowywanie wersji na poziomie kontraktu usługi. Na przykład przez utworzenie PostPurchaseOrder2 operacji, która przyjmuje PurchaseOrder2 parametr, lub przez utworzenie PoProcessing2 kontraktu usługi, w którym PostPurchaseOrder operacja przyjmuje PurchaseOrder2 kontrakt danych.

Należy pamiętać, że zmiany kontraktów danych, do których odwołuje się inne kontrakty danych, również rozszerzają się na warstwę modelu usług. Na przykład w poprzednim scenariuszu PurchaseOrder kontrakt danych nie musi się zmieniać. Zawiera jednak element członkowski danych kontraktu Customer danych, który z kolei zawierał element członkowski kontraktu Address danych, który musi zostać zmieniony. W takim przypadku należy utworzyć Address2 kontrakt danych z wymaganymi zmianami, Customer2 kontraktem danych zawierającym Address2 element członkowski danych i kontraktem danych zawierającym PurchaseOrder2 element członkowski Customer2 danych. Podobnie jak w poprzednim przypadku, umowa serwisowa musiałaby być również wersjonowana.

Chociaż w tych przykładach nazwy są zmieniane (dołączając znak "2"), zaleca się zmianę przestrzeni nazw zamiast nazw przez dołączenie nowych przestrzeni nazw z numerem wersji lub datą. Na przykład http://schemas.contoso.com/2005/05/21/PurchaseOrder kontrakt danych zmieni się na http://schemas.contoso.com/2005/10/14/PurchaseOrder kontrakt danych.

Aby uzyskać więcej informacji, zobacz Najlepsze rozwiązania: przechowywanie wersji usługi.

Czasami należy zagwarantować ścisłą zgodność schematu dla komunikatów wysyłanych przez aplikację, ale nie można polegać na przychodzących komunikatach, aby być ściśle zgodne ze schematem. W takim przypadku istnieje niebezpieczeństwo, że komunikat przychodzący może zawierać nadmiarowe dane. Nadmiarowe wartości są przechowywane i zwracane przez usługę WCF, co powoduje wysłanie nieprawidłowych komunikatów schematu. Aby uniknąć tego problemu, funkcja zaokrąglania powinna być wyłączona. Istnieją dwa sposoby, aby to zrobić.

Aby uzyskać więcej informacji na temat zaokrąglania, zobacz Kontrakty danych zgodne z przekazywaniem.

Przechowywanie wersji, gdy weryfikacja schematu nie jest wymagana

Ścisła zgodność schematu jest rzadko wymagana. Wiele platform toleruje dodatkowe elementy, które nie są opisane przez schemat. O ile jest to tolerowane, można użyć pełnego zestawu funkcji opisanych w artykule Przechowywanie wersji kontraktów danych i kontrakty danych zgodne z przekazywaniem. Zalecane są następujące wskazówki.

Niektóre z wytycznych muszą być dokładnie zgodne, aby wysyłać nowe wersje typu, w których oczekuje się starszej wersji lub wysłać stary, w którym oczekuje się nowego. Inne wytyczne nie są ściśle wymagane, ale są wymienione tutaj, ponieważ mogą one mieć wpływ na przyszłość przechowywania wersji schematu.

  1. Nie należy próbować wersjonować kontraktów danych według dziedziczenia typu. Aby utworzyć nowsze wersje, zmień kontrakt danych na istniejący typ lub utwórz nowy niepowiązany typ.

  2. Korzystanie z dziedziczenia razem z kontraktami danych jest dozwolone, pod warunkiem, że dziedziczenie nie jest używane jako mechanizm przechowywania wersji i że są przestrzegane pewne reguły. Jeśli typ pochodzi z określonego typu podstawowego, nie należy go uzyskiwać z innego typu podstawowego w przyszłej wersji (chyba że ma ten sam kontrakt danych). Istnieje jeden wyjątek: można wstawić typ do hierarchii między typem kontraktu danych a jego typem podstawowym, ale tylko wtedy, gdy nie zawiera elementów członkowskich danych o takich samych nazwach jak inne elementy członkowskie w dowolnej możliwej wersji innych typów w hierarchii. Ogólnie rzecz biorąc, używanie elementów członkowskich danych o tych samych nazwach na różnych poziomach tej samej hierarchii dziedziczenia może prowadzić do poważnych problemów z przechowywaniem wersji i należy unikać.

  3. Począwszy od pierwszej wersji kontraktu danych, zawsze zaimplementuj IExtensibleDataObject , aby włączyć round-tripping. Aby uzyskać więcej informacji, zobacz Kontrakty danych zgodne z przekazywaniem. Jeśli wydano co najmniej jedną wersję typu bez implementowania tego interfejsu, zaimplementuj go w następnej wersji typu.

  4. W nowszych wersjach nie zmieniaj nazwy kontraktu danych ani przestrzeni nazw. W przypadku zmiany nazwy lub przestrzeni nazw typu bazowego kontraktu danych należy zachować nazwę kontraktu danych i przestrzeń nazw przy użyciu odpowiednich mechanizmów, takich jak Name właściwość DataContractAttribute. Aby uzyskać więcej informacji na temat nazewnictwa, zobacz Nazwy kontraktów danych.

  5. W nowszych wersjach nie zmieniaj nazw żadnych elementów członkowskich danych. W przypadku zmiany nazwy pola, właściwości lub zdarzenia bazowego elementu członkowskiego danych użyj Name właściwości DataMemberAttribute , aby zachować istniejącą nazwę elementu członkowskiego danych.

  6. W nowszych wersjach nie zmieniaj typu żadnego pola, właściwości lub zdarzenia bazowego elementu członkowskiego danych, tak aby wynikowa umowa danych dla tego elementu członkowskiego danych uległa zmianie. Należy pamiętać, że typy interfejsów są równoważne Object do celów określania oczekiwanego kontraktu danych.

  7. W nowszych wersjach nie zmieniaj kolejności istniejących elementów członkowskich danych, dostosowując Order właściwość atrybutu DataMemberAttribute .

  8. W nowszych wersjach można dodać nowe elementy członkowskie danych. Powinny one zawsze przestrzegać następujących reguł:

    1. Właściwość IsRequired powinna zawsze być pozostawiona na wartości domyślnej false.

    2. Jeśli wartość null domyślna lub zero dla elementu członkowskiego jest niedopuszczalna, należy podać metodę wywołania zwrotnego przy użyciu OnDeserializingAttribute elementu , aby zapewnić rozsądną wartość domyślną w przypadku, gdy element członkowski nie jest obecny w strumieniu przychodzącym. Aby uzyskać więcej informacji na temat wywołania zwrotnego, zobacz Wywołania zwrotne serializacji odporne na wersje.

    3. Właściwość powinna służyć do upewnienia DataMemberAttribute.Order się, że wszystkie nowo dodane elementy członkowskie danych są wyświetlane po istniejących elementach członkowskich danych. Zalecanym sposobem wykonania tej czynności jest następująca: Żaden z elementów członkowskich danych w pierwszej wersji kontraktu danych nie powinien mieć zestawu Order właściwości. Wszyscy członkowie danych dodani w wersji 2 kontraktu danych powinni mieć właściwość Order ustawioną na 2. Wszyscy członkowie danych dodani w wersji 3 kontraktu danych powinni mieć ustawioną Order wartość 3 itd. Dopuszczalne jest posiadanie więcej niż jednego elementu członkowskiego danych ustawionego na tę samą Order liczbę.

  9. Nie usuwaj elementów członkowskich danych w nowszych wersjach, nawet jeśli IsRequired właściwość została pozostawiona we właściwości domyślnej w poprzednich false wersjach.

  10. Nie zmieniaj IsRequired właściwości istniejących elementów członkowskich danych z wersji na wersję.

  11. W przypadku wymaganych elementów członkowskich danych (gdzie IsRequired to true), nie należy zmieniać EmitDefaultValue właściwości z wersji na wersję.

  12. Nie należy próbować tworzyć rozgałęzionych hierarchii przechowywania wersji. Oznacza to, że zawsze powinna istnieć ścieżka w co najmniej jednym kierunku od dowolnej wersji do innej wersji przy użyciu tylko zmian dozwolonych przez te wytyczne.

    Jeśli na przykład wersja 1 kontraktu danych osoby zawiera tylko element członkowski danych Name, nie należy tworzyć wersji 2a kontraktu dodającego tylko element członkowski wieku i wersję 2b, dodając tylko element członkowski Adresu. Przejście z zakresu od 2a do 2b wiązałoby się z usunięciem wieku i dodaniem adresu; przejście w innym kierunku wiązałoby się z usunięciem adresu i dodaniem wieku. Usunięcie elementów członkowskich nie jest dozwolone przez te wytyczne.

  13. Zazwyczaj nie należy tworzyć nowych podtypów istniejących typów kontraktów danych w nowej wersji aplikacji. Podobnie nie należy tworzyć nowych kontraktów danych, które są używane zamiast elementów członkowskich danych zadeklarowanych jako Obiekt lub jako typy interfejsów. Tworzenie tych nowych klas jest dozwolone tylko wtedy, gdy wiesz, że można dodać nowe typy do znanej listy typów wszystkich wystąpień starej aplikacji. Na przykład w wersji 1 aplikacji może istnieć typ kontraktu danych LibraryItem z podtypami kontraktu książki i gazety. BibliotekaItem będzie mieć znaną listę typów zawierającą książkę i gazetę. Załóżmy, że teraz dodasz typ magazynu w wersji 2, która jest podtypem BibliotekiItem. Jeśli wyślesz wystąpienie magazynu z wersji 2 do wersji 1, umowa danych magazynu nie zostanie znaleziona na liście znanych typów i zostanie zgłoszony wyjątek.

  14. Nie należy dodawać ani usuwać elementów członkowskich wyliczenia między wersjami. Nie należy również zmieniać nazwy elementów członkowskich wyliczenia, chyba że używasz właściwości Name atrybutu EnumMemberAttribute , aby zachować ich nazwy w modelu kontraktu danych tak samo.

  15. Kolekcje są wymienne w modelu kontraktu danych zgodnie z opisem w temacie Typy kolekcji w kontraktach danych. Zapewnia to dużą elastyczność. Upewnij się jednak, że nie przypadkowo zmieniasz typu kolekcji w sposób niezamienny z wersji na wersję. Na przykład nie należy zmieniać kolekcji niestandardowej (bez atrybutu CollectionDataContractAttribute ) na niestandardową lub dostosowaną kolekcję do kolekcji, która nie jest niestandardowa. Ponadto nie należy zmieniać właściwości w CollectionDataContractAttribute wersji z na wersję. Jedyną dozwoloną zmianą jest dodanie właściwości Nazwa lub Przestrzeń nazw, jeśli nazwa lub przestrzeń nazw bazowego typu kolekcji uległa zmianie i musisz ustawić jej nazwę kontraktu danych i przestrzeń nazw tak samo jak w poprzedniej wersji.

Niektóre z wymienionych tutaj wytycznych można bezpiecznie zignorować, gdy mają zastosowanie specjalne okoliczności. Przed odejmowaniem od wytycznych upewnij się, że w pełni rozumiesz mechanizmy serializacji, deserializacji i schematu.

Zobacz też