Delen via


KnownAssemblyAttribute

Het voorbeeld KnownAssemblyAttribute laat zien hoe de serialisatie- en deserialisatieprocessen kunnen worden aangepast met behulp van de DataContractResolver klasse. In dit voorbeeld ziet u hoe u dynamisch bekende typen toevoegt tijdens serialisatie en deserialisatie.

Voorbeelddetails

Dit voorbeeld bestaat uit vier projecten. Een van deze komt overeen met de service, die wordt gehost door IIS, waarmee het volgende servicecontract wordt gedefinieerd.

// Definition of a service contract.
[ServiceContract(Namespace = "http://Microsoft.Samples.KAA")]
[KnownAssembly("Types")]
public interface IDataContractCalculator
 {
    [OperationContract]
    ComplexNumber Add(ComplexNumber n1, ComplexNumber n2);

    [OperationContract]
    ComplexNumber Subtract(ComplexNumber n1, ComplexNumber n2);

    [OperationContract]
    ComplexNumber Multiply(ComplexNumber n1, ComplexNumber n2);

    [OperationContract]
    ComplexNumber Divide(ComplexNumber n1, ComplexNumber n2);

    [OperationContract]
    List<ComplexNumber> CombineLists(List<ComplexNumber> list1, List<ComplexNumber> list2);
}

Het servicecontract wordt geïmplementeerd, zoals wordt weergegeven in het volgende voorbeeld.

// Service class that implements the service contract.
public class DataContractCalculatorService : IDataContractCalculator
 {
    public ComplexNumber Add(ComplexNumber n1, ComplexNumber n2)
    {
        return new ComplexNumberWithMagnitude(n1.Real + n2.Real, n1.Imaginary + n2.Imaginary);
    }

    public ComplexNumber Subtract(ComplexNumber n1, ComplexNumber n2)
    {
        return new ComplexNumberWithMagnitude(n1.Real - n2.Real, n1.Imaginary - n2.Imaginary);
    }

    public ComplexNumber Multiply(ComplexNumber n1, ComplexNumber n2)
    {
        double real1 = n1.Real * n2.Real;
        double imaginary1 = n1.Real * n2.Imaginary;
        double imaginary2 = n2.Real * n1.Imaginary;
        double real2 = n1.Imaginary * n2.Imaginary * -1;

        return new ComplexNumber(real1 + real2, imaginary1 + imaginary2);
    }

    public ComplexNumber Divide(ComplexNumber n1, ComplexNumber n2)
    {
        ComplexNumber conjugate = new ComplexNumber(n2.Real, -1 * n2.Imaginary);
        ComplexNumber numerator = Multiply(n1, conjugate);
        ComplexNumber denominator = Multiply(n2, conjugate);

        return new ComplexNumber(numerator.Real / denominator.Real, numerator.Imaginary);
    }

    public List<ComplexNumber> CombineLists(List<ComplexNumber> list1, List<ComplexNumber> list2)
    {
        List<ComplexNumber> result  = new List<ComplexNumber>();
        result.AddRange(list1);
        result.AddRange(list2);

        return result;
    }
}

Een ander project komt overeen met de client, die communiceert met de server en de methoden aanroept die beschikbaar worden gesteld. De definitie van de client wordt weergegeven in het volgende voorbeeld.

 // Client implementation code.
class Client
 {
    static void Main()
    {
        // Create a channel.
         EndpointAddress address = new EndpointAddress("http://localhost/servicemodelsamples/service.svc/IDataContractCalculator");
        BasicHttpBinding binding = new BasicHttpBinding();
        ChannelFactory<IDataContractCalculator> factory = new ChannelFactory<IDataContractCalculator>(binding, address);
        IDataContractCalculator channel = factory.CreateChannel();

        // Call the Add service operation.
         ComplexNumber value1 = new ComplexNumber(1, 2);
        ComplexNumber value2 = new ComplexNumberWithMagnitude(3, 4);
        ComplexNumber result = channel.Add(value1, value2);
        Console.WriteLine("Add({0} + {1}i, {2} + {3}i) = {4} + {5}i",
            value1.Real, value1.Imaginary, value2.Real, value2.Imaginary, result.Real, result.Imaginary);
        if (result is ComplexNumberWithMagnitude)
        {
            Console.WriteLine("Magnitude: {0}", ((ComplexNumberWithMagnitude)result).Magnitude);
        }
        else
         {
            Console.WriteLine("No magnitude was sent from the service");
        }
        Console.WriteLine();

        // Call the Subtract service operation.
         value1 = new ComplexNumber(1, 2);
        value2 = new ComplexNumber(3, 4);
        result = channel.Subtract(value1, value2);
        Console.WriteLine("Subtract({0} + {1}i, {2} + {3}i) = {4} + {5}i",
            value1.Real, value1.Imaginary, value2.Real, value2.Imaginary, result.Real, result.Imaginary);
        if (result is ComplexNumberWithMagnitude)
        {
            Console.WriteLine("Magnitude: {0}", ((ComplexNumberWithMagnitude)result).Magnitude);
        }
        else
         {
            Console.WriteLine("No magnitude was sent from the service");
        }
        Console.WriteLine();

        // Call the Multiply service operation.
         value1 = new ComplexNumber(2, 3);
        value2 = new ComplexNumber(4, 7);
        result = channel.Multiply(value1, value2);
        Console.WriteLine("Multiply({0} + {1}i, {2} + {3}i) = {4} + {5}i",
            value1.Real, value1.Imaginary, value2.Real, value2.Imaginary, result.Real, result.Imaginary);
        if (result is ComplexNumberWithMagnitude)
        {
            Console.WriteLine("Magnitude: {0}", ((ComplexNumberWithMagnitude)result).Magnitude);
        }
        else
         {
            Console.WriteLine("No magnitude was sent from the service");
        }
        Console.WriteLine();

        // Call the Divide service operation.
         value1 = new ComplexNumber(3, 7);
        value2 = new ComplexNumber(5, -2);
        result = channel.Divide(value1, value2);
        Console.WriteLine("Divide({0} + {1}i, {2} + {3}i) = {4} + {5}i",
            value1.Real, value1.Imaginary, value2.Real, value2.Imaginary, result.Real, result.Imaginary);
        if (result is ComplexNumberWithMagnitude)
        {
            Console.WriteLine("Magnitude: {0}", ((ComplexNumberWithMagnitude)result).Magnitude);
        }
        else
         {
            Console.WriteLine("No magnitude was sent from the service");
        }
        Console.WriteLine();

        // Call the CombineLists service operation.
         List<ComplexNumber> list1 = new List<ComplexNumber>();
        List<ComplexNumber> list2 = new List<ComplexNumber>();
        list1.Add(new ComplexNumber(1, 1));
        list1.Add(new ComplexNumber(2, 2));
        list1.Add(new ComplexNumberWithMagnitude(3, 3));
        list1.Add(new ComplexNumberWithMagnitude(4, 4));
        List<ComplexNumber> listResult = channel.CombineLists(list1, list2);
        Console.WriteLine("Lists combined:");
        foreach (ComplexNumber n in listResult)
        {
            Console.WriteLine("{0} + {1}i", n.Real, n.Imaginary);
        }
        Console.WriteLine();

        // Close the channel
         ((IChannel)channel).Close();

        Console.WriteLine();
        Console.WriteLine("Press <ENTER> to terminate client.");
        Console.ReadLine();
    }
}

De definitie van het servicecontract wordt gemarkeerd met het KnownAssembly kenmerk. Dit kenmerk bevat de naam van een bibliotheek met typen, die allemaal bekend worden tijdens runtime door zowel de service als de client.

Het KnownAssembly kenmerk wordt geïmplementeerd IContractBehavior om een DataContractSerializer met een DataContractResolver gedefinieerde definitie te definiëren voor elk van de bewerkingsgedragen. Het DataContractResolver weerspiegelt de assembly wanneer deze wordt gemaakt en maakt de woordenlijst met de toewijzing tussen typen en namen die moeten worden gebruikt bij het serialiseren en deserialiseren van de verschillende typen. Op die manier moeten de ResolveType en ResolveName typen de gegevens opzoeken die vereist zijn in de woordenlijst.

De DataContractResolver gedefinieerde voor dit voorbeeld wordt weergegeven in het volgende voorbeeld.

public class MyDataContractResolver : DataContractResolver
    {
       Dictionary<string, XmlDictionaryString> dictionary = new Dictionary<string, XmlDictionaryString>();
       Assembly assembly;

       public MyDataContractResolver(string assemblyName)
       {
           this.KnownTypes = new List<Type>();

           assembly = Assembly.Load(new AssemblyName(assemblyName));
           foreach (Type type in assembly.GetTypes())
           {
               bool knownTypeFound = false;
               System.Attribute[] attrs = System.Attribute.GetCustomAttributes(type);
               if (attrs.Length != 0)
               {
                   foreach (System.Attribute attr in attrs)
                   {
                       if (attr is KnownTypeAttribute)
                       {
                           Type t = ((KnownTypeAttribute)attr).Type;
                           if (this.KnownTypes.IndexOf(t) < 0)
                           {
                               this.KnownTypes.Add(t);
                           }
                           knownTypeFound = true;
                       }
                   }
               }
               if (!knownTypeFound)
               {
                   string name = type.Name;
                   string namesp = type.Namespace;
                   if (!dictionary.ContainsKey(name))
                   {
                       dictionary.Add(name, new XmlDictionaryString(XmlDictionary.Empty, name, 0));
                   }
                   if (!dictionary.ContainsKey(namesp))
                   {
                       dictionary.Add(namesp, new XmlDictionaryString(XmlDictionary.Empty, namesp, 0));
                   }
               }
           }
       }

       public IList<Type> KnownTypes
       {
           get; set;
       }

       // Used at deserialization
        // Allows users to map xsi:type name to any Type
        public override Type ResolveName(string typeName, string typeNamespace, DataContractResolver knownTypeResolver)
       {
           XmlDictionaryString tName;
           XmlDictionaryString tNamespace;

           if (dictionary.TryGetValue(typeName, out tName) && dictionary.TryGetValue(typeNamespace, out tNamespace))
           {
               return this.assembly.GetType(tNamespace.Value + "." + tName.Value);
           }
           else
            {
               return knownTypeResolver.ResolveName(typeName, typeNamespace, null);
           }
       }

       // Used at serialization
        // Maps any Type to a new xsi:type representation
        public override void ResolveType(Type dataContractType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
       {
           knownTypeResolver.ResolveType(dataContractType, null, out typeName, out typeNamespace);
           if (typeName == null || typeNamespace == null)
           {
               typeName = new XmlDictionaryString(XmlDictionary.Empty, dataContractType.Name, 0);
               typeNamespace = new XmlDictionaryString(XmlDictionary.Empty, dataContractType.Namespace, 0);
           }
       }
   }

De bibliotheek met typen die in dit voorbeeld worden gebruikt, wordt weergegeven in het volgende voorbeeld.

 [DataContract]
public class ComplexNumber
 {
    [DataMember]
    private double real;

    [DataMember]
    private double imaginary;

    public ComplexNumber(double r1, double i1)
    {
        this.Real = r1;
        this.Imaginary = i1;
    }

    public double Real
    {
        get { return real; }
        set { real = value; }
    }

    public double Imaginary
    {
        get { return imaginary; }
        set { imaginary = value; }
    }
}

[DataContract]
public class ComplexNumberWithMagnitude : ComplexNumber
 {
    public ComplexNumberWithMagnitude(double real, double imaginary) : base(real, imaginary) { }

    [DataMember]
    public double Magnitude
    {
        get { return Math.Sqrt(Imaginary * Imaginary + Real * Real); }
        set { }
    }
}

Houd er rekening mee dat ComplexNumber u het ComplexNumberWithMagnitude type niet statisch hoeft te kennen, omdat het tijdens runtime bekend wordt.

Wanneer het voorbeeld is gebouwd en uitgevoerd, is dit de verwachte uitvoer die is verkregen in de client:

Add(1 + 2i, 3 + 4i) = 4 + 6i
Magnitude: 7.21110255092798

Subtract(1 + 2i, 3 + 4i) = -2 + -2i
Magnitude: 2.82842712474619

Multiply(2 + 3i, 4 + 7i) = -13 + 26i
No magnitude was sent from the service

Divide(3 + 7i, 5 + -2i) = 0.0344827586206897 + 41i
No magnitude was sent from the service

Lists combined:
1 + 1i
2 + 2i
3 + 3i
4 + 4i

Het voorbeeld instellen, uitvoeren en bouwen

  1. Klik met de rechtermuisknop op de oplossing KnownAssemblyAttribute en selecteer Eigenschappen.

  2. In Algemene eigenschappen selecteert u Opstartproject en klikt u vervolgens op Meerdere opstartprojecten.

  3. Voeg de actie Starten toe aan de service - en clientprojecten .

  4. Klik op OK en druk op F5 om het voorbeeld uit te voeren.

  5. Als de toepassing niet goed wordt uitgevoerd, volgt u deze stappen om te controleren of uw omgeving correct is ingesteld:

  6. Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.

  7. Volg de instructies in het bouwen van het Windows Communication Foundation-voorbeeld om de oplossing te bouwen.

  8. Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.