Измените имя элемента массива xml в сериализованном объекте ASP.NET WebAPI
Я пытаюсь вывести собственный элемент xml root, возвращая список объектов в моем контроллере WebAPI.
Мой метод контроллера выглядит примерно так:
public List<Product> Get()
{
return repository.GetProducts();
}
который выводит xml-вывод следующим образом:
<ArrayOfProduct>
<Product>
<Name>Product1</Name>
</Product>
<Product>
<Name>Product2</Name>
</Product>
</ArrayOfProduct>
Я хотел бы изменить <ArrayOfProduct>
на <Products>
, но не нашел способа сделать это.
Я пробовал разные варианты атрибутов DataContract
и DataMember
безрезультатно.
Кто-нибудь знает, есть ли способ сделать то, что я хочу, за исключением переноса моего объекта List<Product>
в новый класс и возвращения вместо этого?
Ответы
Ответ 1
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; }
}
Ответ 2
Я знаю, что вы не любите идею обертки, но есть решение, которое несколько использует оболочку, но также использует атрибуты 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>
Пожалуйста, не забудьте посмотреть на указанный сайт.
Ответ 3
Как сказал неуловимый....
[XmlArray("Products")]
public List<Product> Get()
{
return repository.GetProducts();
}
Если у вас проблемы, потому что это метод, попробуйте переопределить его как свойство, так как он не принимает никаких параметров и, вероятно, имеет больше смысла.
[XmlArray("Products")]
public List<Product> Products {
get {
return repository.GetProducts();
}
}
Это будет перечислять все элементы Product
внутри элемента элемента с именем "Продукты".
<Products>
<Product>
<Name>Product1</Name>
</Product>
<Product>
<Name>Product2</Name>
</Product>
</Products>
P.S. Чтобы переименовать теги элементов Product
, вы можете использовать атрибут [XmlArrayItem("Product")]
для этого. Если вы хотите иметь плоский список (не вставляйте их в "Продукты" ), вы можете использовать [XmlElement("Product")]
, и они будут перечислять их без их группировки.
Ответ 4
Я предполагаю, что вы используете NetDataContractSerializer
Вы можете указать имя корневого элемента в конструкторе сериализатора:
NetDataContractSerializer serializer = new NetDataContractSerializer("Products", "Your.Namespace");
Взгляните на различные перегрузки:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.netdatacontractserializer.aspx
Ответ 5
Я столкнулся с той же проблемой и обыскал, но не смог найти правильное решение, поэтому, наконец, решил заменить строку "ArrayOfProduct" на "Продукты", и она работает гладко.
Я знаю, что это плохой способ сделать это, но это быстро.
Ответ 6
Вы должны иметь возможность использовать атрибуты сериализации Xml, как описано здесь
С тех пор я работал с ними, но они были быстрыми и легкими в освоении.
Ответ 7
Я делал это много раз, настраивая вывод сериализации xml. Использование атрибутов в определениях моего класса:
[XmlArray("Products")]
public List<Product> Get()
{
return repository.GetProducts();
}
это даст вам результат, который вы ищете...
Ответ 8
Пожалуйста, проверьте это. Существует некоторая информация о том, как настроить вывод класса в формате xml.
https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute%28v=vs.110%29.aspx
По-моему, речь идет не о wep api, а о конфигурации класса.