Wednesday 4 June 2014

Using Data Annotations with Portable Class Libraries

I am currently writing an application that’s targeting multiple platforms – iOS, Android, Windows Phone as clients, and naturally .NET on the server which will be hosted in Azure. I’m making good use of portable class libraries, so that I can share as much code between my clients as possible (and I’m using Xamarin to make all this possible).

For my client projects I have two shared libraries – one with interfaces, another with implementations. As an example I have a DTO class on the client as follows…

public class AccountInformationRequest
{
public string Token { get; set; }

public string MSISDN { get; set; }

public string Carrier { get; set; }
}



This class is also used on the server in a controller method…

public async Task<AccountInformation> PostAccountInformation(AccountInformationRequest request)
{
return await _accountInformationService.GetAccountInformation(request);
}



On the server however I want to use data annotations to minimise the amount of code I need to write in order to validate the incoming request but this poses a problem – the AccountInformationRequest type is defined in a Portable Class Library, and if I update it to add on the data annotation attributes then my PCL will be re-targeted and won’t then run on all of my desired client platforms.


As usual in programming, another level of indirection solves every problem. Since .NET 1.0 we’ve had ICustomTypeDescriptor, and indeed one of the first articles I wrote online was about this interface (the article is long gone, it was written in 2001 ish). Since .NET 2 things have got measurably better for anyone wanting to do some spelunking with types, as it released the TypeDescriptor and TypeDescriptorProvider support. Fast forward a few more years and we now have a very simple way to augment one class with metadata from another – the massively named ‘AssociatedMetadataTypeTypeDescriptionProvider’.


What this class allows you to do is say “Hey, this class X provides metadata for that class Y”. Or more to the point for this article, “This server class which has all the attributes I need replaces the metadata for the PCL class”. All you need to do is create a second class which has all the metadata attributes you need (in my case just validation), then register it. My server side class is as follows…

public class AccountInformationRequestServer
{
[Required]
public string Token { get; set; }

[Required]
public string MSISDN { get; set; }

[Required]
public string Carrier { get; set; }
}



Then I can just register it inside Global.asax…

TypeDescriptor.AddProvider
(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(AccountInformationRequest),
typeof(AccountInformationRequestServer)),
typeof(AccountInformationRequest));



The registration looks a little cryptic, so I’ve altered it below to show the orginalClass (that being the class defined in the PCL) and the metadataClass (that being the one defined server side)…

TypeDescriptor.AddProvider
(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(originalClass), typeof(metadataClass)),
typeof(originalClass));



That’s all there is to it. Now I can make an API call from the client, and have API validation on the server, whilst still using the same datatypes in both PCL and full fat .NET.


You’ll find the AssociatedMetadataTypeTypeDescriptionProvider class defined within System.ComponentModel.DataAnnotations (in the assembly with the same name).