Noocyte’s Weblog

October 28, 2011

ValueInjecter and Expression Magic

Filed under: Work — Tags: — noocyte @ 9:53

In a previous post I have talked some about how I use AutoMapper and I’m using it for all my “Entity To View” model mappings; works like a charm! But what it does not do is to map the other way; ie. take whatever comes from the view and apply that to an entity model. There are some discussions online on the ‘correctness’ of doing this, but I found it to be an easy and productive technique.

But since AutoMapper doesn’t handle this I had to write a lot of LHS-RHS code, right? No I didn’t! Somebody else have already solved this problem in a utility called ValueInjecter. Basically it’s capable of injecting values from one object to another, and this of course is exactly what I need! So how do I use it;

var entityObject = db.GetEntity(viewObject.UniqueId);
entityObject.InjectFrom<CustomInjectionRules>(viewObject);
entityObject.State = EntityState.Modified;
db.Store(entityObject);

The magic happens on line number two; the InjectFrom method will transfer data from my viewObject to the entityObject. The method can be used without specifying a type (generics) to assist in the injection, but I need it to allow for data type and naming variations between the two objects. The CustomInjectionRules class handles those two issues and looks a little like this:

public class CustomInjectionRules : ConventionInjection
   {
       protected override bool Match(ConventionInfo c)
       {
           return c.SourceProp.Name.Equals(“ViewProp”) && c.TargetProp.Name.Equals(“EntityProp”);
       }

       protected override object SetValue(ConventionInfo c)
       {
           return Convert.ToInt32(c.SourceProp.Value);
       }

   }

The class inherits from “ConventionInjection” and overrides two methods; one for matching properties with unequal names and the second for converting between whatever “ViewProp” is and int32 (“EntityProp”).

After writing this code I made sure it worked and then came back to look at it; could I improve it? Refactor it somehow? Not much code in there, so my first instinct was; No, this is fine. But then I looked hard at the “Magic Strings” (“ViewProp”/”EntityProp”)… I do not like magic strings! No refactor/compile time support and all that nonsense. So I had to find a better solution! I immediately thought of another blog post I’d done some time ago; MVC 3, EF 4.1 And Some More… The HtmlHelper methods appear to just take a lambda expression as input and then figures out the name of the property! Which of course is exactly what I needed! So I started Googling… I found a few examples, but they weren’t spot on before I found a question on StackOverflow! Spot on! I did some minor adjustments and not my CustomInjectionRules class looks like this:

public class EvaluationRuleTypeInjection : ConventionInjection
{
    protected override bool Match(ConventionInfo c)
    {
        return c.SourceProp.Name.Equals(GetMemberInfo<ViewObject>(r => r.ViewProp))
                && c.TargetProp.Name.Equals(GetMemberInfo<EntityObject>(r => r.EntityProp));       
    }

    protected override object SetValue(ConventionInfo c)
    {
        return Convert.ToInt32(c.SourceProp.Value);
    }

    private string GetMemberInfo<T>(Expression<Func<T, object>> method)
    {
        LambdaExpression lambda = method as LambdaExpression;
        if (lambda == null)
            throw new ArgumentNullException(“method”);

        MemberExpression memberExpr = null;

        if (lambda.Body.NodeType == ExpressionType.Convert)
            memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
        else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
            memberExpr = lambda.Body as MemberExpression;

        if (memberExpr == null)
            throw new ArgumentException(“method”);

        return memberExpr.Member.Name;
    }
}

Awesome! I immediatly moved the “GetMemberInfo” method out of this class and into a more appropriate class, but included it here to avoid expanding all the code…

Pretty happy about this change. Also loving how easy it is to get stuff such as ValueInjecter into my prosjects using nuget.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

Create a free website or blog at WordPress.com.