Deploying WebMatrix Applications to Windows Azure
In this week’s Cloud Cover episode, Ryan and I deploy an application to Windows Azure that was built using the new WebMatrix beta. For the most part, the process is what I described in my last post, “Building, Running, and Packaging Windows Azure Applications From the Command Line.” In this post, I’ll describe the few extra things I needed to do to get things to work.
For those who did watch the show, you’ll remember that I didn’t have a working example after upgrading to WebMatrix Beta 2, and I wasn’t sure what was broken. It turned out to simply be a mistake on my part. I had left an old binary (from the Beta 1 bits) in the bin
folder of my application, and that mismatch was what was breaking the application. The steps I’ll describe below do work for both Beta 1 and Beta 2 applications.
Adding the right assemblies to the bin
folder
One common cause of deployment errors in Windows Azure is a mismatch between the .NET assemblies in the Global Assembly Cache (GAC) in your development environment versus the assemblies in Windows Azure. When you develop with Visual Studio, you need to remember to mark any assembly as “Copy Local” if it’s not part of a standard .NET installation (like what we have in the cloud).
When building an application outside of Visual Studio, such as with the WebMatrix tools, you’ll need to make sure that the bin
folder of your application contains those assemblies you would have marked “Copy Local” in Visual Studio.
I couldn’t find a list of assemblies I needed for WebMatrix applications, so I did something creative to find out. Once I had my application built, I used WebMatrix’s publish feature to publish it to my local machine. The two options for publishing are Web Deploy and FTP Publishing. I used the latter against an FTP server running on localhost
.
Looking at what was uploaded by the FTP process, I found the following assemblies in the bin
folder:
AdminPackage.dll
Microsoft.Web.Infrastructure.dll
Microsoft.WindowsAzure.StorageClient.dll
(this one was already there before the publish, because I added it when I used Windows Azure blobs in the application)NuPack.Core.dll
System.Web.Helpers.dll
System.Web.Razor.dll
System.Web.WebPages.Deployment.dll
System.Web.WebPages.dll
System.Web.WebPages.Razor.dll
WebMatrix.Data.dll
To that list, I also added System.Web.Mvc.dll
, which it seems WebMatrix relies on but doesn’t publish with your application.
Making sure ASP.NET handles all URLs
Per the instructions in the WebMatrix Beta 2 Release Readme, I created a web.config
file to make sure that ASP.NET saw all web requsets (and not just those to known extensions like .aspx
). While I was there, I also made index.cshtml
the default document. Here’s the web.config
I ended up with:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<defaultDocument enabled="true">
<files>
<clear />
<add value="index.cshtml" />
</files>
</defaultDocument>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
</configuration>
Using the .NET 4 runtime
By default, Windows Azure runs your application using .NET 3.5 SP1 (which was the version available when Windows Azure was first released). To use a different runtime, you need to add a parameter when creating your application package. Visual Studio does this for you automatically if your application targets .NET 4, but when you’re packaging using the command line tools, you need to do this yourself.
Because the WebMatrix libraries require .NET 4, I needed to be careful with how I packaged the application to make sure I got the right runtime version. The way you specify that you want the .NET 4 runtime is by creating a file that contains the string TargetFrameworkVersion=v4.0
and using the rolePropertiesFile
parameter to tell cspack
to apply that setting to your role. My final cspack
command looked like this:
cspack ServiceDefinition.csdef /role:helloworld;helloworld /rolePropertiesFile:helloworld;roleproperties.txt /out:HelloRazor.cspkg
Packaging and deploying to the cloud
With a correct bin
folder and web.config
, I was able to deploy to the cloud using the SDK command line tools as described in my previous post.
Bonus: a utility to copy assemblies from the GAC
Now that I know what assemblies are required, I’d rather not have to publish the application locally each time to get the bin
folder right, so I wrote a small application to fetch assemblies from the GAC and copy them locally for me. Just compile the following code and run it with the target directory (usually bin
) and a list of assemblies:
using System; using System.Reflection; using System.Linq; using System.IO; public class CopyAssembly { public static void Main(string[] argv) { if (argv.Length < 2) { Console.WriteLine("Usage: CopyAssembly <target-directory> <assembly-name-1> <assembly-name-2> ..."); Console.WriteLine("CopyAssembly will attempt to load each of the assemblies (from the GAC or"); Console.WriteLine(" elsewhere) and copy them to the target directory. It will not overwrite"); Console.WriteLine(" existing files."); return; } Directory.CreateDirectory(argv[0]); foreach (var assemblyName in argv.Skip(1)) { var assembly = Assembly.LoadWithPartialName(assemblyName); if (assembly != null) { var fileInfo = new FileInfo(assembly.Location); try { File.Copy(assembly.Location, Path.Combine(argv[0], fileInfo.Directory.GetFiles(fileInfo.Name)[0].Name)); Console.WriteLine("Found and copied {0}.", assemblyName); } catch (IOException e) { Console.WriteLine(e.Message); } } else { Console.WriteLine("Unable to locate assembly {0}.", assemblyName); } } } }
More to come
You can probably tell from this week’s Cloud Cover episode that I’m quite impressed with WebMatrix and the new Razor syntax for ASP.NET Web Pages. I’m sure I’ll be building some demos using these new technologies, along with ASP.NET MVC 3 (which was just released in beta form along with WebMatrix Beta 2).
Let me know what specific topics you’d like to see covered that integrate WebMatrix and Windows Azure. My contact information is on the right side of my blog, so send me an email or a tweet.