简体   繁体   English

修改序列化ASP.NET WebAPI对象中的xml数组元素名称

[英]Modify the xml array element name in serialized ASP.NET WebAPI object

I have been struggling with outputting a custom root xml element when returning a list of objects in my WebAPI controller. 在WebAPI控制器中返回对象列表时,我一直在努力输出自定义根xml元素。

My controller method looks something like this: 我的控制器方法如下所示:

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

which renders an xml output like this: 呈现如下的xml输出:

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

I would like to change <ArrayOfProduct> to <Products> but haven't found a way of doing so. 我想将<ArrayOfProduct>更改为<Products>但是还没有找到一种方法。

I have tried different variations of the DataContract and DataMember attributes to no avail. 我尝试了DataContractDataMember属性的不同变体但无济于事。

Does anyone know if there is a way of doing what I want, short of wrapping my List<Product> object in a new class and returning that instead? 有谁知道是否有一种方法可以完成我的工作,而无需将List<Product>对象包装到新类中并返回它?

I know you are not fond of the wrapper idea but there is a solution that somewhat uses a wrapper but also uses the xml attributes which are very easy to work with. 我知道您不喜欢包装器的想法,但是有一种解决方案某种程度上使用包装器,但也使用非常易于使用的xml属性。 My refusal to using the following approach is the use of the old serializer. 我拒绝使用以下方法是使用旧的序列化程序。

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

Now your controller can just return Products like: 现在,您的控制器可以退货,例如:

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

now you can specify the serializer in start-up like so: 现在您可以在启动时指定序列化器,如下所示:

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

I know it is not the most ideal way as to having to specify the serializer and losing the flexability and convenience of EF and Linq. 我知道,这不是指定序列化程序并失去EF和Linq的灵活性和便利性的最理想方法。 Or at least having to intervene rather than just returning IEnumerable<>. 或者至少必须进行干预,而不仅仅是返回IEnumerable <>。

I have to give credit to the following site as I first learned of this way from the site at: http://justthisguy.co.uk/outputting-custom-xml-net-web-api/ 我必须首先从以下站点了解到以下站点,这是该站点: http : //justthisguy.co.uk/outputting-custom-xml-net-web-api/

This will result in the following xml: 这将导致以下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>

Please don't forget to look at the site listed. 请不要忘记查看列出的站点。

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

As elusive said.... 就像难以捉摸的说...

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

If you are having issues because it is a method, then try redefining it as a property since it takes no parameters, and probably makes more sense. 如果由于它是方法而遇到问题,请尝试将其重新定义为属性,因为它不带参数,并且可能更有意义。

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

That will list all Product items inside an element element named 'Products'. 这将列出名为“产品”的元素元素内的所有Product项目。

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

PS To rename the Product item tags you can use the [XmlArrayItem("Product")] attribute to do this. PS要重命名Product项标签,可以使用[XmlArrayItem("Product")]属性来执行此操作。 If you want to have a flat list (don't wrap them in 'Products'), you can use the [XmlElement("Product")] and that will list them without grouping them. 如果您想拥有一个平面列表(不要将它们包装在“产品”中),则可以使用[XmlElement("Product")] ,这样就可以列出它们而不进行分组。

I guess you're using NetDataContractSerializer 我猜你在用NetDataContractSerializer
You can specify the root element name in the serializer's constructor : 您可以在序列化程序的构造函数中指定根元素名称:

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

Take a look at the differents overloads : 看一下differences重载:

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

I was facing the same issue and searched but could not found any proper solution so finally decided to replace the string "ArrayOfProduct" with "Products" and it is working smooth. 我遇到了同样的问题,并进行了搜索,但找不到任何合适的解决方案,因此最终决定将字符串“ ArrayOfProduct”替换为“ Products”,并且运行顺利。

I know it is bad way to do this but it is quick. 我知道这样做很不好,但是很快。

You should be able to use Xml serialization attirbues as outlined here 您应该能够使用此处概述的Xml序列化属性

Its been a while since I've worked with them, but they were quick and easy to learn. 自从我与他们合作以来已经有一段时间了,但是他们很快又容易学习。

I have done this many times, customizing xml serialization output. 我做了很多次,自定义xml序列化输出。 Using attributes in my class definitions: 在类定义中使用属性:

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

this should get you the output you are seeking... 这应该为您提供您正在寻找的输出...

Please check this out. 请检查一下。 There is some information about how to configure the output of the class in xml format. 有关如何配置xml格式的类的输出的一些信息。

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

In my opinion, it is not about the wep api but the configuration of the class. 我认为,这与wep api无关,而与类的配置有关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM