Deserializing Interface Properties using Json.Net

The Problem

Let’s say that you have a simple class structure such as this one:

public class Thing
{
	public string Name { get; set; }
}

public class ThingContainer
{
	public Thing TheThing { get; set; }
}

Here we have a class ThingContainer that has a single reference property of type Thing, and Json.Net will do a great job of serializing and deserializing instances of ThingContainer without any extra help:

static void Main(string[] args)
{
	var container = new ThingContainer
	{
		TheThing = new Thing { Name = "something" }
	};
	var serialized = JsonConvert.SerializeObject(container, Formatting.Indented);
	Console.WriteLine(serialized);
	// {
	//   "TheThing": {
	//      "Name: "something"
	//   }
	// }
	var deserialized = JsonConvert.DeserializeObject<ThingContainer>(serialized);
	Console.WriteLine(deserialized.TheThing.Name);
	// "something"
}

Unfortunately the real-world is rarely that simple and today you are writing a good model so you can’t go about using concrete types. Instead, you want to specify your properties as interfaces:

public interface IThing
{
	string Name { get; set; }
}

public class Thing : IThing
{
	public string Name { get; set; }
}

public class ThingContainer
{
	//notice that the property is now of an interface type...
	public IThing TheThing { get; set; }
}

After making these changes the serialization will still work as before, but when we try to deserialize the model we get the following error:

Could not create an instance of type JsonSerialization.IThing. Type is an interface or abstract class and cannot be instantated

This means that the JSON deserializer has seen that there is a property of type IThing but doesn’t know what type of object it should create to populate it.

Enter JsonConverter

The solution to this is to explicitly tell the deserializer what type it should be instantiating, and we do this using an attribute – specifically the JsonConverterAttribute.

The JsonConverterAttribute is part of Json.Net, and allows you to specify a custom converter to handle serialization and deserialization of an object by extending JsonConverter.

public class ThingContainer
{
	[JsonConverter(typeof(/*CustomConverterType*/))]
	public IThing TheThing { get; set; }
}

In this case we are going to write a custom implementation of JsonConverter that will behave exactly as the non-attributed property would, but using a specific type.

The code below shows the shell of the converter class and the methods we need to override. Notice that we are specifying a generic type parameter TConcrete on the class – this will set the desired concrete type for the property when we actually use the attribute later.

public class ConcreteTypeConverter<TConcrete> : JsonConverter
{
	public override bool CanConvert(Type objectType)
	{
		//determine whether or not this converted can create an instance of
		//the specified object type
	}

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		//deserialize an object from the specified reader
	}

	public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
	{
		//serialize the object value
	}
}

The roles of the missing methods are fairly self explanatory, and seeing as we’re feeling lazy today we’ll pick off the easy ones first.

CanConvert

What we should be doing in CanConvert is determining whether or not the converter can create values of the specified objectType. What I am actually going to do here is just return true (i.e. “yes, we can create anything”). This will get us through the example and leaves the real implementation as an exercise for the reader…

WriteJson

The WriteJson method is responsible for serializing the object, and (as I mentioned above) the serialization of interface properties already works as expected. We can therefore just use the default serialization to fulfil our needs:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
	//use the default serialization - it works fine
	serializer.Serialize(writer, value);
}

ReadJson

The ReadJson method is where it starts to get interesting, as this is actually what is causing us the problem.

We need to re-implement this method so that it both instantiates and populates an instance of our concrete type.

Thankfully, Json.Net already knows how to populate the object – and any sub-objects, for that matter – so all we really need to do is get it to use the correct concrete type. We can do this by explicitly calling the Deserialize<T> overload on the serializer:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
	//explicitly specify the concrete type we want to create
	//that was set as a generic parameter on this class
	return serializer.Deserialize<TConcrete>(reader);
}

Usage and Final Code

Now that we have our custom attribute we just need to specify it on the model…

public class ThingContainer
{
	[JsonConverter(typeof(ConcreteTypeConverter<Thing>))]
	public IThing TheThing { get; set; }
}

…and we can deserialize without any errors!

The final code for the converter is below. There are quite a few extensions that could be made to this, but as a quick-fix to a problem that I come across often this will do the job nicely.

public class ConcreteTypeConverter<TConcrete> : JsonConverter
{
	public override bool CanConvert(Type objectType)
	{
		//assume we can convert to anything for now
		return true;
	}

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		//explicitly specify the concrete type we want to create
		return serializer.Deserialize<TConcrete>(reader);
	}

	public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
	{
		//use the default serialization - it works fine
		serializer.Serialize(writer, value);
	}
}
Advertisements

The Magic of SignalR

I recently managed to find both the time and a suitable project to get my hands dirty with SignalR – a .NET library that provides real-time updates between web clients.

This post is a bit of a brain dump of the various things I worked through to get it doing what I wanted for the first time. Much of this will probably not apply to everyone – some may not even make sense – but hopefully someone will find it useful.

The Setup

As seems to be the case with most everything coming out for ASP.NET these days, SignalR is very quick to get up and running.

Before starting I had read a few tutorials and watched a couple of videos so I already had a pretty good idea that this would be the case, but it bears repeating: SignalR is ridiculously easy to set up. So much so that it almost feels like you’re cheating.

Once you’ve installed the nuget package you just create a Hub class and start adding methods.

Want to invoke server-side code from JavaScript? Easy – just add a method:

//server
public class ExampleHub : Hub
{
	public void SendMessage(string message)
	{
		//do something with message
	}
}

Then on the client just create and start a hub instance and call that method directly:

//client
$(function () {
    var hub = $.connection.exampleHub;

    $.connection.hub.start(function() {
        hub.sendMessage("a message from the client");
    });
});

How about calling the JavaScript clients from the server-side .NET code? Just call Clients.[method]:

//server
public void SendMessage(string message)
{
	Clients.receiveMessage(message);
}
//client
hub.receiveMessage = function (message) {
    alert("Received from server: " + message);
};

That’s it! 5 minutes from “Install Package” to the basics of a chat client!

Filtering Bits Out

Having gotten to the “wow it works” stage pretty quickly, I started to write some real functionality and began to stumble across a few problems. Firstly, what if some clients don’t want to be notified of every message?

Take the class chat room example: if you have multiple rooms you really don’t want to send messages from room A to the people in rooms B, C and D. The way to solve this in SignalR is with Groups.

Filtering with Groups

Grouping with SignalR allows you to call methods on a subset of all clients based on a name:

public void SendMessage(string message)
{
	//only send message to group named 'Room A'
	Clients["Room A"].receiveMessage(message);
}

To get this to work you need to write a bit of code to assign clients to a group, which I implemented by adding a join method to my hub that the clients could call when they first connect:

//client
$(function () {
    $.connection.hub.start(function() {
        hub.join("Room A");
    });
});

On the server we need to associate the client that has called Join with the group name they have specified. SignalR already gives every client connection a unique identifier which is available through the Context.ConnectionId, and we use this ID to associate the current caller with the specified group.

//server
public void Join(string groupName)
{
	Groups.Add(Context.ConnectionId, groupName);
}

Once this is hooked up, only clients that explicitly join “Room A” will see the message for that room.

Filtering out the Caller

As well as avoiding sending messages to people who aren’t interested, I also wanted to avoid sending them back to the sender – after all, they already know about it.

Unfortunately there isn’t a similar solution to Groups (that I could find, anyway) so I had to take a different approach: send the message, but allow the client to filter it out.

I mentioned above that every client of a Hub is associated with a unique ConnectionId. If we pass this along with every message then each client can filter out anything that has originated from themselves:

hub.receiveMessage = function (message, from) {
    if (/* from !== this client */) {
        alert("Message from server: " + message);
    }
};

For some reason the hub implementation in JavaScript is not automatically aware of it’s connection ID, so to get this working client-side we need to add a little bit to our Join method to set that property on the client:
Update: Damian Edwards mentions in the comments that you can get the connection ID without writing anything yourself using $.connection.hub.id, but I’m leaving in the below as it’s a nice example of setting properties on clients from the server.

//server
public void Join(string groupName)
{
	Caller.connectionId = Context.ConnectionId;
	//add to groups etc
}
//client
hub.receiveMessage = function (message, from) {
    if (from !== hub.connectionId) {
        alert("Message from server: " + message);
    }
};

In the server code we are using the Caller property to refer to the client that has called Join. We can set a property on the caller and it just shows up on our hub object in JavaScript!

It’s not just about the messages

The primary function of SignalR is to allow real-time communication between server and client, but that’s not all that you can use the hubs for.

Lets suppose that when a client joins a room they are going to need to get some data – lists of participants, recent messages etc. We could write a Controller or WebAPI method to allow a client to get that information from the server, but why make a second call if we don’t need to? SignalR can handle all serialization of complex objects for us, so we can just return whatever information we want from the call to Join:

//server
public RoomInfo Join(string groupName)
{
	return new RoomInfo {
		Participants = { /*...*/ },
		RecentMessages = { /*...*/ }
	}
}

When a hub method returns an object, SignalR will automatically serialize it and return it as the first parameter to the done handler on the client:

//client
 hub.join("Room A")
        .done(function (roomInfo) {
            //use roomInfo object
        });

The generated methods on the hub will in fact always return an instance of $.Deferred() to allow us to track the progress of a call.

To take things a step further you can use a hub almost as a replacement for WebAPI (as suggested by Yngve Bakken Nilsen here). Obviously this doesn’t make a sense in every scenario, but it is definitely an option, and I particularly like the fact that this method removes the need for URLs in the JavaScript.

A quick note on Windows Azure

For this particular project I was using Windows Azure preview to host the site, and on deploying it I noticed an extremely strange performance characteristic. The first notification that was sent from server to client was basically instantaneous, but all subsequent ones would take much much longer – up to 30s – to come through.

It took me a little while to get an answer, but eventually my Stack Overflow question was answered by David Fowler himself – there is a known issue with Windows Azure Preview sites that causes messages to be buffered.

The solution is very simple: just specify long polling as the desired transport mechanism:

$.connection.hub.start({ transport: 'longPolling' }, function() {
    //...
});

Once this is in place, every notification started coming through instantaneously.

The Conclusion

My first experience with SignalR was overwhelmingly positive. The effortless way it gives you live updates is immensely impressive, and when I did have problems I was able to find answers relatively quickly through Stack Overflow and other community sites.

The real beauty, though, is the fact that it is such a good abstraction from the underlying implementation that the first time you get it working it feels a little bit like magic.

Using Constraints for Better Routing in MVC

The default routing in a new MVC project (3 or 4) is pretty great. If I create an AppointmentController then I get a bunch of friendly URLs for free:

  • /Appointment/Index to view all appointments
  • /Appointment/Details/[id] to view the detail of the appointment with ID = [id]
  • /Appointment/Create to create a new appointment
  • /Appointment/Edit/[id] to edit the appointment with ID = [id]
  • /Appointment/Delete/[id] to (you guessed it) delete the appointment with ID = [id]

This is fantastic – a large part of the reason I love working with MVC is how easy the ASP.NET team have made it to create an application in seconds – but I don’t love the default routes. More specifically, I don’t love /Appointment/Details.

What I Want

Being unreasonably greedy, what I would really prefer is URLs like the below:

  • /Appointment/All to view all appointments
  • /Appointment/[id] to view the detail of the appointment with ID = [id]
  • Create/Edit/Delete can stay the same

Changing the Index URL is very simple – I just have to rename my controller action from Index to All (and any View that has been created), et voila: my URL is changed to /Appointment/All.

Removing the Details from the detail URL proves a little harder though.

Custom Routes

At this point, anyone who has been using MVC for more than 5 minutes will be shouting “custom routes” at the screen, so let’s give that a go. The normal means of defining a new route that doesn’t include “Details” would look something like the below:

routes.MapRoute(
	name: "NiceDetailsRoute",
	url: "{controller}/{id}",
	defaults: new { controller = "Appointment", action = "Details", id = UrlParameter.Optional }
);

Here we’re specifying a new route that is made up of the segments “controller” (e.g. Appointment) and “id” (the ID of the appointment). By specifying action = "Details" in the defaults we can remove the need to include it in the URL.

If we insert this route before the default route in either the Global.cs.asax or RouteConfig (depending on what version of MVC you are using) then it will work – we are able to use /Appointment/123 to view appointment #123. Unfortunately there is one slight problem with this approach: everything else is now broken.

Why is Everything Else Now Broken?

The problem with the route above is that the {id} segment will match anything. This means that when someone tries to browse to /Appointment/Create, MVC will assume that the Create segment of that URL is actually the ID that should be passed to the Details action on the appointment controller. Obviously it won’t be able to parse a valid integer from the string “Create” so it will fail.

What we need is some way to say “assume that the second segment is an ID but only if it looks like an ID“.

Route Constraints

Thankfully MVC comes with a nice simple way to solve this problem: constraints. We can specify a regular expression for each one of the URL segments in our route, and the route will then only be used if the regular expression matches.

In this example we only want to treat numbers as IDs so have a nice short solution:

routes.MapRoute(
	name: "NoDetails",
	url: "{controller}/{id}",
	defaults: new { controller = "Appointment", action = "Details", id = UrlParameter.Optional },
	constraints: new { id = @"^[0-9]+$" }
);

Now we can use both /Appointment/123 and /Appointment/Create without any problems.