KnownAssemblyAttributeKnownAssemblyAttribute

In diesem Beispiel wird veranschaulicht, wie die Serialisierungs- und Deserialisierungsprozesse mit der DataContractResolver-Klasse angepasst werden können.This sample demonstrates how the serialization and deserialization processes can be customized by using the DataContractResolver class. In diesem Beispiel wird gezeigt, wie bekannte Typen während der Serialisierung und Deserialisierung dynamisch hinzugefügt werden.This sample shows how to dynamically add known types during serialization and deserialization.

BeispieldetailsSample Details

Dieses Beispiel besteht aus vier Projekten.This sample is composed of four projects. Eines davon entspricht dem Dienst, der von IIS gehostet werden soll und im folgenden Dienstvertrag definiert ist.One of them corresponds to the service, to be hosted by IIS, which defines the following service contract.

// 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);  
}  

Der Dienstvertrag wird wie im folgenden Code gezeigt implementiert.The service contract is implemented as shown in the following example.

// 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;  
    }  
}  

Ein anderes Projekt entspricht dem Client, der mit dem Server kommuniziert und die Methoden aufruft, die damit verfügbar gemacht werden.Another project corresponds to the client, which communicates with the server and invokes the methods that it exposes. Die Definition des Clients wird im folgenden Beispiel dargestellt.The definition of the client is shown in the following example.

 // 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();  
    }  
}  

Die Definition des Dienstvertrags wird mit dem KnownAssembly-Attribut markiert.The definition of the service contract is marked with the KnownAssembly attribute. Dieses Attribut enthält den Namen einer Bibliothek von Typen, die alle zur Laufzeit sowohl dem Dienst als auch dem Client bekannt werden.This attribute contains the name of a library of types, which all become known at runtime by both the service and the client.

Das KnownAssembly-Attribut implementiert IContractBehavior, um einen DataContractSerializer mit einem DataContractResolver, der für jedes der Vorgangsverhalten definiert ist.The KnownAssembly attribute implements IContractBehavior in order to define a DataContractSerializer with a DataContractResolver defined for each of the operation behaviors. Der DataContractResolver gibt die Assembly wieder, wenn diese erstellt wird, und erstellt das Wörterbuch mit der Zuordnung zwischen Typen und Namen, das bei der Serialisierung und Deserialisierung mit verschiedenen Typen verwendet wird.The DataContractResolver reflects over the assembly when it is created, and creates the dictionary with the mapping between types and names to be used when serializing and deserializing the different types. Auf diese Weise müssen die erforderlichen Daten vom ResolveType-Typ und vom ResolveName-Typ im Wörterbuch nachgeschlagen werden.In that way, the ResolveType and ResolveName types must look up the data required in the dictionary.

Im folgenden Beispiel wird der in diesem Beispiel definierte DataContractResolver dargestellt.The DataContractResolver defined for this sample is shown in the following example.

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);  
           }  
       }  
   }  

Die Bibliothek von Typen, die in diesem Beispiel verwendet wurde, wird im folgenden Beispiel dargestellt.The library of types used in this sample is shown in the following example.

 [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 { }  
    }  
}  

Beachten Sie, dass die ComplexNumber den ComplexNumberWithMagnitude-Typ nicht statisch kennen muss, da er zur Laufzeit verfügbar gemacht wird.Note that ComplexNumber does not need to statically know the ComplexNumberWithMagnitude type, because it becomes known at runtime.

Bei der Erstellung und Ausführung des Beispiels wird die folgende Ausgabe im Client erwartet:When the sample is built and executed, this is the expected output obtained in the 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  

So richten Sie das Beispiel ein, führen es aus und erstellen esTo set up, run, and build the sample

  1. Mit der rechten Maustaste in der Projektmappe KnownAssemblyAttribute , und wählen Sie Eigenschaften.Right-click the solution KnownAssemblyAttribute and select Properties.

  2. In allgemeine EigenschaftenOption Startprojekt, und klicken Sie dann auf mehrere Startprojekte.In Common Properties, select Startup Project, and then click Multiple startup projects.

  3. Hinzufügen der starten Aktion aus, um die Service und Client Projekte.Add the Start action to the Service and Client projects.

  4. Klicken Sie auf OK, und drücken Sie die F5 zum Ausführen des Beispiels.Click OK, and press F5 to run the sample.

  5. Wenn die Anwendung nicht ordnungsgemäß ausgeführt wird, führen Sie die folgenden Schritte aus, um sicherzustellen, dass die Umgebung ordnungsgemäß eingerichtet wurde:If the application does not run properly, follow these steps to make sure your environment has been properly set up:

  6. Stellen Sie sicher, dass Sie ausgeführt haben die zum einmaligen Setupverfahren für Windows Communication Foundation-Beispiele.Ensure that you have performed the One-Time Set Up Procedure for the Windows Communication Foundation Samples.

  7. Führen Sie zum Erstellen der Projektmappe die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the solution, follow the instructions in Building the Windows Communication Foundation Sample.

  8. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, rufen Sie Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 auf, um alle Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) - und WFWF -Beispiele herunterzuladen.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Contract\Data\KnownAssemblyAttribute

Siehe auchSee Also