Сериализация пар Имя / Значение в Пользовательском объекте с помощью веб-сервиса

StackOverflow https://stackoverflow.com/questions/255400

Вопрос

Это очень сложный вопрос, касающийся того, как сериализовать данные с помощью вызова веб-службы, когда данные не являются строго типизированными.Я постараюсь изложить это как можно лучше.

Образец Объекта хранения:

[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, поскольку мне нужно было бы заранее знать, что это за список, и он был бы неизменяемым..скажем, из Базы данных.

Спасибо всем!!Я надеюсь, что мы сможем найти какое-то решение этой проблемы.Вот еще раз требования:

  1. Схема WSDL не должна нарушаться
  2. Пары Имя-значение (NVP) должны быть сериализованы в формат атрибута
  3. Должен быть легкий доступ к NVP в PHP по имени ["Хобби"]
  4. Должен быть легкодоступен на C # (и совместим с его прокси-генератором).
  5. Быть легко сериализуемым
  6. Не требуйте от меня строгого ввода данных

Теперь я / полностью / открыт для обсуждения лучшего / другого способа сделать это.Я храню некоторую относительно "статическую" информацию (например, имя) и кучу фрагментов данных.Если есть способ получше, я бы с удовольствием его послушал.

Это было полезно?

Решение

Это похоже на динамические свойства объекта. 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 сериализуемый словарь. Этот производный класс вам нужно использовать вместо универсального словаря.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top