ASP.NET Web API supports JSON.NET natively. This code is no longer maintained. Please see List of ASP.NET Web API and HttpClient Samples for updated samples.

Json.Net is a popular framework for working with JSON. In particular, it has a bunch of features that are not supported by the DataContractJsonSerializer such as being much more flexible in what kind of types it can serialize and exactly how they should be serialized. The ASP.NET Web API Beta supports an open-ended set of formatters that can read and write data to and from any media type you want to support. For example, if you want to support the vCard format which has the media type text/vcard (previously it was text/directory) media type then you can write a formatter for vCard and register it for the media type (or types) in question. Please see the blog "Using JSON.NET with ASP.NET Web API" for details.

Note: If you are completely new to ASP.NET Web API then I recommend that you check out some of the tutorials.

This sample shows how to hook in Json.Net as a formatter replacing the built in DataContractJsonSerializer formatter. There are already a bunch of Json.Net formatters provided by the community that may well be more full-featured but this should allow you to get started.

Building the Formatter

The first thing we do is building the formatter. The key part of the formatter is to provide support for reading and writing content of a given media type. The sample formatter derives from the base MediaTypeFormatter class; we are working on a buffered media type formatter that will help working with lots of small reads and writes but for this sample the goal is to keep things simple. The formatter looks like this:

 

C#
Edit|Remove
publicclass JsonNetFormatter : MediaTypeFormatter 
    { 
        private JsonSerializerSettings _jsonSerializerSettings; 
 
        public JsonNetFormatter(JsonSerializerSettings jsonSerializerSettings) 
        { 
            _jsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings(); 
 
            // Fill out the mediatype and encoding we support 
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); 
            Encoding = new UTF8Encoding(falsetrue); 
        } 
 
        protectedoverridebool CanReadType(Type type) 
        { 
            if (type == typeof(IKeyValueModel)) 
            { 
                returnfalse; 
            } 
 
            returntrue; 
        } 
 
        protectedoverridebool CanWriteType(Type type) 
        { 
            returntrue; 
        } 
 
        protectedoverride Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext) 
        { 
            // Create a serializer 
            JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings); 
 
            // Create task reading the contentreturn Task.Factory.StartNew(() => 
            { 
                using (StreamReader streamReader = new StreamReader(stream, Encoding)) 
                { 
                    using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader)) 
                    { 
                        return serializer.Deserialize(jsonTextReader, type); 
                    } 
                } 
            }); 
        } 
 
        protectedoverride Task OnWriteToStreamAsync(Type type, objectvalue, Stream stream, HttpContentHeaders contentHeaders, FormatterContext formatterContext, TransportContext transportContext) 
        { 
            // Create a serializer 
            JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings); 
 
            // Create task writing the serialized contentreturn Task.Factory.StartNew(() => 
            { 
                using (StreamWriter streamWriter = new StreamWriter(stream, Encoding)) 
                { 
                    using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter)) 
                    { 
                        serializer.Serialize(jsonTextWriter, value); 
                    } 
                } 
            }); 
        } 
    } 

 

Building a Sample ApiController

Next we need a controller to try things out. For illustrative purposes we create a type that would not serialize well with DataContractJsonSerializer but other than that this is a completely vanilla controller that knows nothing about serialization:

 

C#
Edit|Remove
publicclass HomeController : ApiController 
    { 
        public HomeInfo Get() 
        { 
            returnnew HomeInfo(); 
        } 
    } 
 
    publicclass HomeInfo 
    { 
        privatereadonly DateTime _created = DateTime.UtcNow; 
        privatereadonly Dictionary<intstring> _colorMap = new Dictionary<intstring> 
        { 
            { 1"blue"}, 
            { 2"red" }, 
            { 3"green" }, 
            { 4"black" }, 
            { 5"white" }, 
        }; 
 
        public DateTime Created { get { return _created; } } 
 
        public IDictionary<intstring> ColorMap { get { return _colorMap; } } 
    }

 

Hosting the Controller

Now that we have the controller we can host it in either ASP or as selfhost. In this case we selfhost the controller in a simple console application but it would work exactly the same if hosted in ASP.

The first part is to configure the selfhost server and injecting the JsonNetFormatter. We also configure Json.Net to serialize DateTime types using ISO 8601 format. That part of the console app that configures and starts the server looks like this:

 

C#
Edit|Remove
// Set up server configuration 
                HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost:8080"); 
                config.Routes.MapHttpRoute("Default""{controller}"new { controller = "Home" }); 
 
                // Create Json.Net formatter serializing DateTime using the ISO 8601 format 
                JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); 
                serializerSettings.Converters.Add(new IsoDateTimeConverter()); 
                config.Formatters[0] = new JsonNetFormatter(serializerSettings); 
 
                // Create server 
                server = new HttpSelfHostServer(config); 
 
                // Start listening 
                server.OpenAsync().Wait();

 

Note: In order to successfully start the selfhost server you have to run as admin (or configure http.sys with the appropriate URI prefix).

Trying it Out

Once the controller is running, we can access it using any HTTP client. In this case we use HttpClient to access it and print out the result to the console. If we put both the server configuration and the client in the same Main then we get something like this:

 

C#
Edit|Remove
class Program 
    { 
        staticvoid Main(string[] args) 
        { 
            HttpSelfHostServer server = null; 
            try 
            { 
                // Set up server configuration 
                HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost:8080"); 
                config.Routes.MapHttpRoute("Default""{controller}"new { controller = "Home" }); 
 
                // Create Json.Net formatter serializing DateTime using the ISO 8601 format 
                JsonSerializerSettings serializerSettings = new JsonSerializerSettings(); 
                serializerSettings.Converters.Add(new IsoDateTimeConverter()); 
                config.Formatters[0] = new JsonNetFormatter(serializerSettings); 
 
                // Create server 
                server = new HttpSelfHostServer(config); 
 
                // Start listening 
                server.OpenAsync().Wait(); 
 
                // Create HttpClient, do an HTTP GET on the controller, and show the output 
                HttpClient client = new HttpClient(); 
                client.GetAsync("http://localhost:8080").ContinueWith( 
                    (requestTask) => 
                    { 
                        // Get HTTP response from completed task. 
                        HttpResponseMessage response = requestTask.Result; 
 
                        // Check that response was successful or throw exception 
                        response.EnsureSuccessStatusCode(); 
 
                        // Read response asynchronously as string and write out 
                        response.Content.ReadAsStringAsync().ContinueWith( 
                            (readTask) => 
                            { 
                                Console.WriteLine(readTask.Result); 
                            }); 
                    }); 
 
                Console.WriteLine("Hit ENTER to exit..."); 
                Console.ReadLine(); 
 
            } 
            finally 
            { 
                if (server != null) 
                { 
                    // Stop listening 
                    server.CloseAsync().Wait(); 
                } 
            } 
        } 
    } 

 

The resulting output written to the console is

{"Created":"2012-02-18T00:54:06.8447642Z","ColorMap":{"1":"blue","2":"red","3":"green","4":"black","5":"white"}}

Note the ISO date and the nice serialization of the dictionary!

Henrik