The chicken can dance

Rubber Chicken Paradise

Making the chicken dance one line of code at a time

When AutoMapper isn't Auto

Or why I have no hair.

Jeremy Oursler

3 minutes read

Recently I was working on the API gateway and ran into an issue while trying to use Auto Mapper. It was working well until I was trying to map some XML from one name space to another.

The basics was that I had created a copy of the interface so we could change the server listening to our external endpoint from a third party app to one we controlled and could insulate our customers from any api changes in the future.

The interface was similar to this:

//Copy everything into a new namespace
//Prevents changes in the third party api changing our interface
namespace Gateway
{
    //Some "Random" xml attributes
    public class School
    {
        public MyTypeEnum[] MyTypeName {get; set;}
    
        [XmlElementAttribute("Address", typeof(string), Form = Unqualified)]
        [XmlElementAttribute("Gym", typeof(Gymnasium), Form = Unqualified)]
        [XmlElementAttribute("ClassRoom", typeof(ClassRoom), Form = Unqualified)]
        [XmlChoiceIdentifierAttribute("MyTypeName")]
        public object[] MyObject {get; set;}
    }
}

namespace ThirdPartyApi
{
    //Some "Random" xml attributes
    public class School
    {
        public MyTypeEnum[] MyTypeName {get; set;}
    
        [XmlElementAttribute("Address", typeof(string), Form = Unqualified)]
        [XmlElementAttribute("Gym", typeof(Gymnasium), Form = Unqualified)]
        [XmlElementAttribute("ClassRoom", typeof(ClassRoom), Form = Unqualified)]
        [XmlChoiceIdentifierAttribute("MyTypeName")]
        public object[] MyObject {get; set;}
    }
}

I have never really seen this type of design but given that there are XML Attributes coded that enable it, it is used out there. This caused issues with AutoMapper because the ThirdPartyApi class was being injected into the object array and causing serialization issues on the other side.

Poking around the internet with a quick google search to see if I could avoid reading the manual, I found a question on stack overflow from 6 years ago and no answer (and answered it after solving the issue) which was the only hit I found on the issue (the only thing better is a self answer of “Fixed it” and no description of what they did). After digging through the AutoMapper documentation which is very thorough I found ITypeConverter (RTFM).

With that in hand off I went to write some manual mapping code to work around the issue. Since we were in C# there was some ToString() and GetType() use which may not be the fastest at run time but did get the job done.

So in our above example the type converter would look something like this (I had one going each way):

public class ThirdPartyApiSchoolTypeConverter : ITypeConverter<ThirdPartyApi.School,Gateway.School>
{
    public Gateway.School Convert(ThirdPartyApi.School source, Gateway.School destination, ResolutionContext context)
    {
        var retVal = new Gateway.School
                     {
                         MyObject = new object[source.MyObject.Lengt],
                         MyTypeName  = new Gateway.MyTypeEnum[source.MyObject.Length]
                     };
        //Loop through and do an index by index mapping
        for (int i = 0; i < source.MyObject.Length; i++)
        {
            //Get the string representation of the source then parse it the destination enum
            retVal.MyTypeName[i] = (Gateway.MyTypeEnum)Enum.Parse(typeof(Gateway.MyTypeEnum), source.MyTypeName[i].ToString());

            switch (source.MyTypeName[i])
            {
                case ThirdPartyApi.MyTypeEnum.Gym:
                    //Automapper conversion between ThirdPartyApi.Gym and Gateway.Gym
                    break;
                //All the other types I needed to change the namespace on
                
                //finally if it was a value type (string, int, decimal etc) map it over.
                default:
                    retVal.SomeValueVar[i] = source.SomeValueVar[i]
            }
        }

        return retVal;
    }
}

All in all the solution was not to difficult, it was really just figuring out how to make the AutoMapper library do what I wanted.

Recent posts

See more

Categories

About

An ADHD programmer writing about the random stuff they run into. Check the about page for more.