KnownAssemblyAttribute
Exemplet KnownAssemblyAttribute visar hur serialiserings- och deserialiseringsprocesserna kan anpassas med hjälp DataContractResolver av klassen. Det här exemplet visar hur du dynamiskt lägger till kända typer under serialisering och deserialisering.
Exempelinformation
Det här exemplet består av fyra projekt. En av dem motsvarar tjänsten, som ska hanteras av IIS, som definierar följande tjänstkontrakt.
// 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);
}
Tjänstkontraktet implementeras enligt följande exempel.
// 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;
}
}
Ett annat projekt motsvarar klienten, som kommunicerar med servern och anropar de metoder som den exponerar. Definitionen av klienten visas i följande exempel.
// 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();
}
}
Definitionen av tjänstkontraktet är markerad med attributet KnownAssembly
. Det här attributet innehåller namnet på ett bibliotek med typer, som alla blir kända vid körning av både tjänsten och klienten.
Attributet KnownAssembly
implementeras IContractBehavior
för att definiera en DataContractSerializer
med en definierad för var och en DataContractResolver
av åtgärdsbeteendena. Reflekterar DataContractResolver
över sammansättningen när den skapas och skapar ordlistan med mappningen mellan typer och namn som ska användas vid serialisering och deserialisering av de olika typerna. På så sätt måste typerna ResolveType
och ResolveName
leta upp de data som krävs i ordlistan.
Det DataContractResolver
definierade för det här exemplet visas i följande exempel.
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);
}
}
}
Biblioteket med typer som används i det här exemplet visas i följande exempel.
[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 { }
}
}
Observera att ComplexNumber
du inte behöver känna ComplexNumberWithMagnitude
till typen statiskt eftersom den blir känd vid körning.
När exemplet skapas och körs är det här de förväntade utdata som hämtas i klienten:
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
Så här konfigurerar du, kör och skapar exemplet
Högerklicka på lösningen KnownAssemblyAttribute och välj Egenskaper.
I Vanliga egenskaper väljer du Startprojekt och klickar sedan på Flera startprojekt.
Lägg till startåtgärden i service- och klientprojekten.
Klicka på OK och tryck på F5 för att köra exemplet.
Om programmet inte körs korrekt följer du dessa steg för att kontrollera att din miljö har konfigurerats korrekt:
Kontrollera att du har utfört engångskonfigurationsproceduren för Windows Communication Foundation-exemplen.
Skapa lösningen genom att följa anvisningarna i Skapa Windows Communication Foundation-exemplet.
Om du vill köra exemplet i en konfiguration med en eller flera datorer följer du anvisningarna i Köra Windows Communication Foundation-exempel.