Archive for Windows Azure
A friend of mine posted to Twitter a bit ago that he was having trouble dealing with HttpCompression on Windows Azure. Specifically, only certain default MimeTypes were being compressed (like ASPX and CSS), while other important ones like JSON and SOAP were not.
During another Azure project, I also ran into an issue where logins stopped working after upgrading to
Azure OS 2.X Azure SDK 1.3. It turns out that there is a bug in that release that doesn’t allow configuration inheritance for the MachineKey, and the workaround was to manipulate the server configuration in the RoleEntryPoint.
Since I’m already having to manipulate the server config to synchronize the MachineKey settings, I thought I’d whip up some code real quick to solve this problem during the same process, using the httpConpression topic on IIS.net as a guide.
If you don’t already have a RoleEntryPoint in your app… well, you should. Copy the code below into a new class file in your main application, and add a reference to Microsoft.Web.Administration.dll, as specified here. You’ll also notice Gibraltar-specific code peppered throughout… this is all that you need to get Gibraltar working on Windows Azure (as long as you’re also using the tip from my previous post as well).
(The code is long, and it’s in VB… because that’s the language this particular app was in. If you need it converted to C#, you can do so here.
UPDATE: My colleage Kendall pointed out that the role event handlers should be declared at the very beginning, and that, even though the RoleInstance’s OnStart event is called on a separate thread from the main app, it should still run the WarmUp loop on a separate thread, so that the function can return MyBase.OnStart() and exit properly. Good call.
Imports System.Linq Imports Microsoft.WindowsAzure.Diagnostics Imports Microsoft.WindowsAzure.ServiceRuntime Imports Microsoft.Web.Administration Imports System.Threading Namespace Fon.Apps Public Class WebRole Inherits RoleEntryPoint Public Overrides Function OnStart() As Boolean ' For information on handling configuration changes ' see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357. AddHandler RoleEnvironment.Changing, AddressOf RoleEnvironment_Changing AddHandler RoleEnvironment.Stopping, AddressOf RoleEnvironment_Stopping Gibraltar.Agent.Log.SendSessionsOnExit = True Using server As New ServerManager() 'Cycle through the sites and set the MachineKey for each one. For Each site In server.Sites Dim siteConfig = site.GetWebConfiguration() 'Get the appSettings section Dim appSettings = siteConfig.GetSection("appSettings").GetCollection().ToDictionary(Function(e) DirectCast(e("key"), String), Function(e) DirectCast(e("value"), String)) 'Reconfigure the machine key Dim machineKeySection = siteConfig.GetSection("system.web/machineKey") machineKeySection.SetAttributeValue("validationKey", appSettings("validationKey")) machineKeySection.SetAttributeValue("validation", appSettings("validation")) machineKeySection.SetAttributeValue("decryptionKey", appSettings("decryptionKey")) machineKeySection.SetAttributeValue("decryption", appSettings("decryption")) Next 'Turn on compression for JSON and SOAP. Dim config As Configuration = server.GetApplicationHostConfiguration() Dim httpCompressionSection As ConfigurationSection = config.GetSection("system.webServer/httpCompression") Dim dynamicTypesCollection As ConfigurationElementCollection = httpCompressionSection.GetCollection("dynamicTypes") Dim e1 As ConfigurationElement = dynamicTypesCollection.CreateElement("add") e1("mimeType") = "application/json" e1("enabled") = True dynamicTypesCollection.AddAt(0, e1) Dim e2 As ConfigurationElement = dynamicTypesCollection.CreateElement("add") e2("mimeType") = "application/json;charset=utf-8" e2("enabled") = True dynamicTypesCollection.AddAt(0, e2) Dim e3 As ConfigurationElement = dynamicTypesCollection.CreateElement("add") e3("mimeType") = "application/soap+xml" e3("enabled") = True dynamicTypesCollection.AddAt(0, e3) server.CommitChanges() End Using 'Poor man's Application Warm-up here Tasks.Task.Factory.StartNew(Sub() Try While (True) Trace.WriteLine("Warming up web site...") Dim webClient As New Net.WebClient() webClient.DownloadString("http://mysite.com/WarmUp.ashx?WarmUp=True") Thread.Sleep(TimeSpan.FromMinutes(9)) End While Catch ex As Exception Gibraltar.Agent.Log.RecordException(ex, "WindowsAzure.WebRole.Startup", True) End Try End Sub) Return MyBase.OnStart() End Function Private Sub RoleEnvironment_Stopping(sender As Object, e As RoleEnvironmentStoppingEventArgs) Gibraltar.Agent.Log.EndSession(Gibraltar.Agent.SessionStatus.Normal, "Azure's configuration settings have changed.") End Sub Private Sub RoleEnvironment_Changing(sender As Object, e As RoleEnvironmentChangingEventArgs) ' If a configuration setting is changing If e.Changes.Any(Function(change) TypeOf change Is RoleEnvironmentConfigurationSettingChange) Then ' Set e.Cancel to true to restart this role instance Gibraltar.Agent.Log.EndSession(Gibraltar.Agent.SessionStatus.Normal, "Azure's configuration settings have changed.") e.Cancel = True End If End Sub End Class End Namespace
You might have noticed the While loop that cycles every 9 minutes and makes a request to a specific website. Though the actual site details have been abstracted out, this is a trick that I use to keep my application “warmed up,” and is a variation on the technique used by Christian Weyer.
For the MachineKey part, you’ll also need to add the following entries to the appSettings section of each of the web.configs in your Role, being sure to replace your values where appropriate:
<add key="decryption" value="Auto" /> <add key="decryptionKey" value="YOURVALUEHERE" /> <add key="validation" value="SHA1" /> <add key="validationKey" value="YOURVALUEHERE" />
You’ll also notice that it’s also pretty easy to add additional MimeTypes to compress. Just continue to copy the pattern for any of the items you think are missing. Be sure not to add ones that don’t already exist, or you’ll likely crash your role.
Anyways, I I hope that helps some of you that are trying to resolve various Azure issues.