Archives

Archives / 2009 / July
  • JSON Standard Business Card

    Front:

    Doughnuts. Is there anything they can't do?

    Back:

    Just because I don't care doesn't mean I don't understand.

    Awesome.

    I think it is pretty cool that the entire standard can be put on the back of a business card (and a quarter of that is for defining what a number is!).

    From here.

  • Implicit Conversions and LINQ to JSON

    I have been doing a lot of work with Json.NET recently and have really been using LINQ to JSON in anger for the first time.

    Pretty quickly I became annoyed with having to constantly wrap .NET primitive objects (int, long, string, DateTime, etc) in JValue whenever they’re added to a JSON object or array.

    JObject moss = new JObject();
    moss["FirstName"] = new JValue("Maurice");
    moss["LastName"] = new JValue("Moss");
    moss["BirthDate"] = new JValue(new DateTime(1977, 12, 30));
    moss["Department"] = new JValue("IT");
    moss["JobTitle"] = new JValue("Support");
     
    Console.WriteLine(moss.ToString());
    //{
    //  "FirstName": "Maurice",
    //  "LastName": "Moss",
    //  "BirthDate": "\/Date(252241200000+1300)\/",
    //  "Department": "IT",
    //  "JobTitle": "Support"
    //}

    Gross. Why?

    For all the LINQy goodness I’ve added to Json.NET to work everything has to inherit from a common object: JToken. Container objects (JObject and JArray) inherit from JToken and all their child values must also be JTokens. For that reason JObject implements IDictionary<string, JToken> and JArray implements IList<JToken>.

    Because the containers only allow JTokens, basic primitive values need to be wrapped in an object which inherits from JToken: JValue.

    Each time we want to set a value on an object or add a value to an array it has to be manually wrapped in a JValue. Ugly!

    Implicit Conversions

    The solution is really simple: implicit conversions. Adding an implicit conversion operator allows .NET to automatically convert from the primitive to JValue without any of the above unpleasantness.

    ///<summary>
    /// Performs an implicit conversion from <see cref="String"/> to <see cref="JToken"/>.
    ///</summary>
    ///<param name="value">The value to create a <see cref="JValue"/> from.</param>
    ///<returns>The <see cref="JValue"/> initialized with the specified value.</returns>
    public static implicit operator JToken(string value)
    {
      return new JValue(value);
    }

    And here is the new end user experience:

    JObject jen = new JObject();
    jen["FirstName"] = "Jen";
    jen["LastName"] = "Barber";
    jen["BirthDate"] = new DateTime(1978, 3, 15);
    jen["Department"] = "IT";
    jen["JobTitle"] = "Manager";

    Much better I think you’ll agree. I only wish I had done it earlier [:)]

  • Backstage With Office 2010 Website Live!

    The past two weeks I have been working long hours with a small band from Intergen on the Backstage With Office 2010 website. I can happily say that today Backstage went live with the unveiling of Microsoft Office 2010!

    Backstage is full of videos from the Office 2010 team who go behind the scenes of Office development and talk about what they have been busy working on since 2007. The main Backstage website is 100% Silverlight shows off lots of neat features.

    • 100% Silverlight design
    • Smooth streaming – videos will scale from HD for awesome broadband connections down to speed optimized resolutions for mobile devices
    • Embedded social links to those sites all the cool kids are using (Twitter, Facebook, Delicious, Digg, Live)
    • Deep linking directly to videos
    • Commenting and rating videos, video view counts

    Uh, no, they’re saying "Boo-urns, Boo-urns."

    As well as the main site we have created an RSS feed of recently added videos. Not only can you subscribe to it an RSS reader but the feed also works with iTunes and other video podcast clients.

    I was saying "Boo-urns."

    Finally visiting mobile users will automatically be redirect to an HTML mobile version of the site, complete with low resolution videos for 3G mobile devices. It looks fantastic on my iPhone.

    Fat Tony is a cancer on this fair city! He is the cancer and I am the…uh…what cures cancer?

    Its been a crazy ride getting everything done in time for the launch but I think the end result was worth it. Check out Backstage With Office 2010 here.

  • ADO.NET Entity Framework support accidently added to Json.NET

    I sat down today resolved to finally add support for serializing ADO.NET Entities objects… and instead I came away surprised to find that it already worked. My initial “Lets prove it breaks first and then fix it” test passed first time and it wasn’t until I debugged through the test that I was convinced NUnit wasn’t the one that was broken.

    My simple test Entities model of a file system:

    Marge: "Homer, the plant called. They said if you don't show up tomorrow don't bother showing up on Monday." Homer: "Woo-hoo. Four-day weekend!"

    And the JSON serialized with a couple of folders and files in it:

    Folder rootFolder = CreateEntitiesTestData();
     
    string json = JsonConvert.SerializeObject(rootFolder, Formatting.Indented);
     
    Console.WriteLine(json);
    //{
    //  "$id": "1",
    //  "FolderId": "a4e8ba80-eb24-4591-bb1c-62d3ad83701e",
    //  "Name": "Root folder",
    //  "Description": null,
    //  "CreatedDate": "\/Date(978087000000)\/",
    //  "Files": [],
    //  "ChildFolders": [
    //    {
    //      "$id": "2",
    //      "FolderId": "484936e2-7cbb-4592-93ff-b2103e5705e4",
    //      "Name": "Child folder",
    //      "Description": null,
    //      "CreatedDate": "\/Date(978087000000)\/",
    //      "Files": [
    //        {
    //          "$id": "3",
    //          "FileId": "cc76d734-49f1-4616-bb38-41514228ac6c",
    //          "Name": "File 1.txt",
    //          "Description": null,
    //          "CreatedDate": "\/Date(978087000000)\/",
    //          "Folder": {
    //            "$ref": "2"
    //          }
    //        }
    //      ],
    //      "ChildFolders": [],
    //      "ParentFolder": {
    //        "$ref": "1"
    //      }
    //    }
    //  ],
    //  "ParentFolder": null
    //}

    That looks pretty good!

    Features added in Beta 4, reference tracking and support for the DataContract/DataMember attributes from WCF, means that instead of Json.NET exploding in a heap of timber (complete with lone wagon wheel spinning off into the distance) at the mere site of an ADO.NET Entities object, serializing now works out of the box!

    I love it when things come together [:)]

  • Json.NET 3.5 Beta 4 – JsonSerializer Improvements Part Deux

    1. Alice in Wonderland? Must be a rip off of Alice in Underpants Best. Serializer. Ever.
    2. ???
    3. Profit!

    JsonSerializer Improvements Part Deux

    A huge amount has changed in the Json.NET serializer since beta 3. As well as a general refactor (the JsonSerializer.cs file was pushing 1000 lines last release), tons and tons of new features have been added.

    New to the serializer is reference tracking, type tracking, serialization callback events, MetadataTypeAttribute support for when working with code generation, additional property level control over serialization settings, a BinaryConverter to convert byte arrays, a StringEnumConverter to convert enum values to their string name, a Populate method for populating JSON values onto an existing object, additional programmatic control over serialization via the IReferenceResolver interface (it replaces IMappingResolver), and much more…

    There is too much to cover in one blog post so I’m going to split everything up over a couple of weeks. If you’re really eager for the inside scoop then check out the Json.NET help.

    I’m going to be adding more as I go. The first topic to be covered is my favourite new feature, one that very few serializers support and no JSON serializers anywhere as far as I know: Object reference tracking

    Preserving Object References

    By default Json.NET will serialize all objects it encounters by value. If a list contains two Person references, and both references point to the same object then the JsonSerializer will write out all the names and values for each reference.

    Person p = new Person
      {
        BirthDate = new DateTime(1980, 12, 23, 0, 0, 0, DateTimeKind.Utc),
        LastModified = new DateTime(2009, 2, 20, 12, 59, 21, DateTimeKind.Utc),
        Name = "James"
      };
     
    List<Person> people = new List<Person>();
    people.Add(p);
    people.Add(p);
     
    string json = JsonConvert.SerializeObject(people, Formatting.Indented);
    //[
    //  {
    //    "Name": "James",
    //    "BirthDate": "\/Date(346377600000)\/",
    //    "LastModified": "\/Date(1235134761000)\/"
    //  },
    //  {
    //    "Name": "James",
    //    "BirthDate": "\/Date(346377600000)\/",
    //    "LastModified": "\/Date(1235134761000)\/"
    //  }
    //]

    In most cases this is the desired result but in certain scenarios writing the second item in the list as a reference to the first is a better solution. If the above JSON was deserialized now then the returned list would contain two completely separate Person objects with the same values. Writing references by value will also cause problems on objects where a circular reference occurs.

    PreserveReferencesHandling

    Settings PreserveReferencesHandling will track object references when serializing and deserializing JSON.

    string json = JsonConvert.SerializeObject(people, Formatting.Indented,
      new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
    //[
    //  {
    //    "$id": "1",
    //    "Name": "James",
    //    "BirthDate": "\/Date(346377600000)\/",
    //    "LastModified": "\/Date(1235134761000)\/"
    //  },
    //  {
    //    "$ref": "1"
    //  }
    //]
     
    List<Person> deserializedPeople = JsonConvert.DeserializeObject<List<Person>>(json,
      new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
     
    Console.WriteLine(deserializedPeople.Count);
    // 2
     
    Person p1 = deserializedPeople[0];
    Person p2 = deserializedPeople[1];
     
    Console.WriteLine(p1.Name);
    // James
    Console.WriteLine(p2.Name);
    // James
     
    bool equal = Object.ReferenceEquals(p1, p2);
    // true

    The first Person in the list is serizlied with the addition of an object Id. The second Person in JSON is now only a reference to the first.

    With PreserveReferencesHandling on now only one Person object is created on deserialization and the list contains two references to it, mirroring what we started with.

    IsReference on JsonObjectAttribute, JsonArrayAttribute and JsonPropertyAttribute

    The PreserveReferencesHandling setting on the JsonSerializer will change how all objects are serialized and deserialized. For fine grain control over which objects and members should be serialized there is the IsReference property on the JsonObjectAttribute, JsonArrayAttribute and JsonPropertyAttribute.

    Setting IsReference on JsonObjectAttribute or JsonArrayAttribute to true will mean the JsonSerializer will always serialize the type the attribute is against as a reference. Setting IsReference on the JsonPropertyAttribute to true will serialize only that property as a reference.

    [JsonObject(IsReference = true)]
    public class EmployeeReference
    {
      public string Name { get; set; }
      public EmployeeReference Manager { get; set; }
    }

    IReferenceResolver

    To customize how references are generated and resolved the IReferenceResolver interface is available to inherit from and use with the JsonSerializer.

    Changes

    Here is a complete list of what has changed since Json.NET 3.5 Beta 3.

    • New feature - Added StringEnumConverter to convert enum values to and from their string name rather than number value
    • New feature - Added BinaryConverter which converts byte array's, Binary and SqlBinary values to and from base64 text.
    • New feature - Added NullValueHandling, DefaultValueHandling and ReferenceLoopHandling to JsonPropertyAttribute
    • New feature - Added MetadataTypeAttribute support when searching for attributes
    • New feature - JsonSerializer now looks for DataContractAttribute and DataMemberAttribute on a type
    • New feature - Now able to explicitly serialize private members when marked up with JsonPropertyAttribute or DataMemberAttribute
    • New feature - Added CustomCreationConverter. Used to customize creation of an object before the serializer populates values
    • New feature - Added Populate method to JsonSerializer. Pass existing object to serializer and have current object's values populated onto it
    • New feature - Added IsReference to JsonContainerAttribute and JsonPropertyAttribute
    • New feature - Added PreserveReferencesHandling to JsonSerializer
    • New feature - Added IReferenceResolver (replacing IMappingResolver) to JsonSerializer
    • New feature - JsonObjectAttribute will now force a collection class to be serialized as an object
    • New feature - Added JsonContract, JsonObjectContract, JsonArrayContract and JsonDictionaryContract
    • New feature - Added support for OnSerializing, OnSerialized, OnDeserializing, OnDeserialized callback methods
    • Change - Rename JsonTokenReader, JsonTokenWriter, JsonTokenType to JTokenReader, JTokenWriter, JTokenType
    • Change - DefaultDateTimeFormat on IsoDateTimeConverter no longer displays milliseconds zeros
    • Change - JObject now enumerates over KeyValuePair<string, JToken> rather than JToken
    • Change - Moved serialize stack used to check for reference loops from JsonWriter (yuck) to JsonSerializerWriter (yay)
    • Change - Renamed JsonMemberMapping to JsonProperty
    • Fix - JToken now successfully casts to a float or decimal value
    • Fix - Serializer now handles comments encountered in JSON while deserializing
    • Fix - Fixed (hopefully) cache threading issues
    • Fix - Uri objects are now correctly serizlized on Silverlight/Compact Framework
    • Fix - Whole decimals will now always be written with a decimal place

    Links

    Json.NET CodePlex Project

    Json.NET 3.5 Beta 4 Download – Json.NET source code, documentation and binaries

  • Simple .NET Profanity Filter

    A website I am working on right now accepts public comments, and one of the requirements is to do a basic check for dirty language. Surprisingly for such a common problem I wasn’t able to find any code on the net that did what I wanted and so I’ve ended up writing my own.

    The Censor class is pretty simple: you give it a list of words you want to censor, either simple text or with wildcards, and the censor will star out any matches it finds.

    IList<string> censoredWords = new List<string>
    {
      "gosh",
      "drat",
      "darn*",
    };
     
    Censor censor = new Censor(censoredWords);
    string result;
     
    result = censor.CensorText("I stubbed my toe. Gosh it hurts!");
    // I stubbed my toe. **** it hurts!
     
    result = censor.CensorText("The midrate on the USD -> EUR forex trade has soured my day. Drat!");
    // The midrate on the USD -> EUR forex trade has soured my day. ****!
     
    result = censor.CensorText("Gosh darnit, my shoe laces are undone.");
    // **** ******, my shoe laces are undone.

    The first example is a simple whole word match on gosh. The second example replaces drat but doesn’t star out the drat in midrate. The final example shows the censor starting out multiple matches and also matching darnit against the wildcard darn*.

    I’m passing a collection of strings in my examples but it is easy enough to find a list of swear words on the net, put them in a text file and call something like File.GetAllLines to get an array of words to filter on.

    The code:

    public class Censor
    {
      public IList<string> CensoredWords { get; private set; }
     
      public Censor(IEnumerable<string> censoredWords)
      {
        if (censoredWords == null)
          throw new ArgumentNullException("censoredWords");
     
        CensoredWords = new List<string>(censoredWords);
      }
     
      public string CensorText(string text)
      {
        if (text == null)
          throw new ArgumentNullException("text");
     
        string censoredText = text;
     
        foreach (string censoredWord in CensoredWords)
        {
          string regularExpression = ToRegexPattern(censoredWord);
     
          censoredText = Regex.Replace(censoredText, regularExpression, StarCensoredMatch,
            RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
        }
     
        return censoredText;
      }
     
      private static string StarCensoredMatch(Match m)
      {
        string word = m.Captures[0].Value;
     
        return new string('*', word.Length);
      }
     
      private string ToRegexPattern(string wildcardSearch)
      {
        string regexPattern = Regex.Escape(wildcardSearch);
     
        regexPattern = regexPattern.Replace(@"\*", ".*?");
        regexPattern = regexPattern.Replace(@"\?", ".");
     
        if (regexPattern.StartsWith(".*?"))
        {
          regexPattern = regexPattern.Substring(3);
          regexPattern = @"(^\b)*?" + regexPattern;
        }
     
        regexPattern = @"\b" + regexPattern + @"\b";
     
        return regexPattern;
      }
    }

    kick it on DotNetKicks.com