guyfromfargo
guyfromfargo

Reputation: 863

How to set content disposition on individual azure blob requests?

I have an application that hosts videos, and we recently migrated to Azure.

On our old application we gave the ability for users to either play or download the video. However on Azure it seems like I have to pick between which functionality I want, as the content disposition has to be set on the file and not on the request.

So far I have came up with two very poor solutions.

The first solution is streaming the download through my MVC server.

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
                        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                        CloudBlobContainer container = blobClient.GetContainerReference("videos");
                        string userFileName = service.FirstName + service.LastName + "Video.mp4";
                        Response.AddHeader("Content-Disposition", "attachment; filename=" + userFileName); // force download
                        container.GetBlobReference(service.Video.ConvertedFilePath).DownloadToStream(Response.OutputStream);
                        return new EmptyResult();

This option works okay for smaller videos, but it is very taxing on my server. For larger videos the operation times out.

The second option is hosting every video twice.

This option is obviously bad, as I will have to pay double the storage cost.

Upvotes: 4

Views: 5714

Answers (2)

Gaurav Mantri
Gaurav Mantri

Reputation: 136216

However on Azure it seems like I have to pick between which functionality I want, as the content disposition has to be set on the file and not on the request.

There's a workaround for that. As you may know there's a Content-Disposition property that you can define on a blob. However when you define a value for this property, it will always be applied on that blob. When you want to selectively apply this property on a blob (say on a per request basis), what you do is create a Shared Access Signature (SAS) on that blob and override this request header there. Then you can serve the blob via SAS URL.

Here's the sample code for this:

        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("videos");
        string userFileName = service.FirstName + service.LastName + "Video.mp4";
        CloudBlockBlob blob = container.GetBlockBlobReference(userFileName);
        SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
        {
            Permissions = SharedAccessBlobPermissions.Read,
            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1)
        };
        SharedAccessBlobHeaders blobHeaders = new SharedAccessBlobHeaders()
        {
            ContentDisposition = "attachment; filename=" + userFileName
        };
        string sasToken = blob.GetSharedAccessSignature(policy, blobHeaders);
        var sasUrl = blob.Uri.AbsoluteUri + sasToken;//This is the URL you will use. It will force the user to download the video.

I wrote a blog post about the same long time ago that you may find useful: http://gauravmantri.com/2013/11/28/new-changes-to-windows-azure-storage-a-perfect-thanksgiving-gift/.

Upvotes: 10

Brando Zhang
Brando Zhang

Reputation: 28067

As far as I know, azure blob storage doesn't support add the custom header to the special container.

I suggest you could follow and vote this feedback to push the azure develop team to support this feature.

Here is a workaround, you could compression the video file firstly, then uploaded to the azure blob storage.

It will not be opened by the browser.

Upvotes: 0

Related Questions