2

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?

Community
  • 1
  • 1
bpruitt-goddard
  • 3,174
  • 2
  • 28
  • 34

1 Answers1

2

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);
}

paaschpa
  • 4,816
  • 11
  • 15
  • I wasn't able to get either of those to work properly. CompressedFileResult assumes the data is already [compressed](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Common/Web/CompressedFileResult.cs#L62). The ToOptimizedResult extension didn't work because that method [expects a DTO](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/RequestContextExtensions.cs#L20), not a filestream. I think I can use `CompressedFileResult` to handle the headers, but I'll have to manually determine whether to compress and do the compression myself. – bpruitt-goddard Sep 26 '13 at 13:54
  • Not exactly sure of the specific reason you want to write directly to the OutputStream but could you create/hydrate an instance of CompressedResult, do your cleanup and return the CompressedResult instance? – paaschpa Sep 26 '13 at 16:48