Sunday, May 31, 2009

Duck typing extensions for Windsor

Whenever you have to use some piece of legacy code that's badly designed (i.e. static, no coding to interfaces, god classes), your own code gets tainted with some unwanted dependencies or it gets harder to test because of that unmockable legacy code.

The usual cure for this is to isolate the legacy code with adapters, factories, etc. But what if the legacy code isn't so bad? What if we only need to extract an interface? The resulting adapter would be just trivially forwarding calls to the real object... which is boring code. Can't we do better?

After my last post I've been playing a bit more with David Meyer's Duck Typing Project (aka DeftTech) and thought it would be nice to have the ability to expose a registered Windsor component under one or more duck-typed interfaces. Kind of like forwarded types, but without having the service actually implement those interfaces.

So I came up with a couple of simple extension methods that allow this:

public class Duck {
    public bool HasQuacked { get; private set; }
    public bool HasSwum { get; private set;}

    public void Quack() {
        HasQuacked = true;
    }

    public void Swim() {
        HasSwum = true;
    }
}

public interface IQuack {
    void Quack();
}

public interface ISwimmer {
    void Swim();
}

[Test]
public void WindsorDuckTyping() {
    var container = new WindsorContainer();
    DuckComponentExtensions.Kernel = container.Kernel;
    container.AddFacility<FactorySupportFacility>();
    container.Register(Component.For(typeof(Duck))
        .Duck<IQuack>()
        .Duck<ISwimmer>());
    ISwimmer swimmer = container.Resolve<ISwimmer>();
    swimmer.Swim();
    IQuack quack = container.Resolve<IQuack>();
    quack.Quack();
    Duck duck = container.Resolve<Duck>();
    Assert.IsTrue(duck.HasQuacked);
    Assert.IsTrue(duck.HasSwum);
}

So the Duck can be resolved as IQuack even though it doesn't implement IQuack. Here's the code that enables this:

public static class DuckComponentExtensions {
    public static IKernel Kernel { get; set; }

    public static ComponentRegistration<object> Duck<TDuck>(this ComponentRegistration<object> reg) {
        var targetType = reg.Implementation ?? reg.ServiceType;
        if (!DuckTyping.CanCast<TDuck>(targetType))
            throw new ApplicationException(string.Format("Can't duck type '{0}' to type '{1}'", targetType, typeof(TDuck)));
        Kernel.Register(Component.For<TDuck>()
                            .UsingFactoryMethod(k => DuckTyping.Cast<TDuck>(k.Resolve(reg.Name, reg.ServiceType))));
        return reg;
    }
}

Full source code with tests available here.
Apparently the proxies generated by DeftTech can't be proxied by DynamicProxy... so don't try to define any interceptors for these components! Again, the optimal solution would be to implement proper duck-typing with DynamicProxy...

Monday, May 25, 2009

Duck typing with Castle DynamicProxy

I was trying to come up with some duck typing solution using C# 4.0, based on this, and this, when I realized that DynamicProxy could do this without any new language features:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.Core.Interceptor;
using Castle.DynamicProxy;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DuckTypingTests {
    public class Duck {
        public void Quack() {
            Console.WriteLine("Quack Quack!");
        }

        public void Swim() {
            Console.WriteLine("Swimming...");
        }
    }

    public interface IQuack {
        void Quack();
    }

    public interface ISwimmer {
        void Swim();
    }

    [TestClass]
    public class DuckTypingTests {
        [TestMethod]
        public void DuckTyping() {
            var duck = new Duck();
            duck.As<IQuack>().Quack();
            duck.As<ISwimmer>().Swim();
        }
    }

    public static class DuckTypingExtensions {
        private static readonly ProxyGenerator generator = new ProxyGenerator();

        public static T As<T>(this object o) {
            return generator.CreateInterfaceProxyWithoutTarget<T>(new DuckTypingInterceptor(o));
        }
    }

    public class DuckTypingInterceptor : IInterceptor {
        private readonly object target;

        public DuckTypingInterceptor(object target) {
            this.target = target;
        }

        public void Intercept(IInvocation invocation) {
            var methods = target.GetType().GetMethods()
                .Where(m => m.Name == invocation.Method.Name)
                .Where(m => m.GetParameters().Length == invocation.Arguments.Length)
                .ToList();
            if (methods.Count > 1)
                throw new ApplicationException(string.Format("Ambiguous method match for '{0}'", invocation.Method.Name));
            if (methods.Count == 0)
                throw new ApplicationException(string.Format("No method '{0}' found", invocation.Method.Name));
            var method = methods[0];
            if (invocation.GenericArguments != null && invocation.GenericArguments.Length > 0)
                method = method.MakeGenericMethod(invocation.GenericArguments);
            invocation.ReturnValue = method.Invoke(target, invocation.Arguments);
        }
    }
}

Again, this is just a spike, it only matches methods, not properties, and even the method matching in the interceptor will break with method overloading. And let's not mention performance.

It would be interesting to somehow merge David Meyer's Duck Typing Project into Castle DynamicProxy, as it is the most complete duck-typing solution for .net that I know...

Testing private methods with C# 4.0

Here's another practical use for dynamic in C# 4: testing private methods. I won't discuss here whether this should or shouldn't be done, that's been argued to death for years. Instead, I'll show how it can be done easier with C# 4, without resorting to reflection (at least not directly) or stubs, while also reducing some of the friction associated with doing TDD in statically-typed languages like C#.

The answer is very simple: we just walk away from static typing using C# dynamic:

public class Service {
    private int Step1() {
        return 1;
    }
}

[TestClass]
public class TransparentObjectTests {
    [TestMethod]
    public void PrivateMethod() {
        dynamic s = new Service().AsTransparentObject();
        Assert.AreEqual(1, s.Step1());
    }
}

When going dynamic, it's kind of like turning off the compiler, so, for example, it won't bother you at compile-time if a method isn't present. Instead, you'll just get an exception when you run your test, which is more like the dynamic language way of testing things.

Here's the code that enables this. Just like my last post, it's just a spike, it's incomplete and I didn't test it properly, but it could serve as a base for a more complete implementation:

using System;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DynamicReflection {
    public class Service {
        private int Step1() {
            return 1;
        }

        protected int Step2() {
            return 2;
        }

        internal int Step3() {
            return 3;
        }

        private int Prop { get; set; }

        public int Execute(int a) {
            return Step1() + Step2() + Step3() + a;
        }

        private string ExecuteGeneric<T>(T a) {
            return a.ToString();
        }
    }

    [TestClass]
    public class TransparentObjectTests {
        [TestMethod]
        public void PublicMethod() {
            dynamic s = new Service().AsTransparentObject();
            Assert.AreEqual(10, s.Execute(4));
        }

        [TestMethod]
        public void PrivateMethod() {
            dynamic s = new Service().AsTransparentObject();
            Assert.AreEqual(1, s.Step1());
        }

        [TestMethod]
        public void ProtectedMethod() {
            dynamic s = new Service().AsTransparentObject();
            Assert.AreEqual(2, s.Step2());
        }

        [TestMethod]
        public void InternalMethod() {
            dynamic s = new Service().AsTransparentObject();
            Assert.AreEqual(3, s.Step3());
        }

        [TestMethod]
        public void PrivateProperty() {
            dynamic s = new Service().AsTransparentObject();
            Assert.AreEqual(0, s.Prop);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GenericPrivateMethod_type_mismatch() {
            dynamic s = new Service().AsTransparentObject();
            s.ExecuteGeneric<int>("lalal"); // type param mismatch
        }

        [TestMethod]
        public void GenericPrivateMethod() {
            dynamic s = new Service().AsTransparentObject();
            Assert.AreEqual("1", s.ExecuteGeneric<int>(1));
        }
    }

    public static class TransparentObjectExtensions {
        public static dynamic AsTransparentObject<T>(this T o) {
            return new TransparentObject<T>(o);
        }
    }

    public class TransparentObject<T> : DynamicObject {
        private readonly T target;

        public TransparentObject(T target) {
            this.target = target;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result) {
            var members = typeof(T).GetMember(binder.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            var member = members[0];
            if (member is PropertyInfo) {
                result = (member as PropertyInfo).GetValue(target, null);
                return true;
            }
            if (member is FieldInfo) {
                result = (member as FieldInfo).GetValue(target);
                return true;
            }
            result = null;
            return false;
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
            var csBinder = binder as CSharpInvokeMemberBinder;
            var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            if (method == null)
                throw new ApplicationException(string.Format("Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
            if (csBinder.TypeArguments.Count > 0)
                method = method.MakeGenericMethod(csBinder.TypeArguments.ToArray());
            result = method.Invoke(target, args);
            return true;
        }
    }
}

UPDATE 5/17/2010: Igor Ostrovsky recently got the same idea outlined here and has written a proper implementation of this.

Saturday, May 23, 2009

Rails-like finders for NHibernate with C# 4.0

Now that VS2010 Beta 1 is out, I figured I'd take another look and try to actually do something with it. So I spiked a little proof of concept for what I mentioned about six months ago: Rails-like finders for NHibernate. In RoR's ActiveRecord you can write:

Person.find_by_name("pepe")

without really having a find_by_name method, thanks to Ruby's method_missing. Now, with a few lines of code, you can write this in C# 4.0, thanks to DynamicObject:

ISession session = ...
Person person = session.AsDynamic().GetPersonByName("pepe");

which behind the scenes will parse the method name "GetPersonByName" (using a Pascal-Casing convention) into a DetachedCriteria and execute it.

Note that I wrote "Person person = ..." instead of "var person = ...", that's because the result of GetPersonByName() is a dynamic so it has to be cast to its proper type to jump back to the strongly-typed world.

As I said before, this is only a proof of concept. It doesn't support finders that return collections, or operators (as in FindPersonByNameAndCity("Pepe", "Boulogne-sur-Mer")), etc. It would certainly be interesting to really implement this, but I wonder if people would use it, with IQueryable being more strongly-typed, way more flexible, and with better language integration.

Anyway, here's the code that makes this possible. Pay no attention to Castle ActiveRecord, I just used it because... well, geographical convenience, really.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text.RegularExpressions;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework.Config;
using log4net.Config;
using NHibernate;
using NHibernate.Criterion;
using NUnit.Framework;

namespace NHDynamicTests {
    [TestFixture]
    public class DynamicTests {
        [Test]
        public void DynamicGetPersonByName() {
            using (ISession s = ActiveRecordMediator.GetSessionFactoryHolder().GetSessionFactory(typeof(object)).OpenSession()) {
                dynamic ds = s.AsDynamic();
                Person person = ds.GetPersonByName("pepe");
            }
        }

        [ActiveRecord]
        public class Person {
            [PrimaryKey]
            public int Id { get; set; }

            [Property]
            public string Name { get; set; }
        }

        [TestFixtureSetUp]
        public void FixtureSetup() {
            BasicConfigurator.Configure();
            var arConfig = new InPlaceConfigurationSource();
            var properties = new Dictionary<string, string> {
                {"connection.driver_class", "NHibernate.Driver.SQLite20Driver"},
                {"dialect", "NHibernate.Dialect.SQLiteDialect"},
                {"connection.provider", "NHibernate.Connection.DriverConnectionProvider"},
                {"connection.connection_string", "Data Source=test.db;Version=3;New=True;"},
            };

            arConfig.Add(typeof(ActiveRecordBase), properties);
            ActiveRecordStarter.ResetInitializationFlag();
            var arTypes = GetType().GetNestedTypes()
                .Where(t => t.GetCustomAttributes(typeof(ActiveRecordAttribute), true).Length > 0)
                .ToArray();
            ActiveRecordStarter.Initialize(arConfig, arTypes);
            ActiveRecordStarter.CreateSchema();
        }
    }

    public static class ISessionExtensions {
        public static dynamic AsDynamic(this ISession session) {
            return new DynamicSession(session);
        }
    }

    public class DynamicSession : DynamicObject {
        private readonly ISession session;

        public DynamicSession(ISession session) {
            this.session = session;
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
            result = null;
            if (!binder.Name.StartsWith("Get"))
                return false;
            var tokens = Regex.Replace(binder.Name, "([A-Z])", " $1").Split(' ').Skip(1).ToArray();
            if (tokens.Length < 4 || args.Length < 1)
                return false; // some parameter is missing
            var typeName = tokens[1];
            var type = session.SessionFactory.GetAllClassMetadata()
                .Cast<DictionaryEntry>()
                .Select(e => e.Key).Cast<Type>()
                .FirstOrDefault(t => t.Name == typeName);
            if (type == null)
                throw new ApplicationException(string.Format("Type '{0}' is not mapped in NHibernate", typeName));
            var fieldName = tokens[3];
            var criteria = DetachedCriteria.For(type).Add(Restrictions.Eq(fieldName, args[0]));
            result = criteria.GetExecutableCriteria(session).UniqueResult();
            return true;
        }
    }
}

BTW: I just can't stand WPF's font rendering, it's so blurry! I don't care if it uses Ideal Width or Compatible Width or whatever you want to call it, it just looks very bad. Please vote for this issue so they fix it as soon as possible!

Tuesday, May 12, 2009

Abusing using to prioritize threads

Welcome to another chapter of "Abusing Using"! IDisposable has been used or abused (depending on who you ask) to create scopes/contexts of all sorts, from database testing to HTML generation to clipboard overriding. Here's another little (ab)use: thread priority setting, for all those background tasks that eat our CPUs:

public static class ThreadSettings {
    private class DisposableThreadPriority: IDisposable {
        private readonly ThreadPriority originalPriority;

        public DisposableThreadPriority(ThreadPriority p) {
            originalPriority = Thread.CurrentThread.Priority;
            Thread.CurrentThread.Priority = p;
        }

        public void Dispose() {
            Thread.CurrentThread.Priority = originalPriority;
        }
    }

    public static IDisposable LowestPriority {
        get {
            return new DisposableThreadPriority(ThreadPriority.Lowest);
        }
    }
}

I like to keep this in an interceptor so I can easily apply it to different components just by adding a couple of lines in my web.config:

public class LowPriorityInterceptor : IInterceptor {
    public void Intercept(IInvocation invocation) {
        using (ThreadSettings.LowestPriority) {
            invocation.Proceed();
        }
    }
}

Friday, May 8, 2009

SolrNet 0.2.2 released

SolrNet is a Solr client for .NET

Here's the changelog from 0.2.1:

Changelog

  • Bugfix: semicolons are now correctly escaped in queries
  • Bugfix: invalid xml characters (control chars) are now correctly filtered
  • Deleting a list (IEnumerable) of documents now uses a single request (requires unique key and Solr 1.3+)
  • Added support for arbitrary parameters, using the QueryOptions.ExtraParams dictionary. These parameters are pass-through to Solr's query string, so you can use this feature to select a different request handler (using "qt") or use LocalSolr.
  • Added per-field facet parameters
  • Breaking change: as a consequence of the previous change, facet queries and other facet parameters were moved to FacetParameters. Instead of:
    var r = solr.Query(new SolrQuery("blabla"), new QueryOptions {
    	FacetQueries = new ISolrFacetQuery[] {
    		new SolrFacetFieldQuery("id") {Limit = 3}
    	}
    });
    Now it's:
    var r = solr.Query(new SolrQuery("blabla"), new QueryOptions {
    	Facet = new FacetParameters {
    	  Queries = new ISolrFacetQuery[] {
    	  	new SolrFacetFieldQuery("id") {Limit = 3}
    	  }
    	}
    });
  • Added a couple of fluenty QueryOptions building methods. Some self-explanatory samples:
    new QueryOptions().AddFields("f1", "f2");
    new QueryOptions().AddOrder(new SortOrder("f1"), new SortOrder("f2", Order.ASC));
    new QueryOptions().AddFilterQueries(new SolrQuery("a"), new SolrQueryByField("f1", "v"));
    new QueryOptions().AddFacets(new SolrFacetFieldQuery("f1"), new SolrFacetQuery(new SolrQuery("q")));
  • Added dictionary mapping support (thanks Jeff Crowder). The defined field name is used as the prefix of the actual Solr field to match. An example:
    public class TestDoc {
        [SolrUniqueKey]
        public int Id { get; set; }
    
        [SolrField]
        public IDictionary<string, int> Dict { get; set; }
    }

    With this mapping, a field named "Dictone" will be mapped to Dict["one"], "Dictblabla" to Dict["blabla"] and so on.
  • Upgraded Windsor facility, now it uses the recently released Windsor 2.0
  • Merged all SolrNet assemblies (SolrNet, SolrNet.DSL, the Castle facility, the Ninject module and the internal HttpWebAdapters). It was getting too annoying having to reference all those assemblies.
  • Windsor and Ninject are not packaged anymore. If you use Windsor or Ninject, you already have them in your app so the I'm not packaging them anymore. Only Microsoft.Practices.ServiceLocation.dll is now included, for users that don't use any IoC container (actually they use the built-in container).

Last but not least, don't forget there's a google group for the project, so if you have any issues, suggestions or doubts, feel free to join!

Downloads

Monday, May 4, 2009

Internet Explorer 8 - intranet Compatibility View

If you ever find yourself testing something on Internet Explorer 8 and your testing environment looks different from production, see that you don't have the "Display intranet sites in Compatibility View" option checked:

ie8-compat1 ie8-compat copy

 

I read here that the rationale for this "smart default" is to be "compatible with line-of-business applications that expect IE7 behavior", so it seems that they actively decided to punish applications built with standards.

Oh well, I just hope this saves someone a few grey hairs... I lost about half an hour to this today.

Friday, May 1, 2009

Windsor - configurable component initialization

This question was raised on the Castle forums a couple of days ago:

I have a third party dependency. It uses a property class for configuration with only a default constructor.

public class Properties { 
      public Properties() {...} 

      public void Add(string name, string value) {...} 
} 

I would love to be able to invoke the .Add to setup this object. Something like this:

<components> 
  <component id="Properties" type="Example.Properties, thirdParty"> 
    <Add> 
      <name>key1</name> 
      <value>value1</value> 
    </Add> 
    <Add> 
      <name>key2</name> 
      <value>value2</value> 
    </Add> 
  </component> 
</components> 

I do realize that I could write an adapter class to interact with the Properties class and then di the adapter. But I'm wondering if I'm missing something or if there is a reason that method invocation is not supported.

Windsor has so many extensibility points that sometimes I have a hard time picking the right one. Windsor lets you change, override or customize almost every aspect of its behaviour thanks to its extensible design. To solve this one, I chose to override the default component activator. The component activator is the internal service responsible for instantiating the component object. To quote Windsor's reference manual:

The ComponentActivator takes a few steps to create the instance

  • Selects the constructor it can satisfy more parameters
  • Creates the instance using the constructor selected
  • Tries to supply dependencies to properties
  • Runs the commission phase lifecycle steps (if any was registered)

Our custom activator will call the default activator, then "deserialize" the method calls from the configuration to the appropriate MethodInfo objects, and finally call those methods on the component instance. We can use the componentActivatorType attribute to select the custom activator.

Here's a demo:

[TestFixture]
public class Tests {
    public class MyComponent {
        public int C { get; private set; }

        public void Add(int i) {
            C += i;
        }

        public void NoParameters() {
            C += 2;
        }
    }

    [Test]
    public void Init() {
        var c = new WindsorContainer(new XmlInterpreter(new StaticContentResource(@"<castle>
<components>
<component id=""mycomponent"" type=""WindsorInitConfig.Tests+MyComponent, WindsorInitConfig"" componentActivatorType=""WindsorInitConfig.InitComponentActivator, WindsorInitConfig"">
<init>
    <Add>
        <i>5</i>
    </Add>
    <Add>
        <i>3</i>
    </Add>
    <NoParameters/>
</init>
</component>
</components>
</castle>")));
        Assert.AreEqual(10, c.Resolve<MyComponent>().C);
    }
}

 

You can checkout the whole code here. Note that this is not really production-quality code: it's not properly tested and it probably won't work on generic methods and overloaded methods with the same parameter names, but it's enough for most cases. Please feel free to enhance it and send me a patch! :-)