bpruitt-goddard
bpruitt-goddard

Reputation: 3324

ServiceStack Stream Compression

I am returning a stream of data from a ServiceStack service as follows. Note that I need to do it this way instead of the ways outlined here because I need to perform some cleanup after the data has been written to the output stream.

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
    fs.WriteTo(Response.OutputStream);
}
Response.EndRequest();
...cleanup code...

Compression is handled in the other services that return simple DTOs by using a ServiceRunner similar to this answer. However the stream response above never hits that code as the response object in OnAfterExecute is always null. I am able to manually compress the result inside of the service method as follows, but it requires a lot of setup to determine if and what compression is needed and manually setting up the correct HTTP headers (omitted below).

var outStream = new MemoryStream();
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
{
    fs.CopyTo(tinyStream);
    outStream.WriteTo(Response.OutputStream);
}
Response.EndRequest();
...cleanup code...

Is there a way in ServiceStack to handle this compression for me similar to the way it works with the ServiceRunner?

Upvotes: 2

Views: 457

Answers (1)

paaschpa
paaschpa

Reputation: 4816

I'm not exactly sure what you like about the way ServiceStack handles compression within ServiceRunner. Is it because it is global across ServiceStack APIs?

For your example, I think something like below works and meets your need to perform some cleanup after the data has been written to the output stream ...

public class FStreamService : Service
{
    public object Get(FStream request)
    {
        var filePath = @"c:\test.xml";
        var compressFileResult = new CompressedFileResult(filePath); //CompressedResult in ServiceStack.Common.Web.CompressedFileResult
        compressFileResult.WriteTo(Response.OutputStream);
        Response.EndRequest();
        //  ...cleanup code...
    }
}

Based on comments update of above to add compression using some ServiceStack extensions

public object Get(FStream request)
{
    var filePath = @"c:\test.xml";
    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
    {
        var compressedBtyes = fs.ToUtf8String().Compress(this.RequestContext.CompressionType);
        new CompressedResult(compressedBtyes).WriteTo(Response.OutputStream);           
    }
    Response.EndRequest();
        //  ...cleanup code...
}

If you want it within a ServiceRunner something like this should work...

public override object OnAfterExecute(IRequestContext requestContext, object response)
{
    var resp = requestContext.Get<IHttpResponse>();
    response = requestContext.ToOptimizedResult(requestContext.Get<IHttpResponse>().OutputStream);       

    return base.OnAfterExecute(requestContext, response);
}

Upvotes: 2

Related Questions