Finishing off this guide with part 2, we will be covering how to get a list of blobs, basics of blob access, and actually implement a gallery of our uploaded blob images.
Getting started, we’ll get a list of our uploaded blobs. Just like in part 1, we’ll be adding the functionality we want to the BlobService, named simply GetBlobList(), which will return a List<IListBlobItem>. We can utilize our previously defined function to get a reference to our blob container. Then, we can get our list using the following code:
var list = container.ListBlobsSegmentedAsync(null).Result.Results;
This looks strange, but it’s not as complicated as it looks. ListBlobsSegmentedAsync takes a BlobContinuationToken (null for what we want), and returns a Task<BlobResultSegment>. This gets resolved to just a BlobResultSegment with a .Result, which we then get .Results of to give us an IEnumerable<IListBlobItem>. After that, we can simply loop through the list items and add the item if it’s of type CloudBlockBlob (to only get the files we want).
Now that we have our list of blobs, we can just display them right? Well, not exactly. This is where permissions come into play. By default, containers have no public access. As such, if you try to hit a newly uploaded file directly, it won’t display. You can change this from the Storage Explorer by right clicking the container, selecting Set Public Access Level…, and selecting public read access.
So how do we display our blobs without public access? We just need to add a SAS (shared access signature) to the end of our URLs. While likely not best practice, we can see the utilization of a SAS in action by looping through our list of blobs and getting a SAS for each blob. Then we can subsequently add the SAS to the end of the URL.
var urls = new List<string>(); foreach (var item in list) { var sas = ((CloudBlockBlob)item).GetSharedAccessSignature(policy); if (item.GetType() == typeof(CloudBlockBlob)) { CloudBlockBlob blob = (CloudBlockBlob)item; urls.Add(blob.Uri.ToString() + sas); } }
We can do this because the SAS is simply a query string. So, for example, our URLs will go from
http://127.0.0.1:10000/devstoreaccount1/myfirstcontainer/2016-09-09.jpg
to
http://127.0.0.1:10000/devstoreaccount1/myfirstcontainer/2016-09-09.jpg?sv=2016-05-31&sr=b&sig=L7DEldCMG%2FisVzu57gdwJ8gWtXdl7FDtR0C3oRFiIjg%3D&se=2017-04-12T14%3A41%3A59Z&sp=racwdl
When we were just uploading files, we were using access that was provided via the connection string, acting as ourselves. This is usually fine, especially if you have your upload functionality behind an authentication process, and tie the files to the user. However, it’s important to keep your production storage account connection string secure and hidden. You can find more information about SAS here.
Last up is to actually display our blobs in a gallery. Again, for convenience, I created a BlobViewModel with Url, File, and Type attributes, all strings. In our Home controller we can add the following logic after we have gotten our list of blobs from the blob service:
ViewData["Blobs"] = blobs.Select(x => new BlobViewModel { Url = x.Uri + ((CloudBlockBlob)x).GetSharedAccessSignature(sasPolicy), File = ((CloudBlockBlob)x).Name.Substring(((CloudBlockBlob)x).Parent.Prefix.Length, ((CloudBlockBlob)x).Name.Length - ((CloudBlockBlob)x).Parent.Prefix.Length), Type = ((CloudBlockBlob)x).Properties.ContentType.ToLower() }).Where(y => y.Type.ToLower().StartsWith("image")).ToList();
Note that we are using Linq to verify that we only get files with content type starting with image. The idea is that since we’re going to be looping through the files in <img> tags, we don’t want to show junk because of an invalid file. We do that looping in the .cshtml view with the following code:
<div class="row"> @foreach (var item in (List<BlobViewModel>)ViewData["Blobs"]) { <div class="form-group col-md-3"> <div class="gallery"> <a target="_blank" href="@item.Url"> <img src="@item.Url" style="max-width:100%;"> </a> <div class="desc">@item.File</div> </div> </div> } </div>
Styling can be kind of wonky for creating a gallery, as if there are different aspect ratios, files can be distorted or make the grid format confusing or unappealing. I am not a designer by any stretch of the definition, but here’s how the provided code should more or less look:
And just like that, we’re done! We now have a fully functioning gallery and uploader that utilizes Azure Blobs/Storage accounts. This code works the same between the emulated Azure Storage and an actual Storage Account on Azure, so it’s simply a matter of changing the connection string. Full code is available here: https://github.com/mvalenta/blob-gallery.