Search code examples
.netdynamicjson.netautomapperautomapper-5

Using Automapper to Copy Properties from a Dynamic


I have a dynamic object (actually, a JObject, from JSON.NET) being built dynamically from JSON. I want to have its properties copied to an existing object. The properties from the dynamic object should exist in the target object's type, if not, it's ok to have an error. I am looking at Automapper, latest version, for this. I tried to create a map from JObject to the proper type, but I don't think it'll work because the properties in the JObject are stored in an internal dictionary. Is this possible at all?


Solution

  • Yes, this is possible.

    If you already have a JObject, then you don't really need Automapper to copy the properties from it to your existing target object. The Json.Net serializer provides a Populate() method which will do this. You can create an extension method to make it easy to call right from the JObject:

    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    
    public static class JsonExtensions
    {
        public static void PopulateObject<T>(this JToken jt, T target)
        {
            JsonSerializer serializer = new JsonSerializer();
            serializer.Populate(jt.CreateReader(), target);
        }
    }
    

    Then, whenever you need to copy the properties you can do this:

    jObj.PopulateObject<Foo>(existingFoo);
    

    Note: if your variable that holds the JObject is declared as dynamic then you'll have to cast it so the runtime binder can find the extension method:

    ((JObject)jObj).PopulateObject<Foo>(existingFoo);
    

    Here is a quick demo to prove the concept: https://dotnetfiddle.net/dhPDCj

    If you would still prefer to use Automapper, you can configure it to do this same conversion instead of its usual member-based mapping. The trick is to use the ConvertUsing method when setting up the mapping:

    Mapper.Initialize(cfg => cfg.CreateMap<JObject, Foo>().ConvertUsing((jo, foo) =>
    {
        JsonSerializer serializer = new JsonSerializer();
        serializer.Populate(jo.CreateReader(), foo);
        return foo;
    }));
    

    Then use this code to copy the properties:

    Mapper.Map<JObject, Foo>(jObj, existingFoo);