#c# #xml #xsd #automapper
#c# #xml #xsd #automapper
Вопрос:
У меня возникли проблемы с настройкой automapper для объектов, сгенерированных в файле .cs из .xsd.
Не совсем уверен, как решить проблему, когда объект имеет несколько атрибутов, как показано ниже:
Просматривал TypeConverters и т.д., Но не совсем уверен, как это правильно настроить. Уже некоторое время использую automapper и не испытываю проблем, пока к одному элементу не подключено несколько атрибутов.
public partial class customerInfo {
private object itemField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("customerInfoBasic", typeof(customerInfoBasic))]
[System.Xml.Serialization.XmlElementAttribute("customerInfoSimple", typeof(customerInfoSimple))]
[System.Xml.Serialization.XmlElementAttribute("customerInfoEnhanced", typeof(customerInfoEnhanced))]
public object Item {
get {
return this.itemField;
}
set {
this.itemField = value;
}
}
}
public partial class customerInfoBasic{
private string nameField;
/// <remarks/>
public string name {
get {
return this.nameField;
}
set {
this.nameField= value;
}
}
}
public partial class customerInfoSimple{
private string nameField;
private string idField;
/// <remarks/>
public string name {
get {
return this.nameField;
}
set {
this.nameField= value;
}
}
public string id {
get {
return this.idField;
}
set {
this.idField= value;
}
}
}
public partial class customerInfoEnhanced{
private string nameField;
private string idField;
private string ageField;
/// <remarks/>
public string name {
get {
return this.nameField;
}
set {
this.nameField= value;
}
}
public string id {
get {
return this.idField;
}
set {
this.idField= value;
}
}
public string age {
get {
return this.ageField;
}
set {
this.ageField= value;
}
}
}
Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю, как настроить его, чтобы CustomerInfo правильно отображался в зависимости от некоторого значения в «Info».
Например, если «Info» содержит «age» и «id», это должно быть сопоставлено с customerInfoEnhanced и т.д.
public static void AddSessionTransformationMappings(IMapperConfiguration cfg)
{
cfg.AllowNullCollections = true;
cfg.CreateMap<IEnumerable<Info>, customerInfoList>()
.ForMember(x => x.customerInfo, x => x.MapFrom(y => y));
cfg.CreateMap<Info, customerInfo>()
.ForMember(x => x.Item, x => x.MapFrom(y => y));
cfg.CreateMap<Info, customerInfoBasic>()
.ForMember(x => x.Name, x => x.MapFrom(y => y.name));
cfg.CreateMap<Info, customerInfoSimple>()
.ForMember(x => x.Name, x => x.MapFrom(y => y.name))
.ForMember(x => x.Id, x => x.MapFrom(y => y.id));
cfg.CreateMap<Info, customerInfoEnhanced>()
.ForMember(x => x.Name, x => x.MapFrom(y => y))
.ForMember(x => x.Id, x => x.MapFrom(y => y.id))
.ForMember(x => x.Age, x => x.MapFrom(y => y.age));
}
Вот также код для сериализатора:
var output = provider.Transform(new List<Info> { input });
customerInfoList actual = null;
XmlSerializer serializer = new XmlSerializer(typeof(customerInfoList));
using (MemoryStream ms = new MemoryStream())
{
serializer.Serialize(ms, output);
ms.Position = 0;
actual = (customerInfoList)serializer.Deserialize(ms);
}
Если я установлю .ForMember(x => x.customerInfo, x => x.MapFrom(y => (Object)null));
код работает, и «actual» выдает мне список с item = null, как и ожидалось, поэтому я знаю, что проблема связана с отображением «Item» в CustomerInfo.
Я ожидаю, что mapper сопоставит с правильным классом, прямо сейчас я получаю либо отсутствующую карту типов, либо «Информация не ожидалась. Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые не известны статически.
Был бы очень признателен за несколько советов о том, как решить проблему!
Комментарии:
1. Классу CustomerInfo нужны три свойства. У вас не может быть одного свойства с тремя разными именами тегов. Единственный другой способ справиться с этим — иметь три класса, которые наследуют один и тот же базовый класс, и тогда вам нужно будет использовать свойство INCLUDE для указания трех унаследованных классов.
2. @jdweng Это то, что я подозревал, поскольку класс CustomerInfo находится в файле .cs, сгенерированном из customers .xsd, я думаю, мне придется попросить их изменить структуру xml-схемы. Спасибо за быстрый ответ!
3. Похоже, им действительно нужен базовый класс CustomerInfo, который имеет три унаследованных класса.
Ответ №1:
Решил это для своих нужд, решение ниже, если кто-то другой столкнется с такой же проблемой.
Решением для меня было использовать ResolveUsing вместо MapFrom для конкретных свойств, у которых было несколько имен тегов, и использовать Mapper.Сопоставьте с правильными классами для разных случаев.
Полный код выглядит следующим образом:
public static void AddSessionTransformationMappings(IMapperConfiguration cfg)
{
cfg.AllowNullCollections = true;
cfg.CreateMap<IEnumerable<Info>, customerInfoList>()
.ForMember(x => x.customerInfo, x => x.MapFrom(y => y));
cfg.CreateMap<Info, customerInfo>()
.ForMember(x => x.Item, x => x.ResolveUsing(y => CustomerInfoLevel(y)));
cfg.CreateMap<Info, customerInfoBasic>()
.ForMember(x => x.Name, x => x.MapFrom(y => y.name));
cfg.CreateMap<Info, customerInfoSimple>()
.ForMember(x => x.Name, x => x.MapFrom(y => y.name))
.ForMember(x => x.Id, x => x.MapFrom(y => y.id));
cfg.CreateMap<Info, customerInfoEnhanced>()
.ForMember(x => x.Name, x => x.MapFrom(y => y.name))
.ForMember(x => x.Id, x => x.MapFrom(y => y.id))
.ForMember(x => x.Age, x => x.MapFrom(y => y.age));
}
private static Object CustomerInfoLevel(Info info)
{
if (info.age != null)
{
return Mapper.Map<customerInfoEnhanced>(info);
}
else if (info.id != null)
{
return Mapper.Map<customerInfoSimple>(info);
}
else
{
return Mapper.Map<customerInfoBasic>(info);
}
}
Комментарии:
1. AM не чувствителен к регистру, поэтому большинство этих MapFrom-ов не нужны.
2. @LucianBargaoanu Да, я в курсе этого, приведенный выше код не является моим фактическим кодом и предназначен только для того, чтобы упростить понимание проблемы и решения. Большое спасибо за совет!