Service GET method returning IReturn<Stream>

Hi guys,
I need to create a GET method into my service to return a Stream of huge files (>100Mb).

My get method looks like this:

    public object Get(GetDocumentStream request)
    {
        return new HttpResult(new FileInfo(request.Path), asAttachment: true);            
    }

and my JSonServiceClient consumer invoke

        using (var stream = client.Get<GetDocumentStream>(new GetDocumentStream(){ Path="" }))
        {
            using (var fs = new FileStream(""))
            {
                await stream.CopyToAsync(fs);
            }
        }

My GetDocumentStream route is;

public class GetDocumentStream : IReturn<Stream>
{
    public string Path { get; set; }
}

What is really strange to me is that some client need more time to get the same file. Using 3 different PC I got 3 very different timings, so I’m wondering if I did something wrong on how I wrote these methods. Can you please link me to the right direction?

I’m using ServiceStack 5.0.2, and my app host is SelfHostApp on a Windows Service

Thanks
Thomas

As an overall strategy, for efficiently downloading very large files I would avoid having the download go through an App Server and just have your Service return a redirect to the file that’s served by your Web Server:

return HttpResult.Redirect(pathToFile);

Where it would be served directly by your Web Server, e.g. IIS / nginx so requests bypasses .NET and the contents are streamed natively.

Likewise when dealing with large files you should avoid buffering when possible and write them directly to the file system:

var url = "http://example.org/file.zip";

var client = new HttpClient();
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
using (var stream = await response.Content.ReadAsStreamAsync())
{
    string filePath = @"C:\path\to\file.zip"; // or temp file: Path.GetTempFileName();
    using (var fs = File.Open(filePath, FileMode.Create))
    {
        await stream.CopyToAsync(fs);
    }
}

Otherwise returning files with:

return new HttpResult(new FileInfo(request.Path), asAttachment: true); 

Where the file contents are written as a Stream and Get<Stream> (or preferably GetAsync<Stream>) will download the contents as a Stream although the above approach of using HttpCompletionOption.ResponseHeadersRead minimizes the amount of internal buffering the HttpClient will use.

If you’re using .NET Core I’d recommend using JsonHttpClient instead of JsonServiceClient as .NET’s WebRequest is a wrapper over HttpClient in .NET Core so it’s more efficient to use HttpClient used in JsonHttpClient directly.

Hi,
I tried your suggestions and got some improvements, but not huge as expected. I changed your code in this way because I need a byte array of the stream

            using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
            {
                using (var stream = await response.Content.ReadAsStreamAsync())
                {                        
                    Byte[] b = stream.ReadFully();
                }
            }

and the “ReadFully” method in my pc took 3s to read a 3mb file. Another pc execute instantly.
Both pc are using Windows10 with same specs (i7 + 16Giga ram + SSD disk), the service is hosted on windows service connected with a 1giga cabled network. I’m wondering why, if it could due to a nic driver or something related to the “download” methods

I’m updating my bios and my nic driver, just to see if this may help

Thanks
Thomas