Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing around values to an AutoMapper Type Converter from outside

Tags:

c#

automapper

I have a multilingual database, which returns values based on a key and an enum Language. When I convert a DB object to a model, I want the model to contain the translated value based on the key and the current language.

The key comes from the DB object but how can I pass the current language to the the Mapper.Map() function?

Currently, I am using a [ThreadStatic] attribute to set the culture before calling Mapper.Map<>, and to retrieve it in the TypeConverter.

public enum Language
{
    English, French, Italian, Maltese
}

public class MultilingualValue<T>
{
    public Dictionary<Language, T> Value { get; set; }
    public MultilingualValue()
    {
        this.Value = new Dictionary<Language, T>();
    }
}

public class PersonData
{
    public string FirstName { get; set; }
    public MultilingualValue<string> City { get; set; }
}

public void MapPerson()
{
    PersonData personData = new PersonData();
    personData.FirstName = "John";
    personData.City = new MultilingualValue<string>();
    personData.City.Value[ Language.English] = "The Zurrieq";
    personData.City.Value[Language.French] = "Le Zurrieque";

    MultilingualValueData.CurrentLanguage = Language.English; 

    var personModel = Mapper.Map<PersonData, PersonModel>(personData);
}

public class MultilingualValueToBasicDataTypeConverter<T> : ITypeConverter<MultilingualValue<T>, T> 
{
    public T Convert(ResolutionContext context)
    {
        var currentLanguage = MultilingualValueData.CurrentLanguage; //THIS IS THE [ThreadStatic] VARIABLE
        if (currentLanguage == null) throw new InvalidOperationException("Please make sure to fill in CurrentLanguage");

        MultilingualValue<T> sourceMultilingualValue = (MultilingualValue < T > )context.SourceValue;

        T destinationValue = default(T);
        if (sourceMultilingualValue != null)
        {
            destinationValue = sourceMultilingualValue.Value[currentLanguage.Value];
        }

        return destinationValue;
    }
}        

public static class MultilingualValueData
{
    [ThreadStatic]
    public static Language? CurrentLanguage;
}

I left out the configurations as I think they're unneccessary for this example. If you need them, I'll post them as well.

While this works, I find this workaround quite ugly. Is there any way to pass data through the ResolutionContext?

like image 374
Karl Cassar Avatar asked Oct 14 '14 17:10

Karl Cassar


1 Answers

Just use the Map overload that takes a Action<IMappingOperationOptions>. You can add configuration elements to the Items property that are then passed to your ITypeConverter

public class CustomConverter : ITypeConverter<string, string>
{
    public string Convert(ResolutionContext context)
    {
        return "translated in " + context.Options.Items["language"];
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        AutoMapper.Mapper.CreateMap<string, string>().ConvertUsing<CustomConverter>();
        var result = AutoMapper.Mapper.Map<string, string>("value" , opt => opt.Items["language"] = "english");
        Console.Write(result); // prints "translated in english"
        Console.ReadLine();
    }
}
like image 55
samy Avatar answered Nov 02 '22 13:11

samy