Archive for August, 2010

I’m working on a project that requires a fair amount of object-to-object mapping, mostly due to the necessity to expose data to external systems using DTO’s (Data Transfer Objects).

As in many other cases the domain objects must be mapped to the DTO that will expose the data, and this is generally involves writing a lot of object-to-object mapping code, but fortunately there are several tools to help this task. After some searching I end up with two AutoMapper and Value Injecter.

Why using the two? Because both work in different ways, although the final result is to automatically map objects. AutoMapper seems to be more popular, so I’ll write about it in the future, for now I’ll talk a little bit about Value Injecter.
Value Injecter is a really small but powerful tool (I advice you to take a good look at the codeplex site). It’s also very easy to extend. It provides several classes to flattening and unflattening objects, and it very easy to use. It provides you with an extension method to inject the object, like this.

target.InjectFrom(source);

This will use the existing LoopValueInjection to inject the values from the source into the target object. All this is very nice and easy, the problem is that in the real world nothing is as simple as it seems. One of the conditions that object mappers evaluate is the name and type of each parameter. Lets take a look at an example similar to one of the documentation examples.

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public DateTime DateOfBirth { get; set; }
}

public class PersonViewModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Age { get; set; }
    public DateTime DateOfBirth { get; set; }
}

This is a simple but pretty common scenario. Properties that have the same name, but different types, and in reality they should be mapped to a different type. In my case, a common scenario is that integer values from the domain objects must be converted to strings in the DTO’s, and or vice versa. So in Value Inject you map these objects like this

personViewModel.InjectFrom(person) // this does the props of the same name and type
             .InjectFrom<IntToString>(person); // this does the props (by same name) that are of type int in viewmodel and of type string in person

And create a new value injector to map from int to string like this

public class IntToString : LoopValueInjection
{
    protected override bool TypesMatch(Type sourceType, Type targetType)
    {
        return sourceType == typeof(int) && targetType == typeof(string);
    }

    protected override object SetValue(object sourcePropertyValue)
    {
        return Convert.ToString(sourcePropertyValue);
    }
}

All this is great, but wouldn’t be better if you could create a generic injector. One that’s capable to convert the property using the appropriated conversion, knowing that the property name is the same. So let’s create a new injector that can do exactly that.

//Check if the property types match.
if (TypesMatch(sourceProp.PropertyType, targetProp.PropertyType))
{
    //Get property value from the source object.
    targetValue = sourceProp.GetValue(source);
}
else
{
    //Create a new type converter.
    TypeConverter converter = TypeDescriptor.GetConverter(targetProp.PropertyType);
    //Validate converter.
    if (converter == null)
        continue;

    //Convert from the source to target type.
    targetValue = converter.CanConvertFrom(sourceProp.PropertyType)
			? converter.ConvertTo(sourceValue, targetProp.PropertyType)
			: System.Convert.ChangeType(sourceValue, targetProp.PropertyType);
}

//Validate value
if (targetValue == null)
    continue;

//Set target value.
targetProp.SetValue(target, targetValue);

A TypeConverter is created based on the target type, and will try to convert using standard .net conversion methods. This will avoid the boring task to create different injectors for most framework types. More specific scenarios will always require custom injectors, but hopefully this will save some work.

The full source code can be downloaded from here.

The next step is to create an injector, that can convert properties of the same type but with  partial name matches. Like ReleaseDate to Release, or IsValid to Valid.

Hope this can help.


Fatal error: Internal zval's can't be arrays, objects or resources in Unknown on line 0