Maarten Balliauw {blog}

ASP.NET MVC, Microsoft Azure, PHP, web development ...

NAVIGATION - SEARCH

Lightweight PHP application deployment to Windows Azure

Those of you who are deploying PHP applications to Windows Azure, are probably using the Windows Azure tooling for Eclipse or the fantastic command-line tools available. I will give you a third option that allows for a 100% customized setup and is much more lightweight than the above options. Of course, if you want to have the out-of-the box functionality of those tools, stick with them.

Note: while this post is targeted at PHP developers, it also shows you how to build your own .cspkg from scratch for any other language out there. That includes you, .NET and Ruby!

Oh, my syntax highlighter is broken so you won't see any fancy colours down this post :-)

Phase 1: Creating a baseline package template

Every Windows Azure package is basically an OpenXML package containing your application. For those who don’t like fancy lingo: it’s a special ZIP file. Fact is that it contains an exact copy of a folder structure you can create yourself. All it takes is creating the following folder & file structure:

  • ServiceDefinition.csdef
  • ServiceConfiguration.cscfg
  • PhpOnAzure.Web
    • bin
    • resources
    • Web.config

I’ll go through each of those. First off, the ServiceDefinition.csdef file is the metadata describing your Windows Azure deployment. It (can) contain the following XML:

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="PhpOnAzure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="PhpOnAzure.Web" enableNativeCodeExecution="true">
    <Sites>
      <Site name="Web" physicalDirectory="./PhpOnAzure.Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="HttpEndpoint" />
        </Bindings>
      </Site>
    </Sites>
    <Startup>
      <Task commandLine="add-environment-variables.cmd" executionContext="elevated" taskType="simple" />
      <Task commandLine="install-php.cmd" executionContext="elevated" taskType="simple" />
    </Startup>
    <Endpoints>
      <InputEndpoint name="HttpEndpoint" protocol="http" port="80" />
    </Endpoints>
    <Imports>
      <Import moduleName="Diagnostics"/>
    </Imports>
    <ConfigurationSettings>
    </ConfigurationSettings>
  </WebRole>
</ServiceDefinition>

Basically, it tells Windows Azure to create a WebRole named “PhpOnAzure.Web” (notice the not-so-coincidental match with one directory of the folder structure described earlier). It will contain one site that listens on a HttpEndpoint (port 80). Next, I added 2 startup tasks, add-environment-variables.cmd and install-php.cmd. More on these later on.

Next, ServiceConfiguration.cscfg is the actual configuration file for your Windows Azure deployment. It looks like this:

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="PhpOnAzure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*">
  <Role name="PhpOnAzure.Web">
    <Instances count="1" />
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="<your diagnostics connection string here>"/>
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

Just like in a tooling-based WIndows Azure deployment, it allows you to set configuratio ndetails like the connection string where the diagnostics monitor should write all logging to.

The PhpOnAzure.Web folder is the actual root where my web application will live. It’s the wwwroot of your app, the htdocs folder of your app. Don’t put any contents n here yet, as we’ll automate that later in this post. Anyways, it (optionally) contains a Web.config file where I specify that index.php should be the default document:

<?xml version="1.0"?>
<configuration>
  <system.webServer>
    <defaultDocument>
      <files>
        <clear />
        <add value="index.php" />
      </files>
    </defaultDocument>
  </system.webServer>
</configuration>

Everything still OK? Good! (I won’t take no for an answer :-)). Add a bin folder in there as well as a resources folder. The bin folder will hold our startup tasks (see below), the resources folder will contain a copy of the Web Platform Installer command-line tools.

That’s it! A Windows Azure deployment package is actually pretty simple and easy to create yourself.

Phase 2: Auto-installing the PHP runtime

I must admit: this one’s stolen from the excellent Canadian Windows Azure MVP Cory Fowler aka SyntaxC4. He blogged about using startup tasks and the WebPI Command-line tool to auto-install PHP when your Windows Azure VM boots. Read his post for in-depth details, I’ll just cover the startup task doing this. Which I shamelessly copied from his blog as well. Credits due.

Under PhpOnAzure.Web\bin, add a script named install-php.cmd and copy in the following code:

@echo off
ECHO "Starting PHP installation..." >> ..\startup-tasks-log.txt

md "%~dp0appdata"
cd "%~dp0appdata"
cd ..

reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" /v "Local AppData" /t REG_EXPAND_SZ /d "%~dp0appdata" /f
"..\resources\WebPICmdLine\webpicmdline" /Products:PHP53 /AcceptEula  >> ..\startup-tasks-log.txt 2>>..\startup-tasks-error-log.txt
reg add "hku\.default\software\microsoft\windows\currentversion\explorer\user shell folders" /v "Local AppData" /t REG_EXPAND_SZ /d %%USERPROFILE%%\AppData\Local /f

ECHO "Completed PHP installation." >> ..\startup-tasks-log.txt

What it does is:

  • Create a local application data folder
  • Add that folder name to the registry
  • Call “webpicmdline” and install PHP 5.3.x. And of course, /AcceptEula will ensure you don’t have to go to a Windows Azure datacenter, break into a container and click “I accept” on the screen of your VM.
  • Awesomeness happens: PHP 5.3.x is installed!
  • And everything gets logged into the startup-tasks-error-log.txt file in the root of your website. It allows you to inspect the output of all these commands once your VM has booted.

Phase 3: Fixing a problem

So far only sunshine. But… Since the technique used here is creating a full-IIS web role (a good thing), there’s a small problem there… Usually, your web role will spin up IIS hosted core and run in the same process that launched your VM in the first place. In a regular web role, the hosting process contains some interesting environment variables about your deployment: the deployment ID and the role name and even the instance name!

With full IIS, your web role is running inside IIS. The real IIS, that’s right.  And that’s a different process from the one that launched your VM, which means that these useful environment variables are unavailable to your application. No problem for a lot of applications, but if you’re using the PHP-based diagnostics manager from the Windows Azure SDK for PHP (or other code that relies on these environment variables, well, you’re sc…. eh, in deep trouble.

Luckily, startup tasks have access to the Windows Azure assemblies that can also give you this information. So why not create a task that copies this info into a machine environment variable?

We’ll need two scripts: one .cmd file launching PowerShel, and of course PowerShell. Let’s start with a file named add-environment-variables.cmd under PhpOnAzure.Web\bin:

@echo off
ECHO "Adding extra environment variables..." >> ..\startup-tasks-log.txt

powershell.exe Set-ExecutionPolicy Unrestricted
powershell.exe .\add-environment-variables.ps1 >> ..\startup-tasks-log.txt 2>>..\startup-tasks-error-log.txt

ECHO "Added extra environment variables." >> ..\startup-tasks-log.txt

Nothing fancy, just as promised we’re launching PowerShell. But to ensure that we have al possible options in PowerShell, the execution policy is first set to Unrestricted. Next, add-environment-variables.ps1 is launched:

[Reflection.Assembly]::LoadWithPartialName("Microsoft.WindowsAzure.ServiceRuntime")

$rdRoleId = [Environment]::GetEnvironmentVariable("RdRoleId", "Machine")

[Environment]::SetEnvironmentVariable("RdRoleId", [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id, "Machine")
[Environment]::SetEnvironmentVariable("RoleName", [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Role.Name, "Machine")
[Environment]::SetEnvironmentVariable("RoleInstanceID", [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id, "Machine")
[Environment]::SetEnvironmentVariable("RoleDeploymentID", [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::DeploymentId, "Machine")


if ($rdRoleId -ne [Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::CurrentRoleInstance.Id) {
    Restart-Computer
}

[Environment]::SetEnvironmentVariable('Path', $env:RoleRoot + '\base\x86;' + [Environment]::GetEnvironmentVariable('Path', 'Machine'), 'Machine')

Wow! A lot of code? Yes. First of all, we’re loading the Microsoft.WindowsAzure.ServiceRuntime assembly. Next, we query the current environment variables for a variable named RdRoleId and copy it in a variable named $rdRoleId. Next, we set all environment variables (RdRoleId, RoleName, RoleInstanceID, RoleDeploymentID) to their actual values. Just like that. Isn’t PowerShell a cool thing?

After all this, the $rdRoleId variable is compared with the current RdRoleId environment variable. Are they the same? Good! Are they different? Reboot the instance. Rebooting the instance is the only easiest way for IIS and PHP to pick these new values up.

Phase 4: Automating packaging

One thing left to do: we do have a folder structure now, but I don’t see any .cspkg file around for deployment…  Let’s fix that. by creating a good old batch file that does the packaging for us. Note that this is *not* a necessary part, but it will ease your life. Here’s the script:

@echo off

IF "%1"=="" GOTO ParamMissing

echo Copying default package components to temporary location...
mkdir deploy-temp
xcopy /s /e /h deploy deploy-temp

echo Copying %1 to temporary location...
xcopy /s /e /h %1 deploy-temp\PhpOnAzure.Web

echo Packaging application...
"c:\Program Files\Windows Azure SDK\v1.4\bin\cspack.exe" deploy-temp\ServiceDefinition.csdef /role:PhpOnAzure.Web;deploy-temp\PhpOnAzure.Web /out:PhpOnAzure.cspkg
copy deploy-temp\ServiceConfiguration.cscfg

echo Cleaning up...
rmdir /S /Q deploy-temp

GOTO End

:ParamMissing
echo Parameter missing: please specify the path to the application to deploy.

:End

You can invoke it from a command line:

package c:\patch-to-my\app

This will copy your application to a temporary location, merge in the template we created in the previous steps and create a .cspkg file by calling the cspack.exe from the Windows Azure SDK, and a ServiceConfiguration.cscfg file containing your configuration.

Phase 5: Package hello world!

Let’s create an application that needs massive scale. Here’s the source code for the index.php file which will handle all requests. Put it in your c:\temp or wherever you want.

<?php
echo “Hello, World!”;

Next, call the package.bat created previously:

package c:\patch-to-my\app

There you go: PhpOnAzure.cspkg and ServiceConfiguraton.cscfg at your service. Upload, deploy and enjoy. Once the VM is booted in Windows Azure, all environment variables will be set and PHP will be automatically installed. Feel free to play around with the template I created (lightweight-php-deployment-azure.zip (854.44 kb)), as you can also install, for example, the Wincache extension or SQL Server Driver for PHP from the WebPI command-line tools. Or include your own PHP distro. Or achieve world domination by setting the instance count to a very high number (of course, this requires you to call Microsoft if you want to go beyond 20 instances, just to see if you’re worthy for world domination).

Conclusion

Next to the officially supported packaging tools, there’s also the good old craftsmen’s hand-made deployment. And if you automate some parts, it’s extremely easy to package your application in a very lightweight fashion. Enjoy!

Here’s the download: lightweight-php-deployment-azure.zip (854.44 kb)

Windows Azure and scaling: how? (PHP)

One of the key ideas behind cloud computing is the concept of scaling.Talking to customers and cloud enthusiasts, many people seem to be unaware about the fact that there is great opportunity in scaling, even for small applications. In this blog post series, I will talk about the following:

Creating and uploading a management certificate

In order to keep things DRY (Don’t Repeat Yourself), I’ll just link you to the previous post (Windows Azure and scaling: how? (.NET)) for this one.

For PHP however, you’ll be needing a .pem certificate. Again, for the lazy, here’s mine (management.pfx (4.05 kb), management.cer (1.18 kb) and management.pem (5.11 kb)). If you want to create one yourself, check this site where you can convert and generate certificates.

Building a small command-line scaling tool (in PHP)

In order to be able to scale automatically, let’s build a small command-line tool in PHP. The idea is that you will be able to run the following command on a console to scale to 4 instances:

1 php autoscale.php "management.cer" "subscription-id0" "service-name" "role-name" "production" 4

Or down to 2 instances:

1 php autoscale.php "management.cer" "subscription-id" "service-name" "role-name" "production" 2

Will this work on Linux? Yup! Will this work on Windows? Yup! Now let’s get started.

The Windows Azure SDK for PHP will be quite handy to do this kind of thing. Download the latest source code (as the Microsoft_WindowsAzure_Management_Client class we’ll be using is not released officially yet).

Our script starts like this:

1 <?php 2 // Set include path 3 $path = array('./library/', get_include_path()); 4 set_include_path(implode(PATH_SEPARATOR, $path)); 5 6 // Microsoft_WindowsAzure_Management_Client 7 require_once 'Microsoft/WindowsAzure/Management/Client.php';

This is just making sure all necessary libraries have been loaded. next, call out to the Microsoft_WindowsAzure_Management_Client class’ setInstanceCountBySlot() method to set the instance count to the requested number. Easy! And in fact even easier than Microsoft's .NET version of this.

1 // Do the magic 2 $managementClient = new Microsoft_WindowsAzure_Management_Client($subscriptionId, $certificateFile, ''); 3 4 echo "Uploading new configuration...\r\n"; 5 6 $managementClient->setInstanceCountBySlot($serviceName, $slot, $roleName, $instanceCount); 7 8 echo "Finished.\r\n";

Here’s the full script:

1 <?php 2 // Set include path 3 $path = array('./library/', get_include_path()); 4 set_include_path(implode(PATH_SEPARATOR, $path)); 5 6 // Microsoft_WindowsAzure_Management_Client 7 require_once 'Microsoft/WindowsAzure/Management/Client.php'; 8 9 // Some commercial info :-) 10 echo "AutoScale - (c) 2011 Maarten Balliauw\r\n"; 11 echo "\r\n"; 12 13 // Quick-and-dirty argument check 14 if (count($argv) != 7) 15 { 16 echo "Usage:\r\n"; 17 echo " AutoScale <certificatefile> <subscriptionid> <servicename> <rolename> <slot> <instancecount>\r\n"; 18 echo "\r\n"; 19 echo "Example:\r\n"; 20 echo " AutoScale mycert.pem 39f53bb4-752f-4b2c-a873-5ed94df029e2 bing Bing.Web production 20\r\n"; 21 exit; 22 } 23 24 // Save arguments to variables 25 $certificateFile = $argv[1]; 26 $subscriptionId = $argv[2]; 27 $serviceName = $argv[3]; 28 $roleName = $argv[4]; 29 $slot = $argv[5]; 30 $instanceCount = $argv[6]; 31 32 // Do the magic 33 $managementClient = new Microsoft_WindowsAzure_Management_Client($subscriptionId, $certificateFile, ''); 34 35 echo "Uploading new configuration...\r\n"; 36 37 $managementClient->setInstanceCountBySlot($serviceName, $slot, $roleName, $instanceCount); 38 39 echo "Finished.\r\n";

Now schedule or cron this (when needed) and enjoy the benefits of scaling your Windows Azure service.

So you’re lazy? Here’s my sample project (AutoScale-PHP.zip (181.67 kb)) and the certificates used (management.pfx (4.05 kb), management.cer (1.18 kb) and management.pem (5.11 kb)).

Windows Azure and scaling: how? (.NET)

One of the key ideas behind cloud computing is the concept of scaling.Talking to customers and cloud enthusiasts, many people seem to be unaware about the fact that there is great opportunity in scaling, even for small applications. In this blog post series, I will talk about the following:

Creating and uploading a management certificate

In order to be able to programmatically (and thus possibly automated) scale your Windows Azure service, one prerequisite exists: a management certificate should be created and uploaded to Windows Azure through the management portal at http://windows.azure.com. Creating a certificate is easy: follow the instructions listed on MSDN. It’s as easy as opening a Visual Studio command prompt and issuing the following command:

1 makecert -sky exchange -r -n "CN=<CertificateName>" -pe -a sha1 -len 2048 -ss My "<CertificateName>.cer"

Too anxious to try this out? Download my certificate files (management.pfx (4.05 kb) and management.cer (1.18 kb)) and feel free to use it (password: phpazure). Beware that it’s not safe to use in production as I just shared this with the world (and you may be sharing your Windows Azure subscription with the world :-)).

Uploading the certificate through the management portal can be done under Hosted Services > Management Certificates.

Management Certificate Windows Azure

Building a small command-line scaling tool

In order to be able to scale automatically, let’s build a small command-line tool. The idea is that you will be able to run the following command on a console to scale to 4 instances:

1 AutoScale.exe "management.cer" "subscription-id0" "service-name" "role-name" "production" 4

Or down to 2 instances:.

1 AutoScale.exe "management.cer" "subscription-id0" "service-name" "role-name" "production" 2

Now let’s get started. First of all, we’ll be needing the Windows Azure service management client API SDK. Since there is no official SDK, you can download a sample at http://archive.msdn.microsoft.com/azurecmdlets. Open the solution, compile it and head for the /bin folder: we’re interested in Microsoft.Samples.WindowsAzure.ServiceManagement.dll.

Next, create a new Console Application in Visual Studio and add a reference to the above assembly. The code for Program.cs will start with the following:

1 class Program 2 { 3 private const string ServiceEndpoint = "https://management.core.windows.net"; 4 5 private static Binding WebHttpBinding() 6 { 7 var binding = new WebHttpBinding(WebHttpSecurityMode.Transport); 8 binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; 9 binding.ReaderQuotas.MaxStringContentLength = 67108864; 10 11 return binding; 12 } 13 14 static void Main(string[] args) 15 { 16 } 17 }

This constant and WebHttpBinding() method will be used by the Service Management client to connect to your Windows Azure subscription’s management API endpoint. The WebHttpBinding() creates a new WCF binding that is configured to use a certificate as the client credential. Just the way Windows Azure likes it.

I’ll skip the command-line parameter parsing. Next interesting thing is the location where a new management client is created:

1 var managementClient = Microsoft.Samples.WindowsAzure.ServiceManagement.ServiceManagementHelper.CreateServiceManagementChannel( 2 WebHttpBinding(), new Uri(ServiceEndpoint), new X509Certificate2(certificateFile));

Afterwards, the deployment details are retrieved. The deployment’s configuration is in there (base64-encoded), so the only thing to do is read that into an XDocument, update the number of instances and store it back:

1 var deployment = managementClient.GetDeploymentBySlot(subscriptionId, serviceName, slot); 2 string configurationXml = ServiceManagementHelper.DecodeFromBase64String(deployment.Configuration); 3 4 var serviceConfiguration = XDocument.Parse(configurationXml); 5 6 serviceConfiguration 7 .Descendants() 8 .Single(d => d.Name.LocalName == "Role" && d.Attributes().Single(a => a.Name.LocalName == "name").Value == roleName) 9 .Elements() 10 .Single(e => e.Name.LocalName == "Instances") 11 .Attributes() 12 .Single(a => a.Name.LocalName == "count").Value = instanceCount; 13 14 var changeConfigurationInput = new ChangeConfigurationInput(); 15 changeConfigurationInput.Configuration = ServiceManagementHelper.EncodeToBase64String(serviceConfiguration.ToString(SaveOptions.DisableFormatting)); 16 17 managementClient.ChangeConfigurationBySlot(subscriptionId, serviceName, slot, changeConfigurationInput);

Here’s the complete Program.cs code:

1 using System; 2 using System.Linq; 3 using System.Security.Cryptography.X509Certificates; 4 using System.ServiceModel; 5 using System.ServiceModel.Channels; 6 using System.Xml.Linq; 7 using Microsoft.Samples.WindowsAzure.ServiceManagement; 8 9 namespace AutoScale 10 { 11 class Program 12 { 13 private const string ServiceEndpoint = "https://management.core.windows.net"; 14 15 private static Binding WebHttpBinding() 16 { 17 var binding = new WebHttpBinding(WebHttpSecurityMode.Transport); 18 binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate; 19 binding.ReaderQuotas.MaxStringContentLength = 67108864; 20 21 return binding; 22 } 23 24 static void Main(string[] args) 25 { 26 // Some commercial info :-) 27 Console.WriteLine("AutoScale - (c) 2011 Maarten Balliauw"); 28 Console.WriteLine(""); 29 30 // Quick-and-dirty argument check 31 if (args.Length != 6) 32 { 33 Console.WriteLine("Usage:"); 34 Console.WriteLine(" AutoScale.exe <certificatefile> <subscriptionid> <servicename> <rolename> <slot> <instancecount>"); 35 Console.WriteLine(""); 36 Console.WriteLine("Example:"); 37 Console.WriteLine(" AutoScale.exe mycert.cer 39f53bb4-752f-4b2c-a873-5ed94df029e2 bing Bing.Web production 20"); 38 return; 39 } 40 41 // Save arguments to variables 42 var certificateFile = args[0]; 43 var subscriptionId = args[1]; 44 var serviceName = args[2]; 45 var roleName = args[3]; 46 var slot = args[4]; 47 var instanceCount = args[5]; 48 49 // Do the magic 50 var managementClient = Microsoft.Samples.WindowsAzure.ServiceManagement.ServiceManagementHelper.CreateServiceManagementChannel( 51 WebHttpBinding(), new Uri(ServiceEndpoint), new X509Certificate2(certificateFile)); 52 53 Console.WriteLine("Retrieving current configuration..."); 54 55 var deployment = managementClient.GetDeploymentBySlot(subscriptionId, serviceName, slot); 56 string configurationXml = ServiceManagementHelper.DecodeFromBase64String(deployment.Configuration); 57 58 Console.WriteLine("Updating configuration value..."); 59 60 var serviceConfiguration = XDocument.Parse(configurationXml); 61 62 serviceConfiguration 63 .Descendants() 64 .Single(d => d.Name.LocalName == "Role" && d.Attributes().Single(a => a.Name.LocalName == "name").Value == roleName) 65 .Elements() 66 .Single(e => e.Name.LocalName == "Instances") 67 .Attributes() 68 .Single(a => a.Name.LocalName == "count").Value = instanceCount; 69 70 var changeConfigurationInput = new ChangeConfigurationInput(); 71 changeConfigurationInput.Configuration = ServiceManagementHelper.EncodeToBase64String(serviceConfiguration.ToString(SaveOptions.DisableFormatting)); 72 73 Console.WriteLine("Uploading new configuration..."); 74 75 managementClient.ChangeConfigurationBySlot(subscriptionId, serviceName, slot, changeConfigurationInput); 76 77 Console.WriteLine("Finished."); 78 } 79 } 80 }

Now schedule this (when needed) and enjoy the benefits of scaling your Windows Azure service.

So you’re lazy? Here’s my sample project (AutoScale.zip (26.31 kb)) and the certificates used (management.pfx (4.05 kb) and management.cer (1.18 kb)).

Note: I use the .cer file here because I generated it on my machine. If you are using a certificate created on another machine, a .pfx file and it's key should be used.

Windows Azure CDN updates

The Windows Azure team has just put out the new Windows Azure SDK 1.4 for download. Next to that, I noticed some interesting new capabilities for the CDN (Content Delivery Network):

  • Windows Azure CDN for Hosted Services
    Developers can use the Windows Azure Web and VM roles as “origin” for objects to be delivered at scale via the Windows Azure Content Delivery Network. Static content in your website can be automatically edge-cached at locations throughout the United States, Europe, Asia, Australia and South America to provide maximum bandwidth and lower latency delivery of website content to users.
  • Serve secure content from the Windows Azure CDN
    A new checkbox option in the Windows Azure management portal to enable delivery of secure content via HTTPS through any existing Windows Azure CDN account.

That first one looks very interesting: before today, if you wanted to use the CDN feature, you’d have to upload all static content that should be served by the CDN to your bob storage account. Today, you can just use any hosted service as your CDN “source data” provider. This means you can deploy your application on Windows Azure and have its static content (or cachable dynamic content) cached in the CDN and delivered from edge locations all over the world.

Using the Windows Azure CDN with a hosted service 

As with blob storage based CDN, the management portal will give you a domain name in the format http://<identifier>.vo.msecnd.net/. This is the CDN endpoint that will serve content you specify for caching on the CDN. Of course, a prettier domain name can be linked to this URL as well. The source for this data willl come from your hosted service's subfolder "cdn", e.g. http://maarten.cloudapp.net/cdn. This means that all content under that folder will be cached on the CDN. For example, say you have a URL http://maarten.cloudapp.net/cdn/rss.ashx. This will be cached on the CDN at http://<identifier>.vo.msecnd.net/rss.ashx. It's even possible to cache by query string, e.g. http://<identifier>.vo.msecnd.net/rss.ashx?category=Windows-Azure.

One closing hint here: make sure to specify correct cache control headers for content. This will greatly improve your end user's CDN experience and reduce bandwidth costs between your source (blob or hosted service) and the CDN in many cases.

And one closing question for the Windows Azure team: it would be great if I could use my current blog as the CDN source. It's not on Windows Azure yet I would want to use the CDN with my current host's data. This feature would also fit into the "cloud is not all or nothing" philosophy. Vote for this here :-)

Put your cloud on a diet (or: Windows Azure and scaling: why?)

Windows Azure scalingOne of the key ideas behind cloud computing is the concept of scaling.Talking to customers and cloud enthusiasts, many people seem to be unaware about the fact that there is great opportunity in scaling, even for small applications. In this blog post series, I will talk about the following:

Windows Azure and scaling: why?

Both for small and large project, scaling your application’s capacity to meet the actual demand can be valuable. Imagine a local web application that is being used mostly during office hours, with peak demand from 6 PM to 8 PM. It consists of 4 web role instances running all day, which is enough to cope with peaks. Also, the number can be increased over time to meet actual demand of the web application.

Let’s do a cost breakdown of that… In short, one small instance on Windows Azure will cost $ 0.12 per hour per instance, totaling $ 11.52 per day for this setup. If you do this estimation for a month, costs will be somewhere around $ 345.14 for the compute demand of this application, not counting storage and bandwidth.

Flashback one paragraph: peak load is during office hours and from 6 PM to 8 PM. Interesting, as this may mean the application can be running on less instances for the hours off-peak. Even more interesting: there are no office hours in the weekend (unless, uhmm, Bill Lumbergh needs you to come and work). Here’s a closer estimate of the required number of instances, per hour of day:

Windows Azure cost breakdown

Interesting! If these values are extrapolated to a month, costs will be somewhere around $ 219.31 for the compute demand of this application, not counting storage and bandwidth. That’s more than a $ 100 difference with the “always 4 instances” situation. Or over $ 1200 yearly. Imagine having a really big project and doing this: that’s a lot of beer difference :-)

Of course, this is a rough estimation, but it clearly shows there is value in scaling up and down at the right moments. The example I gave is based on a local application with clear demand differences during each day and could be scaled based on the time of day. And that’s what I will be demonstrating in the next 2 blog posts of this series: how to scale up and down automatically using the current tooling available for Windows Azure. Stay tuned!

PS: The Excel sheet I used to create the breakdown can be found here: Scaling.xlsx (11.80 kb)

Authenticate Orchard users with AppFabric Access Control Service

From the initial release of Orchard, the new .NET CMS, I have been wondering how difficult (or easy) it would be to integrate external (“federated”) authentication like Windows Azure AppFabric Access Control Service with it. After a few attempts, I managed to wrap-up a module for Orchard which does that: Authentication.Federated.

After installing, configuring and enabling this module, Orchard’s logon page is replaced with any SAML 2.0 STS that you configure. To give you a quick idea of what this looks like, here are a few screenshots:

Orchard Log On link is being overriddenOrchard authentication via AppFabricOrchard authenticated via SAML - Username is from the username claim

As you can see from the sequence above, Authentication.Federated does the following:

  • Override the default logon link
  • Redirect to the configured STS issuer URL
  • Use claims like username or nameidentifier to register the external user with Orchard. Optionally, it is also possible to configure roles through claims.

Just as a reference, I’ll show you how to configure the module.

Configuring Authentication.Federated – Windows Azure AppFabric side

In my tests, I’ve been using the AppFabric LABS release, over at https://portal.appfabriclabs.com. From there, create a new namespace and configure Access Control Service with the following settings:

Identity Providers

  • Pick the ones you want… I chose Windows Live ID and Google

Relying Party Applications

Add your application here, using the following settings:

  • Name: pick one :-)
  • Realm: The http(s) root URL for your site. When using a local Orchard CMS installation on localhost, enter a non-localhost URL here, e.g. https://www.examle.org
  • Return URL: The root URL of your site. I chose http://localhost:12758/ here to test my local Orchard CMS installation
  • Error URL: anything you want
  • Token format: SAML 2.0
  • Token encryption: none
  • Token lifetime: anything you want
  • Identity providers: the ones you want
  • Rule groups: Create new rule group
  • Token signing certificate: create a Service Namespace token and upload a certificate for it. This can be self-signed. Ensure you know the certificate thumbprint as we will need this later on.

Edit Rule Group

Edit the newly created rule group. Click “generate” to generate some default rules for the identity providers chosen, so that nameidentifier and email claims are passed to Orchard CMS. Also, if you want to be the site administrator later on, ensure you issue a roles claim for your Google/Windows Live ID, like so:

Add a role claim for your administrator

Configuring Authentication.Federated – Orchard side

In Orchard, download Authentication.Federated from the modules gallery and enable it. After that, you’ll find the configuration settings under the general “Settings” menu item in the Orchard dashboard:

Authentication.Federated configuration

These settings speak for themselves mostly, but I want to give you some pointers:

  • Enable federated authentication? – Enables the module. Ensure you’ve first tested the configuration before enabling it. If you don’t, you may lose access to your Orchard installation unless you do some database fiddling…
  • Translate claims to Orchard user properties? – Will use claims values to enrich user data.
  • Translate claims to Orchard roles? – Will assign Orchard roles based on the Roles claim
  • Prefix for federated usernames (e.g. "federated_") – Just a prefix for federated users.
  • STS issuer URL – The STS issuer URL, most likely the root for your STS, e.g. .accesscontrol.appfabriclabs.com">https://<account>.accesscontrol.appfabriclabs.com
  • STS login page URL – The STS’ login page, e.g. .accesscontrol.appfabriclabs.com:443/v2/wsfederation">https://<account>.accesscontrol.appfabriclabs.com:443/v2/wsfederation
  • Realm – The realm configured in the Windows Azure AppFabric Access Control Service settings
  • Return URL base – The root URL for your website
  • Audience URL – Best to set this identical to the realm URL
  • X509 certificate thumbprint (used for issuer URL token signing) – The token signing certificate thumbprint

Thank you for getting me in Vegas!

I wish to thank everyone who has been voring for getting me in Vegas, speaking at MIX11. Without having expectations, I was really really surprised (and happy!) my session got selected. Thanks a bunch!

MIX11_BB_I'mSpeakingAt_2

Oh and thanks, RealDolmen, for supporting me in doing things like this!

MvcSiteMapProvider 3.0.0 released

Just a quick note to tell that MvcSiteMapProvider 3.0.0 has been released and is available on CodePlex and NuGet. This version is targeted at ASP.NET MVC 3. If you are still using ASP.NET MVC 2, no worries: version 2.3.1 contains the exact same functionality but is targeted at ASP.NET MVC 2.

The changelog:

Enjoy!

ASP.NET MVC and the Managed Extensibility Framewok on NuGet

imageIf you search on my blog, there’s a bunch of posts where I talk about ASP.NET MVC and MEF. And what’s cool: these posts are the ones that are actually being read quite often. I’m not sure about which bloggers actually update their posts like if it was software, but I don’t. Old posts are outdated, that’s the convention when coming to my blog. However I recently received a on of questions if I could do something with ASP.NET MVC 3 and MEF. I did, and I took things seriously.

I’m not sure if you know MefContrib. MefContrib is a community-developed library of extensions to the Managed Extensibility Framework (MEF). I decided to wear my bad-ass shoes and finally got around installing a Windows-friendly Git client and decided to just contribute an ASP.NET MVC + MEF component to MefContrib. And while I was at it, I created some NuGet packages for all MefContrib components.

Let’s see how easy it is to use ASP.NET MVC and MEF…

Here’s the sample code I used: MefMvc.zip (698.58 kb)

Obtaining MefContrib.MVC3 in an ASP.NET MVC application

Here’s the short version of this blog post section for the insiders: Install-Package MefContrib.MVC3

Assuming you have already heard something about NuGet, let’s get straight to business. Right-click your ASP.NET MVC project in Visual Studio and select “Add Library Package Reference…”. Search for “MefContrib.MVC3”. Once found, click the “Install” button.

This action will download and reference the new MefContrib.Web.Mvc assembly I contributed as well as the MefContrib package.

How to get started?

You may notice a new file “AppStart_MefContribMVC3.cs” being added to your project. This one is executed at application start and wires all the MEF-specific components into ASP.NET MVC 3. Need something else than our defaults? Go ahead and customize this file. Are you happy with this code block? Continue reading…

You may know that MEF is cool as ICE and thus works with Import, Compose and Export. This means that you can now start composing your application using [Import] and [Export] attributes, MefContrib will do the rest. In earlier posts I did, this also meant that you should decorate your controllers with an [Export] attribute. Having used this approach on many projects, most developers simply forget to do this at the controller model. Therefore, MefContrib.Web.Mvc  uses the ConventionCatalog from MefContrib to automatically export every controller it can find. Easy!

To prove it works, open your FormsAuthenticationService class and add an ExportAttribute to it. Like so:

1 [Export(typeof(IFormsAuthenticationService))] 2 public class FormsAuthenticationService : IFormsAuthenticationService 3 { 4 // ... 5 }

Do the same for the AccountMembershipService class:

1 [Export(typeof(IMembershipService))] 2 public class AccountMembershipService : IMembershipService 3 { 4 // ... 5 }

Now open up the AccountController and lose the Initialize method. Yes, just delete it! We’ll tell MEF to resolve the IFormsAuthenticationService and IMembershipService. You can even choose how you do it. Option one is to add properties for both and add an ImportAttribute there:

1 public class AccountController : Controller 2 { 3 [Import] 4 public IFormsAuthenticationService FormsService { get; set; } 5 6 [Import] 7 public IMembershipService MembershipService { get; set; } 8 9 // ... 10 }

The other option is to use an ImportingConstructor:

1 public class AccountController : Controller 2 { 3 public IFormsAuthenticationService FormsService { get; set; } 4 public IMembershipService MembershipService { get; set; } 5 6 [ImportingConstructor] 7 public AccountController(IFormsAuthenticationService formsService, IMembershipService membershipService) 8 { 9 FormsService = formsService; 10 MembershipService = membershipService; 11 } 12 }

Now run your application, visit the AccountController and behold: dependencies have been automatically resolved.

Conclusion

There’s two conclusions to make: MEF and ASP.NET MVC3 are now easier than ever and available through NuGet. Second: MefContrib is now also available on NuGet, featuring nifty additions like the ConventionCatalog and AOP-style interception.

Enjoy! Here’s the sample code I used: MefMvc.zip (698.58 kb)

Need domain registration?

Viva, Las Vegas!

Vote your MIX sessionI have asked it last year, and I’ll ask it again. One of my session proposals made it to the “short”list for MIX11. One thing left though: votes are the only currency to get my session proposal in Vegas.

Here’s the session abstract:

Fun with ASP.NET MVC 3 and MEF

So you have a team of developers? And a nice architecture to build on? How about making that architecture easy for everyone and getting developers up to speed quickly? Learn all about integrating the managed extensibility framework and ASP.NET MVC for creating loosely coupled, easy to use architectures that anyone can grasp.

If you think this session deserves a place in Vegas, please cast your vote right here. And while you are at it, feel free to vote for both of my direct colleagues Kevin Dockx and Sandrino Di Mattia as well.

PS: No, I will not steal Mike Tyson’s tiger.