0%

AutoMapper與Json.NET JObject對應問題

使用套件:
Json.NET 7.0.1 : https://www.nuget.org/packages/Newtonsoft.Json/7.0.1
AutoMapper 4.04 : https://www.nuget.org/packages/AutoMapper/4.0.4

今天碰到一個問題,就是有個API回傳值的欄位是不固定無法掌握的,所以只好在轉型成強型別時以object當做該屬性的類別,但JsonConvert碰到類別為Object的東西就會轉成JObject ,而AutoMapper對應JObject會炸掉。以下是簡單時間的範例Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Main()
{
Mapper.CreateMap<source, destination>()
.ForMember(d => d.d_name, o => o.MapFrom(s => s.name))
.ForMember(d => d.d_obj, o => o.MapFrom(s => s.obj));

source test = new source
{
name = "test",
obj = new {code = 100},
};

var result = Mapper.Map<destination>(test);
result.Dump();
}

public class source
{
public string name { get; set; }
public object obj { get; set; }
}

public class destination
{
public string d_name { get; set; }
public object d_obj { get; set; }
}

Source與Destination都有個property為object的類別屬性,在Main()裡面也想好兩個類別的對應關係,並且先準備好Source 然後透過AutoMapper轉出Result,在以上的範例執行正確沒問題

換個寫法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Main()
{
Mapper.CreateMap<source, destination>()
.ForMember(d => d.d_name, o => o.MapFrom(s => s.name))
.ForMember(d => d.d_obj, o => o.MapFrom(s => s.obj));

source test = JsonConvert.DeserializeObject<source>("{\"name\":\"test\",\"obj\" : {\"code\":100}}");
var result = Mapper.Map<destination>(test);
result.Dump();
}

public class source
{
public string name { get; set; }
public object obj { get; set; }
}

public class destination
{
public string d_name { get; set; }
public object d_obj { get; set; }
}

差別只在於原本Source改成透過Json.Net由字串轉回來而已,這時候只要執行到AutoMapper那一行就會爆炸,錯誤訊息如下

AutoMapperMappingException:

Mapping types:
JObject -> JObject
Newtonsoft.Json.Linq.JObject -> Newtonsoft.Json.Linq.JObject

Destination path:
destination.d_obj.d_obj

Source value:
{
“code”: 100
}

JsonConvert碰到目標為Object型別的欄位,會轉成JObject塞進去,AutoMapper用它來對應,
所以如果要解決這個問題需要做一些處理

1
2
3
4
5
6
7
8
9
10
11
12
13
//將Mapper改成如下
Mapper.CreateMap<source, destination>()
.ForMember(d => d.d_name, o => o.MapFrom(s => s.name))
.ForMember(d => d.d_obj, o => o.ResolveUsing(s =>
{
if (s.obj is JObject)
{
var temp = s.obj as JObject;
return temp.ToObject<Dictionary<string, object>>();
}
return s.obj;
}));

這樣就可以正確地取出了