Here’s the presentation materials that I’ve put together for tonight.
Azure
Bellingham Cloud Talk, Coming Right Up
Here’s the basic outline of what I intend to speak on at the upcoming presentation I have for the Bellingham, Washington .NET Users Group. If you happen to be in the area you should swing by and give it a listen (or heckle, whatever you feel like doing).
On April 5th I have a talk lined up with the Bellingham .NET Users Group. So far here’s a quick one over of the talk:
What Cloud Computing REALLY is to us techies
- Geographically dispersed data centers.
- Node based – AKA grid computing configurations that are…
- Highly Virtualized – thus distributed.
- Primarily compute and storage functionality.
- Auto-scalable based on demand.
What kind of offerings exist out in the wild?
- Amazon Web Services
- Rackspace
- Orcs Web
- GoGrid
- Joyent
- Heroku
- EngineYard
…many others and then the arrival in the last year”ish” of…
- Windows Azure
- AppHarbor
Developing for the cloud, what are the fundamentals in the .NET world?
Well, let’s talk about who has been doing the work so far, pushing ahead this technology.
- Linux is the OS of choice… free, *nix, most widely used on the Internet by a large margin, and extremely capable…
- Java
- Ruby on Rails
- Javascript & jQuery, budding into Node.js via Google’s V8 Engine
- The Heroku + EngineYard + Git + AWESOMESAUCE capabilities of pushing… LIVE to vastly scalable and distributable cloud provisions!
So where does that leave us .NETters?
AWS .NET SDK released a few years ago.
Windows Azure & SDK released about a year ago.These two have however been lacking compared to Heroku and EngineYard for those that want something FAST,
something transformative, easy to use, without extra APIs or odd tightly coupled SDKs.
Enter…
AppHarborIn Summary the .NET Platform has primarily:
AWS for the top IaaS and most widely available zones & capabilities at the absolutely lowest prices,
Windows Azure for the general build to PaaS Solution, and for the people lucky enough to be going the Git +
MVC + real Agile route, AppHarbor is the peeminent solution.
Demo Time…
Windows Azure Demo
AWS Demo
AppHarbor Demo
Git Rid of Windows Azure and Amazon Web Services (AWS) SDKs with .NET + Git + AppHarbor Deployment Revolution
I’ve been wanting to do a quick write up on the state of cloud apps from my perspective. What’s my perspective? Well I’m keeping up with the SDKs from the big players; AWS and Windows Azure. I’m also working on several cloud applications and providing consulting for some people and companies when approached related to which stack to go with, how to apply their current stacks (such as Ruby on Rails or .NET) in migrating to a cloud service provider. Cloud services, or really more accurately utility computing has my personal and professional interest. Above all, I keep trying to stay informed and know what the best path is for anyone that seeks my advice for moving into hosting & working in the SaaS, PaaS, or IaaS Space. Feel free to contact me in regards to cloud questions: adronhall at the famous gmail dot com. :)
Now on to the good tidbits that have been released lately.
The latest Microsoft goodies area available. For the Windows Azure SDK go check out the Microsoft MSDN Site.
For the latest awesome from AWS (Amazon Web Services) SDK check out the AWS .NET Site.
These two SDKs are great for customers who want to build on the bare bones X platform. Now whatever language & stack one builds in they are tied to that. Ruby on Rails, .NET, Java, PHP, or whatever. But getting tied to the stack is kind of like breathing air, one has to live with what air they have. You can’t exactly get a refund very easily on that.
The Cloud SDKs though for Azure & AWS provide a certain amount of lock in, in addition to the stack lock in you’re using. One of the easiest ways to prevent this lock in is to use a general deployment method backed by source control on something like Git or Mercurial. So far though, .NET has been left out the cold. There has been almost zero support for pushing .NET via Git or Mercurial into a cloud.
Ruby on Rails however has had support for this since… well since the idea popped into the minds of the people at Heroku, EngineYard, and the other companies that are pushing this absolutely amazing and powerful technology pairing.
Again, for .NET, the problem is it has been left in the dust. Smoked. It has left a lot of .NET Developers moving to Ruby on Rails (which isn’t new, this is just one more thing that has pulled more developers away from the .NET stack).
Well, that’s changed a bit. FINALLY someone has gotten the Git + .NET Pairing in the Cloud put together! FINALLY you can get a cloud application running in a minute or two, instead of the absolutely inane amount of time it takes on Windows Azure (15+ minutes most of the time). So who has done something about this?
AppHarbor is the first fully deployable solution for the cloud that allows Git + .NET to get going FAST! I don’t work for these guys at all, so don’t think I’m shilling for them. I’m just THAT happy that .NET has been pulled out of the dust bins and the community has this option. I am flippin’ stoked matter of fact.
Currently, because of pricing and ease of deployment, I’ve been solely using AWS. I can have a .NET MVC app running in AWS in about 5-10 minutes. Between that speed of setup and the pricing, I pay 2/3 as much as Azure would be and can deploy much fast with a completely traditional .NET deployment. No special project type needed, no extra configs, just a straight deployment with full control over the server (i.e. I can RDP in with no problem). Anyway, the list of reasons I went with AWS over Azure really deserve an entire blog entry unto themselves.
With AppHarbor though I can step into the realm of doing exactly the same thing a Ruby on Rails Developer would do with Heroku or EngineYard. Fully PaaS Capable with the scalability and features without needing to port or migrate to an entirely new stack! I’ll probably keep a number of things running on AWS (such as the pending WordPress Websites I am about to push up to AWS), but will absolutely be starting up some applications to run in AppHarbor.
If you’re a .NET Developer and you’ve been wanting, looking for, and frustrated that the .NET Community didn’t have a Git + Cloud Deployment option for .NET, wait no longer. Give AppHarbor a look ASAP!
Anyway… off to do a little work on my infrastructure project. Cheers!
Put Stuff in Your Windows Azure Junk Trunk – Windows Azure Worker Role and Storage Queue
Click on Part 1 and Part 2 of this series to review the previous examples and code. First and foremost have the existing code base created in the other two examples opened and ready in Visual Studio 2010. Next, I’ll just start rolling ASAP.
In the JunkTrunk.Storage Project add the following class file and code to the project. This will get us going for anything else we needed to do for the application from the queue perspective.
public class Queue : JunkTrunkBase
{
public static void Add(CloudQueueMessage msg)
{
Queue.AddMessage(msg);
}
public static CloudQueueMessage GetNextMessage()
{
return Queue.PeekMessage() != null ? Queue.GetMessage() : null;
}
public static List<CloudQueueMessage> GetAllMessages()
{
var count = Queue.RetrieveApproximateMessageCount();
return Queue.GetMessages(count).ToList();
}
public static void DeleteMessage(CloudQueueMessage msg)
{
Queue.DeleteMessage(msg);
}
}
Once that is done open up the FileBlobManager.cs file in the Models directory of the JunkTrunk ASP.NET MVC Web Application. In the PutFile() Method add this line of code toward the very end of that method. The method, with the added line of code should look like this.
public void PutFile(BlobModel blobModel)
{
var blobFileName = string.Format("{0}-{1}", DateTime.Now.ToString("yyyyMMdd"), blobModel.ResourceLocation);
var blobUri = Blob.PutBlob(blobModel.BlobFile, blobFileName);
Table.Add(
new BlobMeta
{
Date = DateTime.Now,
ResourceUri = blobUri,
RowKey = Guid.NewGuid().ToString()
});
Queue.Add(new CloudQueueMessage(blobUri + "$" + blobFileName));
}
Now that we have something adding to the queue, we want to process this queue message. Open up the JunkTrunk.WorkerRole and make sure you have the following references in the project.
Next create a new class file called PhotoProcessing.cs. First add a method to the class titled ThumbnailCallback with the following code.
public static bool ThumbnailCallback()
{
return false;
}
Next add another method with a blobUri string and filename string as parameters. Then add the following code block to it.
private static void AddThumbnail(string blobUri, string fileName)
{
try
{
var stream = Repository.Blob.GetBlob(blobUri);
if (blobUri.EndsWith(".jpg"))
{
var image = Image.FromStream(stream);
var myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
var thumbnailImage = image.GetThumbnailImage(42, 32, myCallback, IntPtr.Zero);
thumbnailImage.Save(stream, ImageFormat.Jpeg);
Repository.Blob.PutBlob(stream, "thumbnail-" + fileName);
}
else
{
Repository.Blob.PutBlob(stream, fileName);
}
}
catch (Exception ex)
{
Trace.WriteLine("Error", ex.ToString());
}
}
Last method to add to the class is the Run() method.
public static void Run()
{
var queueMessage = Repository.Queue.GetNextMessage();
while (queueMessage != null)
{
var message = queueMessage.AsString.Split('$');
if (message.Length == 2)
{
AddThumbnail(message[0], message[1]);
}
Repository.Queue.DeleteMessage(queueMessage);
queueMessage = Repository.Queue.GetNextMessage();
}
}
Now open up the WorkerRole.cs File and add the following code to the existing methods and add the additional even method below.
public override void Run()
{
Trace.WriteLine("Junk Trunk Worker entry point called", "Information");
while (true)
{
PhotoProcessing.Run();
Thread.Sleep(60000);
Trace.WriteLine("Working", "Junk Trunk Worker Role is active and running.");
}
}
public override bool OnStart()
{
ServicePointManager.DefaultConnectionLimit = 12;
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString");
RoleEnvironment.Changing += RoleEnvironmentChanging;
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
RoleEnvironment.Changed += (sender, arg) =>
{
if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
.Any((change) => (change.ConfigurationSettingName == configName)))
{
if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
{
RoleEnvironment.RequestRecycle();
}
}
};
});
Storage.JunkTrunkSetup.CreateContainersQueuesTables();
return base.OnStart();
}
private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
{
if (!e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)) return;
Trace.WriteLine("Working", "Environment Change: " + e.Changes.ToList());
e.Cancel = true;
}
At this point everything needed to kick off photo processing using Windows Azure Storage Queue as the tracking mechanism is ready. I’ll be following up these blog entries with some additional entries regarding rafactoring and streamlining what we have going on. I might even go all out and add some more functionality or some such craziness! So hope that was helpful and keep reading. I’ll have more bits of rambling and other trouble coming down the blob pipeline soon! Cheers!
Put Stuff in Your Windows Azure Junk Trunk – ASP.NET MVC Application
If you haven’t read Part 1 of this series (part 3 click here), you’ll need to in order to follow along with the JunkTrunk Repository. Open the solution up if you haven’t already and navigate to the Models Folder within the ASP.NET MVC JunkTrunk Project. In the folder add another class titled FileItemModel.cs and BlobModel.cs. Add the following properties to the FileItemModel.
public class FileItemModel
{
public Guid ResourceId { get; set; }
public string ResourceLocation { get; set; }
public DateTime UploadedOn { get; set; }
}
Add the following property to the BlobModel and inherit from the FileItemModel Class.
public class BlobModel : FileItemModel
{
public Stream BlobFile { get; set; }
}
Next add a new class file titled FileBlobManager.cs and add the following code to the class.
public class FileBlobManager
{
public void PutFile(BlobModel blobModel)
{
var blobFileName = string.Format("{0}-{1}", DateTime.Now.ToString("yyyyMMdd"), blobModel.ResourceLocation);
var blobUri = Blob.PutBlob(blobModel.BlobFile, blobFileName);
Table.Add(
new BlobMeta
{
Date = DateTime.Now,
ResourceUri = blobUri,
RowKey = Guid.NewGuid().ToString()
});
}
public BlobModel GetFile(Guid key)
{
var blobMetaData = Table.GetMetaData(key);
var blobFileModel =
new BlobModel
{
UploadedOn = blobMetaData.Date,
BlobFile = Blob.GetBlob(blobMetaData.ResourceUri),
ResourceLocation = blobMetaData.ResourceUri
};
return blobFileModel;
}
public List GetBlobFileList()
{
var blobList = Table.GetAll();
return blobList.Select(
metaData => new FileItemModel
{
ResourceId = Guid.Parse(metaData.RowKey),
ResourceLocation = metaData.ResourceUri,
UploadedOn = metaData.Date
}).ToList();
}
public void Delete(string identifier)
{
Table.DeleteMetaDataAndBlob(Guid.Parse(identifier));
}
}
Now that the repository, management, and models are all complete the focus can turn to the controller and the views of the application. At this point the break down of each data element within the data transfer object and the movement of the data back and forth becomes very important to the overall architecture. One of the things to remember is that the application should not pass back and forth data such as URIs or other long easy to hack strings. This is a good place to include Guids or if necessary integer values that identify the data that is getting created, updated, or deleted. This helps to simplify the UI and help decrease the chance of various injection attacks. The next step is to open up the HomeController and add code to complete each of the functional steps for the site.
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to the Windows Azure Blob Storing ASP.NET MVC Web Application!";
var fileBlobManager = new FileBlobManager();
var fileItemModels = fileBlobManager.GetBlobFileList();
return View(fileItemModels);
}
public ActionResult About()
{
return View();
}
public ActionResult Upload()
{
return View();
}
public ActionResult UploadFile()
{
foreach (string inputTagName in Request.Files)
{
var file = Request.Files[inputTagName];
if (file.ContentLength > 0)
{
var blobFileModel =
new BlobModel
{
BlobFile = file.InputStream,
UploadedOn = DateTime.Now,
ResourceLocation = Path.GetFileName(file.FileName)
};
var fileBlobManager = new FileBlobManager();
fileBlobManager.PutFile(blobFileModel);
}
}
return RedirectToAction("Index", "Home");
}
public ActionResult Delete(string identifier)
{
var fileBlobManager = new FileBlobManager();
fileBlobManager.Delete(identifier);
return RedirectToAction("Index", "Home");
}
}
The view hasn’t been created for the Upload just yet, so the method will cause a build error at this point. But before I add a view for this action, I’ll cover what has been created for the controller.
The Index Action I’ve changed moderately to have a list of the Blobs that are stored in the Windows Azure Blob Storage. This will be pulled from the manager class that we created earlier and passed into the view for rendering. I also, just for cosmetic reasons, changed the default display message passed into the ViewData so that the application would have something displayed more relevant to the application.
The About message I just left as is. The Upload action simply returns what will be a view we create.
The UploadFile Action checks for files within the request, builds up the model and then puts the model into storage via the manager.
The last method is the Delete Action that instantiates the manager and then calls a delete against the storage. This action then in turn traces back through, finds the Table & Blob Entities that are related to the specific blob and deletes both from the respective Windows Azure Storage Table and Blob Mediums.
The next step is to get the various views updated or added to enable the upload and deletion of the blob items.
Add a view titled Upload.aspx to the Home Folder of the Views within the JunkTrunk Project.
First change the inherits value for the view from System.Web.Mvc.ViewPage to System.Web.Mvc.ViewPage. After that add the following HTML to the view.
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Upload an Image
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Upload</h2>
<% using (Html.BeginForm("UploadFile", "Home", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
Select file to upload to Windows Azure Blob Storage:
</div>
<div class="editor-field">
<input type="file" id="fileUpload" name="fileUpload" />
</div>
<p>
<input type="submit" value="Upload" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
After adding the HTML, then change the HTML in the Index.aspx View to have an action link for navigating to the upload page and for viewing the list of uploaded Blobs. Change the inherits first form System.Web.Mvc.ViewPage to System.Web.Mvc.ViewPage<IEnumerable>. The rest of the changes are listed below.
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
<%: ViewData["Message"] %></h2>
<p>
<%: Html.ActionLink("Upload", "Upload", "Home") %>
a file to Windows Azure Blob Storage.
</p>
Existing Files:<br />
<table>
<tr>
<th>
</th>
<th>
FileName
</th>
<th>
DownloadedOn
</th>
</tr>
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%: Html.ActionLink("Delete", "Delete",
new { identifier = item.ResourceId })%>
</td>
<td>
<%: item.ResourceLocation %>
</td>
<td>
<%: String.Format("{0:g}", item.UploadedOn) %>
</td>
</tr>
<% } %>
</table>
</asp:Content>
Make sure the Windows Azure Project is set as the startup project and click on F5 to run the application. The following page should display first.
Click through on it to go to the upload page.
On the upload page select and image to upload and then click on upload. This will then upload the image and redirect appropriately to the home page.
On the home page the list should now have the uploaded blob image listed. Click delete to delete the image. When deleted the table and the blob itself will be removed from the Windows Azure Storage. To see that the data & image are being uploaded open up the Server Explorer within Visual Studio 2010.
View the data by opening up the Windows Azure Storage tree. Double click on either of the storage mediums to view table or blob data.









