8 Stimmen

Wie man ein vererbtes Wörterbuch über WCF implementiert

Ich versuche, ein Wörterbuch für die Verwendung mit WCF zu implementieren. Meine Anforderungen sind:

  • actual (private Variable oder Basis Klasse) entspricht dem Typ Wörterbuch
  • Komparator = System.StringComparer.InvariantCultureIgnoreCase
  • Custom (override/new) Add(key, Wert) Methode (zur Einbeziehung von Validierungen).
  • Override ToString()
  • Verwendung desselben Typs sowohl auf dem Client als auch auf dem Host

Ich habe versucht, diese Klasse in einem gemeinsamen Projekt zu verwenden, das von den WCF-Host- und Clientprojekten gemeinsam genutzt wird:

[Serializable]
public class MyDictionary : Dictionary<string, object>
{
  public MyDictionary()
    : base(System.StringComparer.InvariantCultureIgnoreCase)
  { }

  public new void Add(string key, object value)
  { /* blah */ }

  public override string ToString()
  { /* blah */ }
}

[DataContract]
[KnownType(typeof(MyDictionary))]
[KnownType(typeof(object[]))]
[KnownType(typeof(double[]))]
[KnownType(typeof(string[]))]
[KnownType(typeof(DateTime[]))]
public class ResultClass
{
  public object Value{ get; set; }
  /* More properties */
}
public class ParmData
{
  public object Value{ get; set; }
  /* More properties */
}
[DataContract]
[KnownType(typeof(MyDictionary))]
[KnownType(typeof(object[]))]
[KnownType(typeof(double[]))]
[KnownType(typeof(string[]))]
[KnownType(typeof(DateTime[]))]
public class ParameterClass
{
  public List<ParmData> Data{ get; set; }
  /* More properties */
}

[OperationContract]
ResultClass DoSomething(ParameterClass args);

Ergebnisse:

  • Wenn ich MyDictionary als eines der Elemente ParameterClass.Data.Value übergebe, erhalte ich eine fehlende KnownType-Ausnahme.
  • Ich kann sicher MyDictionary in der ResultClass zurückgeben, aber es ist nicht mehr mein Typ. Es ist nur ein Dictionary, und kann nicht in MyDictionary . Auch comparer = System.Collections.Generic.GenericEqualityComparer<string> nicht der von der Groß- und Kleinschreibung unabhängige Vergleicher, den ich suche.

Die Hilfe, um die ich bitte, besteht darin, entweder meinen gescheiterten Versuch zu korrigieren oder einen völlig anderen Weg zu finden, um meine Anforderungen zu erfüllen. Jede Lösung sollte nicht das Kopieren eines Wörterbuchs in ein anderes beinhalten.

Danke

0 Stimmen

Ist ein NetDataContractAttribute eine brauchbare Option? Das heißt, können Sie Kopien derselben Assembly mit Ihrer MyDictionary-Klasse sowohl auf der Client- als auch auf der Serverseite garantiert zur Verfügung stellen?

0 Stimmen

Danke für die Antwort auf meinen Beitrag - aber Sie haben nicht geantwortet: funktioniert der Code, den ich gepostet habe, mit Ihrer Einrichtung? Oder löst er eine Ausnahme aus (oder bringt die Daten nicht zurück)?

0 Stimmen

Marc - Ich habe nur 1 Versuch mit deinem Test gemacht. clone.Data hat eine Nullwert-Ausnahme geworfen. Vielen Dank für die Hilfe, aber jezell wies mich in die richtige allgemeine Richtung.

10voto

jezell Punkte 2522

Hinzufügen von CollectionDataContract zur Klasse Dictionary:

Weitere Informationen über die Verwendung von Erhebungsdatenverträgen zur Implementierung von Wörterbüchern finden Sie unter diesem Link:

http://msdn.microsoft.com/en-us/library/aa347850.aspx

1voto

Marc Gravell Punkte 970173

Präambel: Beachten Sie, dass das Hinzufügen eines "neuen" Add hält die Leute nicht davon ab, den alten Add einfach durch einen Wurf. Was "mex" betrifft, so ist dies ein sehr vager Datenvertrag - muss er so offen sein? (viele object etc...)

Erstens: Haben Sie nicht ein paar Dinge verpasst? [DataContract] / [DataMember] Markierungen dort? Im Besonderen:

  • ErgebnisKlasse.Wert
  • ParamData
  • ParamData.Wert
  • ParameterKlasse.Daten

Können Sie Folgendes klarstellen genau Welche Version von .NET verwenden Sie? DataContractSerializer usw. wurden über Service Packs optimiert. Mit 3.5 SP1 installiert (das einzige, was ich zur Hand haben) tut es zumindest serialisieren und deserialisieren über DataContractSerializer (kein WCF-Stack), und die korrekte Add Methode aufgerufen wird.

Können Sie überprüfen, ob das Folgende mit Ihrer lokalen Version funktioniert? (bei mir funktioniert es mit 3.5 SP1 und mit den fehlenden Attributen) [output first]:

1
MyDictionary
abc=123
def=ghi

Code:

        // or long-hand in C# 2.0
        ParameterClass pc = new ParameterClass {
            Data = new List<ParmData> { new ParmData {
                Value = new MyDictionary  {
                    {"abc",123},
                    {"def","ghi"}
                }}}};
        DataContractSerializer dcs = new DataContractSerializer(pc.GetType());
        string xml;
        using(StringWriter sw = new StringWriter())
        using(XmlWriter xw = XmlWriter.Create(sw)) {
            dcs.WriteObject(xw, pc);
            xw.Close();
            xml = sw.ToString();
        }
        using(StringReader sr = new StringReader(xml)) {
            ParameterClass clone = (ParameterClass)dcs.ReadObject(XmlReader.Create(sr));
            Console.WriteLine(clone.Data.Count);
            Console.WriteLine(clone.Data[0].Value.GetType().Name);
            MyDictionary d = (MyDictionary)clone.Data[0].Value;
            foreach (KeyValuePair<string, object> pair in d)
            {
                Console.WriteLine("{0}={1}", pair.Key, pair.Value);
            }
        }

Offensichtlich werden hier nur Tests durchgeführt DataContractSerializer (ohne den gesamten WCF-Stack), aber es scheint zu funktionieren... also: funktioniert derselbe Code auch mit Ihrer lokalen Version von .NET? Wenn nicht, ist die Installation des neuesten 3.0 Service Packs eine Option? (idealerweise über die Installation von 3.5 SP1).

Zur Information erhalte ich xml:

<?xml version="1.0" encoding="utf-16"?><ParameterClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/"><Data><ParmData><Value xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:type="d4p1:ArrayOfKeyValueOfstringanyType"><d4p1:KeyValueOfstringanyType><d4p1:Key>abc</d4p1:Key><d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">123</d4p1:Value></d4p1:KeyValueOfstringanyType><d4p1:KeyValueOfstringanyType><d4p1:Key>def</d4p1:Key><d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">ghi</d4p1:Value></d4p1:KeyValueOfstringanyType></Value></ParmData></Data></ParameterClass>

1voto

chilltemp Punkte 8596
  • Verwenden Sie die CollectionDataContract Attribut wie von Jezell vorgeschlagen
  • Generieren Sie den Referenzcode (Proxy) manuell mit SvcUtil, indem Sie den Parameter /collectionType verwenden. Dieser Parameter wird von der vs2008 Service Reference GUI nicht unterstützt.

Fuente: Gemeinsame Nutzung von WCF-Sammlungsarten

1voto

Shaun Bowe Punkte 9412

Ich habe endlich einen Weg gefunden, dies zu tun. Ich fand dieser Link die in die richtige Richtung weisen, aber ich werde versuchen, sie zusammenzufassen.

  1. Stellen Sie sicher, dass Sie Folgendes hinzufügen [CollectionDataContract] zu Ihrer persönlichen Sammlung
  2. Fügen Sie eine Service-Referenz über VS hinzu, wie Sie es normalerweise tun
  3. Erweitern Sie die Dienstreferenz und suchen Sie die Datei Reference.svcmap
  4. Unter dem Knoten Client-Optionen sehen Sie

<CollectionMappings/>

Ersetzen Sie sie durch die folgende xml.

<CollectionMappings>
  <CollectionMapping TypeName="Full.Namespace.Here" Category="List" />
</SammlungZuordnungen>

  1. Klicken Sie mit der rechten Maustaste auf die Servicereferenz und klicken Sie auf Aktualisieren. Die "Proxy"-Klasse sollte nun nicht mehr generiert werden und Sie können Ihre gemeinsame Klasse verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X