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.

 image

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:

image

and the updated the Entity Model on my service layer:

:image

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:

  1. public interface IAlertTypeModifier
  2. {
  3.     Int32 AlertTypeModifierId { get; set; }
  4.     Int32 AlertTypeId { get; set; }
  5.     Int32 ModifierId { get; set; }
  6.     Int32 ValueId { get; set; }
  7.     double Modifier { get; set; }
  8. }

 

I then updated the service interface like this:

  1. [ServiceContract(Namespace = "http://schemas.tff.com/2013/07/RoadAlert.Services")]
  2. public interface IRoadAlert
  3. {
  4.     [OperationContract]
  5.     Location GetLocation(Int32 locationId);
  6.  
  7.     [OperationContract]
  8.     List<Location> GetLocations();
  9.  
  10.     [OperationContract]
  11.     List<Location> GetLocationsForMultipleAlertTypes(List<Int32> alertTypeIds);
  12.  
  13.     [OperationContract]
  14.     AlertType GetAlertType(Int32 alertTypeId);
  15.  
  16.     [OperationContract]
  17.     List<AlertType> GetAlertTypes();
  18.  
  19.     [OperationContract]
  20.     IAlertTypeModifier GetAlertTypeModifier(Int32 alertTypeId, Int32 modifierId, Int32 valueId);
  21.     
  22.     [OperationContract]
  23.     List<IAlertTypeModifier> GetAlertTypeModifiers();
  24.  
  25.     [OperationContract]
  26.     List<IAlertTypeModifier> GetAlertTypeModifiersForAnAlertType(Int32 alertTypeId);
  27.  
  28.     [OperationContract]
  29.     List<IAlertTypeModifier> GetAlertTypeModifiersForAModifierId(Int32 modifierId);
  30.  
  31.     [OperationContract]
  32.     List<IAlertTypeModifier> GetAlertTypeModifiersForAnAlertTypeAndModifierId(Int32 alertTypeId, Int32 modifierId);
  33.  
  34. }

 

I then created the supporting internal methods to these public methods and ran them though my unit tests and the public methods ran green.  For example:

  1. [TestMethod]
  2. public void GetModifiers_ReturnExpectedValue()
  3. {
  4.     RoadAlert roadAlert = new RoadAlert();
  5.     List<IAlertTypeModifier> modifiers = roadAlert.GetAlertTypeModifiers();
  6.  
  7.     Int32 notExpected = 0;
  8.     Int32 actual = modifiers.Count;
  9.  
  10.     Assert.AreNotEqual(notExpected, actual);
  11. }

image

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:

 

  1. [TestMethod]
  2. public void GetModifiers_ReturnExpectedValue()
  3. {
  4.     RoadAlertClient client = new RoadAlertClient();
  5.     List<IAlertTypeModifier> modifiers = client.GetAlertTypeModifiers();
  6.  
  7.     Int32 notExpected = 0;
  8.     Int32 actual = modifiers.Count;
  9.  
  10.     Assert.AreNotEqual(notExpected, actual);
  11. }

 

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:

  1. [ServiceContract(Namespace = "http://schemas.tff.com/2013/07/RoadAlert.Services&quot;)]
  2. public interface IRoadAlert
  3. {
  4.     [OperationContract]
  5.     Location GetLocation(Int32 locationId);
  6.  
  7.     [OperationContract]
  8.     List<Location> GetLocations();
  9.  
  10.     [OperationContract]
  11.     List<Location> GetLocationsForMultipleAlertTypes(List<Int32> alertTypeIds);
  12.  
  13.     [OperationContract]
  14.     AlertType GetAlertType(Int32 alertTypeId);
  15.  
  16.     [OperationContract]
  17.     List<AlertType> GetAlertTypes();
  18.  
  19.     [OperationContract]
  20.     AlertTypeDayOfMonthModifier GetAlertTypeDayOfMonthModifier(Int32 AlertTypeDayOfMonthModifierId);
  21.  
  22.     [OperationContract]
  23.     List<AlertTypeDayOfMonthModifier> GetAlertTypeDayOfMonthModifiers();
  24.  
  25.     [OperationContract]
  26.     AlertTypeDayOfWeekModifier GetAlertTypeDayOfWeekModifier(Int32 AlertTypeDayOfWeekModifierId);
  27.  
  28.     [OperationContract]
  29.     List<AlertTypeDayOfWeekModifier> GetAlertTypeDayOfWeekModifiers();
  30.  
  31.     [OperationContract]
  32.     AlertTypeHourModifier GetAlertTypeHourModifier(Int32 AlertTypeHourModifierId);
  33.  
  34.     [OperationContract]
  35.     List<AlertTypeHourModifier> GetAlertTypeHourModifiers();
  36.  
  37.     [OperationContract]
  38.     AlertTypeMonthModifier GetAlertTypeMonthModifier(Int32 AlertTypeMonthModifierId);
  39.  
  40.     [OperationContract]
  41.     List<AlertTypeMonthModifier> GetAlertTypeMonthModifiers();
  42. }

 

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:

  1. public abstract class AlertTypeModifier
  2. {
  3.     public Int32 AlertTypeId { get; set; }
  4.     public Int32 ModifierId { get; set; }
  5.     public double Modifier { get; set; }
  6.  
  7. }

 

And had each of the implementations like this:

  1. public class AlertTypeDayOfMonthModifier : AlertTypeModifier
  2. {
  3.     public Int32 AlertTypeDayOfMonthModifierId { get; set; }
  4.     public Int32 DayOfMonthId { get; set; }
  5. }

 

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.

image

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

Data Transfer using WCF

So forgetting OData for a minute (not hard to do), I was thinking about how to transfer SDO classes to and from a WCF service.  All of the WCF projects I have worked on have been POCOs with the appropriate WCF attributes from System.ServiceModel and System.Runtime.Serialization.  I never thought about putting an ADO.NET recordset as a return value from a WCF method.  I also wondered about putting the recordset as a parameter to a WCF method.  I assume it is possible, I was curious about how much effort it would take.  I Binged on Google (or was it Googled on Bing) and these was nothing that jumped out.

I fired up a typical WCF project and then added a consuming console app to the solution.  I then wrote an interface that returns a dataTable like so:

[ServiceContract]
public interface IDataFactory
{
    [OperationContract]
    DataTable GetDataTable();
}
public class DataFactory : IDataFactory
{
    public DataTable GetDataTable()
    {
        throw new NotImplementedException();
    }
}

I then hit F6 and sure enough it compiled.  I then changed the implementation to this

public DataTable GetDataTable()
{
    DataTable dataTable = new DataTable();
    dataTable.TableName = "Customers";
    dataTable.Columns.Add("CustomerId");
    dataTable.Columns.Add("CustomerName");

    DataRow row1 = dataTable.NewRow();
    row1[0] = 1;
    row1[1] = "Customer #1";
    dataTable.Rows.Add(row1);
    DataRow row2 = dataTable.NewRow();
    row2[0] = 2;
    row2[1] = "Customer #2";
    dataTable.Rows.Add(row2);

    return dataTable;

}

and I am still compiling.  So then I went to the client and added a reference and it worked:

image

I then fired up the client like so:

static void Main(string[] args)
{
    Console.WriteLine("Starting");

    DataFactoryClient client = new DataFactoryClient();
    DataTable table = client.GetDataTable();

    foreach (DataRow row in table.Rows)
    {
        Console.WriteLine(String.Format("Customer {0} named {1}.",row[0],row[1]));
    }

    Console.WriteLine("Ending");
    Console.ReadKey();
}

And I hit F5:

image

 

Wow.  Microsoft made this stupid simple.

I then though about how to pass in an individual data row. 

[OperationContract]
String InsertDataRow(DataRow row);
public String InsertDataRow(DataRow row)
{
    return String.Format("You entered {0}.", row[0].ToString());
}

And when I hit update reference from my consuming app, I got this:

image

Crud!  I then thought I could just add a serializable data row like so:

[Serializable]
public class SerializableDataRow: DataRow
{
}

And this:

[OperationContract]
String InsertDataRow(SerializableDataRow row);

But no, I get this:

image

So now I have to jump down a rabbit hole and possible violate the Liskov Substitution Principle.  Since I want things to be stupid simple, I gave up with inheritance.  I then found this post.  So either use a datatable (and suffer the overhead) or convert the DataRow into something that can be seialized (like XML, custom classes, etc..)

So I give Microsoft a C on this – somewhat stupid simple, but not entirely…

Consuming JSON from a C# Project

I was thinking about an app that I have wanted to write for a while.  Part of the application uses weather data.  Since I have been using weather underground since forever (Go Blue), that seemed like a natural place to start.  I hopped over to wunderground and sure enough, at the bottom of the page is a link for consuming its API. 

image

Following the Weather API for Developers – JSON link, I signed up for a free developer account.  Within minutes I got my API key and I was ready to start looking for the data I was interested in for my application. I first went to the documentation page, I started with the current conditions for a city example:

http://api.wunderground.com/api/axxxxxx/conditions/q/CA/San_Francisco.json

I then switched out the state/city criteria with my zip code:

http://api.wunderground.com/api/axxxxxxxx/conditions/q/27519.json

Sure enough, data is getting returned.

image

Now that I have a source of data, I need a way to consume the data using Visual Studio.  I fired up a Console project just to see how difficult it would be to consume.  I put in a typical webrequest/response:

Uri uri = new Uri(@"http://api.wunderground.com/api/xxxxxxxx/conditions/q/27519.json");
WebRequest webRequest = WebRequest.Create(uri);
WebResponse response = webRequest.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());
String responseData = streamReader.ReadToEnd();
Console.WriteLine(responseData);

Sure enough, I am getting the data back:

image

The next step is to parse this string so I can do something useful with it.  Fortunately, I was coding this solution during a meeting of Cary’s Technology Task Force and I was sitting next to an OData/JSON expert: Ian Cillay .  Ian told me that to parse Json from VS, I needed to get Newtonsoft’s Json.NET framework because MSFT has essentially given up on the parsing and is deferring everything to NewtonSoft.  Once I had that installed via NuGet, I the realized I still needed a class pre-defined to populate from the Json feed.  I fired up a new class with a couple of properties:

public class WeatherData
{
    public String pressue_mb { get; set; }
    public String pressume_in { get; set; }
    public String pressure_trend { get; set; }
    public String relative_humidity { get; set; }
}

I then coded up line to use that Json library to put the data from the response string into an instantiated class:

var outObject = JsonConvert.DeserializeObject<WeatherData>(responseData);

However, when I ran it, nothing was getting populated.

image

Ian told me that my simple class did not reflect the actual Json.  Stumped (and still hating Json), I then stumbled across this site.  Sure enough  it was like SVCUTIL.exe for Json.  I got the classes created for me

image

and I then could consume the data like this:

var outObject = JsonConvert.DeserializeObject<RootObject>(responseData);

and the output is

image

Wahoo!  I will use the Visual Studio’s External Tools Feature to generate classes for me on the fly:

image

Consuming REST services using Visual Studio 2010

Aetna is dipping its toe into public facing APIs via Carepass.  I signed up for a license and wanted to see how easy it was to consume some HHS drug data found here.  I first checked a GET inside a browser with the following uri:

https://api.carepass.com/hhs-directory-api/drugs/search?name=Cymbalta&apikey=xxx

and I got my results:

image

I then fired up Visual Studio to see how easy it would be to make a REST WCF call.  Turns out, there is not a way to add-> service reference like you can with SOAP.  This means I am turning back the clock of HttpWebRequest and HttpWebResponse.  Interestingly, there are not very good examples on Stackoverflow and MSDN about consuming non-WCF REST services.  The best example I found was here on Yahoo!

I created a simple ConsoleApp (changed it target runtime from client profile to full .NET 4.0) and launched into code:

static void Main(string[] args)
{
    Uri address = new Uri(@"https://api.carepass.com/hhs-directory-api/drugs/search?name=Cymbalta&apikey=t8bnhyvu9hj7eh4c8tg97jgb");   
    HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;   
    request.Method = "POST";   
    request.ContentType = "application/x-www-form-urlencoded";   

    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)   
    {   
        StreamReader reader = new StreamReader(response.GetResponseStream());   
        Console.WriteLine(reader.ReadToEnd());   
    }

    Console.ReadKey();
}

Sure enough, it worked like a charm:

image

So then the next problem – how to I parse this blob of name/value pairs?  And is there hierarchical data in there?  I first thought (hoped) it would be easy – just split by the ‘:’

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)   
{
    StreamReader reader = new StreamReader(response.GetResponseStream());
    String output = reader.ReadToEnd();
    Console.WriteLine("Response was: " + output.Length);
    String[] splitOutput = output.Split(':');
    foreach (String item in splitOutput)
    {
        Console.WriteLine(item);
    }
}

No dice:

image

I then switched my delimited to a comma:

image

That is actually better.  The next thing is seems is to check to see if the comma is inside the double quotes.  I know that the industry is going to REST from SOAP – but this is so much worse than adding a reference in Visual Studio….