Сериализация пар имя / значение в пользовательском объекте через веб-службу
это очень сложный вопрос о том, как сериализовать данные через вызов веб-службы, когда данные не типизированы. Я постараюсь изложить все как можно точнее.
Образец Объекта Хранения:
[Serializable]
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<NameValuePairs> OtherInfo { get; set; }
}
[Serializable]
public class NameValuePairs {
public string Name { get; set; }
public string Value { get; set; }
}
Пример Использования:
[WebMethod]
public List<StorageObject> GetStorageObjects() {
List<StorageObject> o = new List<StorageObject>() {
new StorageObject() {
Name = "Matthew",
Birthday = "Jan 1st, 2008",
OtherInfo = new List<NameValuePairs>() {
new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
}
},
new StorageObject() {
Name = "Joe",
Birthday = "Jan 10th, 2008",
OtherInfo = new List<NameValuePairs>() {
new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
}
}
};
return o;
}
возвращаемое значение от веб-службы:
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<NameValuePairs>
<Name>Hobbies</Name>
<Value>Programming</Value>
</NameValuePairs>
<NameValuePairs>
<Name>Website</Name>
<Value>Stackoverflow.com</Value>
</NameValuePairs>
</OtherInfo>
</StorageObject>
что хочется:
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
Причина & Другие Вещи:
во-первых, я сожалею о длине сообщения, но я также хотел дать воспроизводимый код.
Я хочу его в этом формате, потому что я потребляю веб-службы из PHP. Я хочу легко пойти:
/ / ЭТО IMPORANT
In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".
если это в другом формате, то для меня не было бы никакого способа сделать это вообще. Кроме того, в C# , если я потребляю услугу, я также хотел бы иметь возможность сделать следующий:
/ / ЭТО IMPORANT
In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];
к сожалению, я не уверен, как это сделать. Я смог получить его таким образом, создав пользовательский словарь, который реализовал IXmlSerializer (см. StackOverflow: Словарь IXmlSerializer), однако, он взорвал схему WSDL из воды. Это также слишком сложно и привело к ужасным результатам в моем приложении WinFormsTester!
есть ли способ сделать это ? Какой тип объекта нужно создать ? Есть ли способ сделать это /кроме как сделать строго типизированную коллекцию/ ? Очевидно, если я сделаю это сильно набранным следующим образом:
public class OtherInfo {
public string Hobbies { get; set; }
public string FavoriteWebsite { get; set; }
}
тогда он будет работать отлично, у меня не будет проблем с WSDL, я смогу легко получить доступ к нему из PHP и C# (.OtherInfo.Хобби.)
тем не менее, я бы полностью потерял точку NVP, в том, что я должен был бы заранее знать, что такое список, и он был бы неизменным.. скажем, из базы данных.
спасибо всем!! Надеюсь, мы сможем найти какое-то решение. Вот требования снова:
- схема WSDL не должна ломаться
- пары значений имен (NVP) должны быть сериализованы в формат атрибута
- должно быть легко получить доступ к NVP в PHP по имени ["хобби"]
- должно быть легко получить доступ в C# (и быть совместимым с его генератором Прокси)
- будет легко сериализуемый
- не требуйте от меня строго вводить данные
теперь я / полностью / открыт для ввода на лучший / другой способ сделать это. Я храню некоторую относительно "статическую" информацию (например, имя) и кучу фрагментов данных. Если есть лучший способ, я с удовольствием послушаю.
5 ответов
это похоже на динамические свойства объекта. C# не совсем динамический язык в отличие от javascript или, возможно, PHP может анализировать свойства объекта на лету. Следующие два метода - это то, что я могу придумать. Второй может соответствовать вашим требованиям.
путь поцелуя
держать его простым глупым способом
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public List<string> OtherInfo { get; set; }
}
вы можете иметь пары значений имен, которые разделены на'/'
OtherInfo = {"Hobbies|Programming", "Website|Stackoverflow.com"}
сериализовать формы
<StorageObject>
<Name>Matthew</Name>
<Birthday>Jan 1st, 2008</Birthday>
<OtherInfo>
<string>Hobbies|Programming</string>
<string>Website|Stackoverflow.com</string>
</OtherInfo>
</StorageObject>
динамический путь в C#
сделайте часть пары значений имен элементом XML, чтобы вы могли создавать ее динамически.
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
public XElement OtherInfo { get; set; } // XmlElement for dot net 2
}
вы можете легко создать объект OtherInfo как элемент, ориентированный например,
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..Hobbies xelement & text value..);
OtherInfo.Add( ..WebSite xelement & text value..);
сериализованная форма будет
<OtherInfo>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</OtherInfo>
или построить его как атрибут centric
XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..nvp xattribute Hobbies & value..);
OtherInfo.Add( ..nvp xattribute WebSite & value..);
<OtherInfo>
<nvp n="Hobbies" v="Programming" />
<nvp n="Website" v="Stackoverflow.com" />
</OtherInfo>
для любого динамического языка он может напрямую обращаться к свойствам. В остальном, они могут получить доступ к значению, прочитав XML. Чтение XML хорошо поддерживается большинством framework.
вот на чем я остановился.
Классовую Структуру:
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
[XmlAnyElement("Info")] // this prevents double-nodes in the XML
public XElement OtherInfo { get; set; }
}
использование:
StorageObject o = new StorageObject();
o.OtherInfo.Add(new XElement("Hobbies","Programming");
o.OtherInfo.Add(new XElement("Website","Stackoverflow.com");
выход:
<Info>
<Hobbies>Programming</Hobbies>
<Website>Stackoverflow.com</Website>
</Info>
Я хотел бы поблагодарить всех за их помощь, я действительно ценю помощь и идеи.
как совершенно другой подход к этому, почему бы не подумать о том, чтобы сделать это совершенно по-другому. Есть один метод веб-службы для возврата сериализованного объекта хранения, минус OtherInfo
и другой метод для возврата списка свойств (ключей) для OtherInfo
, и третий, чтобы вернуть список значений для любого ключа. Конечно, потребуется больше поездок туда и обратно в веб-сервис, если вы хотите получить все данные, но решение будет намного проще и гибче.
[Serializable]
public class StorageObject {
public string Name { get; set; }
public string Birthday { get; set; }
[Nonserializable]
public Dictionary<string,List<string>> OtherInfo { get; set; }
}
[WebMethod]
public List<StorageObject> GetStorageObjects() {
// returns list of storage objects from persistent storage or cache
}
[WebMethod]
public List<string> GetStorageObjectAttributes( string name )
{
// find storage object, sObj
return sObj.Keys.ToList();
}
[WebMethod]
public List<string> GetStorageObjectAtributeValues( sting name, string attribute )
{
// find storage object, sObj
return sObj[attribute];
}
посмотрите в систему.XML.Сериализация.Атрибут XmlSerializerAssemblyAttribute. Это позволяет указать пользовательский сериализатор уровня класса. Вы сможете выплюнуть любой XML, который вам нравится.
быстрый способ получить до скорости на них, чтобы использовать сгэн.exe для генерации одного и взглянуть на него с отражателем.
- Oisin
Я не уверен, что это решит вашу проблему (это было бы в C#, но, возможно, не в PHP), но попробуйте использовать Dictionary<string,List<string>> OtherInfo
вместо List<NameValuePairs>
. Тогда "хобби" и "веб-сайты" будут вашими ключами, а ценности-списком хобби или веб-сайтов. Хотя я не уверен, как это будет сериализовано.
вы сможете ссылаться на списки хобби как:
List<string> hobbies = storageObject.OtherInfo["Hobbies"];
[EDIT] см.здесь для универсального XML-сериализуемого словаря. Этот производный класс является единственным вам нужно будет использовать вместо универсального словаря.