【问题标题】:Rails compatible .NET xml serializationRails 兼容的 .NET xml 序列化
【发布时间】:2010-02-02 16:42:06
【问题描述】:

我正在编写一个带有 REST 端点的 ASP.NET MVC 2 站点。我想在 Rails Web 应用程序中通过 ActiveResource 使用此服务。

到目前为止,我已经设法在 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 属性装饰对象来解决这些问题。但这容易出错且乏味。

有谁知道在.NET 中反序列化由 Rails 的 ActiveResource 序列化的 XML 的更好方法?

【问题讨论】:

  • 你所说的'就像rails一样'是什么意思?单词的顺序让我很困惑。
  • 抱歉,我忘记转义标签,所以它们没有显示出来。现已修复。

标签: .net ruby-on-rails asp.net-mvc xml-serialization


【解决方案1】:

这可以使用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 对象。

【讨论】:

    【解决方案2】:

    是的。

    [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; } 
    } 
    

    【讨论】:

    • 我在问题中指出这种方法有效,但容易出错且乏味。我正在寻找一种不需要装饰每个对象的更好方法。有任何想法吗?谢谢。
    • 您可以使用通过 XmlAttributeOverrides 对象实例化的特殊 XmlSerializer。您必须动态构建 XmlAttributeOverrides 来处理下划线到破折号的约定和小写约定。对于任何类型的对象,它都是一个单一的序列化器类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多