Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ukázka KnownAssemblyAttribute ukazuje, jak lze procesy serializace a deserializace přizpůsobit pomocí třídy DataContractResolver. Tato ukázka ukazuje, jak dynamicky přidávat známé typy během serializace a deserializace.
Ukázkové podrobnosti
Tato ukázka se skládá ze čtyř projektů. Jedna z nich odpovídá službě, která má být hostována službou IIS, která definuje následující kontrakt služby.
// 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);
}
Kontrakt služby se implementuje, jak je znázorněno v následujícím příkladu.
// 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;
}
}
Další projekt se týká klienta, komunikuje se serverem a vyvolává metody, které poskytuje. Definice klienta je znázorněna v následujícím příkladu.
// 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();
}
}
Definice kontraktu služby je označena atributem KnownAssembly . Tento atribut obsahuje název knihovny typů, které jsou všechny známy za běhu jak službou, tak klientem.
Atribut KnownAssembly implementuje IContractBehavior za účelem definice DataContractSerializer, které má DataContractResolver definovaný pro každé chování operace.
DataContractResolver se odráží na sestavení při jeho vytvoření a sestaví slovník s mapováním mezi typy a názvy, které se mají použít při serializaci a deserializaci různých typů. Tímto způsobem musí typy ResolveType a ResolveName vyhledat požadovaná data ve slovníku.
Definice DataContractResolver pro tuto ukázku je znázorněna v následujícím příkladu.
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);
}
}
}
Knihovna typů použitých v této ukázce je znázorněna v následujícím příkladu.
[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 { }
}
}
Mějte na paměti, že ComplexNumber nemusí staticky znát ComplexNumberWithMagnitude typ, protože je znám za běhu.
Při sestavení a spuštění ukázky se jedná o očekávaný výstup získaný v klientovi:
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
Nastavení, spuštění a sestavení ukázky
Klikněte pravým tlačítkem na řešení KnownAssemblyAttribute a vyberte Vlastnosti.
V okně Společné vlastnosti vyberte Spouštěný projekt a potom klepněte na tlačítko Více projektů po spuštění.
Přidejte akci Start do projektů Služby a Klient .
Klikněte na OK a stisknutím klávesy F5 spusťte ukázku.
Pokud se aplikace nespustí správně, postupujte podle těchto kroků a ujistěte se, že je vaše prostředí správně nastavené:
Ujistěte se, že jste provedli One-Time Postup nastavení pro vzorové programy Windows Communication Foundation.
Pokud chcete sestavit řešení, postupujte podle pokynů v Sestavení ukázky Windows Communication Foundation.
Pokud chcete spustit ukázku v konfiguraci pro jeden počítač nebo pro více počítačů, postupujte podle pokynů v Spuštění ukázek Windows Communication Foundation.