Azure Storage Service - Uploading an Image from Xamarin Forms
In the previous post I talked about using the Media Plugin for Xamarin Forms to add functionality for selecting an image from the phone's gallery or take a picture, this post will expand on the functionality that that project already implements, to upload the selected/taken image to the cloud, specifically, to an Azure Storage Service's blob.
You can get the initial code (from the previous post) from here.
1. Creating the Storage Account
You will need to have an Azure account to complete this exercise, we will be creating a specific kind of service from our Azure account, that is a Storage service, oriented to storing files. This exercise is normally one that follows the implementation of Mobile App Services (also from Azure) into an app, which includes connecting a SQL database, often I say how the Storage Service is the perfect complement to the Mobile App Service, because of course, even though you could, you should not store an image (for example) on a SQL database (the base64 string would be super long and take a lot of space), it is simply much much much cheaper to use a Storage Service, which will give you a URL with which you can access the file, and store THAT in the SQL database.
Lets then navigate to our Azure Portal and sign in with our Microsoft accounts, we will create a new Storage Service. After clicking on the "Create a Resource" in the top left corner of the website, go ahead and select, from the Storage section, the Storage account option.
In the new blade make sure you fill and select:
Name: self-explanatory right? Make sure its unique
Deployment model: Resource Manager
Account kind: blob storage
Performance: standard
Replication: RA-GRS
Access tier: Hot
Secure transfer required: disabled
Virtual networks: disabled
You will also be asked to select your subscription, and whether you want to use an existing Resource group or create a new one as well as the location. These will depend on whether you had created a resource group before and if you want to use the same one with this service, if not just create a new one, and in the case of the location, it will be highly dependant on the location of your users. Try to select the location that is closest to your users. Finally, simply click on create and wait a few seconds.
Once the Storage account is created, navigate to it and select the Containers tab and create a new container with anonymous access to containers and blobs.
Keep in mind the name of your container, since you will be using it from the Xamarin Forms app, and the name has to be identical to what you set in this field.
Before going to Visual Studio, here in the Storage account navigate to the Access keys tab and copy one of the connection strings, this will also be used from the Xamarin Forms in the next step.
2. Preparing the Xamarin Forms project
To be able to connect to an Azure Storage account, or Xamarin Forms app will require the use of a package called WindowsAzure.Storage, that we will have to add to all our projects. Just as I described in the previous post, if you are on Visual Studio 2017 you can simply right-click on the solution, select "Manage NuGet packages for solution" and when installing the package, select all projects. If you are using Visual Studio for Mac, you will have to go to each project, right-click on the packages folder, and select "Add packages..".
3. Uploading the image
Inside the ImageUploaderPage.xaml.cs file there is an event handler that executes the entire functionality of receiving an image, the last line of that method is setting the retrieved file as the source of an Image.
Right after this last line, we will be calling a new method, called something like UploadImage(), which will require the image to be uploaded as a stream, so the definition of the method will be this:
void UploadImage(Stream imageToUpload);
And the way to call this method (still from the event handler that was already there from the previous post) will be this:
UploadImage(selectedImageFile.GetStream());
Inside this new method is where the magic will happen. The first step is to retrieve the storage account using the connection string, that string you copied from the Azure Portal in the Access keys tab, remember? You will need to call the Parse method from the CloudStorageAccount class (one of the classes available in the WindowsAzure.Storage package that we referenced) like this:
var account = CloudStorageAccount.Parse("YOUR_CONNECTION_STRING");
The next step will be to create a blob client, and though it, get a container reference. In this step, it is very important to use the exact same name (this is case sensitive and upper case is not permitted) that you set back in the Azure Portal when creating the container. Otherwise, a new container with this different name would be created, and you will have to get back to the Portal and change its privacy settings.
var blobClient = account.CreateCloudBlobClient(); var container = blobClient.GetContainerReference("images");
Now it is time to create the block blob that will be uploaded, first, just like with the container, you need a reference, in this case, you can set whatever name you want, making sure that the extension is .jpg or .jpeg or maybe even .png. As a quick note, you can use the Guid class to create a unique string that in this case will be used to set the name of the file. Once you have the reference, using the UploadFromStreamAsync method from that block blob reference, you can pass the image stream that the UploadImage method is receiving. This is the method that will upload the image.
string uniqueName = Guid.NewGuid().ToString(); var blockBlob = container.GetBlockBlobReference($"{uniqueName}.jpg"); await blockBlob.UploadFromStreamAsync(imageToUpload);
Awaiting the UploadFromStreamAsync is very important if you want to get the URL for the uploaded image (which I do recommend), so you will need to mark your UploadImage method as async too.
Finally the, if you do want to get that image's new URL, you can access it like this after calling and awaiting the UploadFromStreamAsync method:
string thePlaceInTheInternetWhereThisImageIsNowLocated = blockBlob.Uri.OriginalString;
If you tested this on either Android or iOS, you will be able to navigate back to your Azure Portal, to the container that you created, select one of the blobs (yey! we successfully uploaded the image!) and click on the download button to check how the image that you just uploaded from your phone is now downloadable from the internet.
The complete code for this exercise can be found here.