.NET – Kaliatech https://blog.kaliatech.com Required reading IMO. Wed, 26 Sep 2018 18:25:47 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.8 Posting compressed JSON Content to ASP.NET Web API Controller https://blog.kaliatech.com/2013/02/posting-compressed-json-content-to-asp-net-web-api-controller/ https://blog.kaliatech.com/2013/02/posting-compressed-json-content-to-asp-net-web-api-controller/#comments Wed, 20 Feb 2013 22:24:21 +0000 http://blog.kaliatech.com/?p=242 Continue reading ]]> I had a requirement to POST gzipped JSON content to a .NET web api controller. It turns out the technique for doing this is not easy, or at least not common knowledge. This is the solution I came up with that works:

public class GZipToJsonHandler : DelegatingHandler
{
	protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
	{
		// Handle only if content type is 'application/gzip'
		if (request.Content.Headers.ContentType == null ||
			request.Content.Headers.ContentType.MediaType != "application/gzip")
		{
			return base.SendAsync(request, cancellationToken);
		}

		// Read in the input stream, then decompress in to the outputstream.
		// Doing this asynronously, but not really required at this point
		// since we end up waiting on it right after this.
		Stream outputStream = new MemoryStream();
		Task task = request.Content.ReadAsStreamAsync().ContinueWith(t =>
			{
				Stream inputStream = t.Result;
				var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress);

				gzipStream.CopyTo(outputStream);
				gzipStream.Dispose();

				outputStream.Seek(0, SeekOrigin.Begin);
			});

		// Wait for inputstream and decompression to complete. Would be nice
		// to not block here and work async when ready instead, but I couldn't
		// figure out how to do it in context of a DelegatingHandler.
		task.Wait();

		// This next section is the key...

		// Save the original content
		HttpContent origContent = request.Content;

		// Replace request content with the newly decompressed stream
		request.Content = new StreamContent(outputStream);

		// Copy all headers from original content in to new one
		foreach (var header in origContent.Headers)
		{
			request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
		}

		// Replace the original content-type with content type
		// of decompressed data. In our case, we can assume application/json. A
		// more generic and reuseable handler would need some other
		// way to differentiate the decompressed content type.
		request.Content.Headers.Remove("Content-Type");
		request.Content.Headers.Add("Content-Type", "application/json");

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

Added to the MessageHandlers in WebApiConfig.cs with:

    config.MessageHandlers.Add(new GZipToJsonHandler());

Using this approach, existing controllers which normally work with JSON content and automatic model binding, continue to work without any changes. Related StackOverflow question with my answer here.

]]>
https://blog.kaliatech.com/2013/02/posting-compressed-json-content-to-asp-net-web-api-controller/feed/ 7