Совместимая с Rails сериализация .NET xml - PullRequest
1 голос
/ 02 февраля 2010

Я пишу сайт ASP.NET MVC 2 с конечными точками REST. Я хочу использовать этот сервис с ActiveResource в веб-приложении Rails.

До сих пор мне удалось настроить маршруты в ASP.NET MVC, которые соответствуют соглашениям ActiveResource. Но у меня проблемы с десериализацией данных, которые ActiveResource отправляет службе REST.

Кажется, что Rails делает сериализацию xml очень отличающейся от .NET (но я не смог найти эти соглашения, документированные где-либо) Например, с классом .NET, подобным этому:

public class Person
{
  public string first_name { get; set; }
  public string last_name { get; set; }
  public bool active { get; set; }
}

Вот некоторые различия:

  1. .NET сериализует корень как , в то время как rails делает
  2. .NET добавляет пространство имен, в то время как rails не
  3. .NET сериализует свойства наподобие , а rails делает
  4. .NET сериализует bool как , в то время как rails делает

Кажется, что номер 4 не вызывает никаких проблем, но другие 3 заставляют .NET не десериализовать сообщение. Вы можете решить эти проблемы, украсив объект атрибутами XmlRoot и XmlElement. Но это подвержено ошибкам и утомительно.

Кто-нибудь знает лучший способ десериализации XML в .NET, который был сериализован ActiveResource Rails?

Ответы [ 2 ]

2 голосов
/ 04 февраля 2010

Это может быть достигнуто с помощью XmlAttributeOverrides .

Ниже приведен базовый пример, GetOverrides() является важной частью:

public class RailsXmlSerializer
{
  private Type type;

  public RailsXmlSerializer(Type type)
  {
    this.type = type;
  }

  public void Serialize(Stream stream, object o)
  {
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("", "");

    XmlSerializer xmlSerializer = new XmlSerializer(type, GetOverrides(type));
    xmlSerializer.Serialize(stream, o, ns);
  }

  public object Deserialize(Stream stream)
  {
    XmlSerializer xmlSerializer = new XmlSerializer(type, GetOverrides(type));
    return xmlSerializer.Deserialize(stream);
  }

  private XmlAttributeOverrides GetOverrides(Type type)
  {
    XmlAttributeOverrides overrides = new XmlAttributeOverrides();

    XmlAttributes classAttributes = new XmlAttributes();
    classAttributes.XmlType = new XmlTypeAttribute(type.Name.ToLower());
    overrides.Add(type, classAttributes);

    foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(type))
    {
      XmlAttributes propertyAttributes = new XmlAttributes();
      propertyAttributes.XmlElements.Add(new XmlElementAttribute(property.Name.ToLower().Replace('_', '-')));
      overrides.Add(type, property.Name, propertyAttributes);
    }

    return overrides;
  }
}

Очевидно, что это должна быть более надежная реализация, возможно, в качестве декоратора для XmlSerializer , с проверкой ошибок и типов. Конечно, GetOverrides() также может быть настроен для получения желаемого результата. Тем не менее, вот результирующий вывод с учетом образца Person объекта:

<?xml version="1.0" encoding="utf-16"?>
<person>
  <first-name>Jason</first-name>
  <last-name>Bourne</last-name>
  <active>true</active>
</person>

И, учитывая этот ввод, десериализация также выполняется правильно, чтобы обеспечить надлежащий объект Person.

1 голос
/ 03 февраля 2010

да.

[XmlType("person",   // issue #1
     Namespace="")]  // issue #2
public class Person 
{ 
  [XmlElement("first-name")]  // issue #3
  public string first_name { get; set; } 

  [XmlElement("last-name")]  // issue #3
  public string last_name { get; set; } 

  public bool active { get; set; } 
} 
...