For those that are interested, I solved this by writing a compression plugin that intercepts the response and handles the compression outside of the service method, which is where I believe it should be done. It also addresses the JSONP issue described above.
In my opinion, compression is an orthogonal concern to the service method logic, and moving this outside of the service method as a response filter enables service to service calls to exist with inherent strong typing instead of the ugly public object MyServiceMethod(DtoType request) { }
signatures for allowing arbitrary compressed/uncompressed responses. I've taken the assumption here that if the client states a valid Accept-Encoding
header then the response will be compressed regardless, which I think is a fair call to make.
For now, I've opted against a pull request to ServiceStack as I see it as a major change in the approach to how the framework handles compression and would require considerable upfront discussion with the owners. This code is purely for demonstrative purposes, but I'm using it and it works very well.
Code:
public class CompressionFeature : IPlugin
{
public void Register(IAppHost appHost)
{
appHost.ResponseFilters.Add((request, response, dto) =>
{
if (dto == null || dto is AuthResponse || dto is CompressedResult || dto is Exception) return;
using (var serializationContext = new HttpRequestContext(request, response, dto))
{
if (!serializationContext.RequestAttributes.AcceptsDeflate && !serializationContext.RequestAttributes.AcceptsGzip) return;
var serializedDto = EndpointHost.ContentTypeFilter.SerializeToString(serializationContext, dto);
var callback = request.GetJsonpCallback();
var isJsonpRequest = EndpointHost.Config.AllowJsonpRequests && !string.IsNullOrEmpty(callback);
if (isJsonpRequest)
{
serializedDto = (callback + "(") + serializedDto + ")";
serializationContext.ResponseContentType = ContentType.JavaScript;
}
var compressedBytes = serializedDto.Compress(serializationContext.CompressionType);
var compressedResult = new CompressedResult(compressedBytes, serializationContext.CompressionType, serializationContext.ResponseContentType);
response.WriteToResponse(compressedResult, serializationContext.ResponseContentType);
}
});
}
}
Register the plugin in your AppHost:
appHost.Plugins.Add(new CompressionFeature());