Wednesday, 23 May 2012

Embedded RavenDB Indexes with Obfuscation

I ran into an issue today with using RavenDB from an obfuscated assembly.  RavenDB started giving some nasty looking errors like:

System.InvalidOperationException: Could not understand query:
-- line 2 col 43: invalid NewExpression

After bashing my head against this for too long, I had run out of ideas and so I posted the problem on the RavenDB group.  One of the really good things about RavenDB is the amazing support from both the Hibernating Rhinos team and the community on this group.  So, pretty soon it was problem solved!

The problem: the obfuscation was renaming the anonymous types that are used when defining indexes from code in RavenDB.

The solution: either put your types into a non-obfuscated assembly or tell the obfuscator to stop renaming anonymous types.  Let’s look at the second option a bit more.

Okay, so how do you detect an anonymous type?  One way is to look at their names.  The compiler gives anonymous types names and puts the text “AnonymousType” into the name. For example:

new { Name = "Sean"}.GetType().Name // Gives: <>f__AnonymousType0`1

Simple enough, but there is a caveat:  the naming of anonymous types is an implementation detail and may vary with different compiler implementations.  You cannot rely in this working with different compilers. 

So, with that in mind, let’s look at a solution…

Different obfuscators allow you to add obfuscation rules in various ways.  In this repo there is an example of using Eazfuscator with a RavenDB index.  (Note that you will need to install Eazfuscator to be able to run the code.)  All that is needed is to use an assembly scoped ObfuscationAttribute to prevent renaming of any type whose name contains the text “AnonymousType”:

[assembly: Obfuscation(Feature = "Apply to type *AnonymousType*: renaming", Exclude = true, ApplyToMembers = true)]

Bingo, everything works as it should again…happy days!