.NET’s new fast, compact Web Service endpoint: The JSV Format
New! Benchmarks graphs are now available to better visualize the performance of ServiceStack’s JSON and JSV text serializers.
Service Stack’s Git repo is still hot from the fresh check-in that has just added TypeSerializer’s text-serialization format as a first class Web Service endpoint.
JSV Format (i.e. JSON-like Separated Values) is a JSON inspired format that uses CSV-style escaping for the least overhead and optimal performance.
Service Stack’s emphasis has always been on creating high-performance, cross-platform web services with the least amount of effort. In order to maximize performance, our web services are effectively raw text/byte streams over light-weight IHttpHandler’s (Note: SOAP endpoints still use WCF bindings). This approach coupled with extensive use of cached-delegates (eliminating any runtime reflection) has proven to provide superior performance in itself.
So why the new format?
Well up until now the de/serialization for all web service endpoints were done using the DataContract serializers in the .NET BCL. The XML DataContractSerializer looks to be a well written library providing good performance for serialization of XML. Unfortunately for reasons articulated in my previous post on the history of web services, XML although great for interoperability, does not make a good ‘programmatic fit’ for integrating with many programming language models – e.g. for AJAX applications JSON is a much more suitable format. The verbosity and strict-extensibility of XML also does not make it the ideal format in performance-critical, or bandwidth constrained environments.
Quite simply if I want a fast, compact, cross-platform serialization format that’s ideal to use in bandwidth-constrained, performance-critical environments as found in iPhone networked applications I had to code it myself. Drawing on years of experience in handling different serialization formats I had a fair idea on what I thought the ideal text-format should be. Ultimately the core goals of being fast and compact is the major influence in the choice of syntax. It is based on the familiar JSON format but as it is white-space significant, does not require quotes for normal values, which made it the most compact text-format that was still lexically parseable.
Other key goals was that it should be non-invasive to work with any POCO-type. Due to the success of schema-less designs in supporting versioning by being resilient to schema-changes, it is a greedy format that tries to de-serialize as much as possible without error. Other features that sets it apart from existing formats makes it the best choice for serializing any .NET POCO object.
- Fastest and most compact text-serializer for .NET (5.3x quicker than JSON, 2.6x smaller than XML)
- Human readable and writeable, self-describing text format
- Non-invasive and configuration-free
- Resilient to schema changes (focused on deserializing as much as possible without error)
- Serializes / De-serializes any .NET data type (by convention)
- Supports custom, compact serialization of structs by overriding ToString() and static T Parse(string) methods
- Can serialize inherited, interface or ‘late-bound objects’ data types
- Respects opt-in DataMember custom serialization for DataContract DTO types.
For these reasons it is the preferred choice to transparently store complex POCO types for OrmLite (in RDBMS text blobs), POCO objects with ServiceStacks’ C# Redis Client or the optimal serialization format in .NET to .NET web services.
Like most of the interfaces in Service Stack, the API is simple and descriptive. In most cases these are the only methods that you would commonly use:
string TypeSerializer.SerializeToString<T>(T value); void TypeSerializer.SerializeToWriter<T>(T value, TextWriter writer); T TypeSerializer.DeserializeFromString<T>(string value); T TypeSerializer.DeserializeFromReader<T>(TextReader reader);
Where T can be any .NET POCO type. That’s all there is – the API was intentionally left simple :)
By convention only public properties are serialized, unless the POCO is a DataContract in which case only DataMember properties will be serialized. Structs can provide custom (e.g. more compact) serialization value by overloading the ToString() instance method and providing a static TStruct.Parse(string).
The JSV Web Service Endpoint
The home page for TypeSerializer on code.google.com goes into more detail on the actual text-format. You can get a visual flavour of it with the screen shots below
Note: the results have been ‘pretty-formatted’ for readability, the actual format is white-space significant.
In comparison here is the equivalent data formatted in XML (under a nice syntax highlighter):
View JSV live Web Services
One of the major features of Service Stack is that because JSV is a supported out of the box endpoint, it doesn’t require any code for all your web services to take advantage of it. You can access all your web services with the JSV endpoint by simply changing the base URL. Below are live web service examples from the Service Stack’s Examples project:
GetNorthwindCustomerOrders GetFactorial?ForNumber=3 GetFibonacciNumbers?Skip=5&Take=10
*Live webservices hosted on CentOS / Nginx / Mono FastCGI
Download TypeSerializer for your own projects
The JSV-Format is provided by the TypeSerializer class in the ServiceStack.Text namespace. It is perfect for anywhere you want to serialize a .NET type, ideal for storing complex types as text blobs in a RDBMS. Like the rest of Service Stack it is Open Source, released under the New BSD Licence.