【问题标题】:Modify the xml array element name in serialized ASP.NET WebAPI object修改序列化 ASP.NET WebAPI 对象中的 xml 数组元素名称
【发布时间】:2012-07-22 10:21:33
【问题描述】:

在我的 WebAPI 控制器中返回对象列表时,我一直在努力输出自定义根 xml 元素。

我的控制器方法如下所示:

    public List<Product> Get()
    {
        return repository.GetProducts();
    }

呈现这样的 xml 输出:

<ArrayOfProduct>
  <Product>
    <Name>Product1</Name>
  </Product>
  <Product>
    <Name>Product2</Name>
  </Product>
</ArrayOfProduct>

我想将&lt;ArrayOfProduct&gt; 更改为&lt;Products&gt;,但没有找到这样做的方法。

我尝试了DataContractDataMember 属性的不同变体,但无济于事。

有谁知道是否有一种方法可以做我想做的事,而不是将我的 List&lt;Product&gt; 对象包装在一个新类中并返回它?

【问题讨论】:

标签: c# asp.net xml-serialization asp.net-web-api netdatacontractserializer


【解决方案1】:

我知道您不喜欢包装器的想法,但有一个解决方案在某种程度上使用了包装器,但也使用了非常易于使用的 xml 属性。我拒绝使用以下方法是使用旧的序列化程序。

public class Product
{
    [XmlAttribute( "id" )]
    public int Id
    {
        get;
        set;
    }
    [XmlAttribute( "name" )]
    public string Name
    {
        get;
        set;
    }
    [XmlAttribute( "quantity" )]
    public int Quantity
    {
        get;
        set;
    }
}
[XmlRoot( "Products" )]
public class Products
{
    [XmlAttribute( "nid" )]
    public int Id
    {
        get;
        set;
    }
    [XmlElement(ElementName = "Product")]
    public List<Product> AllProducts { get; set; }
}

现在您的控制器可以返回以下产品:

    public Products Get()
    {
        return new Products
        {
            AllProducts = new List<Product>
            {
                new Product {Id = 1, Name = "Product1", Quantity = 20},
                new Product {Id = 2, Name = "Product2", Quantity = 37},
                new Product {Id = 3, Name = "Product3", Quantity = 6},
                new Product {Id = 4, Name = "Product4", Quantity = 2},
                new Product {Id = 5, Name = "Product5", Quantity = 50},
            }
        };
    }

现在您可以像这样在启动时指定序列化程序:

    var productssXmlFormatter = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
    productssXmlFormatter.SetSerializer<Products>( new XmlSerializer( typeof( Products ) ) );

我知道这不是最理想的方式,因为它必须指定序列化程序并失去 EF 和 Linq 的灵活性和便利性。或者至少必须进行干预,而不仅仅是返回 IEnumerable.

当我第一次从以下站点了解到这种方式时,我必须感谢以下站点:http://justthisguy.co.uk/outputting-custom-xml-net-web-api/

这将产生以下 xml:

<Products nid="0">
    <Product id="1" name="Product1" quantity="20"/>
    <Product id="2" name="Product2" quantity="37"/>
    <Product id="3" name="Product3" quantity="6"/>
    <Product id="4" name="Product4" quantity="2"/>
    <Product id="5" name="Product5" quantity="50"/>
 </Products>

请不要忘记查看列出的网站。

【讨论】:

    【解决方案2】:
    class Program
    {
        static void Main(string[] args)
        {
            HttpConfiguration config = new HttpConfiguration();
    
            DataContractSerializer productsSerializer = new DataContractSerializer(typeof(List<Product>), "Products", String.Empty);
            config.Formatters.XmlFormatter.SetSerializer(typeof(List<Product>), productsSerializer);
    
            config.Formatters.XmlFormatter.Indent = true;
    
            config.Formatters.XmlFormatter.WriteToStreamAsync(
                typeof(List<Product>),
                new List<Product> { new Product { Name = "Product1" }, new Product { Name = "Product2" } },
                Console.OpenStandardOutput(),
                null,
                null).Wait();
    
            Console.WriteLine();
        }
    }
    
    [DataContract(Namespace = "")]
    public class Product
    {
        [DataMember]
        public string Name { get; set; }
    }
    

    【讨论】:

      【解决方案3】:

      正如难以捉摸的所说......

      [XmlArray("Products")]
      public List<Product> Get()
      {
          return repository.GetProducts();
      }
      

      如果您因为它是一种方法而遇到问题,请尝试将其重新定义为属性,因为它不带参数,并且可能更有意义。

      [XmlArray("Products")]
      public List<Product> Products { 
        get {
          return repository.GetProducts();
        }
      }
      

      这将列出名为“Products”的元素元素内的所有Product 项目。

      <Products>
        <Product>
          <Name>Product1</Name>
        </Product>
        <Product>
          <Name>Product2</Name>
        </Product>
      </Products>
      

      附:要重命名 Product 项目标签,您可以使用 [XmlArrayItem("Product")] 属性来执行此操作。如果您想要一个平面列表(不要将它们包装在“产品”中),您可以使用[XmlElement("Product")],这样会在不分组的情况下列出它们。

      【讨论】:

      • 嗨。此代码给我一个错误“xmlarray 在此声明类型上无效”。你能建议出路吗?
      【解决方案4】:

      我猜你正在使用NetDataContractSerializer
      您可以在序列化程序的构造函数中指定根元素名称:

      NetDataContractSerializer serializer = new NetDataContractSerializer("Products", "Your.Namespace");
      

      看看不同的重载:

      http://msdn.microsoft.com/en-us/library/system.runtime.serialization.netdatacontractserializer.aspx

      【讨论】:

      • 谢谢,但我没有手动序列化我的对象。我的操作方法将我的对象返回到System.Web.Http.ApiController,所以我看不到如何控制那里的输出?
      【解决方案5】:

      我遇到了同样的问题并进行了搜索,但找不到任何合适的解决方案,因此最终决定将字符串“ArrayOfProduct”替换为“Products”,并且运行顺利。

      我知道这样做很糟糕,但它很快。

      【讨论】:

        【解决方案6】:

        您应该能够使用here 概述的 Xml 序列化属性

        我已经有一段时间没有和他们合作了,但是他们学习起来又快又容易。

        【讨论】:

          【解决方案7】:

          请检查一下。有一些关于如何以 xml 格式配置类的输出的信息。

          https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute%28v=vs.110%29.aspx

          在我看来,这不是关于 wep api 而是关于类的配置。

          【讨论】:

            【解决方案8】:

            我做过很多次,自定义xml序列化输出。在我的类定义中使用属性:

            [XmlArray("Products")]
            public List<Product> Products
            {
                get { return repository.GetProducts(); }
            }
            

            这应该会给你你正在寻找的输出......

            【讨论】:

            • XmlArrayAttribute 在方法上无效。
            • @PeterHedberg 你是对的。编辑以反映属性语法而不是方法。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多