Udostępnij za pośrednictwem


Zastępcze umowy dotyczące danych

Model zastępczy kontraktu danych to zaawansowana funkcja oparta na modelu kontraktu danych. Ta funkcja jest przeznaczona do dostosowywania i zastępowania typów w sytuacjach, w których użytkownicy chcą zmienić sposób serializacji, deserializacji lub projekcji typu na metadane. W niektórych przypadkach, kiedy nie określono kontraktu danych dla typu, pola i właściwości nie są oznaczone atrybutem DataMemberAttribute, lub użytkownicy chcą dynamicznie tworzyć różne warianty schematów, można użyć zastępcy.

Serializacja i deserializację są realizowane przy użyciu DataContractSerializer zastępczego kontraktu danych w celu konwersji z programu .NET Framework na odpowiedni format, na przykład XML. Za pomocą zastępczego kontraktu danych można również modyfikować metadane eksportowane dla typów podczas tworzenia reprezentacji metadanych, takich jak dokumenty schematu XML (XSD). Po zaimportowaniu kod jest tworzony na podstawie metadanych, a w tym przypadku można użyć substytuta do dostosowania wygenerowanego kodu.

Jak działa surogat

Surogat działa przez mapowanie jednego typu (typ "oryginalny") na inny typ (typ "zastępczy"). W poniższym przykładzie przedstawiono oryginalny typ Inventory i nowy typ zastępczy InventorySurrogated . Typ Inventory nie można serializować, ale InventorySurrogated typ to:

public class Inventory
{
    public int pencils;
    public int pens;
    public int paper;
}

Ponieważ dla tej klasy nie zdefiniowano kontraktu danych, przekonwertuj klasę na klasę zastępczą z kontraktem danych. W poniższym przykładzie pokazano klasę zastępczą:

[DataContract(Name = "Inventory")]
public class InventorySurrogated
{
    [DataMember]
    public int numpencils;
    [DataMember]
    public int numpaper;
    [DataMember]
    private int numpens;

    public int pens
    {
        get { return numpens; }
        set { numpens = value; }
    }
}

Implementacja IDataContractSurrogate

Aby użyć zastępczego kontraktu danych, zaimplementuj IDataContractSurrogate interfejs.

Poniżej przedstawiono omówienie każdej metody IDataContractSurrogate z możliwą implementacją.

GetDataContractType (pobierz typ kontraktu danych)

Metoda GetDataContractType mapuje jeden typ na inny. Ta metoda jest wymagana do serializacji, deserializacji, importowania i eksportowania.

Pierwszym zadaniem jest zdefiniowanie, jakie typy będą mapowane na inne typy. Przykład:

public Type GetDataContractType(Type type)
{
    Console.WriteLine("GetDataContractType");
    if (typeof(Inventory).IsAssignableFrom(type))
    {
        return typeof(InventorySurrogated);
    }
    return type;
}
  • Podczas serializacji mapowanie zwrócone przez tę metodę jest następnie używane do przekształcania oryginalnego wystąpienia w wystąpienie zastępcze poprzez wywołanie metody GetObjectToSerialize.

  • W przypadku deserializacji mapowanie zwrócone przez tę metodę jest używane przez serializator do deserializacji w wystąpieniu typu zastępczego. Następnie wywołuje GetDeserializedObject w celu przekształcenia wystąpienia zastępczego na wystąpienie oryginalnego typu.

  • W przypadku eksportu typ zastępczy zwracany przez tę metodę jest odzwierciedlany w celu uzyskania kontraktu danych do użycia do generowania metadanych.

  • Podczas importowania typ początkowy jest zmieniany na typ zastępczy, który jest odzwierciedlony w celu uzyskania kontraktu danych do użycia w celach, takich jak odwoływanie się do pomocy technicznej.

Parametr Type jest typem obiektu, który jest serializowany, deserializowany, importowany lub eksportowany. Metoda GetDataContractType musi zwracać typ danych wejściowych, jeśli zastępca nie obsługuje typu. W przeciwnym razie zwróć odpowiedni typ zastępczy. Jeśli istnieje kilka typów zastępczych, w tej metodzie można zdefiniować wiele mapowań.

Metoda GetDataContractType nie jest wywoływana dla wbudowanych prymitywnych typów kontraktów danych, takich jak Int32 lub String. W przypadku innych typów, takich jak tablice, typy zdefiniowane przez użytkownika i inne struktury danych, ta metoda będzie wywoływana dla każdego typu.

W poprzednim przykładzie metoda sprawdza, czy type parametr i Inventory są porównywalne. Jeśli tak, metoda mapuje ją na InventorySurrogated. Za każdym razem, gdy jest wywoływana serializacja, deserializacja, schemat importu lub schemat eksportu, ta funkcja jest wywoływana jako pierwsza w celu określenia mapowania między typami.

Metoda GetObjectToSerialize

Metoda GetObjectToSerialize konwertuje oryginalne wystąpienie typu na wystąpienie typu zastępczego. Metoda jest wymagana do serializacji.

Następnym krokiem jest zdefiniowanie sposobu mapowania danych fizycznych z oryginalnego wystąpienia na zastępcę przez zaimplementowanie metody GetObjectToSerialize. Przykład:

public object GetObjectToSerialize(object obj, Type targetType)
{
    Console.WriteLine("GetObjectToSerialize");
    if (obj is Inventory)
    {
        InventorySurrogated isur = new InventorySurrogated();
        isur.numpaper = ((Inventory)obj).paper;
        isur.numpencils = ((Inventory)obj).pencils;
        isur.pens = ((Inventory)obj).pens;
        return isur;
    }
    return obj;
}

Metoda GetObjectToSerialize jest wywoływana, gdy obiekt jest serializowany. Ta metoda transferuje dane z oryginalnego typu do pól typu zastępczego. Pola mogą być mapowane bezpośrednio na pola zastępcze, a transformacje oryginalnych danych mogą być przechowywane w surogatach. Niektóre możliwe zastosowania obejmują: bezpośrednie mapowanie pól, wykonywanie operacji na danych do przechowywania w polach zastępczych lub przechowywanie kodu XML oryginalnego typu w polu zastępczym.

Parametr targetType odnosi się do zadeklarowanego typu członka. Ten parametr jest typem zastępczym zwracanym przez metodę GetDataContractType . Serializator nie wymusza przypisywania zwróconego obiektu do tego typu. Parametr obj jest obiektem do serializacji i zostanie przekonwertowany na jego zastępcę w razie potrzeby. Ta metoda musi zwrócić obiekt wejściowy, jeśli surogat nie obsługuje obiektu. W przeciwnym razie zostanie zwrócony nowy obiekt zastępczy. Zastępca nie jest wywoływany, jeśli obiekt ma wartość null. W ramach tej metody można zdefiniować wiele mapowań zastępczych dla różnych wystąpień.

Podczas tworzenia obiektu DataContractSerializermożna poinstruować go o zachowaniu odwołań do obiektów. (Aby uzyskać więcej informacji, zobacz Serializacja i Deserializacja). W tym celu należy ustawić preserveObjectReferences parametr w jego konstruktorze na truewartość. W takim przypadku zastępca jest wywoływany tylko raz dla obiektu, ponieważ wszystkie kolejne serializacji po prostu zapisują odwołanie do strumienia. Jeśli preserveObjectReferences jest ustawione na false, zastępca jest wywoływany za każdym razem, gdy wystąpienie zostanie napotkane.

Jeśli typ serializowanego wystąpienia różni się od zadeklarowanego typu, informacje o typie są zapisywane w strumieniu, na przykład xsi:type, aby umożliwić deserializację wystąpienia na drugim końcu. Proces ten zachodzi niezależnie od tego, czy obiekt jest zastępowany, czy nie.

Powyższy przykład konwertuje dane wystąpienia Inventory na dane InventorySurrogated. Sprawdza typ obiektu i wykonuje niezbędne manipulacje w celu przekonwertowania na typ zastępczy. W takim przypadku pola klasy Inventory są bezpośrednio kopiowane do pól klasy InventorySurrogated.

Metoda GetDeserializedObject

Metoda GetDeserializedObject konwertuje wystąpienie typu zastępczego na wystąpienie oryginalnego typu. Jest to wymagane do deserializacji.

Następnym zadaniem jest zdefiniowanie sposobu mapowania danych fizycznych z wystąpienia zastępczego na oryginał. Przykład:

public object GetDeserializedObject(object obj, Type targetType)
{
    Console.WriteLine("GetDeserializedObject");
    if (obj is InventorySurrogated)
    {
        Inventory invent = new Inventory();
        invent.pens = ((InventorySurrogated)obj).pens;
        invent.pencils = ((InventorySurrogated)obj).numpencils;
        invent.paper = ((InventorySurrogated)obj).numpaper;
        return invent;
    }
    return obj;
}

Ta metoda jest wywoływana tylko podczas deserializacji obiektu. Zapewnia odwrotne mapowanie danych podczas deserializacji z typu zastępczego na jego oryginalny typ. Podobnie jak metoda GetObjectToSerialize, niektóre możliwe zastosowania mogą polegać na bezpośredniej wymianie danych pól, wykonywaniu operacji na danych i przechowywaniu danych XML. Podczas deserializacji nie zawsze można uzyskać dokładne wartości danych z oryginału z powodu manipulacji podczas konwersji danych.

Parametr targetType odnosi się do zadeklarowanego typu członka. Ten parametr jest typem zastępczym zwracanym przez metodę GetDataContractType . Parametr obj odwołuje się do obiektu, który został zdeserializowany. Obiekt można przekonwertować z powrotem na oryginalny typ, jeśli jest on zastępczy. Ta metoda zwraca obiekt wejściowy, jeśli zastępca nie obsługuje obiektu. W przeciwnym razie obiekt deserializowany zostanie zwrócony po zakończeniu konwersji. Jeśli istnieje kilka typów zastępczych, możesz podać konwersję danych z zastępczego na typ podstawowy dla każdego z nich, wskazując każdy typ i jego konwersję.

Podczas zwracania obiektu, tabele obiektów wewnętrznych są aktualizowane obiektem zwróconym przez ten zastępczy obiekt. Kolejne odniesienia do instancji uzyskają jej zastępczą wersję z tabel obiektów.

W poprzednim przykładzie obiekty typu InventorySurrogated są konwertowane z powrotem na typ Inventorypoczątkowy . W takim przypadku dane są bezpośrednio przesyłane z InventorySurrogated do odpowiednich pól w Inventory. Ponieważ nie ma żadnych manipulacji danymi, każde z pól składowych będzie zawierać te same wartości co przed serializacji.

GetCustomDataToExport, metoda

Podczas eksportowania schematu metoda jest opcjonalna GetCustomDataToExport . Służy do wstawiania dodatkowych danych lub wskazówek do wyeksportowanego schematu. Dodatkowe dane można wstawić na poziomie członka lub na poziomie typu. Przykład:

public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
    Console.WriteLine("GetCustomDataToExport(Member)");
    System.Reflection.FieldInfo fieldInfo = (System.Reflection.FieldInfo)memberInfo;
    if (fieldInfo.IsPublic)
    {
        return "public";
    }
    else
    {
        return "private";
    }
}

Ta metoda (z dwoma przeciążeniami) umożliwia dodanie dodatkowych informacji do metadanych na poziomie członka lub typu. Istnieje możliwość uwzględnienia wskazówek, czy członek jest publiczny czy prywatny, oraz komentarzy, które byłyby zachowywane podczas eksportowania i importowania schematu. Takie informacje zostaną utracone bez tej metody. Ta metoda nie powoduje wstawiania lub usuwania elementów członkowskich lub typów, ale raczej dodaje dodatkowe dane do schematów na jednym z tych poziomów.

Metoda jest przeciążona i może przyjmować albo Type (clrtype parametr) albo MemberInfo (memberInfo parametr). Drugi parametr jest zawsze parametrem Type (dataContractType ). Ta metoda jest wywoływana dla każdego członka i typu zastępczego dataContractType.

Któraś z tych przeciążeń musi zwrócić albo null, albo obiekt możliwy do serializacji. Obiekt inny niż null zostanie serializowany jako adnotacja do wyeksportowanego schematu. Type W przypadku przeciążenia każdy typ wyeksportowany do schematu jest wysyłany do tej metody w pierwszym parametrze wraz z typem zastępczym jako parametremdataContractType. MemberInfo W przypadku przeciążenia każdy członek wyeksportowany do schematu wysyła swoje informacje jako parametr memberInfo, a typ zastępczy umieszczany jest w drugim parametrze.

Metoda "GetCustomDataToExport" (typ, typ)

Metoda IDataContractSurrogate.GetCustomDataToExport(Type, Type) jest wywoływana podczas eksportowania schematu dla każdej definicji typu. Metoda dodaje informacje do typów w schemacie podczas eksportowania. Każdy zdefiniowany typ jest wysyłany do tej metody w celu określenia, czy istnieją jakieś dodatkowe dane, które należy uwzględnić w schemacie.

GetCustomDataToExport (metoda) (MemberInfo, Type)

IDataContractSurrogate.GetCustomDataToExport(MemberInfo, Type) jest wywoływany podczas eksportowania dla każdego członka w eksportowanych typach. Ta funkcja umożliwia dostosowanie dowolnych komentarzy dla członków, które zostaną dodane do schematu podczas eksportu. Informacje dotyczące każdego elementu członkowskiego w klasie są wysyłane do tej metody w celu sprawdzenia, czy w schemacie należy dodać jakiekolwiek dodatkowe dane.

W powyższym przykładzie dataContractType jest przeszukiwane dla każdego członka surogatu. Następnie zwraca odpowiedni modyfikator dostępu dla każdego pola. Bez tego dostosowania domyślna wartość modyfikatorów dostępu jest publiczna. W związku z tym wszystkie elementy członkowskie będą zdefiniowane jako publiczne w kodzie wygenerowanym przy użyciu wyeksportowanego schematu niezależnie od tego, jakie są ich rzeczywiste ograniczenia dostępu. Jeśli ta implementacja nie jest używana, element członkowski numpens będzie publiczny w wyeksportowanym schemacie, mimo że został zdefiniowany w surogatce jako prywatny. Za pomocą tej metody w wyeksportowanym schemacie modyfikator dostępu można wygenerować jako prywatny.

Metoda GetReferencedTypeOnImport

Ta metoda przypisuje Type surogat na oryginalny typ. Ta metoda jest opcjonalna w przypadku importu schematu.

Podczas tworzenia zastępczego obiektu, który importuje schemat i generuje dla niego kod, następnym zadaniem jest zdefiniowanie typu wystąpienia obiektu na jego oryginalny typ.

Jeśli wygenerowany kod musi odwoływać się do istniejącego typu użytkownika, jest to wykonywane przez zaimplementowanie GetReferencedTypeOnImport metody .

Podczas importowania schematu metoda ta jest wywoływana dla każdej deklaracji typu, aby zamapować zastępowany kontrakt danych na typ. Parametry łańcuchowe typeName i typeNamespace definiują nazwę i przestrzeń nazw typu zastępczego. Wartość zwracana dla GetReferencedTypeOnImport służy do określania, czy trzeba wygenerować nowy typ. Ta metoda musi zwrócić prawidłowy typ lub wartość null. W przypadku prawidłowych typów zwrócony typ będzie używany jako typ referencyjny w wygenerowanym kodzie. Jeśli zostanie zwrócona wartość null, nie będzie odwołania do żadnego typu i należy utworzyć nowy typ. Jeśli istnieje kilka zastępników, można wykonać mapowanie dla każdego typu zastępnika z powrotem do jego typu początkowego.

Parametr customData jest obiektem pierwotnie zwróconym z GetCustomDataToExport. Jest to customData używane, gdy autorzy zastępczy chcą wstawić dodatkowe dane/wskazówki do metadanych do użycia podczas importowania w celu wygenerowania kodu.

Metoda ProcessImportedType

Metoda ProcessImportedType dostosowuje dowolny typ utworzony na podstawie importu schematu. Ta metoda jest opcjonalna.

Podczas importowania schematu ta metoda umożliwia dostosowanie wszelkich importowanych informacji o typie i kompilacji. Przykład:

public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
    Console.WriteLine("ProcessImportedType");
    foreach (CodeTypeMember member in typeDeclaration.Members)
    {
        object memberCustomData = member.UserData[typeof(IDataContractSurrogate)];
        if (memberCustomData != null
          && memberCustomData is string
          && ((string)memberCustomData == "private"))
        {
            member.Attributes = ((member.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private);
        }
    }
    return typeDeclaration;
}

Podczas importowania ta metoda jest wywoływana dla każdego wygenerowanego typu. Zmień określony CodeTypeDeclaration lub zmodyfikuj element CodeCompileUnit. Obejmuje to zmianę nazwy, elementów członkowskich, atrybutów i wielu innych właściwości obiektu CodeTypeDeclaration. Przetwarzając element CodeCompileUnit, można zmodyfikować dyrektywy, przestrzenie nazw, odwołane zestawy oraz kilka innych aspektów.

Parametr CodeTypeDeclaration zawiera deklarację typu DOM kodu. Parametr CodeCompileUnit umożliwia modyfikację przetwarzania kodu. Zwracanie null powoduje odrzucenie deklaracji typu. Z drugiej strony podczas zwracania CodeTypeDeclaration elementu modyfikacje są zachowywane.

Jeśli dane niestandardowe są wstawiane podczas eksportowania metadanych, należy przekazać je użytkownikowi podczas importowania, aby można było z niego korzystać. Te dane niestandardowe mogą służyć do programowania wskazówek dotyczących modelu lub innych komentarzy. Każde wystąpienie CodeTypeDeclaration i CodeTypeMember zawiera dane niestandardowe jako właściwość UserData, rzutowane na typ IDataContractSurrogate.

W powyższym przykładzie wprowadzono pewne zmiany w zaimportowaniu schematu. Kod zachowuje prywatne elementy członkowskie oryginalnego typu przy użyciu zastępcy. Domyślnym modyfikatorem dostępu podczas importowania schematu jest public. W związku z tym wszyscy członkowie schematu zastępczego będą publiczni, chyba że zostaną zmodyfikowani, jak w tym przykładzie. Podczas eksportowania niestandardowe dane są wstawiane do metadanych o członkach, które są prywatne. Przykład wyszukuje dane niestandardowe, sprawdza, czy modyfikator dostępu jest prywatny, a następnie modyfikuje odpowiedni element członkowski, aby był prywatny, ustawiając jego atrybuty. Bez tego dostosowania element członkowski numpens zostanie zdefiniowany jako publiczny, a nie prywatny.

Metoda GetKnownCustomDataTypes

Ta metoda uzyskuje niestandardowe typy danych zdefiniowane ze schematu. Metoda jest opcjonalna dla importu schematu.

Metoda jest wywoływana na początku eksportowania i importowania schematu. Metoda zwraca niestandardowe typy danych używane w schemacie wyeksportowanym lub zaimportowanym. Metodzie jest przekazywany Collection<T> (czyli parametr customDataTypes), który jest kolekcją typów. Metoda powinna dodać do tej kolekcji dodatkowe znane typy. Aby umożliwić serializacji i deserializacji danych niestandardowych przy użyciu elementu DataContractSerializer, potrzebne są znane niestandardowe typy danych. Aby uzyskać więcej informacji, zobacz Znane typy kontraktów danych.

Implementowanie zastępcy

Aby użyć zastępczego kontraktu danych w programie WCF, należy wykonać kilka specjalnych procedur.

Aby użyć zastępcy do serializacji i deserializacji

Użyj elementu DataContractSerializer, aby wykonać serializację i deserializację danych z surogatem. Element DataContractSerializer jest tworzony przez element DataContractSerializerOperationBehavior. Należy również określić zastępcę.

Aby zaimplementować serializację i deserializację
  1. Utwórz wystąpienie ServiceHost dla swojej usługi. Aby uzyskać pełne instrukcje, zobacz Podstawowe programowanie WCF.

  2. Dla każdego ServiceEndpoint określonego hosta usługi znajdź jego OperationDescription.

  3. Przeszukaj zachowania operacji, aby określić, czy znaleziono wystąpienie obiektu DataContractSerializerOperationBehavior .

  4. Jeśli element DataContractSerializerOperationBehavior zostanie znaleziony, ustaw jego właściwość DataContractSurrogate na nowe wystąpienie obiektu zastępczego. Jeśli nie można znaleźć DataContractSerializerOperationBehavior, utwórz nowe wystąpienie i ustaw członek DataContractSurrogate nowego zachowania na nowe wystąpienie zastępczej klasy.

  5. Na koniec dodaj to nowe zachowanie do bieżących zachowań operacji, jak pokazano w poniższym przykładzie:

    using (ServiceHost serviceHost = new ServiceHost(typeof(InventoryCheck)))
        foreach (ServiceEndpoint ep in serviceHost.Description.Endpoints)
        {
            foreach (OperationDescription op in ep.Contract.Operations)
            {
                DataContractSerializerOperationBehavior dataContractBehavior =
                    op.Behaviors.Find<DataContractSerializerOperationBehavior>()
                    as DataContractSerializerOperationBehavior;
                if (dataContractBehavior != null)
                {
                    dataContractBehavior.DataContractSurrogate = new InventorySurrogated();
                }
                else
                {
                    dataContractBehavior = new DataContractSerializerOperationBehavior(op);
                    dataContractBehavior.DataContractSurrogate = new InventorySurrogated();
                    op.Behaviors.Add(dataContractBehavior);
                }
            }
        }
    

Aby użyć zastępcy do importu metadanych

Podczas importowania metadanych, takich jak WSDL i XSD w celu wygenerowania kodu po stronie klienta, zastępca musi zostać dodany do składnika odpowiedzialnego za generowanie kodu ze schematu XSD. XsdDataContractImporter Aby to zrobić, bezpośrednio zmodyfikuj WsdlImporter używane do importowania metadanych.

Aby zaimplementować surogat do importowania metadanych
  1. Zaimportuj metadane przy użyciu klasy WsdlImporter.

  2. Użyj metody TryGetValue, aby sprawdzić, czy XsdDataContractImporter został zdefiniowany.

  3. Jeśli metoda TryGetValue zwróci false, utwórz nowy XsdDataContractImporter i ustaw jego właściwość Options na nowe wystąpienie klasy ImportOptions. W przeciwnym razie użyj importera zwróconego przez parametr metody outTryGetValue.

  4. Jeśli XsdDataContractImporter nie ma zdefiniowanego ImportOptions, ustaw tę właściwość na nowe wystąpienie klasy ImportOptions.

  5. Ustaw właściwość DataContractSurrogate elementu ImportOptions w XsdDataContractImporter na nowe wystąpienie zastępcze.

  6. Dodaj element XsdDataContractImporter do kolekcji zwróconej przez właściwość StateWsdlImporter (odziedziczonej z klasy MetadataExporter).

  7. Użyj metody ImportAllContracts obiektu WsdlImporter, aby zaimportować wszystkie kontrakty danych w schemacie. W ostatnim kroku kod jest generowany na podstawie schematów załadowanych poprzez wywołanie zastępczego.

    MetadataExchangeClient mexClient = new MetadataExchangeClient(metadataAddress);
    mexClient.ResolveMetadataReferences = true;
    MetadataSet metaDocs = mexClient.GetMetadata();
    WsdlImporter importer = new WsdlImporter(metaDocs);
    object dataContractImporter;
    XsdDataContractImporter xsdInventoryImporter;
    if (!importer.State.TryGetValue(typeof(XsdDataContractImporter),
        out dataContractImporter))
        xsdInventoryImporter = new XsdDataContractImporter();
    
    xsdInventoryImporter = (XsdDataContractImporter)dataContractImporter;
    xsdInventoryImporter.Options ??= new ImportOptions();
    xsdInventoryImporter.Options.DataContractSurrogate = new InventorySurrogated();
    importer.State.Add(typeof(XsdDataContractImporter), xsdInventoryImporter);
    
    Collection<ContractDescription> contracts = importer.ImportAllContracts();
    

Użycie zastępcy do eksportu metadanych

Domyślnie podczas eksportowania metadanych z programu WCF dla usługi należy wygenerować schemat WSDL i XSD. Zastępca musi zostać dodany do składnika odpowiedzialnego za generowanie schematu XSD dla typów kontraktów danych, XsdDataContractExporter. W tym celu można użyć zachowania, które implementuje IWsdlExportExtension do modyfikowania WsdlExporter, lub bezpośrednio zmodyfikować WsdlExporter używany do eksportowania metadanych.

Aby użyć zastępcy do eksportowania metadanych
  1. Utwórz nowy WsdlExporter lub użyj parametru wsdlExporter przekazanego do metody ExportContract.

  2. Użyj funkcji , TryGetValue aby sprawdzić, czy XsdDataContractExporter element został zdefiniowany.

  3. Jeśli TryGetValue zwraca false, utwórz nową XsdDataContractExporter z wygenerowanymi schematami XML z WsdlExporter, i dodaj ją do kolekcji zwracanej przez właściwość State obiektu WsdlExporter. W przeciwnym razie użyj eksportera zwróconego przez parametr out metody TryGetValue.

  4. Jeśli XsdDataContractExporter nie ma zdefiniowanej ExportOptions, ustaw właściwość Options na nowe wystąpienie klasy ExportOptions.

  5. Ustaw właściwość DataContractSurrogate elementu ExportOptions w XsdDataContractExporter na nowe wystąpienie zastępcze. Kolejne kroki eksportowania metadanych nie wymagają żadnych zmian.

    WsdlExporter exporter = new WsdlExporter();
    //or
    //public void ExportContract(WsdlExporter exporter,
    // WsdlContractConversionContext context) { ... }
    object dataContractExporter;
    XsdDataContractExporter xsdInventoryExporter;
    if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter),
        out dataContractExporter))
    {
        xsdInventoryExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
    }
    else
    {
        xsdInventoryExporter = (XsdDataContractExporter)dataContractExporter;
    }
    
    exporter.State.Add(typeof(XsdDataContractExporter), xsdInventoryExporter);
    
    if (xsdInventoryExporter.Options == null)
        xsdInventoryExporter.Options = new ExportOptions();
    xsdInventoryExporter.Options.DataContractSurrogate = new InventorySurrogated();
    

Zobacz także