We just upgraded all of our libs within our Project and so did we upgraded ServiceStack from 4.5.6 - 4.5.14.
There are many services in which we are just directly returning Stream content, like File, Images, Pdf etc.
Everything was working fine until after once we upgraded the lib, we noticed that from our client when we hit the endpoint nothing would get return from the service. Which did use to work before the upgrade. A little experimenting with fiddler we find out that the service is returning Content-Size:0 and Body being empty.
Then I looked back at the stream and thought maybe its with the Position that probably you were resetting the position before but not anymore and so I thought of resetting stream.Position = 0 which surprisingly worked.
Ex.
var stream = new MemoryStream();
stream.Write(list.ToFormattedCsv());
// This doesn't work(meaning that service doesn't seem to write to response output stream) unless I do
//__stream.Position = 0__
// or
// __ stream.ToBytes()__
// or
return stream;
So, Now I couldn’t find the reason as to why this is happening, since it was much flexible and smoother returning the stream.
Also, I tried to look over in the SS source code to see and convince my self with that but wasn’t able to truly find it.
Is there anything am I missing or there has been a change made to it?
Also, I thought of returning the bytes but still was wanting to find out why the Streams won’t work anymore …?
I really appreciate the quick response and the fix.
However, I was anticipating the fix to happen on pre v5 release(like a patch on 4.5).
We would love to upgrade to v5 but we are not any close to upgrading it to 5 because it may require us work to fix any breaking changes. Plus we just released our branch that was totally devoted to lib/packages within our project both the client/service side.
So, is it possible if you could make the patch on the 4.5 as well?
Releases are and have always been forward only where fixes are always applied to the latest/current version which is what gets deployed to NuGet. You can just reset the stream position yourself (which is all this fix does) if you don’t want to upgrade to v5.
Just a follow up on this, so as you remember after the upgrading lib. to 4.5.14 returning Stream directly from services, returned nothing in the body.
So to fix that, I had the Position set manually at my end. Good so far and worked just fine, for memory streams.
However, I have a few more of my services that talks to RavenDb(if you may have heard of NoSql Db) and retrieves the File content as GZipStream, note the file themselves aren’t zipped by any means they just get wrapped inside GZipStream.
The issue I am having is that when I return that from the Service ServiceStack returns nothing 0 content-length and empty content and not sure what is going wrong as this piece was working perfectly fine in 4.5.6.
Is this still an issue with the latest v5.0.2 of ServiceStack? If it is can you provide a stand alone repro that worked before but isn’t working now.
I’m still tracking down support for naked GZipStream return types, but I want to show a more working optimal implementation where you return the compressed bytes if the Client supports it or the original uncompressed file if not:
[Route("/gzip/{FileName}")]
public class DownloadGzipFile : IReturn<byte[]>
{
public string FileName { get; set; }
}
public class DocumentServices : Service
{
public object Get(DownloadGzipFile request)
{
var name = request.FileName;
var filePath = HostContext.AppHost.MapProjectPath("~/img/" + name);
if (Request.RequestPreferences.AcceptsGzip)
{
var targetPath = string.Concat(filePath, ".gz");
Compress(filePath, targetPath);
return new HttpResult(new FileInfo(targetPath)) {
Headers = {
{ HttpHeaders.ContentDisposition, "attachment; filename=" + name },
{ HttpHeaders.ContentEncoding, CompressionTypes.GZip}
}
};
}
return new HttpResult(filePath) {
Headers = {
{ HttpHeaders.ContentDisposition, "attachment; filename=" + name },
}
};
}
}
Where Compress uses your same impl:
private void Compress(string readFrom, string writeTo)
{
byte[] b;
using (var f = new FileStream(readFrom, FileMode.Open))
{
b = new byte[f.Length];
f.Read(b, 0, (int)f.Length);
}
using (var fs = new FileStream(writeTo, FileMode.OpenOrCreate))
using (var gz = new GZipStream(fs, CompressionMode.Compress, false))
{
gz.Write(b, 0, b.Length);
}
}
Basically avoiding any decompression overhead on the server and taking advantage of compression when the client supports it.