다음을 통해 공유


Azure Media Service: Upload Files with MVC From Server Side

In this article we are going to see how we can upload images or any files to Media Service Account in Azure from the server side. We will be doing the uploading in a MVC application. We will also see how we can create thumbnails for the image you upload, once we generated it, we will upload that to media service account.

Download the source code

You can always download the source code here: Upload Files To Azure Media Service

Background

For the past few weeks, we are working in Azure. Recently we got a requirement of storing images to Azure. Thus we decided to create a media service account for this requirement. We hope you saw previous articles related to Media Services, if not please find those here: Media Service.

Now let's assume that you have a little background of below items.

  • Azure media service account
  • Assets in media service account
  • Blobs in media service account

Prerequisites

  • Visual Studio
  • Azure account with active subscription
  • Active media service, associated storage account account and its keys
  • ImageResizer DLL for generating the resized stream

If you are a start-up company or you are in thinking to start a one, you can always go for BizSpark (software and services made for the startups), to join please check here: How to join bizspark. Or you can always create a free account here.

Steps

The following are the tasks we are going to do.

  • Creating a MVC application.
  • Create an Asset in Media service account
  • Upload the file to asset created dynamically
  • Resize the stream with help of ImageResizer and upload
  • Retrieves the uploaded items

Now we will go and create a MVC application.

Create a MVC application

Click on the File > New > Project and name your project. In the upcoming window please select MVC and create your project. Once your project is loaded, you can create a MVC controller as follows.

public class  HomeController : Controller
 {
 public ActionResult Index()
 {
 return View();
 }
 }

And create a view as follows.

@{
 ViewBag.Title = "Home Page";
}
  
<div class="jumbotron">
 <h1>Sibeesh Venu</h1>
 <p class="lead">Welcome to Sibeesh Passion's Azure Media Service Library</p>
 <p><a href="http://sibeeshpassion.com" class="btn btn-primary btn-lg">Learn more ?</a></p>
</div>

Now we need to create an another action in the controller and view for upload.

public ActionResult Upload()
 {
 return View();
 }

And create a view as follows.

@{
 ViewBag.Title = "Upload";
}
  
<h2>Upload</h2>
<style>
 table, td, tr {
 border: 1px solid #ccc;
 border-radius: 5px;
 padding: 10px;
 margin: 10px;
 }
  
 span {
 padding: 10px;
 margin: 10px;
 }
</style>
<input name="myFile" id="myFile" type="file" multiple /><br/>
<input type="button" value="Submit" id="btnSubmit" class="btn btn-info" />
<div id="fiesInfo"></div>
<div id="divOutput"></div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/Upload.js"></script>

Here Upload.js is the file where our client- side code resides. So shall we create the client-side functions related to the upload process?

$('#btnSubmit').click(function () {
 $('#fiesInfo').html('');
 $('#divOutput').html('');
 startDateTime = new  Date();
 $('#fiesInfo').append('<br/><br/><span><b>Uploading starts at</b></span>' + startDateTime);
 var data = new FormData();
 var files = $("#myFile").get(0).files;
 if (files.length > 0) {
 for (var i = 0; i < files.length; i++) {
 data.append("UploadedImage_" + i, files[i]);
 }
 var ajaxRequest = $.ajax({
 type: "POST",
 url: "http://localhost:5022/Home/UploadFile",
 contentType: false,
 processData: false,
 data: data,
 cache: false,
 success: function  (data, status) {
 debugger;
 var totSize = 0;
 $('#divOutput').hide();
 $('#fiesInfo').append('<table></table>');
 for (var i = 0; i < data.length; i++) {
 totSize = totSize + parseFloat(data[i].ImageSize);
 $('#divOutput').append('<img style="float: left;padding:10px;margin:5px;"  src=https://' + mediaServiceAccount + '.blob.core.windows.net/' + data[i].AssetID + '/' + data[i].Title + ' />');
 }
 $('#fiesInfo table').append('<tr><td><b>No of files uploaded: </b></td><td>' + data.length + '</td></tr>');
 $('#fiesInfo table').append('<tr><td><b>Total size uploaded: </b></td><td>' + formatSizeUnits(totSize) + '</td></tr>');
 var endDateTime = new Date();
 $('#fiesInfo table').append('<tr><td><b>Uploading ends at </b></td><td>' + endDateTime + '</td></tr>');
 $('#fiesInfo table').append('<tr><td><b>The time taken is </b></td><td>' + findDateDiff(startDateTime, endDateTime) + ' </td></tr>');
 $('#divOutput').show();
 },
 error: function  (xhr, desc, err) {
 $('#divOutput').html('Error: ' + err);
 }
 });
 }
  
 });

findDateDiff(date1, date2)

function findDateDiff(date1, date2) {
 //Get 1 day in milliseconds
 var one_day = 1000 * 60 * 60 * 24;
  
 // Convert both dates to milliseconds
 var date1_ms = date1.getTime();
 var date2_ms = date2.getTime();
  
 // Calculate the difference in milliseconds
 var difference_ms = date2_ms - date1_ms;
 //take out milliseconds
 difference_ms = difference_ms / 1000;
 var seconds = Math.floor(difference_ms % 60);
 difference_ms = difference_ms / 60;
 var minutes = Math.floor(difference_ms % 60);
 difference_ms = difference_ms / 60;
  
 //var hours = Math.floor(difference_ms % 24);
 //var days = Math.floor(difference_ms / 24);
  
 return minutes + ' minute (s), and ' + seconds + ' second (s)';
 };

formatSizeUnits(bytes)

function formatSizeUnits(bytes) {
 if (bytes >= 1000000000) { bytes = (bytes / 1000000000).toFixed(2) + ' GB'; }
 else if  (bytes >= 1000000) { bytes = (bytes / 1000000).toFixed(2) + ' MB'; }
 else if  (bytes >= 1000) { bytes = (bytes / 1000).toFixed(2) + ' KB'; }
 else if  (bytes > 1) { bytes = bytes + ' bytes'; }
 else if  (bytes == 1) { bytes = bytes + ' byte'; }
 else { bytes = '0 byte'; }
 return bytes;
}

As you can see in the AJAX call we have set URL as http://localhost:5022/Home/UploadFile so we need to create a JsonResult/ActionResult in our Home controller right? We will create an asynchronous JsonResult action there.

#region UploadImages
 /// <summary>
 /// Upload images to the cloud and database. User can upload a single image or a collection of images.
 /// </summary>  
 [HttpPost]
 public async Task<JsonResult> UploadFile()
 {
 try
 {
 List<ImageLists> prcssdImgLists = null;
 if (HttpContext.Request.Files.AllKeys.Any())
 {
 var httpPostedFile = HttpContext.Request.Files;
 if (httpPostedFile != null)
 {
 string result = string.Empty;
 string returnJson = string.Empty;
 using (var ah = new AzureHelper())
 {
 List<Stream> strmLists = new  List<Stream>();
 List<string> lstContntTypes = new List<string>();
 for (int i = 0; i < httpPostedFile.Count; i++)
 {
 strmLists.Add(httpPostedFile[i].InputStream);
 lstContntTypes.Add(httpPostedFile[i].ContentType);
 }
 prcssdImgLists = await ah.UploadImages(strmLists, lstContntTypes);
 }
  
 }
 }
 return Json(prcssdImgLists, JsonRequestBehavior.AllowGet);
 }
 catch (Exception)
 {
 throw;
 }
 }
 #endregion

There we are getting the uploaded files from HttpContext.Request.Files. Did you notice that we are returning the data as collection of the class ImageLists? Where is our *ImageLists *class then?

using System;
using System.IO;
  
namespace WorkingWithImagesAndAzure.Models
{
 /// <summary>
 /// Image Collection, describes the properties of the image uploaded
 /// </summary>
 public class  ImageLists
 {
 #region Private Collections
 private Guid _imageID = Guid.Empty;
 private string  _imageTitle = string.Empty;
 private string  _imageData = string.Empty;
 private string  _assetID = string.Empty;
 private long  _imageSize = 0;
 #endregion
  
 #region Public Properties 
 /// <summary>
 /// The GUID of image
 /// </summary>
 public Guid ImageID
 {
 get
 {
 return _imageID;
 }
 set
 {
 if (value != Guid.Empty && value != _imageID)
 {
 _imageID = value;
 }
 }
 }
 /// <summary>
 /// The name of the image, a string value
 /// </summary>
 public string  Title
 {
 get
 {
 return _imageTitle;
 }
 set
 {
 if (value != string.Empty && value != _imageTitle)
 _imageTitle = value;
 }
 }
 /// <summary>
 /// AssetID
 /// </summary>
 public string  AssetID
 {
 get
 {
 return _assetID;
 }
 set
 {
 if (value != string.Empty && value != _assetID)
 _assetID = value;
 }
 }
 /// <summary>
 /// The filesteam of the single image uploaded
 /// </summary>
 public string  ImageData
 {
 get
 {
 return _imageData;
 }
 set
 {
 if (value != null && value != _imageData)
 _imageData = value;
 }
 }
 /// <summary>
 /// ImageSize
 /// </summary>
 public long  ImageSize
 {
 get
 {
 return _imageSize;
 }
 set
 {
 if (value != 0 && value != _imageSize)
 _imageSize = value;
 }
 }
 #endregion
  
 }
}

You are right, we need to create an another class too, AzureHelper.

public class  AzureHelper : IDisposable
 {  
 void IDisposable.Dispose()
 {
  
 }
 }

Here we will start all of our codes related to media service account. Before going further, please install Microsoft.WindowsAzure.Storage from NuGet package manager. And add the following references.

using ImageResizer;
using Microsoft.WindowsAzure.MediaServices.Client;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Threading.Tasks;

You must add ImageResizer.dll to your references before you start using ImageResizer, you can get the DLL file from the source code attached.

Next, we will configure our Web.config with the keys and connection strings we needed. When we say keys, it includes your media service account keys too. If you don't know your media service account keys, please login to your Azure portal and get it by selecting your media service account. We will be adding the following keys, please replace the information with yours.

<appSettings>
 <add key="webpages:Version" value="3.0.0.0" />
 <add key="webpages:Enabled" value="false" />
 <add key="ClientValidationEnabled" value="true" />
 <add key="UnobtrusiveJavaScriptEnabled" value="true" />
 <add key="imgRszeWdth" value="120" />
 <add key="imgRszeHgth" value="120" />
 <add key="myAzureStorageCon" value="UseDevelopmentStorage=true;" />
 <add key="MediaServicesAccountName" value="" />
 <add key="MediaServicesAccountKey" value="" />
 <add key="myAzureStorageConSetting" value="" />
 </appSettings>

Now we can set our connection strings of both storage account and media service account.

<add name="myAzureStorageCon" connectionString="DefaultEndpointsProtocol=https;AccountName=youraccountname;AccountKey=youraccountkey" />
 <add name="MediaStorage" connectionString="DefaultEndpointsProtocol=https;AccountName=youraccountname;AccountKey=youraccountkey" />

Hope you have set everything. Now we can create the functions and constants we need in our AzureHelper class.

#region Constants 
 private static  readonly string imgRszeWdth = ConfigurationManager.AppSettings["imgRszeWdth"];
 private static  readonly string imgRszeHgth = ConfigurationManager.AppSettings["imgRszeHgth"];
 private static  readonly string mediaServicesAccountName = ConfigurationManager.AppSettings["MediaServicesAccountName"];
 private static  readonly string mediaServicesAccountKey = ConfigurationManager.AppSettings["MediaServicesAccountKey"];
 private static  readonly string myAzureStorageConSetting = ConfigurationManager.AppSettings["myAzureStorageConSetting"];
 private static  readonly string myAzureCon = ConfigurationManager.ConnectionStrings["MediaStorage"].ConnectionString;
 #endregion

And we need to create a function named UploadImages, this is the one we are calling from our controller.

#region Public Methods 
 public async Task<List<ImageLists>> UploadImages(List<Stream> strmLists, List<string> lstContntTypes)
 {
 string myContainerName = "Test007";
 string assetID = CreateBLOBContainer(myContainerName);
 assetID = assetID.Replace("nb:cid:UUID:", "asset-");
 List<ImageLists> retCollection = new  List<ImageLists>();
 CloudStorageAccount storageAccount = CloudStorageAccount.Parse(myAzureStorageConSetting);
 CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
 CloudBlobContainer container = blobClient.GetContainerReference(assetID);
 container.SetPermissions(
 new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
  
 if (strmLists != null)
 {
 for (int i = 0; i < strmLists.Count; i++)
 {
 string strExtension = string.Empty;
 if (lstContntTypes[i] == "image/gif")
 {
 strExtension = ".gif";
 }
 else if  (lstContntTypes[i] == "image/jpeg")
 {
 strExtension = ".jpeg";
 }
 else if  (lstContntTypes[i] == "image/jpg")
 {
 strExtension = ".jpg";
 }
 else if  (lstContntTypes[i] == "image/png")
 {
 strExtension = ".png";
 }
 ImageLists img = new  ImageLists();
 string imgGUID = Guid.NewGuid().ToString();
 CloudBlockBlob blockBlob = container.GetBlockBlobReference(string.Concat(imgGUID, strExtension));
 await blockBlob.UploadFromStreamAsync(strmLists[i]);
  
 img.ImageID = new  Guid(imgGUID);
 img.Title = string.Concat(imgGUID, strExtension);
 img.ImageSize = strmLists[i].Length;
 img.AssetID = assetID;
 retCollection.Add(img);
  
 CloudBlockBlob blockblobthumb = container.GetBlockBlobReference(string.Concat(imgGUID, "_thumb", strExtension));
 Stream strmThumb = ResizeImage(strmLists[i]);
 using (strmThumb)
 {
 await blockblobthumb.UploadFromStreamAsync(strmThumb);
  
 img = new  ImageLists();
 img.ImageID = new  Guid(imgGUID);
 img.Title = string.Concat(imgGUID, "_thumb", strExtension);
 img.ImageSize = strmThumb.Length;
 img.AssetID = assetID;
 retCollection.Add(img);
 }
 }
  
 }
 return retCollection;
 }
 #endregion

As you can see, we are creating the asset as CreateBLOBContainer(myContainerName).

private string  CreateBLOBContainer(string containerName)
 {
 try
 {
 string result = string.Empty;
 CloudMediaContext mediaContext;
 mediaContext = new  CloudMediaContext(mediaServicesAccountName, mediaServicesAccountKey);
 IAsset asset = mediaContext.Assets.Create(containerName, AssetCreationOptions.None);
 return asset.Id;
 }
 catch (Exception)
 {
 throw;
 }
 }

That's fantastic, we just created an asset in our media service account. And this is the code await blockBlob.UploadFromStreamAsync(strmLists[i]); which does the uploading. Once the actual image is uploaded we are passing the stream to a function ResizeImage(strmLists[i]) which will return the converted stream.

private static  MemoryStream ResizeImage(Stream downloaded)
 {
 var memoryStream = new  MemoryStream();
 var settings = string.Format("mode=crop&width={0}&height={1}", Convert.ToInt32(imgRszeWdth), Convert.ToInt32(imgRszeHgth));
 downloaded.Seek(0, SeekOrigin.Begin);
 var i = new  ImageJob(downloaded, memoryStream, new Instructions(settings));
 i.Build();
 memoryStream.Position = 0;
 return memoryStream;
 }

Once we finished uploading we are creating an output as follows.

ImageLists img = new  ImageLists();
 img.ImageID = new  Guid(imgGUID);
 img.Title = string.Concat(imgGUID, strExtension);
 img.ImageSize = strmLists[i].Length;
 img.AssetID = assetID;
 retCollection.Add(img);

Build your application and run! Can you see outputs as below?

Upload Images To Azure Media Service Home Page

Click the link Upload Images and you can see the Upload view now.

Upload Images To Azure Media Service Upload View

Now select the files and click Submit.

Upload Images To Azure Media Service Output

You can select as many files as you wish.

 Upload Images To Azure Media Service Output Multiple

So we have uploaded both thumbnail and the actual image. That's cool. Happy coding!.