Returning a stream from Azure blob store fails in ServiceStack.Core 1.0.44

We have a service running under .NET Core 2.0 that opens a stream from an Azure blob store, and returns it in an HttpResult. It works perfectly in 1.0.43, but in 1.0.44, the web browser receives an empty stream.

The funny thing is this: I was uncertain if the stream was OK, so I wrote it to a file and then set stream.Position = 0 before returning it, just to test. Now it also was delivered correctly to the client.

What has changed in 1.0.44 that could cause this change in behaviour?

Please provide the source code that shows the issue.

using System.Threading.Tasks;
using Funq;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using ServiceStack;
using ServiceStack.Configuration;
using ServiceStack.Web;

namespace ServiceStackBlobStreaming
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
        }
    }

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseServiceStack(new AppHost());

            app.Run(async context =>
            {
                await context.Response.WriteAsync(
@"<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>ImageTest</title>
</head>
<body>
<img src=""/img"">
</body>
</html>");
            });
        }
    }

    public class AppHost : AppHostBase
    {
        public AppHost() : base("StreamTest", typeof(AppHost).Assembly)
        {
            AppSettings = new AppSettings();
        }

        public override void Configure(Container container)
        {
        }
    }

    public class ImageService : Service
    {
        private readonly CloudBlobContainer _container;

        public ImageService()
        {
            var storageAccount = CloudStorageAccount.Parse("long_connection_string");
            var storageClient = storageAccount.CreateCloudBlobClient();
            _container = storageClient.GetContainerReference("container_name");
        }

        public async Task<IHttpResult> Get(ImageRequest request)
        {
            var blobReference = _container.GetBlobReference("some_blob_reference");
            var stream = await blobReference.OpenReadAsync();

            // Uncommenting the following somehow makes it work

            //using (FileStream fileStream = File.OpenWrite(@"C:\Temp\foo.jpg"))
            //{
            //    stream.CopyTo(fileStream);
            //}

            //stream.Position = 0;

            return new HttpResult(stream, "image/jpeg");
        }
    }

    [Route("/img")]
    public class ImageRequest
    {
    }
}

Does it work when stream.Position = 0; ?

I just tested: No, it doesn’t.

I’ve tracked the issue down to HttpResult usage of CopyToAsync() where it will throw an Object Disposed Exception but if we replaced it to use the sync CopyTo, i.e:

ResponseStream.CopyTo(responseStream);

It wont throw the exception and will write the image to the Response.

I’m still tracking down why it’s failing when we use CopyToAsync in HttpResult, but in the meantime you can rewrite your implementation to return the image with:

public async Task Get(ImageRequest request)
{
    var blobReference = _container.GetBlobReference("some_blob_reference");
    var stream = await blobReference.OpenReadAsync();
    base.Response.ContentType = "image/jpeg";
    await stream.CopyToAsync(base.Response.OutputStream);
}

This should be resolved with the latest v4.5.15 / v1.0.45 that’s now available on MyGet.

Where you can return an async Azure Blob Stream in a HttpResult if you prefer:

public async Task<IHttpResult> Get(ImageRequest request)
{
    var blobReference = _container.GetBlobReference("some_blob_reference");
    var stream = await blobReference.OpenReadAsync();
    return new HttpResult(stream, "image/jpeg");
}
1 Like

Thanks for fixing it this fast!

How far off is a release of v1.0.45?

It’s available on MyGet now, the next ServiceStack release is v5 which is very far away from NuGet.

OK, we’ll go for MyGet then. Good luck with v5! :slight_smile: