Question

I'm using AutoMapper in my ASP.NET MVC4 project. I have a problem when mapping 2 class Question and QuestionViewModel. Here my two model classes:

   public class Question
    {
      public int Id { get; set; }
      public string Content { get; set; }
      public Tuple<int, int> GetVoteTuple()
       {
         "some code here"
       }
    }

   public class QuestionViewModel
    {
      public int Id { get; set; }
      public string Content { get; set; }
      public Tuple<int, int> VoteTuple { get; set; }
    }

Here is my controller code :

   public class QuestionController: Controller 
    {
       public ActionResult Index(int id)
         {

            Question question = Dal.getQuestion(id);
            Mapper.CreateMap<Question, QuestionViewModel>()
                .ForMember(p => p.VoteTuple,
                m => m.MapFrom(
                s => s.GetVoteTuple()
            ));

            QuestionViewModel questionViewModel =
                        Mapper.Map<Question, QuestionViewModel>(question);

            return View(questionViewModel);

          }
     }

When I run this code the VoteTuple property in QuestionViewModel has null value. How can I map 2 class with Tuple property ?

Thanks.

Was it helpful?

Solution

Mapping from Tuple to Tuple is not possible by default through Automapper, because Tuple doesn't have setter properties (they can only be initialized through the constructor).

You have 2 options:

1) Create a custom resolver for Automapper and then use the .ResolveUsing method in the mapping config: .ForMember(p => p.VoteTuple, m => m.ResolveUsing<CustomTupleResolver>())

2) Map to a properties / a class instead, like this:

public class QuestionViewModel
{
  public int Id { get; set; }
  public string Content { get; set; }
  public int VoteItem1 { get; set; }
  public int VoteItem2 { get; set; }
}

And then:

.ForMember(p => p.VoteItem1, m => m.MapFrom(g => g.Item1))
.ForMember(p => p.VoteItem2, m => m.MapFrom(g => g.Item2))

You don't really need to use Tuple in your view model, so I'd recommend the 2nd option.

Edit:

I see that you've updated your code so that GetVoteTuple() is a function, not a property. In that case, you could easily adapt the code like this:

.ForMember(p => p.VoteItem1, m => m.MapFrom(g => g.GetVoteTuple().Item1))
.ForMember(p => p.VoteItem2, m => m.MapFrom(g => g.GetVoteTuple().Item2))

OTHER TIPS

Your CreateMap call is incorrect:

Mapper.CreateMap<Question, QuestionViewModel>()
    .ForMember(p => p.VoteTuple,
        m => m.MapFrom(
        s => s.GetVoteTuple()
//-----------^
     ));

Try using ResolveUsing instead of MapFrom (and use the generic s argument in your lambda instead of the local variable reference:

        Mapper.CreateMap<Question, QuestionViewModel>()
            .ForMember(p => p.VoteTuple,
            m => m.ResolveUsing(
            s => s.GetVoteTuple()
        ));

MapFrom is used to map properties directly. Since you're wanting to "map" from the result of a function call, ResolveFrom is more appropriate.

Also, you should only call CreateMap once in your application, typically that's done in Application_Start in global.asax

try this :

 Mapper.CreateMap<Question, QuestionViewModel>()
                .ForMember(p => p.VoteTuple,op=>op.MapFrom(v=>new Tuple<int,int>(v.GetVoteTuple.Item1,v.GetVoteTuple.Item2)));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top