user2399378
user2399378

Reputation: 871

Automapper define a custom variable used to determine the values of several properties from destination

I am using AutoMapper to map some DTOs to ui Models. However, one of my DTOs contains a field with serialized data (the serialized data represents another object with properties) that is used to determine the values of several properties of the model.

For example:

public class SourceDTo
{
  public int Id {get; set;}
  public int Name {get; set;}
  public string SerializedDetails {get; set;} 
}

public source DestinationModel
{
  public int Id {get; set;}
  public int Name {get; set;}
  public string Address {get; set;}
  public string AccountNr {get; set;}
}

So in this case, when mapping the source to destination, I would like to be able to deserialize the SerializedDetails field first and then use it in order to map Address and AccountNr with properties from that object, instead of deserializing it twice, for each property. Can this be done with AutoMapper?

Upvotes: 0

Views: 230

Answers (1)

chambo
chambo

Reputation: 491

May not be the most elegant solution YMMV:

CreateMap<Foo, Bar>()
    .ForMember(dest => dest.prop1
        , opt => opt.MapFrom((src, dest, destMember, context) => context.GetJsonObjectValue<string>("RawMessageJSON", "$.props.prop1")))
    .ForMember(dest => dest.prop2
        , opt => opt.MapFrom((src, dest, destMember, context) => context.GetJsonObjectValue<int>("RawMessageJSON", "$.props.prop2")));

Helper Extension Method for extracting Json path values from the JObject:

public static class AutomapperResolutionContextExtensions
{
    public static T GetJsonObjectValue<T>(this ResolutionContext context, string key, string jsonTokenPath)
        => ((JObject)context.Items[key]).SelectToken(jsonTokenPath).ToObject<T>();
}

Here's the classes we are mapping:

public class Foo
{
    public string RawMessageString { get; set;}

    [NotMapped]
    public JObject RawMessageJSON => JObject.Parse(RawMessageString);
}

public class Bar
{
    public string prop1 { get; set; }
    public int prop2 { get; set; }        
}

When calling Map() we deserialize the string to a JObject and pass it in through in the Items Dictionary:

var bar = mapper.Map<Bar>(foo, opt => opt.Items["RawMessageJSON"] = foo.RawMessageJSON);

Upvotes: 2

Related Questions