Upload Files to Azure Media Services From Server Side in MVC
Here's a start-to-finish tutorial that covers creating thumbnails and uploading files to your Azure Media Services account with a focus on the server side.
Join the DZone community and get the full member experience.
Join For Freein this article, we are going to see how we can upload images (or any files) to a media services account in azure from the server side. specifically, we will be uploading in an mvc application. if you are new to azure media services accounts, i strongly recommend you to read my previous post explaining them . in another earlier article, we saw how we can upload images to azure media services from the client side . here, we will see how we can do the same thing, just from the server side. we will also see how we can create thumbnails for the image you upload. once we've generated it, we will upload it to the media services account. i hope you will like this.
download the source code
you can always download the source code here: upload files to azure media services .
background
i've been working in azure for the past few weeks. recently, i got a requirement for storing images to azure. thus, i decided to create a media services account.
now, i assume that you have a little background of the following:
- azure media services accounts.
- assets in media services accounts.
- blobs in media services accounts.
so, with that, let's begin.
prerequisites
- visual studio.
- an azure account with an active subscription.
- an active media services account, associated storage, and its keys
- imageresizer dll for generating the resized stream.
to-do list
once you have the tools ready, we're going to do the following:
- create an mvc application.
- create an asset in our media services account.
- upload the file.
- resize the stream with help from imageresizer and upload it.
- retrieve the uploaded items.
click on the file->new->project and name your project. in the next window, please select mvc and create your project. once your project is loaded, you can create an 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. shall we?
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 codes 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 the url as http://localhost:5022/home/uploadfile, so we need to create a jsonresult/actionresult in our home controller right? i 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 a 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
}
}
yes, 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 the nuget package manager. then, 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 need. when i said keys, that includes your media services account key, too. if you don't know your media services account key, please log into your azure portal and get it by selecting your media services account. we will be adding the following keys. just 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 the storage account and the media services account.
<add name="myazurestoragecon" connectionstring="defaultendpointsprotocol=https;accountname=youraccountname;accountkey=youraccountkey" />
<add name="mediastorage" connectionstring="defaultendpointsprotocol=https;accountname=youraccountname;accountkey=youraccountkey" />
i hope you have set everything. now we can create the functions and constants we need in our azurehelper class. are you ready?
#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) . let's see the function now.
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 services account. and this code,
await blockblob.uploadfromstreamasync(strmlists[i]);
, 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 finish uploading, we create an output:
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);
all good? build your application and run! can you see outputs as below?
click on the link upload images. y ou can see the upload view now.
now select the files and click on submit.
you can select as many files as you wish.
so we have uploaded both thumbnails and actual images. that's cool. i guess we are done for now. happy coding!
conclusion
did i miss anything? have you ever tried out an azure media services account? did you find this post helpful? i hope you liked this article. please share your valuable suggestions and feedback.
Published at DZone with permission of Sibeesh Venu, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments