Saturday, 28 March 2009

Building a Reusable Builder: An internal DSL in C#

Sitting and enjoying the OpenSpace Coding Day at Conchango, and in particular enjoying Ian Coopers talk on Internal DSLs in C# I came to thinking how it might be quite simple to create a reusable builder object.

I’ve done some posts on this sort of thing before, and have spent quite a bit of time recently at work constructing the beginnings of a Language Workbench (I say beginnings as I’m following YAGNI and there’s only one DSL that uses it so far).

Anyway here’s what I’ve just sketched out at the back of the class.

public class Builder<T>
{
    public BuildingInProgress<T> With(T targetObject)
    {
        return new BuildingInProgress<T>(targetObject);
    }
}

public class BuildingInProgress<T>
{
    private readonly T _target;

    public BuildingInProgress(T targetObject)
    {
        _target = targetObject;
    }

    public BuildingInProgress<T> Set<TValue>(Expression<Func<T, TValue>> property, TValue value)
    {
        PropertyInfo info = ExpressionHelpers.GetPropertyInfo(property);
        info.SetValue(_target, value, null);
        return this;
    }
}

public static class ExpressionHelpers
{
    public static string GetMemberName<TSubject, TMember>(Expression<Func<TSubject, TMember>> subjectMember)
    {
        PropertyInfo propertyInfo = getMemberExpressionMember(subjectMember.Body);
        return propertyInfo.Name;
    }

    public static PropertyInfo GetPropertyInfo<TType,TMember>(Expression<Func<TType,TMember>> property)
    {
        return getMemberExpressionMember(property.Body);
    }

    private static PropertyInfo getMemberExpressionMember(Expression expression)
    {
        if (expression == null) return null;

        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                {
                    MemberExpression memberExpression = (MemberExpression)expression;
                    return (PropertyInfo)memberExpression.Member;
                }
            default:
                throw new InvalidOperationException(string.Format("The Expression Type was not expected: {0}", expression.NodeType));
        }
    }
}

And that’s basically as far as I have got in ten minutes (whilst paying attention as well of course;). Obviously it has weaknesses, the static reflection would need much building out to handle more than simple MemberExpressions for example.

Here is a really trivial example of its intended use:

[TestFixture]
public class BuilderFixture
{
    [Test]
    public void Where_SetIsCalled_Then_AValueShouldBeSet()
    {
        const string testValue = "testValue";
        const int otherTestValue = 12;
        Foo foo = new Foo();
        Builder<Foo> fooBuilder = new Builder<Foo>();
        fooBuilder.With(foo)
            .Set(f => f.Bar, testValue)
            .Set(f => f.Baz, otherTestValue);
        Assert.AreEqual(testValue,foo.Bar);
        Assert.AreEqual(otherTestValue, foo.Baz);
    }
}

public class Foo
{
    public string Bar { get; set; }
    public int Baz { get; set; }
}

Thursday, 22 January 2009

Trying to Bind Form Elements in the View to a Dictionary in the Model with ASP.NET MVC

I've got a class that has, instead of statically typed properties, a dictionary that is used to store different values depending on what is needed for any given instance.

    public class Baz
    {
        public Baz()
        {
            Foo = new Dictionary<string, string> { { "Bar", null } };
        }
 
        public IDictionary<string, string> Foo { get; set; }
    }


I'm using ASP.NET MVC and I want to bind the object to the View. The View is dynamically generated based on a template object, like this:


<% foreach (Field field in ViewData.Model.Template.Fields)
    {%>

        <%= Html.Encode(field.DisplayText) %>
        <%= Html.TextBox(string.Format("Foo[{0}]", field.Name)) %>
 <% } %>


In the above, the field.Name will correspond to the Key of a KVP placed into the dictionary of the Foo instance during its' manufacture.

I am using the DefaultModelBinder, and if I look at the ASP.NET MVC (Beta) source code and in particular the BindModelCore method I see that the first thing it does is to find out if the type being dealt with is a Dictionary type, if it is then the UpdateDictionary method gets called. The first line of the UpdateDictionary method assigns the result of a call to CreateSubPropertyName passing in the BindingContext.ModelName as the prefix, and the string 'index' as the property name.

Now I can't see how this works. The result of this code seems to be that, where the ModelName is foo, a key of 'foo.index' is looked for in the route data, query string and form values (DefaultValueProvider.GetValue). Now this isn't found unless the id's for my form elements that tie in to the Dictionary are called 'foo.index' (yep, same id for multiple elements - already smells very wrong). That means altering my View code to look like this:


 <% foreach (Field field in ViewData.Model.Template.Fields)
    {%>
        <%= Html.Encode(field.DisplayText) %>
        <%= Html.TextBox("Foo.index")) %>
 <% } %>


And, giving each the name of foo.index, I get back the values of each as the attempted values and progress into the code which iterates through these values (now stored in a string[] called 'indicies'. The first line of code in the foreach loop (still in DefaultModelBinder.UpdateDictionary) calls CreateSubIndexName, passing in the ModelName and one of the attempted values, so if the attempted value was 'test', it will return foo[test]. Now this key is formatted how I'd want, but uses the attempted value as the key, which is not what I'd want.

The very next thing that happens is a call to DefaultModelBinder.BindProperty which calls CreateSubPropertyName passing in the ParentContext.ModelName, which right now is 'foo[test]' and the string 'key'. This results in a 'newName' of 'foo[test].key'. The consequence of this is that DefaultValueProvider.GetValue is called and looks for an id called 'foo[bar].key', unsurprisingly this doesn't exist, as I had to give all of the dictionary bound form elements an id of 'foo.index', when the null value is returned up then an exception results and the attempt to bind the elements stops.

What I'd like is for the form element id to read Foo[Bar] (assuming no prefix required, otherwise Baz.Foo[Bar]), and for the binding process to use this to get the attempted value, and to then Try and update the KeyValuePair in the Dictionary Foo where the key is Bar with the attempted value. Is that too much to ask?

Now it's entirely possible (probable?) that I've not understood how to make the UpdateDictionary method tick, Googling has revealed nothing, so I'd be appreciative of any information anyone reading this might be able to impart. Otherwise, if I get a chance, I may look to implement my own ModelBinder that has this behaviour (but i'd rather not).

Monday, 19 January 2009

Refactored: Fluent Test Data Builders Using Generic Extension Methods and Lambda Expressions

Working further with the Fluent Test Data Builder I was working on yesterday has led me to refactor what I had, and the result is, I think, even nicer!

I've added a new method SetValue, and changed the from getting the Member.Name to getting the PropertyInfo from the Member. The other significant change is that I'm now wrapping the SetLength and SetValue methods in try catch blocks so that I can intercept a TargetInvocationException and throw the InnerException in its place, this helps to ensure that when I use the ExpectedExceptionAttribute I am catching the exception I really expect. The drawback with this is the stack trace, but I'm content to live with that for now.

publicstatic T SetLength<T>(this T obj, Expression<Func<T, string>> expression, int length)
{
try
    {
        PropertyInfo member = getMemberExpressionMember(expression.Body);
        string currentValue = expression.Compile().Invoke(obj) ?? string.Empty;
        string newValue = currentValue.PadRight(length);

        member.SetValue(obj, newValue, null);

        return obj;
    }

    catch (TargetInvocationException tie)
    {
        if (tie.InnerException != null) throw tie.InnerException;
        throw;
    }
}
 
public static TObj SetValue<TObj, TVal>(this TObj obj, Expression<Func<TObj, TVal>> expression, TVal value)
{

    try
    {
        PropertyInfo member = getMemberExpressionMember(expression.Body);
        member.SetValue(obj, value, null);
        return obj;
    }
    catch (TargetInvocationException tie)
    {
        if (tie.InnerException != null) throw tie.InnerException;
        throw;
    }
}



So how am I making use of this fluent interface? Well the methods above are two of those I have written, and probably the most interesting, but I have others too. These fall into two main categories:



  1. setting default valid values;

  2. creating default valid objects.


For setting default valid values, these are done as ExtensionMethods on the type I'm interested in. For example:



        public static Extract WithDefaultTitle(this Extract extract)
        {
            extract.QualificationTitle = "Mr";
            extract;
        }


For creating default valid objects, this is also done with an ExtensionMethod on the type that I'm interested in. As my need for different default starting points increases then I can easily write more. Here's an example:


        public static Extract AsValid(this Extract extract)
        {
            return extract
                .WithDefaultCode()
                .WithDefaultTitle()
                .SetValue(e => e.Id, 111)
        }


With these methods available to me I can combine them with my SetValue and SetLength methods to then alter the state of any given property so that I can test the implications of the value set in a degree of isolation (at least consistency).  In particular I am using this to test that behaviour to validate my object works correctly given different combinations of property values on the object under test. Here's an example of this:


        [Test]
        [ExpectedException(typeof(InvalidOperationException), "An Id must be present.")]
        public void NullIdShouldThrowAnInvalidOperationExceptionOnValidate()
        {
            Extract extract = new Extract()
                .AsValid()
                .SetValue(e => e.Id, null);
            extract.Validate();
        }
 
        [Test]
        public void A_SurnameWithLessThan35CharactersShouldBePaddedTo35CharactersInFormattedProperties()
        {
            Extract extract = new Extract()
                .AsValid()
                .SetLength(e => e.Surname, 34);
                
            Assert.AreEqual(34, extract.Surname.Length);
            Assert.AreEqual(35, extract.FormattedProperties["Surname"].Length);
        }

Personally I'm happy with how this is progressing, but we'll see how it goes as I begin to push the current envelope a bit more.

Sunday, 18 January 2009

Fluent Test Data Builders Using Generic Extension Methods and Lambda Expressions

Whilst writing some extension methods this evening to make creating objects in unit tests simpler I found myself writing methods that looked sufficiently similar to each other that I felt the code lacked a little DRYness.

The code being written has to output a data extract in a fixed field length formatted text file. As such the length of the formatted fields is very important, so I had created some methods to initialise the properties of my object with given lengths so that I could ensure the desired behaviour during formatting (such as trimming, padding, exception throwing, etc...). These methods looked much like this:

public static DataExtract WithSetLengthSurname(this DataExtract dataExtract, int length) 
{ 
    dataExtract.Surname = string.Empty.PadRight(length); 
    return dataExtract; 
}
 
public static DataExtract WithSetLengthForenames(this DataExtract dataExtract, int length) 
{ 
    dataExtract.Forenames = string.Empty.PadRight(length); 
    return dataExtract; 
} 
 

As you can see these methods are very similar. What I wanted I felt was to take this fluent interface for creating my DataExtract object, but to make the whole thing more generic.


This is what I came up with:


public static T SetLength<T>(this T obj, Expression<Func<T,string>> expression, int length) 
{ 
    string memberName = getMemberExpressionMemberName(expression.Body); 
    string currentValue = expression.Compile().Invoke(obj) ?? string.Empty; 
    string newValue = currentValue.PadRight(length); 
    obj.GetType().GetProperty(memberName).SetValue(obj, newValue, null); 
    return obj; 
} 
 
private static string getMemberExpressionMemberName (Expression expression) 
{ 
    if (expression == null) return string.Empty; 
 
    switch (expression.NodeType) 
    { 
        case ExpressionType.MemberAccess: 
            { 
                MemberExpression memberExpression = (MemberExpression) expression; 
                return memberExpression.Member.Name; 
            } 
        default: 
            throw new InvalidOperationException(string.Format("The Expression Type was not expected: {0}", expression.NodeType)); 
    } 
 
}

With this code then I can now make a call like this:


DataExtract extract = new DataExtract().SetLength((e) => e.Forenames, 10);

Now it's not unreasonable to look at this and wonder what has been gained, after all I could have written this:


DataExtract extract = new DataExtract { Forenames = "".PadRight(10) };

I suppose for me it comes into its own when combined with other extension methods as a part of a wider ranging Fluent Interface based test object builder, like this:


CandidateExtract extract = new CandidateExtract() 
    .SetLength((e) => e.Surname, 36) 
    .WithValidQualificationCode() 
    .WithValidQualificationTitle() 
    .SetLength((e) => e.Forenames, 36);

As can be seen in the above some property specific methods still exist, because the behaviour that each implements is sufficiently unique, but where the behaviour is very similar (such as setting a string to a default length) this seems to me to provide a number of benefits:


  • the number of methods appearing in Intellisense drops making it easier to find what you want quickly
  • the number of builder methods to be written drops (in my case significantly)
  • by using a fluent interface readability is enhanced.