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

Gzip Encoding an HTTP POST Request Body

I was wondering how difficult it was to Gzip-compress the body of an HTTP POST request (or any HTTP request with a body, that is), for large request bodies. While the .Net HttpClient has supported compression of response bodies for a while, it appears that to this day there is no out-of-the-box support for encoding the body of a request. Setting aside for now that the server may not natively support Gzip-compressed request bodies, let’s look at what we need to do to support this on the client side.

Enter HttpMessageHandler

The HttpMessageHandler abstract base class and its derived classes are used by the HttpClient class to asynchronously send HTTP requests and receive the response from the server. But since we don’t actually want to send the message ourselves – just massage the body and headers a little bit before sending – we’ll derive a new class GzipCompressingHandler from DelegatingHandler so we can delegate sending (and receiving) to another handler and just focus on the transformation of the content. So here’s what that looks like.

public sealed class GzipCompressingHandler : DelegatingHandler
{
    public GzipCompressingHandler(HttpMessageHandler innerHandler)
    {
        if (null == innerHandler)
        {
            throw new ArgumentNullException("innerHandler");
        }

        InnerHandler = innerHandler;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpContent content = request.Content;

        if (request.Method == HttpMethod.Post)
        {
            // Wrap the original HttpContent in our custom GzipContent class.
            // If you want to compress only certain content, make the decision here!
            request.Content = new GzipContent(request.Content);
        }

        return base.SendAsync(request, cancellationToken);
    }
}

As you can see, all we’re doing is just wrapping the original HttpContent in our GzipContent class. So let’s get right to that.

Gzip-compressed HttpContent: GzipContent

We’re almost there, all we need to do is actually compressing the content and modify the request headers to indicate the new content encoding.

internal sealed class GzipContent : HttpContent
{
    private readonly HttpContent content;

    public GzipContent(HttpContent content)
    {
        this.content = content;

        // Keep the original content's headers ...
        foreach (KeyValuePair<string, IEnumerable<string>> header in content.Headers)
        {
            Headers.TryAddWithoutValidation(header.Key, header.Value);
        }

        // ... and let the server know we've Gzip-compressed the body of this request.
        Headers.ContentEncoding.Add("gzip");
    }

    protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        // Open a GZipStream that writes to the specified output stream.
        using (GZipStream gzip = new GZipStream(stream, CompressionMode.Compress, true))
        {
            // Copy all the input content to the GZip stream.
            await content.CopyToAsync(gzip);
        }
    }

    protected override bool TryComputeLength(out long length)
    {
        length = -1;
        return false;
    }
}

Easy, right? Of course you could add other supported compression algorithms, using more or less the same code (or even adding some abstraction for different compression algorithms), but this is basically all that’s required.

Summary

Using the HttpMessageHandler and its associated classes makes it extremely easy to apply transformations to all (or a well-defined subset) of HTTP requests you’re sending. In this case, we’re applying Gzip-compression to the bodies of all outgoing POST requests, but the logic to decide when to compress can be as customized as you want; you could even apply Gzip-compression only if the requested URI ends with “.gzip” or for certain content types.

Migrating ASP.NET Web Services to WCF

I recently had to migrate a common ASP.NET web service over to WCF, making sure that clients of the former would still be able to use the latter. There were a couple of things I stumbled across, so I am blogging about the minimal steps I had to perform to get clients of the old ASP.NET web service running with the new WCF one. Let’s use the following simple ASP.NET web service for this tiny tutorial.

[WebService(Namespace = "http://foo.bar.com/Service/Math")]
public class MathAddService : WebService
{
    [WebMethod]
    public int Add(int x, int y)
    {
        // Let's ignore overflows here ;-)
        return x + y;
    }
}

The first thing we need to do is create a new interface which offers the same methods as the web service did and mark it as a service contract. This is required because the WCF endpoints are contract based, i.e. they need such an interface. So we extract the public web service interface of the MathAddService class and decorate it with the WCF attributes:

[ServiceContract(Namespace = "http://foo.bar.com/Service/Math")]
[XmlSerializerFormat]
public interface IMathAddService
{
    [OperationContract(Action = "http://foo.bar.com/Service/Math/Add")]
    int Add(int x, int y);
}

The ServiceContract attribute tells WCF to use the same namespace for the web service as ASP.NET did. If you don’t do this, your clients will not be able to use the migrated service because the namespaces don’t match. The XmlSerializerFormat attribute is used to make sure that WCF uses the standard SOAP format for messages. If you don’t specify this, your clients will likely see strange error messages of mismatching operations / messages. Then, for each method you exposed in the former web service, you need to add the exact same signature here, plus make sure that the OperationContract attribute for each method has the Action property set to ‘/’ . Without this, you’ll get another set of exceptions like ‘operation not defined’.

Now the next step is to implement this interface in a class, but we basically already have this in the former MathAddService class. So we just adapt the class’ definition as follows.

[WebService(Namespace = "http://foo.bar.com/Service/Math")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(Namespace = "http://foo.bar.com/Service/Math")]
public class MathAddService : WebService, IMathAddService
{
    [WebMethod]
    public int Add(int x, int y)
    {
        // Let's ignore overflows here ;-)
        return x + y;
    }
}

As you can see, we’re also adding two new attributes. AspNetCompatibilityRequirements are used to make sure that the new WCF service is really capable of serving old clients. The ServiceBehavior attribute is used to make sure that the WCF hosted service really uses the correct namespace, i.e. the same as the old ASP.NET service used. By the way, you should find all the additional attributes in the System.ServiceModel and System.ServiceModel.Activation namespaces (from the System.ServiceModel assembly).

Now lets get to the configuration of endpoints and bindings for the web service. The following block shows you the new sections in the web.config file for the virtual directory which hosts the WCF service.

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <system.web>
        <!-- ... -->
    </system.web>
    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
        <services>
            <service name="MathAddService" behaviorConfiguration="MathAddServiceBehavior">
                <endpoint address=""
                          binding="basicHttpBinding"
                          bindingConfiguration="httpsIwa"
                          bindingNamespace="http://foo.bar.com/Service/Math"
                          contract="IMathAddService"/>
            </service>
        </services>
        <bindings>
            <basicHttpBinding>
                <binding name="httpsIwa">
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <behaviors>
            <serviceBehaviors>
                <behavior name="MathAddServiceBehavior">
                    <serviceMetadata httpsGetEnabled="true" />
                    <serviceDebug httpsHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

As you can see on lines 19 and 20, we are using HTTPS and IWA for this particular binding, but you should of course make it the same as you had for your ASP.NET service. If you served all requests without HTTP based authentication and without SSL/TLS, then you should stick to that so you don’t break your clients :). You have to make sure that you are offering at least one basicHttpBinding, because that’s what closest matches the ASP.NET SOAP interface.

Finally, we add a new file called ‘MathAddService.svc’ in the virtual directory on IIS with the following contents.

<%@ ServiceHost Service="MathAddService" %>

This will use the implementation of the MathAddService class to serve the request for the IMathAddService interface. Of course your clients will have to be updated to use the new URL now (or you can try a 302 redirect but depending on the client’s policies, this may fail). In case your requests to the new SVC file produce strange results (or send you back the above contents of the file), in the IIS administrative tools make sure that the .svc extension is mapped properly. If it isn’t, you can run the aspnet_regiis.exe tool from the .NET framework to get that done.

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.