Automapper:将JSON转换为对象列表

9

源对象(JSON格式,如果有影响请使用JSON.NET):

{
    "conum" : 1001,
    "name" : "CLN Industries Corporation",
    "agencyName" : "Murphy, Holmes & Associates, LLC",
    "sAA" : [{
            "code" : 247,
            "description" : "Mechanic\u0027s lien - Bond to Discharge - Fixed penalty - where principal has posted Performance and Pa"
        }, {
            "code" : 277,
            "description" : "Mechanic\u0027s lien - Bond to Discharge - Open Penalty - where principal has posted Performance and Paym"
        }, {
            "code" : 505,
            "description" : "Indemnity Bonds - Contractor\u0027s Indemnity Against Damages where there is a performance bond and addit"
        }
    ]
}

目标对象 (C#):

public class CorporateRatesInfo
{
    public string Conum { get; set; }
    public string Name { get; set; }
    public string AgencyName { get; set; }
    public List<SaaCode> SaaCodes { get; set; }
}

public class SaaCode
{
    public string Code { get; set; }
    public string Description { get; set; }
}

Automapper配置和映射:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<JObject, CorporateRatesInfo>();
    cfg.AddProfile<CorporateRatesProfile>();
});

//config.AssertConfigurationIsValid();
_mapper = config.CreateMapper();


public class CorporateRatesProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<JObject, CorporateRatesInfo>()
            .ForMember("SaaCodes", cfg => { cfg.MapFrom(jo => jo["sAA"]); })
            .ForMember("Conum", cfg => { cfg.MapFrom(jo => jo["conum"]); })
            .ForMember("Name", cfg => { cfg.MapFrom(jo => jo["name"]); })
            .ForMember("AgencyName", cfg => { cfg.MapFrom(jo => jo["agencyName"]); });
    }
}

除了SaaCodes转换之外,一切正常,其中Automapper将每个条目转换为空的SaaCode对象(所有属性设置为null)。

我应该在哪里告诉automapper如何将JSON字段中的项目转换为其目标类型?


1
您还需要将 JObject 映射到 SaaCode 类。 - Nathan
3个回答

8

试试这个 -

public class CorporateRatesInfo
{
    public string Conum { get; set; }
    public string Name { get; set; }
    public string AgencyName { get; set; }
    public List<SaaCode> SaaCodes { get; set; }
}

public class SaaCode
{
    public string Code { get; set; }
    public string Description { get; set; }
}

public class CorporateRatesProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<JObject, SaaCode>()
            .ForMember("Code", cfg => { cfg.MapFrom(jo => jo["code"]); })
            .ForMember("Description", cfg => { cfg.MapFrom(jo => jo["description"]); });

        CreateMap<JObject, CorporateRatesInfo>()
            .ForMember("SaaCodes", cfg => { cfg.MapFrom(jo => jo["sAA"]); })
            .ForMember("Conum", cfg => { cfg.MapFrom(jo => jo["conum"]); })
            .ForMember("Name", cfg => { cfg.MapFrom(jo => jo["name"]); })
            .ForMember("AgencyName", cfg => { cfg.MapFrom(jo => jo["agencyName"]); });
        

    }
}

class Program
{
    static void Main(string[] args)
    {

        var config = new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<JObject, CorporateRatesInfo>();
            cfg.AddProfile<CorporateRatesProfile>();
        });

        //config.AssertConfigurationIsValid();
        var mapper = config.CreateMapper();

        var jsonText =  @"
                            {
                                ""conum"" : 1001,
                                ""name"" : ""CLN Industries Corporation"",
                                ""agencyName"" : ""Murphy, Holmes & Associates, LLC"",
                                ""sAA"" : [{
                                        ""code"" : 247,
                                        ""description"" : ""Mechanic\u0027s lien - Bond to Discharge - Fixed penalty - where principal has posted Performance and Pa""
                                    }, {
                                        ""code"" : 277,
                                        ""description"" : ""Mechanic\u0027s lien - Bond to Discharge - Open Penalty - where principal has posted Performance and Paym""
                                    }, {
                                        ""code"" : 505,
                                        ""description"" : ""Indemnity Bonds - Contractor\u0027s Indemnity Against Damages where there is a performance bond and addit""
                                    }
                                ]
                            }
                        ";

        var jsonoObj = JObject.Parse(jsonText);

        CorporateRatesInfo dto = mapper.Map<CorporateRatesInfo>(jsonoObj);

        

    }
}

编辑:根据https://docs.automapper.org/en/stable/Configuration.html,Automapper 6及以上版本不支持Configure()方法。因此,我稍微调整了我的答案,采用构造函数的方法。

public class CorporateRatesInfo
{
    public string Conum { get; set; }
    public string Name { get; set; }
    public string AgencyName { get; set; }
    public List<SaaCode> SaaCodes { get; set; }
}

public class SaaCode
{
    public string Code { get; set; }
    public string Description { get; set; }
}

public class CorporateRatesProfile : Profile
{
    public CorporateRatesProfile()
    {
        CreateMap<JToken, SaaCode>()
            .ForMember("Code", cfg => { cfg.MapFrom(jo => jo["code"]); })
            .ForMember("Description", cfg => { cfg.MapFrom(jo => jo["description"]); });

        CreateMap<JToken, CorporateRatesInfo>()
            .ForMember("SaaCodes", cfg => { cfg.MapFrom(jo => jo["sAA"]); })
            .ForMember("Conum", cfg => { cfg.MapFrom(jo => jo["conum"]); })
            .ForMember("Name", cfg => { cfg.MapFrom(jo => jo["name"]); })
            .ForMember("AgencyName", cfg => { cfg.MapFrom(jo => jo["agencyName"]); });
    }
}

class Program
{
    static void Main(string[] args)
    {
        var config = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<CorporateRatesProfile>();
        });
        
        var mapper = config.CreateMapper();
        var jsonText =  @"{""conum"":1001,""name"":""CLN Industries Corporation"",""agencyName"":""Murphy, Holmes & Associates, LLC"",""sAA"":[{""code"":247,""description"":""Mechanic's lien - Bond to Discharge - Fixed penalty - where principal has posted Performance and Pa""},{""code"":277,""description"":""Mechanic's lien - Bond to Discharge - Open Penalty - where principal has posted Performance and Paym""},{""code"":505,""description"":""Indemnity Bonds - Contractor's Indemnity Against Damages where there is a performance bond and addit""}]}";
        var jsonoObj = JObject.Parse(jsonText);
        CorporateRatesInfo dto = mapper.Map<CorporateRatesInfo>(jsonoObj);
    }
}

太好了!我尝试过类似的东西,但我认为源类型将是一个字符串。 :( - SvdSinner
1
CorporateRatesProfile的实现仅适用于4.x版本。在5.0之后,它已经过时,您必须改用此方法(并且更加清晰)http://automapper.readthedocs.io/en/latest/Configuration.html#profile-instances - CokoBWare
1
SaaCodes是空的,它没有映射。 - Baglay Vyacheslav
@BaglayVyacheslav,有没有自动完成这个操作的方法,就像这种情况一样? - Prosy Arceno

3

我写了一个简单的解决方案,如果字段名称匹配,你可以在映射器扩展帮助方法中使用Newtonsoft的反序列化程序。我编写了一个通用的ResolveJson扩展方法。

public static class MapperExtensions
{
    public static T ResolveJson<T>(this JObject jobj, string target)
    {
        return JsonConvert.DeserializeObject<T>(jobj.SelectToken(target).ToString());
    }
}

您可以使用下面的方式调用它:
CreateMap<JObject, CorporateRatesInfo>()
    .ForMember(x => x.SaaCodes,m => { m.MapFrom(s => s.ResolveJson<SaaCode>("sAA"));});

0

很不幸,我在新版本的AutoMapper中遵循了Bookamp的问题,并且努力让它工作。

对于其他发现此问题的人,我的替代方法可以在以下中找到。

示例数组

{
'Items': [{
    'Id': '1',
    'EmployeeNo': '1001',
    'FirstName': 'Rajat',
    'LastName': 'Kumar',
    'Gender': {
        'Id': '1',
        'ShortName': 'M',
        'FullName': 'Male'
    }
}, {
    'Id': '2',
    'EmployeeNo': '1003',
    'FirstName': 'Lisa',
    'LastName': 'David',
    'Gender': {
        'Id': '2',
        'ShortName': 'F',
        'FullName': 'Female'
    }
}]

}

示例配置文件

            CreateMap<JObject, List<User>>().ConvertUsing<JObjectToUserListConverter>();
        var employeeMap = CreateMap<JToken, User>();

        employeeMap.ForMember(x => x.Id, y => y.MapFrom(j => j.SelectToken(".Id")));
        employeeMap.ForMember(x => x.DisplayName, y => y.MapFrom(j => j.SelectToken(".LastName").ToString() + ", " + j.SelectToken(".FirstName").ToString()));
        employeeMap.ForMember(x => x.Gender, y => y.MapFrom(j => j.SelectToken(".Gender.FullName")));

        employeeMap.ForMember(x => x.Login, y => y.MapFrom(j => j.SelectToken(".Login")));

类型转换器

public class JObjectToUserListConverter : ITypeConverter<JObject, List<User>>
{
    public List<User> Convert(JObject source, List<User> destination, ResolutionContext context)
    {

        var userList = new List<User>();
        var tokenCountItems = source.SelectTokens("Items").Children().Count();
        for (int i = 0; i < tokenCountItems; i++)
            {
                var token = source.SelectToken($"Items[{i}]");
                var result = new User();

                if (token != null)
                {
                    result = context.Mapper.Map<JToken, User>(token);
                }
                userList.Add(result);
            }
        }

        return userList;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接