Offline JSON Pretty Printing

Today when you’re dealing with Web APIs, you often find yourself in the situation of handling JSON, either in the input for these APIs or in the output, or both. Some browsers have the means to pretty print the JSON from their dev tools. But you don’t always have that opportunity. That’s why there are tools to pretty print JSON. I’ve found quite a few of them on the web, but all the ones I’ve found have one terrible flaw: they actually send the JSON you’re trying to pretty print to the server (*shudder*). I don’t want my JSON data (sensitive or not) to be sent to some random servers!

All your JSON are belong to us!

Now as I wrote, I don’t particularly like the fact that my JSON data is sent over the wire for pretty printing. It may not be super secret or anything, but in these days, you cannot be careful enough. Besides, it’s completely unnecessary to do it. All you need is already in your browser! So I quickly built my own JSON pretty printer (and syntax highlighter). You can find it right here.

Offline JSON Pretty Printing to the Rescue

Actually, the design is very simple. All my JSON pretty printer is doing, is to take your JSON input and try to parse it as JSON in the browser.

JSON.parse(yourJsonInput)

If that fails, I’m showing the parsing error and it’s done. If it succeeds, I get back a JavaScript object/array/value, which then I’m inspecting. For objects, I’m using basic tree navigation to go through all the properties and nested objects/arrays/values for pretty printing. That’s it, really simple. No need to transmit the data anywhere — it stays right in your browser!

So like it, hate it, use it or don’t: cymbeline.ch JSON Pretty Printer

Fun with JSON and WCF, Part II

Following the web app I mentioned in Fun with JSON and WCF (Part I), I ran into another issue with WCF hosted in IIS and serving the callers through JSON objects. My application uses integrated windows authentication to authenticate the users and grant / deny access based on the given credentials. Therefore, I have turned off anonymous access for the entire virtual directory the application is running in and turned on integrated windows authentication. Now when invoking the JSON service, I get the following exception.

[NotSupportedException: Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.]
   System.ServiceModel.Channels.HttpChannelListener.ApplyHostedContext(VirtualPathExtension virtualPathExtension, Boolean isMetadataListener) +11453217
   System.ServiceModel.Activation.VirtualPathExtension.ApplyHostedContext(TransportChannelListener listener, BindingContext context) +75
   System.ServiceModel.Channels.HttpTransportBindingElement.BuildChannelListener(BindingContext context) +119
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +66
   System.ServiceModel.Channels.MessageEncodingBindingElement.InternalBuildChannelListener(BindingContext context) +67
   System.ServiceModel.Channels.WebMessageEncodingBindingElement.BuildChannelListener(BindingContext context) +47
   System.ServiceModel.Channels.BindingContext.BuildInnerChannelListener() +66
[...]

This indicates that according to the configuration of the service binding, anonymous access is to be allowed however IIS does not allow it. Apart from the fact that I don’t understand in the first place, why the service would care about this (if it was the other way around, I’d understand), fixing it is simple. It again requires changes in the Web.config, like follows.

<configuration>
    <!-- ... -->
    <system.serviceModel>
        <behaviors>
            <!-- ... -->
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
        <services>
            <service behaviorConfiguration="MyServiceTypeBehavior" name="MyService">
                <endpoint address="" behaviorConfiguration="MyServiceAspNetAjaxBehavior"
                          binding="webHttpBinding" bindingConfiguration="ServiceAuth"
                          contract="MyService" />
            </service>
        </services>
        <bindings>
            <webHttpBinding>
                <binding name="ServiceAuth">
                    <security mode="TransportCredentialOnly">
                        <transport clientCredentialType="Windows"/>
                    </security>
                </binding>
            </webHttpBinding>
        </bindings>
    </system.serviceModel>
</configuration>

The bindingConfiguration attribute on line 11 refers to the new webHttpBinding definition from lines 17 to 21. Client authentication is there specified to be integrated windows authentication.

Fun with JSON and WCF

One of the projects I am working on at home is something like a media player web application which I use to listen to my favorite music from anywhere. It has a backend database which keeps the music files in a way which allows fast search on information about the files from the tags in the files. The files are then played in a handcrafted media player written in Silverlight 2.0. This being a fancy web 2.0 application, I use AJAX to search the database and return the results as JSON objects. Luckily enough, WCF supports you with this since .net 3.5. All you basically need to do is create a WCF service for your web project in Visual Studio 2008 (SP1). Then you even have IntellliSense support for the client side wrapper of the service, which of course gets generated automatically. On top of this, you do not have to care too much about inter-browser compatibility: The generated scripts with the base libraries work fine with both IE and Firefox.

If on the other hand, you are running the application on a virtual site in IIS which supports multiple host headers (let’s say: foo.bar.com and www.foo.bar.com) you’re likely to run into an exception like the following.

[ArgumentException: This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
Parameter name: item]
   System.ServiceModel.UriSchemeKeyedCollection.InsertItem(Int32 index, Uri item) +11520590
   System.Collections.Generic.SynchronizedCollection`1.Add(T item) +67
   System.ServiceModel.UriSchemeKeyedCollection..ctor(Uri[] addresses) +49
   System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses) +129
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type serviceType, Uri[] baseAddresses) +28
   System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) +331
   System.ServiceModel.HostingManager.CreateService(String normalizedVirtualPath) +11659932
   System.ServiceModel.HostingManager.ActivateService(String normalizedVirtualPath) +42
   System.ServiceModel.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath) +479

This indicates that a binding address which starts with http is already in use, when trying to automatically add the second address. The solution to this is as simple as updating your Web.Config file like shown here. Please take a look at line #9:

<configuration>
    <!-- ... -->
    <system.serviceModel>
        <behaviors>
            <!-- ... -->
        </behaviors>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
            <baseAddressPrefixFilters>
                <add prefix="http://foo.bar.com" />
            </baseAddressPrefixFilters>
        </serviceHostingEnvironment>
        <services>
            <!-- ... -->
        </services>
        <bindings>
            <!-- ... -->
        </bindings>
    </system.serviceModel>
</configuration>

Addendum from Feb 6: Apparently I was not entirely correct about using the service on a site with multiple host headers. While the above changes to Web.config fix the initial problem, they introduce a new problem. You’ll realize that this will work only for the requests using one of the host headers. The request to the service using the other host headers will throw a 404. This is a reported bug and will hopefully be fixed soon.