Dictionary <string,string> map to an object using Automapper

45,030

Solution 1

AutoMapper maps between properties of objects and is not supposed to operate in such scenarios. In this case you need Reflection magic. You could cheat by an intermediate serialization:

var data = new Dictionary<string, string>();
data.Add("Name", "Rusi");
data.Add("Age", "23");
var serializer = new JavaScriptSerializer();
var user = serializer.Deserialize<User>(serializer.Serialize(data));

And if you insist on using AutoMapper you could for example do something along the lines of:

Mapper
    .CreateMap<Dictionary<string, string>, User>()
    .ConvertUsing(x =>
    {
        var serializer = new JavaScriptSerializer();
        return serializer.Deserialize<User>(serializer.Serialize(x));
    });

and then:

var data = new Dictionary<string, string>();
data.Add("Name", "Rusi");
data.Add("Age", "23");
var user = Mapper.Map<Dictionary<string, string>, User>(data);

If you need to handle more complex object hierarchies with sub-objects you must ask yourself the following question: Is Dictionary<string, string> the correct data structure to use in this case?

Solution 2

With the current version of AutoMapper:

public class MyConfig
{
    public string Foo { get; set; }
    public int Bar { get; set; }
}
var config = new MapperConfiguration(cfg => {});
var mapper = config.CreateMapper();

var source = new Dictionary<string, object>
{
    ["Foo"] = "Hello",
    ["Bar"] = 123
};
var obj = mapper.Map<MyConfig>(source);
obj.Foo == "Hello"; // true

Solution 3

This thread is a bit old, but nowadays there's how to do it on automapper without any configuration, as stated at official documentation:

AutoMapper can map to/from dynamic objects without any explicit configuration (...) Similarly you can map straight from Dictionary to objects, AutoMapper will line up the keys with property names.

Update:

The following code shows a working sample (with unit tests).

void Test()
{
    var mapper = new MapperConfiguration(cfg => { }).CreateMapper();
    var dictionary = new Dictionary<string, object>()
    {
        { "Id", 1 },
        { "Description", "test" }
    };

    var product = mapper.Map<Product>(dictionary);

    Assert.IsNotNull(product);
    Assert.AreEqual(product.Id, 1);
    Assert.AreEqual(product.Description, "test");
}

class Product
{
    public int Id { get; set; }
    public string Description { get; set; }
}

Solution 4

AutoMapper is quite a flexible solution. You could probably achieve this using a custom mapping profile, e.g.:

public class UserMappingProfile : Profile
{
  // Props
  public override string ProfileName { get { return "UserMappingProfile"; } }

  // Methods
  public override void Configure()
  {
    CreateMap<User, Dictionary<string, string>>().ConvertUsing<DictionaryTypeConverter>();
    base.Configure();
  }

  // Types
  internal class DictionaryTypeConverter : ITypeConverter<User, Dictionary<string, string>>
  {
    public User Convert(ResolutionContext context)
    {
      var dict = context.SourceValue as Dictionary<string, string>;
      if (dict == null)
        return null;

      return new User() { Name = dict["Name"], Age = dict["Age"] };
    }
  }
}

With this, I can create a custom instance of a mapper:

var config = new Configuration(new TypeMapFactory(), MapperRegistry.AllMappers());
config.AddProfile<UserMappingProfile>();

config.AssertConfigurationIsValid();

var mapper = new MappingEngine(config);

Which I could probably do:

var dict = new Dictionary<string, string> { { "Name", "Matt" }, { "Age", "27" } };
var user = mapper.Map<User, Dictionary<string, string>>(dict);

Solution 5

Much simpler solution. Just map your object from KeyValuePair. Example:

CreateMap<KeyValuePair<Guid, string>, User>()
            .ForMember(u => u.Id, src => src.MapFrom(x => x.Key))
            .ForMember(u => u.Name, src => src.MapFrom(x => x.Value));
Share:
45,030

Related videos on Youtube

Rusi Nova
Author by

Rusi Nova

Updated on April 29, 2022

Comments

  • Rusi Nova
    Rusi Nova about 2 years

    I have a class like

    public User class
    {
     public string Name{get;set;}
     public string Age{get;set;
    }
    

    With a dictionary like

    Dictionary<string,string> data= new Dictionary<string,string>(); 
    data.Add("Name","Rusi");
    data.Add("Age","23");
    
    User user= new User();
    

    Now i want to map User object to this dictionary using Automapper. Automapper maps properties of objects but in my case there is a dictionary and object.

    How can this be mapped?

    • BoltClock
      BoltClock over 12 years
      Go ahead. If you run into any doubts, ask.
    • Rusi Nova
      Rusi Nova over 12 years
      @boltclock: iam unable to map as automapper maps between objects.
    • turdus-merula
      turdus-merula over 6 years
  • EHorodyski
    EHorodyski over 10 years
    Very good solution, especially if you're using conditionally parsing JSON objects into strong types (such that, say a 'TypeOf' property in a JSON item could fall into one or more object types).
  • Euridice01
    Euridice01 over 7 years
    @Darin using your approach, running into this issue (for solely using first approach): 'System.Collections.Generic.Dictionary2[[System.Collections.‌​Generic.Dictionary2+‌​KeyCollection[[Syste‌​m.String, mscorlib, Version=4.0.0.0, Culture=neutral, .....,[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' is not supported for serialization/deserialization of a dictionary, keys must be strings or objects.
  • Toolmaker
    Toolmaker over 4 years
    While the docs state that it should work by default, running a somewhat simple test scenario reveals that this is no the case. This will result in a runtime exception: var mapper = new MapperConfiguration(cfg => { }).CreateMapper(); var result = mapper.Map<Dictionary<String, String>, StringAttribute>(dict);
  • Marcos Jonatan Suriani
    Marcos Jonatan Suriani over 4 years
    The AutoMapper documentation is just fine. I've just updated my original answer to provide a complete example with unit tests to ensure code works fine too.
  • Minelli
    Minelli about 4 years
    The solution given by @marcos-jonatan-suriani (below, on Aug 30 '19) is 'native', simpler and updated.
  • Lucian Bargaoanu
    Lucian Bargaoanu about 4 years
    As some of the more recent answers say, it's built in. You don't need the map.
  • Sheegy
    Sheegy about 4 years
    It's built in if your property names are same, what if they are different or if someone need to map one property in dictionary to another, in that case this type of mappers will help. And in case of writing Unit Test cases while mocking the return response, you need to use this kind of mappers to map the data moq response with the actual class object as your data will don't map automatically.
  • Lucian Bargaoanu
    Lucian Bargaoanu about 4 years
    Yes, but that's not the question here. And in unit tests you should use the exact same mapper/code. So I'm not sure what you're saying.
  • xSx
    xSx about 2 years
    after I using this with ForMember it's don't work :(( Or formember or mapping Dictionary. do you know why this might be?