Carl: "According to the map, the cabin should be right here." Lenny: "Hey, maybe there is no cabin. Maybe it's one of them metaphorical things." Carl: "Oh yeah, yeah... Like maybe the cabin is the place inside each of us, created by our goodwill and teamwork." Lenny: "Oh! ... Nah, they said there would be sandwiches." JsonSerializer is pretty darn flexible. It has a half dozen options on the class to customize how an object is serialized, attributes for more fine grained control and finally JsonConverters if you need to do something completely different.

The most popular request I get these days is control over how JsonSerializer determines what members on a type to serialize (e.g. serialize private as well as public properties) and control over the name of the written property (e.g. instead of “FirstName” write the property camelcase style: “firstName”).

Controlling this behaviour is actually already possible by inheriting from JsonSerializer and overriding GetMemberMappings. The MemberMapping class contains all the information about how a .NET member gets mapped to a JSON property (name, readable, writable, converter, etc) and is used internally by JsonSerializer. The problem is it isn’t terribly discoverable to the average user.

IMappingResolver

What I am thinking of doing is adding is an IMappingResolver interface.

public interface IMappingResolver
{
  JsonMemberMappingCollection ResolveMappings(Type type);
}

JsonSerializer would have a MappingResolver property and the instance of the object assigned to it would determine how the members on a .NET class get mapped to a JSON object (if you’re hip with the GOF urban street lingo this is an example of the strategy pattern).

Examples of resolvers that could come with Json.NET or you could create yourself: CamelCaseMappingResolver, TypeDescriptorMappingResolver, PrivateMembersMappingResolver and so on.

I like this over inheritance because it is obvious and in a user’s face. MappingResolver could also be added to the JsonSerializerSettings class and used from the serialization helper methods on JsonConvert.

Yay or nay? Suggestions welcome Smile

People die all the time, just like that. Why, you could wake up dead tomorrow.

IE7 has been out for two and a half years. It is time to stop living in the past and retire IE6.

IETester

As an aside I highly recommend IETester (see the screenshot above) to anyone needing to test websites in old versions of IE. It renders IE 5.5, 6, 7 and 8 side by side in one application. It even supports tabs!

Trying is the first step toward failure. Twitter (read more about Twitter here) offers a simple JavaScript API to add your status updates to your blog or other website.

The Problem

Injecting HTML into a webpage like this works well enough for the most part put it can produce problems if the website you are getting HTML from, Twitter in this case, is slow or unreliable. An inline script reference will hang the rendering of the page at that point until a response is returned.

If Twitter.com is down, not an uncommon occurrence, and you have an inline script reference like the one above then your website is essentially broken until Twitter fixes itself.

Homer: "There's the right way, the wrong way, and the Max Power way!" Bart: "Isn't that the wrong way?" Homer: "Yes, but faster!"

To get around this problem Twitter advises that the script reference should be placed at the end of a page. That fixes one issue but creates another: The content from Twitter pops into the page only once the page is completely loaded. It looks a little hacky at best and could cause the content on the page to suddenly move and reflow depending upon where the Twitter statuses are being inserted.

An example of content pop-in can be seen in the sidebar of MajorNelson’s blog. Each time the page reloads there is a noticeable delay before the Twitter statues are populated.

The Solution

My solution is simple: cache the result from Twitter in a cookie. Placing the script reference at the bottom of the page gets around the issue of a broken website and caching the result means no content pop-in after the first page view.

The JavaScript is pretty simple.

<script type="text/javascript">
  function setCookie(name, value, expires) {
    document.cookie = name + "=" + escape(value) + "; path=/" + ((expires == null) ? "" : "; expires=" + expires.toGMTString());
  }
 
  function getCookie(name) {
    if (document.cookie.length > 0) {
      var start = document.cookie.indexOf(name + "=");
      if (start != -1) { 
        start = start + name.length + 1; 
        var end = document.cookie.indexOf(";", start);
        if (end == -1) {
          end = document.cookie.length;
        }
        return unescape(document.cookie.substring(start, end));
      } 
    }
    return "";
  }
 
  function twitterCachedCallback(c) {
    // this will create the HTML. Function found inside blogger.js
    twitterCallback2(c);
 
    var content = document.getElementById("twitter_update_list").innerHTML;
 
    // expire cookie after 30 minutes
    var exp = new Date();
    exp.setTime(exp.getTime() + (1000 * 60 * 30));
    setCookie('twitter_content', content, exp);
  }
 
  // set content immediately if cached
  var cachedContent = getCookie('twitter_content');
  if (cachedContent) {
    document.getElementById("twitter_update_list").innerHTML = cachedContent;
  }
</script>

Add this script immediately after the Twitter content. If cached content is found then it will be inserted into the page straight away, improving user experience.

The only other change that needs to be made is to the script reference to Twitter. Rename the callback function from twitterCallback2 to twitterCachedCallback in the querystring and you’re done.

I use this technique on my blog (look to the sidebar on the right). You can also see an example webpage I threw together here.

 

kick it on DotNetKicks.com

I’ve said it before, I’ll say it again: Dates in JSON are hard.

The problem comes from the JSON spec itself, there is no literal syntax for dates in JSON. The spec has objects, arrays, strings, integers and floats, but it defines no standard for what a date looks like.

The default format used by Json.NET for dates is the same one used by Microsoft: "\/Date(1198908717056)\/". You can read more about it here.

JsonConverters

With no standard for dates in JSON, the number of possible different formats when interoping with other systems is endless. Fortunately Json.NET has a solution to deal with reading and writing custom dates: JsonConverters. A JsonConverter is used to override how a type is serialized.

public class LogEntry
{
  public string Details { get; set; }
  public DateTime LogDate { get; set; }
}
 
[Test]
public void WriteJsonDates()
{
  LogEntry entry = new LogEntry
  {
    LogDate = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc),
    Details = "Application started."
  };
 
  string defaultJson = JsonConvert.SerializeObject(entry);
  // {"Details":"Application started.","LogDate":"\/Date(1234656000000)\/"}

 
  string javascriptJson = JsonConvert.SerializeObject(entry, new JavaScriptDateTimeConverter());
  // {"Details":"Application started.","LogDate":new Date(1234656000000)}
 
  string isoJson = JsonConvert.SerializeObject(entry, new IsoDateTimeConverter());
  // {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"}
}

Simply pass the JsonConverter you wish to use to the Json.NET serializer.

JavaScriptDateTimeConverter

The JavaScriptDateTimeConverter class is one of the two DateTime JsonConverters that come with Json.NET. This converter serializes a DateTime as a JavaScript Date object.

new Date(1234656000000)

Technically this is invalid JSON according to the spec but all browsers, and some JSON frameworks including Json.NET, support it.

IsoDateTimeConverter

IsoDateTimeConverter seralizes a DateTime to an ISO 8601 formatted string.

"2009-02-15T00:00:00Z"

The IsoDateTimeConverter class has a property, DateTimeFormat, to further customize the formatted string.

 

One final thing to note is all date values returned by Json.NET are in UTC time.

JSON makes working with dates harder than it needs to be but with a little work it is a problem that is easily solved. Good times.

kick it on DotNetKicks.com

There are a couple of different ways you can write to a file using Json.NET. The first is really simple:

Person person = GetPerson();
 
string json = JsonConvert.SerializeObject(person, Formatting.Indented);
File.WriteAllText(@"c:\person.json", json);

In this C# example we get the string returned from SerializeObject and pass it to WriteAllText, a helper method on the very useful System.IO.File class. The JSON contents of the string is written to the file.

If greater control is required over how the file is written, or the JSON you are writing is large and you don’t want the overhead of having the entire JSON string in memory, a better approach is to use JsonSerializer directly.

Person person = GetPerson();
 
using (FileStream fs = File.Open(@"c:\person.json", FileMode.CreateNew))
using (StreamWriter sw = new StreamWriter(fs))
using (JsonWriter jw = new JsonTextWriter(sw))
{
  jw.Formatting = Formatting.Indented;
 
  JsonSerializer serializer = new JsonSerializer();
  serializer.Serialize(jw, person);
}

More code but also more efficient: the JSON is written directly to the file stream. The other bonus to using this approach is that it can be adapted to write to any .NET Stream: file streams, web response streams, memory streams, etc.

Isn’t polymorphism cool? Smile

 

kick it on DotNetKicks.com

More Posts Next page »