Using a Converter to convert from a Model to a Business Class

In yesterdays posting about using RestSharp, I spent a paragraph at the end talking about Model vs. Business Classes and about converting between them. To recap:

  • Data Model classes are very closely related to the underlying data, be it a database or a web service. They are very fragile as they more or less mirror the data 1:1 and therefore often change. They may have deep nesting and you don't have much freedom designing them as they need to match the data.
  • Business classes are an abstraction of the data model and are used by most parts of the application. They are usually rather flat and mostly stable, and you have the freedom to model them to suit your application, rather than mirror the underlying data.

Now, in order to convert between Data Model and Business Classes, you need some sort of Converter function. This could be a secondary constructor in the Business Class that takes a Model Class (not recommended as this created tight coupling), or this could be a separate class/function. Generally, I always try to find something that's already in the Framework, and conveniently there is a Converter<TInput, TOutput> delegate in the Framework.

What does a standardized delegate allow us to do? It allows us to have a standardized converter function, of course! Let me clarify that: In the example yesterday, we wanted to Convert from a PowerPlantsDTO to a List<PowerPlant>. To do so, we had to run RestClient.Execute<PowerPlantsDTO> to get the DTO, perform the conversion to the List<PowerPlant> and work with that. But what if I want to implement the searchLocation service in our example Web Service? I would want to convert from a LocationsDTO to a List<Location>, right?

I would write a bunch of Converter-Functions and then I have two functions: One for SearchPlants that executes the request, converts it and returns the converted result, and one for SearchLocation which executes the request, converts it, and returns the converted result. As you see, these two functions more or less do the same, they just work with different classes and parameters to the RestRequest. So according to the DRY-principle, we should centralize them as much as possible.

So we want a general "Execute and Convert" function. Our two search functions should only do what is specific to them (that is: Constructing a proper RestRequest), but the execute and convert part is shared (except for the classes) and should be centralized therefore. And that is why standardized delegates matter. Simplified, Delegates are references to functions (you could call them function pointers, although they are not the same as FP's in C++ - read more about them here) and allow us to pass a function into another function.

Let's create an extension method to the RestClient:

public static class RestClientExtensionMethods
{
    public static TBusiness Execute<TModel,TBusiness>(this RestClient client,
      RestRequest request, Converter<TModel,TBusiness> converter) where TModel : new()
    {
        var restResult = client.Execute<TModel>(request);
        return converter.Invoke(restResult);
    }
}

Whoa, bracket overflow here, so let's examine that. We have two generic classes: TBusiness and TModel. TModel is the class you previously passed into Execute, so this is the Data Model class. The "where TModel : new()" constraint is taken from the existing Execute function - if you don't know about generic type constraints, MSDN has an article. TBusiness is the desired return value.

What this function does: It calls the existing Execute function using the class specified as TModel. Then, it invokes the Converter function (keep in mind: We are passing a reference to the converter function, not the result of it) and returns the result.

We have a Converter as a parameter to this class, so we need to pass in a function that has a TInput as it's single parameter and a TOutput as it's return value - check the syntax of the Converter at MSDN:

public delegate TOutput Converter<TInput, TOutput>(TInput input)

We create a new Class that has the functions. I went with a static class, but a non-static works as well.

public static class Converters
{
    public static PowerPlant ItemToPowerPlant(RestTest.Model.item input)
    {
        return new PowerPlant
                   {
                       PlantName = input.name,
                       City = input.location.city.value,
                       Latitude = input.location.latitude,
                       Longitude = input.location.longitude,
                       ZipCode = input.location.zip
                   };
    }

    public static List<PowerPlant> PowerPlantsDTOToList(PowerPlantsDTO input)
    {
        var result = new List<PowerPlant>();
        foreach(var sourcePlant in input) result.Add(ItemToPowerPlant(sourcePlant));
        return result;
    }
}

In this class, we have two converters: A converter that takes an item and returns a PowerPlant, and a converter that takes a PowerPlantsDTO and returns a List of PowerPlants. To invoke this, we need to create a new delegate that holds the desired function and call our extension method:

var convDelegate = 
  new Converter<PowerPlantsDTO, List<PowerPlant>>(Converters.PowerPlantsDTOToList);
var plants = client.Execute(request, convDelegate);

You may ask yourself "Why don't we have to specify TModel and TBusiness on the call to Execute?" - That's because the C# compiler is smart enough to infer the types. It knows that TModel is PowerPantsDTO and that TBusiness is List<PowerPlant>. I don't know exactly how, but I guess it can infer it from the Signature of the delegate.

If you run this code now, plants will be a List<PowerPlant> - Nice!

But... That var convDelegate line is rather ugly, is it? I haven't really found a nice way around it, but you can make it a new method of the static Converters class:

public static Converter<PowerPlantsDTO,List<PowerPlant>>
  GetPowerPlantsDTOToListConverter()
{
    return PowerPlantsDTOToList;
}

You can then simplify the Execute call:

var plants = client.Execute(request,Converters.GetPowerPlantsDTOToListConverter());

The important thing here to notice: You return the function, so no brackets! The .net runtime is smart enough to return it as a Converter, so no need to write "return new Converter<PowerPlantsDTO,List<PowerPlant>>(PowerPlantsDTOToList)" instead (even though that would also work).

Now, this whole approach may seem incredibly complicated with all those extra functions. And for simple projects, it most likely is. But if you need this for a lot of different conversions, it has a big advantage of offering you a standardized interface throughout the entire application.

I'm undecided though if RestClient should have that functionality due to separation of concerns. One could argue that RestClient should only deal with it's own problem domain, which is talking to the REST API and returning a model class, and that someone else should deal with the conversion. In the end, you have to decide what fits your own architecture best. I've just shown one way how you can standardize and centralize this and hope you can gain something from it.

Comments (1)

6 Important Delegates « Log for ITAugust 23rd, 2010 at 10:59

[...] is a nice delegate when a lot of Converting of Model into Business classes is needed, i.e. http://www.stum.de/2009/12/23/using-a-converter-to-convert-from-a-model-to-a-business-class/ August 23rd, 2010 | Tags: delegate | Category: [...]