Search code examples
c#jsonasp.net-coreautomapper

Anyway to use Automapper when destination contains JArray property?


Let say I have a source JObject:

var source = new JObject
                        {
                            { "XCV", Guit.NewGuid().ToString() },
                            { "store", "abc" },
                            { "productAId", "123" },
                            { "productAName", "xxxxxx" },
                            { "productBId", "456" },
                            { "productBName", "yyyyyy" },

                        };

And a custom model:

public class StoreProductModel
{
        public string TransactionId { get; set; }
        public JArray Data { get; set; }
}

If I transform StoreProductModel to json I am expecting the structure like:

{
  "transactionId": "...",
  "data": [
{
  "store": "abc",
  "productA": {
      "id": "123",
      "name": "xxxxxx",
    },
  "productB": {
      "id": "456",
      "name": "yyyyyy"
    }
}
]
}

What I tried as simple as possible:

#region JValue - object 
            CreateMap<JValue, object>().ConvertUsing(source => source.Value);
            #endregion
#region JObject - StoreProductModel

            CreateMap<JObject, StoreProductModel>()
                .ForMember(dest => dest.TransactionId, opt => { opt.MapFrom(src => src["XCV"]); })
                .ForPath(dest => dest.Data[0]["productA"]["id"], opt => { opt.MapFrom(src => src["productAId"]); })
                .ForPath(dest => dest.Data[0]["productA"]["name"], opt => { opt.MapFrom(src => src["productAName"]); });
#endregion

Exception I got:

"Only member accesses are allowed. dest => dest.Data.get_Item(0).get_Item("productA").get_Item("id") (Parameter 'destinationMember')"} System.ArgumentOutOfRangeException

I do have an option to directly initialize the StoreProductModel and assign the values, but looking for some suggestions if it is possible to achieve the goal to map from a JObject source to a custom model with nested properties in JArray.

Automapper version: 12.0.1


Solution

  • you don't need any mapper in this case

    var s = ...your source JObject
    
    StoreProductModel storeProductModel = new StoreProductModel
    {
        TransactionId = (string)s["XCV"],
        Data = new JArray{ new JObject {
                         {"store", s["store"] },
                         {"productA", new JObject { {"productId",   s["productAId"] },
                                                    {"productName", s["productAName"] }}
                         },
                         {"productB", new JObject { {"productId",   s["productBId"] },
                                                    {"productName", s["productBName"] }} }
                         }}
    };
    

    output

    JsonConvert.SerializeObject(storeProductModel, Newtonsoft.Json.Formatting.Indented);
    
    {
      "TransactionId": "d1f88a3c-32c6-4a13-931b-3f819372b850",
      "Data": [
        {
          "store": "abc",
          "productA": {
            "productId": "123",
            "productName": "xxxxxx"
          },
          "productB": {
            "productId": "456",
            "productName": "yyyyyy"
          }
        }
      ]
    }