Как вернуть универсальный словарь в веб-сервис
Я хочу веб-сервис в C#, который возвращает словарь, в соответствии с поиском:
Dictionary<int, string> GetValues(string search) {}
Веб-служба компилируется нормально, однако, когда я пытаюсь сослаться на нее, я получаю следующую ошибку: "не поддерживается, потому что она реализует IDictionary".
¿Что я могу сделать, чтобы заставить это работать? Какие-либо идеи, не связанные с возвращением DataTable?
5 ответов
В этой статье есть метод для сериализации IDictionaries. Ищите "Я заметил, что XmlSerializer не будет сериализовать объекты, которые реализуют IDictionary по умолчанию. Есть ли способ обойти это?" около 2/3 пути вниз по странице.
Там нет "по умолчанию" способ взять словарь и превратить его в XML. Вы должны выбрать способ, и клиенты вашего веб-сервиса должны будут знать об этом точно так же, когда они используют ваш сервис. Если и клиент, и сервер являются.NET, то вы можете просто использовать один и тот же код для сериализации и десериализации словарей в XML на обоих концах.
В этом блоге есть код для этого. Этот код использует сериализацию по умолчанию для ключей и значений словаря, что полезно, когда у вас есть не строковые типы для обоих. Код использует наследование, чтобы сделать свое дело (вы должны использовать этот подкласс для хранения ваших значений). Вы также можете использовать подход типа обертки, как это было сделано в последнем пункте этой статьи, но обратите внимание, что код в этой статье просто использует ToString, поэтому вы должны объединить его с первой статьей.
Поскольку я согласен с Джоэлом в том, что Stackru является каноническим источником всего, ниже приведена копия кода из первой ссылки. Если вы заметили какие-либо ошибки, отредактируйте этот ответ!
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
this.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
foreach (TKey key in this.Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
TValue value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
#endregion
}
Создать тип MyKeyValuePair<K,V>
и вернуть List<MyKeyValuePair<int,string>>
скопировано из словаря.
Я использую этот класс утилит для сериализации словарей, может быть, это может быть полезно для вас
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Utils {
///<summary>
///</summary>
public class SerializableDictionary : IXmlSerializable {
private readonly IDictionary<int, string> dic;
public DiccionarioSerializable() {
dic = new Dictionary<int, string>();
}
public SerializableDictionary(IDictionary<int, string> dic) {
this.dic = dic;
}
public IDictionary<int, string> Dictionary {
get { return dic; }
}
public XmlSchema GetSchema() {
return null;
}
public void WriteXml(XmlWriter w) {
w.WriteStartElement("dictionary");
foreach (int key in dic.Keys) {
string val = dic[key];
w.WriteStartElement("item");
w.WriteElementString("key", key.ToString());
w.WriteElementString("value", val);
w.WriteEndElement();
}
w.WriteEndElement();
}
public void ReadXml(XmlReader r) {
if (r.Name != "dictionary") r.Read(); // move past container
r.ReadStartElement("dictionary");
while (r.NodeType != XmlNodeType.EndElement) {
r.ReadStartElement("item");
string key = r.ReadElementString("key");
string value = r.ReadElementString("value");
r.ReadEndElement();
r.MoveToContent();
dic.Add(Convert.ToInt32(key), value);
}
}
}
}
Это решение с SerializableDictionary прекрасно работает, но во время работы Вы можете получить
cannot convert from 'SerializableDictionary<string,string>' to 'System.Data.DataSet'
ошибка. В этом случае вам нужно перейти Project-> Show all files, а затем отредактировать тип аргумента в SerializableDictionary в файле Reference.cs веб-сервиса. Это официальная ошибка Microsoft, более подробно здесь: