#c# #.net #json.net #automapper
#c# #.net #json.net #automapper
Вопрос:
У меня есть приведенный ниже код, все работало отлично с использованием AutoMapper v4, но когда я обновился до версии 8, он начинает возвращать null в дочерних свойствах.
Теперь результат [{«Id»: null,»Name»:null},{«Id»:null,»Name»:null}]-TTR0
Что-то не так с моим кодом?
using System;
using System.Collections.Generic;
using AutoMapper;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
public class WarehouseObj{
public Warehouse[] Whs { get; set; }
public string Location { get; set; }
}
public class Warehouse{
public string Id { get; set; }
public string Name {get; set; }
}
public class Program
{
public static void Main()
{
var jsonString = @"{ 'wareh': [{
'wid': '1234',
'wname': 'W0986E'
},{
'wid': '1235',
'wname': 'E0948T'
}], 'lc' : 'TTR0'}";
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<JObject,WarehouseObj>()
.ForMember("Whs", opt=>{ opt.MapFrom(jo => jo["wareh"]); })
.ForMember("Location", opt=>{ opt.MapFrom(jo => jo["lc"]); });
cfg.CreateMap<JObject, Warehouse>()
.ForPath(dest => dest.Id, opt => { opt.MapFrom(src => src["wid"]); })
.ForPath(dest => dest.Name, opt => { opt.MapFrom(src => src["wname"]); });
});
IMapper mapper = config.CreateMapper();
var jArray = JObject.Parse(jsonString);
Console.WriteLine("{0}-{1}",JsonConvert.SerializeObject(mapper.Map<WarehouseObj>(jArray).Whs), mapper.Map<WarehouseObj>(jArray).Location);
}
}
Комментарии:
1. Вы можете увидеть живой код здесь: dotnetfiddle.net/CGUJdA
2. Поскольку в комментариях вы указали, что мой ответ поможет вам решить проблему, пожалуйста, отметьте его как принятый, отметив V слева.
Ответ №1:
Одним из способов решения такой проблемы является десериализация вашей строки json для конкретных классов, таких как
public class Wareh
{
public string wid { get; set; }
public string wname { get; set; }
}
public class Root
{
public List<Wareh> wareh { get; set; }
public string lc { get; set; }
}
Затем вы можете определить свои карты со статически типизированными свойствами источника и назначения, и все будет работать нормально.
Для иллюстрации смотрите Код ниже.
using AutoMapper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
public class WarehouseObj
{
public Warehouse[] Whs { get; set; }
public string Location { get; set; }
}
public class Warehouse
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Wareh
{
public string wid { get; set; }
public string wname { get; set; }
}
public class Root
{
public List<Wareh> wareh { get; set; }
public string lc { get; set; }
}
public class Program
{
public static void Main()
{
var jsonString = @"{ 'wareh': [{
'wid': '1234',
'wname': 'W0986E'
},{
'wid': '1235',
'wname': 'E0948T'
}], 'lc' : 'TTR0'}";
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Root, WarehouseObj>()
.ForMember(dest => dest.Whs, opts => opts.MapFrom(src => src.wareh))
.ForMember(dest => dest.Location, opts => opts.MapFrom(src => src.lc));
cfg.CreateMap<Wareh, Warehouse>()
.ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.wid))
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.wname));
});
IMapper mapper = config.CreateMapper();
var jArray = JsonConvert.DeserializeObject<Root>(jsonString);
var mapped = mapper.Map<WarehouseObj>(jArray);
Console.WriteLine("{0}-{1}", JsonConvert.SerializeObject(mapper.Map<WarehouseObj>(jArray).Whs), mapper.Map<WarehouseObj>(jArray).Location);
}
}
Комментарии:
1. Я исправил это с помощью решения OfirD, я не могу десериализовать его в класс, поскольку исходная структура JSON является общей.
Ответ №2:
Изменение второго сопоставления на JToken
вместо JObject
работает.
Поэтому вместо:
cfg.CreateMap<JObject, Warehouse>()
Используйте:
cfg.CreateMap<JToken, Warehouse>()
- Также обратите внимание, что вы можете использовать
ForMember
вместоForPath
.
Что касается причины, я не совсем уверен. Мое текущее предположение заключается в том, что существует некоторая проблема с синтаксическим JArray
анализом элементов в JObject
s; даже если используется менее сложный json:
var json = @"[{
'wid': '1234',
'wname': 'W0986E'
},{
'wid': '1235',
'wname': 'E0948T'
}]
";
следующее не работает (т. Е. Оно инициализирует Warehouse
свойства с null
помощью):
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<JObject, Warehouse>()
.ForMember(dest => dest.Id, opt => { opt.MapFrom(src => (string)src["wid"]); })
.ForMember(dest => dest.Name, opt => { opt.MapFrom(src => (string)src["wname"]); });
});
IMapper mapper = config.CreateMapper();
var jArray = JArray.Parse(json);
var des = mapper.Map<Warehouse[]>(jArray);
Но изменение его на use JToken
будет работать.
Комментарии:
1.
ForPath()
предлагает гораздо меньший диапазон опций, то естьCondition()
,Ignore()
иMapFrom()
в то времяForMember()
как предлагает дополнительные преобразования, конвертеры, замену null, предварительное условие и многое другое. Информация основана на версии 10.