Search code examples
c#serializationautomapperflattenvalueinjecter

How to map dynamic ViewModel List Type to DTO


Problem is to map dynamic list of nested objects to a flattened DTO. It includes flattening of nested object. Also, it is interface type.

Interface IfinalOutput
{
   object MainOutput;
   object CalcOutput;
   object SupportOutput;
}

class finalOutput<T,T2,T3> : IfinalOutput where T: IMainOutput, T2: ICalcOutput, T3: ISupportOutput
{
  public object MainOutput;
  public object CalcOutput;
  Public object SupportOutput;
  ...Other Properties
}

We have multiple concrete type of IMainOutput, ICalcOutput, ISupportOutput that can be returned belonging to different source systems. eg. ABC system has ABCMainOutput, ABCCalcOutput, ABCSupportOutput XYZ system has XYZMainOutput, XYZCalcOutput and so on

Now we have DTOs for each source system like ABCDto, XYZDto kind of flattened structure.

Problem is to serialize and map IEnumerable to IEnumerable or IEnumerable based on object type and keep the list sorted.

I tried using Automapper as below

public List<Tto> Serialize<Tfrom, Tto>(
        IEnumerable<IFinalOutput> outputTableCompositeViewModel)
{
   List<Tto> sourceSystemDTOList = new List<Tto>();
   AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<Tfrom, Tto>());
   foreach (var item in outputTableCompositeViewModel)
   {
     Tto outputItem = new Tto();              

     var outputTableItem = item.MainOutput;
     outputItem = AutoMapper.Mapper.Map<Tto>(outputTableItem);
     var supportTableItem = item.SupportOuput;
     var calculatedTableItem = item.CalcOutput;

     sourceSystemDTOList.Add(outputItem);
   }
   return new List<Tto>(sourceSystemDTOList);
}

Now all the properties are not mapped. Please guide how to map calc and support output to Dto and avoid using forloop. I can use Automapper or ValueInjector. Need an efficient way to do it.


Solution

  • I implemented below changes and it worked.

    First, I had to create map for all my concrete class of IMainOutput, ICalcOutput, ISupportOutput with specific source system like below:

     Mapper.Initialize(cfg =>
            {
    
                cfg.CreateMap<ABCMainOutput, ABCdto>();
                cfg.CreateMap<ABCCalcOutput, ABCdto>();
                cfg.CreateMap<ABCSupportOutput, ABCdto>();
            });
    

    Second, I added one automapper extension:

     public static TDestination Map<TSource, TDestination>(
           this TDestination destination, TSource source)
        {
            return Mapper.Map(source, destination);
        }
    

    And Finally, I used above extension to serialize the final output.

    public List<Tto> Serialize<Tfrom, Tto>(
        IEnumerable<IFinalOutput> outputTableCompositeViewModel)
    {
       List<Tto> sourceSystemDTOList = new List<Tto>();       
       foreach (var item in outputTableCompositeViewModel)
       {
        Tto outputItem = new Tto();              
    
        var outputTableItem = item.MainOutput;       
        var supportTableItem = item.SupportOuput;
        var calculatedTableItem = item.CalcOutput;
        outputItem = Mapper.Map<Tto>(outputTableItem)
                                            .Map(calculatedTableItem)
                                            .Map(supportTableItem);
        sourceSystemDTOList.Add(outputItem);
       }
      return new List<Tto>(sourceSystemDTOList);
    }
    

    and the solution works.