Web API 2, OData v4 and Automapper

6

I have a problem that I have no idea how I can fix it.

I have a class as follows:

public class Message {
      public long Id { get; set; }
      public DateTime DateCreated { get; set; }
      public DateTime DateModified { get; set; }
      public string AddressIp { get; set; }
      public string English { get; set; }
      public string Spanish { get; set; }
      public string French { get; set; }
      public string Portuguese { get; set; }
}

And another class like this:

public class MessageDto
{
   public long Key { get; set; }
   public string MessageValue { get; set; }
}

Now, to get the message in the user's language, he used this function:

public static string GetPropValue(object source)
{
   var propertyName = CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.Name).Parent.EnglishName;

   return source.GetType().GetProperty(propertyName).GetValue(source, null).ToString();
}

In my controller OData I have this:

[EnableQuery]
public IQueryable<MessageDto> Get()
{
   var messages = _messageService.Queryable();

   var messagesDto =  messages.ToList().Select(t => _messageFactory.GetMessageViewModel(t));

   return other.AsQueryable();
}

The GetMessageViewModel() function does this:

public MessageDto GetMessageViewModel(Message model)
{
   return new MessageDto
   {
      Key = model.Id,
      MessageValue = PropertyValueHelper.GetPropValue(model)
   };
}

Now, is it possible to do the same but by using Automapper ?

For example at the time of mapping, I have no idea how to do it for the column MessageDto.MessageValue

Mapper.CreateMap<Message, MessageDto>()
   .ForMember(dest => dest.MessageValue, opt => opt.MapFrom(src => src.???))
   .ForMember(dest => dest.Key, opt => opt.MapFrom(src => src.Id));

Neither have I managed to convert the message in the user's language into the class where I mapped:

Mapper.CreateMap<Message, MessageDto>()
            .AfterMap((src, dest) => dest.MessageValue = PropertyValueHelper.GetPropValue(src));

Can someone guide me or support me to do it?

    
asked by ericardezp 11.12.2015 в 00:25
source

2 answers

3

I have some doubts about your implementation, starting with

CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.Name).Parent.EnglishName;

This code is server side true? This returns Culture in the service account that runs on the server, not the client that logs into the service.

Now, if you are exposing the data in oData, the flow to implement would be that part of the parameters received in each request would be the language in which you want to receive the response.

  • If there is no specified language, respond in a default language
  • If the specified language does not exist, reply in a default language

So the language is determined by the client application by some mechanism and this in turn makes the request orData including in the parameters the language in which you want to receive the answer.

It may be that by some business rule you expect to never have more than 4 languages or languages different from those specified, however the implementation

public class Message {
      public long Id { get; set; }
      public DateTime DateCreated { get; set; }
      public DateTime DateModified { get; set; }
      public string AddressIp { get; set; }
      public string English { get; set; }
      public string Spanish { get; set; }
      public string French { get; set; }
      public string Portuguese { get; set; }
}

looks pretty hardcode, so I would suggest using a dictionary that was created to solve this type of scenarios

public class Message {
      public long Id { get; set; }
      public DateTime DateCreated { get; set; }
      public DateTime DateModified { get; set; }
      public string AddressIp { get; set; }
      public Dictionary<string, string> MessageContent{ get; set; }
} 

If the number of messages is not large enough to persist in a BD then my recommendation would be to use resource files and access them by the full name according to the selected language.

Another option is to persist them anyway and use Redis Cache for the whole theme of these chains.

    
answered by 16.12.2015 в 23:01
1

The solution I currently have is this:

  • Create a class that contains the languages to be handled

    [ComplexType]
    public class LocalizedString
    {
       public string English { get; set; }
       public string Spanish { get; set; }
       public string French { get; set; }
       public string Portuguese { get; set; }
    
       [NotMapped]
       public string Current
       {
          get { return (string)LanguageProperty().GetValue(this, null); }
          set { LanguageProperty().SetValue(this, value, null); }
       }
    
       public override string ToString()
       {
          return Current;
       } 
    
       private PropertyInfo LanguageProperty()
       {
          string currentLanguage = Thread.CurrentThread.CurrentUICulture.DisplayName;
      return GetType().GetProperty(currentLanguage);
       }
    }
    
  • The model class must contain a property of type LocalizedString

    public class Message
    {
       public long Id { get; set; }
       public DateTime DateCreated { get; set; }
       public DateTime DateModified { get; set; }
       public LocalizedString Value { get; set; }
    }
    
  • Have a mapping as follows:

    private static void CreateMaps()
    {
       string language = null;
       Mapper.CreateMap<LocalizedString, string>().ProjectUsing(src =>
          language == "English" ? src.English :
          language == "Spanish" ? src.Spanish :
          language == "French" ? src.French :
          src.Portuguese);
    
       Mapper.CreateMap<Message, MessageViewModel>()
          .ForMember(dest => dest.Key, opt => opt.MapFrom(src => src.Id))
          .ForMember(dest => dest.MessageValue, opt => opt.MapFrom(src => src.Value));
    }
    
  • In my controller OData I do this:

    public IQueryable<MessageViewModel> Get()
    {
       var messages = _messageService.Queryable();
       return messages.ProjectTo<MessageViewModel>(new { language = CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.Name).Parent.EnglishName });
    }
    
  • answered by 11.12.2015 в 17:33