WCF and Interfaces

I went back to my Road Alert project and I wanted to add modifiers to the geolocations to account for the seasonality of the alter types. For example, there are 36% more crashes in May and 27% more crashes in November.

To that end, I added some more tables to my database – a table for each of the seasonal factors. I kept the database in third normal form:

and the updated the Entity Model on my service layer:

:

I then need to update my service interface to account for the new data. I noticed that all of the tables all had the same format: PK (Int32), FKs(Int32), TableValueId(Int32), and ModifierValue(Float). The only variation is the TableValue – in the Month table it is 1-12, in the DayOfWeek it is 0-6, DayOfMonth is 1-31 and Hour is 0-23)

Channeling my Inner Uncle Bob, I created an interface for these data structures like so:

I then deployed the service to my web hosting provider and updated the service interface on my other tests. Whn I did that, I ran into trouble:

[TestMethod]

publicvoid GetModifiers_ReturnExpectedValue()

{

RoadAlertClient client = newRoadAlertClient();

List<IAlertTypeModifier> modifiers = client.GetAlertTypeModifiers();

Int32 notExpected = 0;

Int32 actual = modifiers.Count;

Assert.AreNotEqual(notExpected, actual);

}

With the exception:

Cannot implicitly convert type ‘System.Collections.Generic.List

And When I Googled on Bing, I found out that you can’t return interfaces because you can’t serialize interfaces. Crap! Looks like I need to concrete classes if I want to use WCF.

So now I have a choice:

1) Return each concrete type so I add 8 methods to the service interface (GetMonth, GetMonths, etc…) Put these together on the client side

2) Return a more generic concrete class (equiv to an abstract class) and parse the results on the client

3) Use REST

Since I am already down the SOAP path on this project, I do not want to pivot to REST right now. In order to offload processing from the client, I decided to clutter up my Service interface with more methods. So I changed my interface like this:

And because I don’t need to abstract the valueId, I renamed it to be more reflective of its intent. For example:

AlertTypeDayOfWeekModifier.ValueId is now AlertTypeDayOfWeekModifier.DayOfWeekId

Also, I changed the PK to more intention revealing also:

AlertTypeDayOfMonthModifier.AlertTypeModifierId is now AlertTypeDayOfMonthModifier.AlertTypeDayOfMonthModifierId

I then ditched the interface and put the common fields into a base class:

publicabstractclassAlertTypeModifier

{

publicInt32 AlertTypeId { get; set; }

publicInt32 ModifierId { get; set; }

publicdouble Modifier { get; set; }

}

And had each of the implementations like this:

publicclassAlertTypeDayOfMonthModifier : AlertTypeModifier

{

publicInt32 AlertTypeDayOfMonthModifierId { get; set; }

publicInt32 DayOfMonthId { get; set; }

}

Which severs well enough. Then it was just a question of updating the service.cs file with the implementation (an incredibly boring 15 minutes) and adding some tests. I got green locally and then green via the web service.

So I guess the lesson learned is that you really can’t apply the Open/Closed principle using WCF Web Services.