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!

Saturday 21 April 2012

RavenDB Magic – Modelling Polymorphic Collections

I'm starting to port my main application over to RavenDB.  A driving design principle for RavenDB is to reduce friction for the developer and the main reason I’m choosing RavenDB is to make my life easier.  Here's one example of that...

Let’s say that you’ve got a model with a marker interface and some types implementing that interface.  Something like this:
   public interface ILookup { }

   public class IntegerLookup : ILookup
   {
      public int Number { get; set; }
   }
   
   public class StringLookup : ILookup
   {
      public string Text { get; set; }
   }
Then you have a type that holds a collection of the interface:
   public class Container
   {
      public ILookup[] Lookups { get; set; }
   }
All good so far, and now you want to store this in a database.  Not quite so simple!  If you’re using a relational database, whether through an ORM or another means, you will have to do quite a bit more work to get your objects into the database and back.

However, if you’re using RavenDB then your work is done!  Well, nearly - all you need to do is to add an Id property to your container to tell RavenDB to store it as a root:
   public class Container
   {
      public string Id { get; set; }
      public ILookup[] Lookups { get; set; }
   }

That’s it – the rest is pure Raven magic!  Here’s a test showing how Raven it handles it:
   [Test]
   public void can_store_polymorphic_collection()
   {
      using (var store = new EmbeddableDocumentStore
      {
         DataDirectory = "Data",
         RunInMemory = true
      })

      {
         store.Initialize();

         var holder = new Container
               {
                  Lookups = new ILookup[]
                              {
                                 new StringLookup {Text = "Hello"},
                                 new IntegerLookup {Number = 123}
                              }
               };
         using (var session = store.OpenSession())
         {
            session.Store(holder);
            session.SaveChanges();
         }

         using (var session = store.OpenSession())
         {
            var h = session.Load<Container>(holder.Id);

            Assert.That(h.Lookups
               .OfType<StringLookup>().Single().Text == "Hello");
            Assert.That(h.Lookups
               .OfType<IntegerLookup>().Single().Number == 123);
         }
      }
   }
You just new up an instance of Container, add in a couple of ILookup instances, then save it.  When I load it back up, it’s all there just as you need it to be.  Now, that is seriously impressive!