AutoMapper for Silverlight 3.0 Alpha

In between workshops here at the MVP Summit, I’ve been working on pushing out an early Alpha for an AutoMapper version built against Silverlight 3.0.  Thanks to some existing patches from the community, it was pretty straightforward to get things going.  I’ve also started working against an AutoMapper github repository, which also made some other things much, much easier (which I’ll touch on soon).  To get the alpha, grab the binaries from the CodePlex site:

AutoMapper for Silverlight 3.0 Alpha

All existing features of AutoMapper 1.0 are supported, except for:

  • IDataReader
  • IListSource

Neither of which even exist in Silverlight 3.0.  Since I don’t do any Silverlight development, I labeled this one as “Alpha” as I’ll need to rely on folks in the wild to let me know if it actually works or not.

Supporting two runtimes

Before this whole conversion process, I had almost zero experience with Silverlight 3.0.  I vaguely remembered that there was a separate runtime, but it’s really interesting how it all works out.  To get AutoMapper working with Silverlight, I had several big obstacles:

  • Some assemblies don’t exist in Silverlight
  • Some types don’t exist in Silverlight
  • Some types have only partial members defined
  • Some types only have some method overloads defined

Some goals I have is that going foward:

  • Any feature added to AutoMapper will also get added to the Silverlight version
  • Unit tests are executed against the Silverlight version
  • Any test added to AutoMapper will also get added to the Silverlight version

Project setup

To support two runtimes against basically one codebase, I opted for a model where I create Silverlight class libraries, then use linked files to keep the source the same.  Linked files allow me to keep only one source code file on disk (and in source control), but reference the same file from two projects.  I created a new project, AutoMapper.Silverlight, and a new unit tests project as well.  Some files weren’t needed as the feature wouldn’t be supported (such as IDataReader), so I just didn’t link that file in.

When things don’t line up

If a whole file isn’t supported, that’s fine, I just don’t add it.  But what if the API is different?  For example, Silverlight has no TypeDescriptor class.  In those cases, I relied on conditional compilation to provide two implementations in one file:

        private static TypeConverter GetTypeConverter(ResolutionContext context)
        {
#if !SILVERLIGHT
            return TypeDescriptor.GetConverter(context.SourceType);
#else
            var attributes = context.SourceType.GetCustomAttributes(typeof(TypeConverterAttribute), false);

            if (attributes.Length != 1)
                return new TypeConverter();

            var converterAttribute = (TypeConverterAttribute)attributes[0];
            var converterType = Type.GetType(converterAttribute.ConverterTypeName);

            if (converterType == null)
                return new TypeConverter();

            return Activator.CreateInstance(converterType) as TypeConverter;
#endif
        }

Because I opened this file from the regular project, the Silverlight code is grayed out.  Opening the file from the Silverlight project makes all that extra code available, while the top part is commented out.  For places where I just couldn’t support features, I’d just leave them out:

        public static Func<IEnumerable<IObjectMapper>> AllMappers = () => new IObjectMapper[]
        {
#if !SILVERLIGHT
            new DataReaderMapper(),
#endif
            new TypeMapMapper(TypeMapObjectMapperRegistry.AllMappers()),
            new StringMapper(),
            new FlagsEnumMapper(),
            new EnumMapper(),
            new ArrayMapper(),
            new EnumerableToDictionaryMapper(),
            new DictionaryMapper(),
#if !SILVERLIGHT
            new ListSourceMapper(),
#endif
            new EnumerableMapper(),
            new AssignableMapper(),
            new TypeConverterMapper(),
            new NullableMapper()
        };
    }

It’s slightly ugly, but the places where I have to do this are very small.  Luckily, things are reasonably factored out that individual features are usually individual classes.

Third-party libraries

AutoMapper uses proxy classes to support mapping to interfaces.  Originally, I went with LinFu to do this dynamic proxy stuff because it was small, targeted and focused on what I needed to do.  Unfortunately, there is not a Silverlight version, so I switched to Castle Dynamic Proxy to get things going.

It was a very straightforward switch, as the APIs are quite similar.  The only big fix I had to do was update the IL Merge business, and make sure that I excluded the right types so that interface mapping worked when everything was merged up.

Testing

Silverlight unit testing is…weird.  A lot of the documentation out there talks about executing unit tests in a Silverlight application, which is not what I’m interested in.  For NUnit, I merely create a regular class library, and test runners run the test in whatever environment they want.  I needed to find an NUnit version supported for Silverlight, and that was not easy to find.  I went through around three or four different builds out there before I found one I liked:

http://wesmcclure.tumblr.com/post/152727000

I also use NBehave, but I didn’t really feel like porting NBehave over as well, so I just grabbed the source files I needed and included them directly in my testing project.

Executing the tests from NAnt was also completely straightforward, and worked as soon as my TestDriven.NET worked.

Packaging

Based on community feedback, I built the Silverlight-based AutoMapper assembly as a new assembly name, “AutoMapper.Silverlight.dll”.  The only other work I needed to do was duplicate the packaging NAnt tasks, and make sure I included the relevant Silverlight assemblies into my source repository so that the automated build would work.  Installing Silverlight on a build machine is just a bad idea.

Final thoughts

The conversion was smoother than I thought it would be.  The biggest hurdles I had were just getting the unit tests running.  The unit testing framework I use doesn’t have a supported Silverlight build, so I had to do quite a bit of hunting to find one that works.  But other than that, linked files and conditional compilation made things quite easy to do.  Also, playing around on github with easy branching and merging made adding intermittent patches to master very easy to do.  In fact, I was even able to cherry pick a single commit to push back to master from a Silverlight branch…but my git experience should wait for another post.

Thanks again to everyone that sent me patches to get Silverlight working with AutoMapper.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in AutoMapper. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.tavaresstudios.com Chris Tavares

    We had similar concerns when building the Silverlight version of Unity. We chose to avoid partial compilation; I started having flashbacks to my Unix days and gigantic tangles of #ifdefs. What we did instead was to segregate the code by file. Every file in the codebase is either just filename.cs (goes in both), filename.Desktop.cs (desktop CLR only) or filename.Silverlight.cs (silverlight version only). The silverlight .csproj file does the same thing you do – it’s all linked files, but it omits linking the .Desktop files and includes the .Silverlight ones. And the reverse for the desktop version.

    Then, we made the classes that had to vary across platform partial classes. So for some types, you’ll have .cs and .Desktop.cs and Silverlight.cs. The main file would have the invariant stuff with the partial keyword on it, and the other two would have the variations. Between this and using partial methods to get a hook into the other methods when needed, it worked out quite well.

    Probably overkill if you’ve got only a small amount of variation, but it worked well for us and is probably easier to manage if things get bigger.

  • http://blog.kellybrownsberger.com Kelly Brownsberger

    I’m trying to get our Silverlight code and accompanying unit test code running w/ our CCNET builds and I’m running into some pain. Forgive my ignorance, but how are you running w/ via NAnt? I followed the links to the NUnitSilverlight build, but it’s just a custom build of nunit.framework.dll and nunit.silverlight.dll. It’s not clear to me what is loading these and how it’s running the tests. This [1] was linked off of the NunitSilverlight blog announcement, which makes me believe this can be done w/ a full .NET process, but according to Jamie’s comments he “some ilasm / ildasm tricks and I never got around to automating it”. When I try to load up a Silverlight Class Library dll with references to these nunit dll’s and try to run it from the full nunit.exe for 2.5.1, I get poopoo’ed (as expected) with failure to load assembly exceptions.

    What am I missing here? The fact statlight [2] exists leads me to believe I can run my test with the traditional runners, or did they author not now about some trick?

    Wow – a little surprising this is so difficult :( Any advice would be appreciated

    [1] http://weblogs.asp.net/nunitaddin/archive/2008/05/01/silverlight-nunit-projects.aspx
    [2] http://statlight.codeplex.com/

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Kelly

    I’m using the regular NAnt NUnit task to build. I had to bundle the SL 3.0 assemblies as part of my source tree, and select “CopyLocal” to true for my SL projects for the system dll’s. This made sure that the correct system.dll was used, instead of some GAC version.

    I have no idea how it’s working, other than I was getting real test failures in all of my test runners tested (R#, TD.NET, NAnt).

    I did talk to the statlight guys, and we’re talking with the teamcity.codebetter folks to see if we can’t get that working on my build server.

  • http://blog.kellybrownsberger.com Kelly Brownsberger

    Thanks Jimmy

    What’s not clear to me is if all the various test runners are capable of loading and running Silverlight assemblies (obviously there needs to be a SL compatible framework/metadata assembly for you testing framework of choice), then why does statlight need to exist? My understanding was it was created as a way to running tests and ultimately invoked the browser under the covers.

    All this is really confusing… just needed to rant :)

    You getting it to work is inspiring though – I’m going to keep plugging. Thanks again -kelly

  • http://blog.kellybrownsberger.com Kelly Brownsberger

    Wow – I did the same (CopyLocal=true + Nant + the SL build of nunit) and it worked for me as well – TD.NET is happy, Nant is happy, and Kelly is happy :)

    Now I’m really confused by what statlight is intended to solve

  • http://plaureano.blogspot.com Philip Laureano

    LinFu.DynamicProxy now has a SL3 port:

    http://is.gd/aQGB2

    You can change it back from Castle now :)