Сериализация пар Имя / Значение в Пользовательском объекте с помощью веб-сервиса
-
05-07-2019 - |
Вопрос
Это очень сложный вопрос, касающийся того, как сериализовать данные с помощью вызова веб-службы, когда данные не являются строго типизированными.Я постараюсь изложить это как можно лучше.
Образец Объекта хранения:
[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.Я хочу легко уйти:
// ЭТО ВАЖНО
In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".
Если бы это было в другом формате, то у меня вообще не было бы возможности это сделать.Кроме того, в C #, если я использую сервис, я также хотел бы иметь возможность выполнять следующее:
// ЭТО ВАЖНО
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.Hobbies).
Тем не менее, я бы полностью потерял смысл NVP, поскольку мне нужно было бы заранее знать, что это за список, и он был бы неизменяемым..скажем, из Базы данных.
Спасибо всем!!Я надеюсь, что мы сможем найти какое-то решение этой проблемы.Вот еще раз требования:
- Схема WSDL не должна нарушаться
- Пары Имя-значение (NVP) должны быть сериализованы в формат атрибута
- Должен быть легкий доступ к NVP в PHP по имени ["Хобби"]
- Должен быть легкодоступен на C # (и совместим с его прокси-генератором).
- Быть легко сериализуемым
- Не требуйте от меня строгого ввода данных
Теперь я / полностью / открыт для обсуждения лучшего / другого способа сделать это.Я храню некоторую относительно "статическую" информацию (например, имя) и кучу фрагментов данных.Если есть способ получше, я бы с удовольствием его послушал.
Решение
Это похоже на динамические свойства объекта. C # не совсем динамический язык в отличие от javascript или, может быть, PHP может анализировать свойства объекта на лету. Следующие два метода - это то, о чем я могу думать. Второй может соответствовать вашим требованиям.
Путь KISS
Глупый способ держать его простым
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>
или создайте его как ориентированный на атрибут
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 хорошо поддерживается большинством фреймворков.
Другие советы
Это то, на чем я остановился.
Классовая структура:
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
и другой метод для возврата списка свойств (ключей) для <=>, а третий - для возврата списка значений для любого ключа. Конечно, если вы захотите получить все данные, потребуется больше циклических переходов к веб-службе, но решение будет намного проще и гибче.
[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];
}
Взгляните на System.Xml.Serialization.Атрибут XmlSerializerAssemblyAttribute.Это позволяет вам указать пользовательский сериализатор уровня класса.Вы сможете использовать любой XML-файл, который вам понравится.
Быстрый способ освоиться с ними - использовать sgen.exe для создания одного из них и взглянуть на него с помощью Reflector.
-Ойсин
Я не уверен, что это решит вашу проблему (как в C #, но, возможно, не в PHP), но попробуйте использовать Dictionary<string,List<string>> OtherInfo
вместо List<NameValuePairs>
. Тогда & Quot; Хобби & Quot; и " сайты " будут ваши ключи и значения будут список хобби или веб-сайтов. Я не уверен, как это будет сериализовать.
Вы можете ссылаться на списки хобби как:
List<string> hobbies = storageObject.OtherInfo["Hobbies"];
[РЕДАКТИРОВАТЬ] См. здесь для получения информации о универсальный XML сериализуемый словарь. Этот производный класс вам нужно использовать вместо универсального словаря.