Homam's Mind

Thursday, July 9, 2009

Returning Anonymous Types in Web Services

When coding an AJAX app that makes relatively many calls to the server in short periods of time, the main concern is to minimize the bandwidth it consumes. For example think of an AJAX chat application. For it to look like a real time app we have to query the server every few seconds.

If you're using .NET, you already knew how easy it is to return objects and have them serialized in JSON in Web Services. All we need to do is to deal with the logics and .NET does all the things and tricks related to the communication. For our example, this is the method that needed to be called periodically from the client:

[WebMethod]


public IEnumerable<ChatMessage> GetMessages()


{


var currentPlayer = OnlinePlayers.Single(p => p.Id == CurrentPlayerId);


var messages = Messages.Where(m => m.DateSent > currentPlayer.DateSynced);


currentPlayer.DateSynced = DateTime.Now;


return messages;


}



The problem is that .NET really serializes everything. If we have the following definitions:

[Serializable]


public class Player


{


public Player() { }


public string Name { get; set; }


public string Id { get; set; }


public string PhotoUrl { get; set; }


public DateTime DateSynced { get; set; }


// other properties


}



[Serializable]


public class ChatMessage


{


public ChatMessage() { }


public Player Sender { get; set; }


public string Message { get; set; }


public DateTime DateSent { get; set; }


}



It is certainly not desirable to send a Player object back to the client by every ChatMessage. Assuming that the client already knows all the Players involved in the Chat, the ChatMessage object that is being sent to the client only needs to have a Sender ID property. One obvious solution that is very familiar for hardcore client-server developers is to have another type, let's say ClientChatMessage that only contains the required information. If you're taking this approach remember ClientChatMessage should be a struct type:

[WebMethod]


public IEnumerable<ClientChatMessage> GetMessages()


{


//...


return messages.Select(m => (ClientChatMessage)m);


}



[Serializable]


public struct ClientChatMessage


{


public string SenderId;


public DateTime DateSent;


public string Message;



public static explicit operator ClientChatMessage(ChatMessage m)


{


return new ClientChatMessage()


{


DateSent = m.DateSent,


Message = m.Message,


SenderId = m.Sender.Id


};


}


}



When we are targeting only AJAX clients it's very handy to return anonymously typed objects. Anonymous objects cannot be serialized by XML serialization, but JavaScript (JSON) serializer is able to serialize them. I prefer it:

[WebMethod]


public IEnumerable<Object> GetMessages()


{


//...


return messages.Select(m =>


new {


s = m.Sender.Id,


m = m.Message,


d = m.DateSent


});


}



Here I've shortened the names of the properties, hey it is AJAX, we should save bandwidth by every mean possible.

We've used this trick in many places of the games we are developing for Hyzonia, as the current games only will be available for JavaScript clients. We found another similar trick very handy: a web method can take an object as an argument; if you send a JSON serialized object from the client to these methods, you'll have a Dictionary<String, Object> in the server side.
[WebMethod]

public IEnumerable<ChatMessage> GetMessages()

{

var currentPlayer = OnlinePlayers.Single(p => p.Id == CurrentPlayerId);

var messages = Messages.Where(m => m.DateSent > currentPlayer.DateSynced);

currentPlayer.DateSynced = DateTime.Now;

return messages;

}
Saturday, July 4, 2009

Lecture in UOWD

Reza, our business dev manager, has a lecture on advergaming in UOWD. Everybody's welcome to join: http://blog.hyzonia.com