1

I wrote an asmx service on one server1 and and asp.net/c# on another server2.

I want to transfer a dictionary<string,string> from srv1 to srv2. I read Dictionary is not serializable and should be sent as List<KeyValuePair<string,string>>.

on srv2 I try to read the result but it's of type:

KeyValuePairOfStringString[] result = response.GetTemplatesParamsPerCtidResult;

i try to retrieve the key,value but cannot unflat each element:

 foreach (var pair in result)
   {
// pair has just 4 generic methods: toString, GetHashCode,GetType,Equals
   }

How do I do this? Is there anything I should change in my implementation?

TIA

Nivid Dholakia
  • 5,272
  • 4
  • 30
  • 55
Elad Benda
  • 35,076
  • 87
  • 265
  • 471
  • if you know that the return type is not serializable, why not change your contract into something that is consumable by your clients? – rie819 Sep 21 '11 at 14:03
  • List> is serializable, but I have problem deserializing it – Elad Benda Sep 21 '11 at 14:04
  • Why do you say that Dictionary is not serializable? It is, according to this: http://msdn.microsoft.com/en-us/library/xfhwa508.aspx – Icarus Sep 21 '11 at 14:04
  • 3
    It's not XML serializable. http://stackoverflow.com/questions/1124597/why-isnt-there-an-xml-serializable-dictionary-in-net – onof Sep 21 '11 at 14:06
  • Are you setting the DataContractAttribute.IsReference property? http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.isreference(v=vs.95).aspx – rie819 Sep 21 '11 at 14:09
  • @rie819: no need. i'm using a .net class - List> – Elad Benda Sep 21 '11 at 14:12
  • Suggestion: don't use ASMX services! That's a legacy technology. Try this exercise using WCF. – John Saunders Sep 21 '11 at 14:40

2 Answers2

4

How about using an array MyModel[] where MyModel looks like this:

public class MyModel
{
    public string Key { get; set; }
    public string Value { get; set; }
}

Generics should be avoiding when exposing SOAP web services.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • But how do I deserialze response.GetTemplatesParamsPerCtidResult to MyModel? – Elad Benda Sep 21 '11 at 14:14
  • @Elad Benda, you should not deserialize anything. You simply point the web reference to the WSDL of the web service and it generates strongly typed client: `MyModel[] result = client.response.GetTemplatesParamsPerCtid();`. – Darin Dimitrov Sep 21 '11 at 14:18
  • If this is required, there should be a standard type for doing it. Isn't there one? – ozone May 07 '15 at 16:25
1

XmlSerializer won't serialize objects that implement IDictionary by default.

One way around this is to write a new class that wraps an IDictionary object and copies the values into an array of serializable objects.

So you can write a class like that :

public class DictionarySerializer : IXmlSerializable
{
    const string NS = "http://www.develop.com/xml/serialization";

    public IDictionary dictionary;

    public DictionarySerializer() 
    {
        dictionary = new Hashtable();
    }
    public DictionarySerializer(IDictionary dictionary)
    {
        this.dictionary = dictionary;
    }

    public void WriteXml(XmlWriter w)
    {
        w.WriteStartElement("dictionary", NS);
        foreach (object key in dictionary.Keys)
        {
            object value = dictionary[key];
            w.WriteStartElement("item", NS);
            w.WriteElementString("key", NS, key.ToString());
            w.WriteElementString("value", NS, value.ToString());
            w.WriteEndElement();
        }
        w.WriteEndElement();
    }

    public void ReadXml(XmlReader r)
    {
        r.Read(); // move past container
        r.ReadStartElement("dictionary");
        while (r.NodeType != XmlNodeType.EndElement)
        {            
            r.ReadStartElement("item", NS);
            string key = r.ReadElementString("key", NS);
            string value = r.ReadElementString("value", NS);
            r.ReadEndElement();
            r.MoveToContent();
            dictionary.Add(key, value);
        }
    }
    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return LoadSchema();
    }
}

You then create your webservice method with this return type.

[WebMethod]
public DictionarySerializer GetHashTable()
{
    Hashtable ht = new Hashtable();
    ht.Add(1, "Aaron");
    ht.Add(2, "Monica");
    ht.Add(3, "Michelle");
    return new DictionarySerializer (h1);
}

If you need more information, the paper contain some information about this technic.

Patrick Desjardins
  • 136,852
  • 88
  • 292
  • 341