24 July 2009

Storing objects as compressed messages in the Windows Azure Queue

For my current private R&D project I wanted to store 'task set' objects (in code samples below as shown type "Request") on the Windows Azure Queue. To prevent serialization issues I opted for XML serialization, like this:
private void Enqueue(Request tr)
{
  var queueStorage = QueueStorage.Create(
  StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration());
  var queue = queueStorage.GetQueue("MyQueue");
  if (!queue.DoesQueueExist())
  {
    queue.CreateQueue();
  }

  var xmlSerializer = new XmlSerializer(tr.GetType());
  using (var stringWriter = new StringWriter())
  {
    xmlSerializer.Serialize(stringWriter, tr);
    queue.PutMessage(new Message(stringWriter.ToString()));
  }
}
I would let the worker role deserialize the Request object and then execute it. It annoyed me to no end to learn that the Azure Queue limits message sizes to 8192 bytes. I could have redesigned my task sets to smaller units, but that would hurt the efficiency of the process I had in mind. Based upon the StringZipExtensions class I blogged about that can serialize and deserialize any old object to and from compressed XML (which you can download here) I created the following extension methods, which enable you to store objects as a GZip compressed set of bytes on the Azure queue and retrieve them again:
using LocalJoost.Utilities.Compression;
using Microsoft.Samples.ServiceHosting.StorageClient;

namespace LocalJoost.Utilities.Azure
{
  public static class MessageQueueExtensions
  {
    /// <summary>
    /// Decompresses the specified queue message.
    /// </summary>
    /// <param name="message">The message.</param>
    /// <returns></returns>
    public static string Decompress(this Message message)
    {
      return message != null ?
       message.ContentAsBytes().DecompressToString() : null;
    }

    /// <summary>
    /// Decompresses the specified queue message.
    /// to an object
    /// </summary>
    /// <param name="message">The message.</param>
    /// <returns></returns>
    public static T Decompress <T>(this Message message) where T:class
    {
      return message != null ?
       message.ContentAsBytes().DecompressToObject<T>() : null;
    }
  }
}
Adhering to my first code sample, you can now simply put an object to the queue like this
private void Enqueue(Request tr)
{
  var queueStorage = QueueStorage.Create(
    StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration());
  var queue = queueStorage.GetQueue("MyQueue");
  if (!queue.DoesQueueExist())
  {
    queue.CreateQueue();
  }

  queue.PutCompressedObject(tr);
}
and let the worker role use the Decompress extension method on the Message itself:
var queueStorage =
  QueueStorage.Create(
  StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration());
var queue = queueStorage.GetQueue("MyQueue");
if (queue.DoesQueueExist())
{
  var message = queue.GetMessage(600);
  if (message != null)
  {
    var request = message.Decompress<Request>();
    request.Execute();
    queue.DeleteMessage(message);
  }
}
And there you go. It is as simple as that. Although the Window Azure Queue message queue size still is limited to 8192, the amount of data that fits in that space is increased dramatically.

18 July 2009

Calling a service relative to the Silverlight XAP (improved)

In my previous post I showed a way to call a service defined with a full path, as created by the designer, relative to that of the location of your XAP, by means of an extension to a user control. I developed that during a training and while blogging it I alreadly realized that there was room for improvement. And here it is:
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Windows;

namespace LocalJoost.Utilities.Silverlight
{
  public static class ServiceEndpointExtension
  {
    public static void MakeRelative(
      this ServiceEndpoint endpoint)
    {
      var clientbinLocation = 
        Application.Current.Host.Source.ToString().Substring(0,
        Application.Current.Host.Source.ToString().LastIndexOf("/"));
      var rootLocation = 
        clientbinLocation.Substring(0, 
        clientbinLocation.LastIndexOf("/"));
      endpoint.Address = new EndpointAddress(
        new Uri(string.Concat(rootLocation, 
          endpoint.Address.Uri.AbsolutePath)));
    }
  }
}
In stead of extending the user control I now extend the ServiceEndpoint. If you now want to call a service that is sitting in the root of your web application that is hosting you can call it like this:
var client = new CloudMapperDataServiceClient();
client.Endpoint.Address.MakeRelative();
Substitute "CloudMapperDataServiceClient" by your own client proxy class and you are go for launch (Sorry, currently listening to wechoosethemoon.org ;-)

15 July 2009

Calling a service relative to the Silverlight XAP

This post is deprecated and left here for link reference only. See this post or a better way to do this. A small tidbit that I developed when I was following a training by Dennis van der Stelt of Class-A. One of the assigments was to consume a service and display data. The lab contained a string with a hard coded path. I thought of the following, IMHO much cleaner solution. I also discovered that WCF services are defined in a ServiceReferences.ClientConfig that contains a full path to the service. That is not nice on deployment time. This may have been caused by the fact I hosted the Silverlight App in an Azure project, I am not sure yet. But anyhow, I made an extension method to the Silverlight System.Windows.Controls.Control like this
using System;
using System.ServiceModel;
using System.Windows;
using System.Windows.Controls;

namespace LocalJoost.Utilities.Silverlight
{
  public static class UserControlExtensions
  {
    public static EndpointAddress GetRelativeEndpointAdress(
      this UserControl control, string path)
    {
      var clientbinLocation = 
          Application.Current.Host.Source.ToString().Substring(0,
          Application.Current.Host.Source.ToString().LastIndexOf("/"));
      return new EndpointAddress(new Uri(string.Format("{0}/{1}",
        clientbinLocation.Substring(0,
        clientbinLocation.LastIndexOf("/")), path)));
    }
  }
}
If you now want to call a service that is sitting in the root of your web application that is hosting you can call it like this:
var client = new CloudMapperDataServiceClient();
client.Endpoint.Address = 
 this.GetRelativeEndpointAdress("CloudMapperDataService.svc");
Substitute "CloudMapperDataServiceClient" by your own client proxy class and "CloudMapperDataService.svc" by your own svc and you are ready to roll. Seeing this again while I blog it I think it might be even better to get the name of the svc from the original Endpoint.Address setting. Well, that's something for later

13 July 2009

Adding a Silverlight (3) gui to an existing Azure webrole

This is extremely easy. Steve Marx points out in a comment on this blog post:
To add a Silverlight project to a Web Role project, simply right-click your project file in the solution explorer and select "Properties". In the Project properties view, the bottom-most tab on the left is "Silverlight Applications" - select this, and there is an "Add..." button that allows you to add (and configure) a new or existing Silverlight app to your web role.
And that is really all there is to it. I've tried this with a Silverlight 3 project but since the comment is from december 2008 I have every reason to believe this works for Silverlight 2.0 projects as well. Not that I can think of any reason to stick with 2.0... but that's another story ;-)

07 July 2009

Using the "global" prefix to prevent namespace clashes

I was running into a snag into the situation in which the compiler was accidentally took my local namespace when I wanted it to use the root namespace of CSLA. I had defined a dll "LocalJoost.Utilities.Csla" with the following code:
using Csla;
using Csla.Validation;

namespace LocalJoost.Utilities.Csla
{
  public static class LocalJoostCommonRules
  {
    public static bool NotNull(object target, RuleArgs args)
    {
      args.Description = string.Format("{0} is required", 
        args.PropertyName);
      var value = global::Csla.Utilities.CallByName(
       target, args.PropertyName, CallType.Get);
      return value != null;

    }
  }
}
and although I had referenced the Csla.dll nicely, it did not compile. The compiler errorred out telling me that "The type or namespace name 'Utilities' does not exist in the namespace 'LocalJoost.Utilities.Csla' (are you missing an assembly reference?)" Well of course does the namespace "LocalJoost.Utilities.Csla.Utilities" not exist: I wanted it to use "Csla.Utilities". I had created myself a nice namespace clash. Or kludge, whatever you want to call this. In stead of searching from the root of the namespace, the compiler started to search relatively from my namespace. Turns out this is very easy to fix: there is a .NET directive "global" that is the .NET equivalent of starting an URL with a "/". I changed my code to
using Csla;
using Csla.Validation;

namespace LocalJoost.Utilities.Csla
{
  public static class LocalJoostCommonRules
  {
    public static bool NotNull(object target, RuleArgs args)
    {
      args.Description = string.Format("{0} is required", 
        args.PropertyName);
      var value = global::Csla.Utilities.CallByName(
       target, args.PropertyName, CallType.Get);
      return value != null;
    }
  }
}
and the compiler was happy again. And so was I, incidently.

01 July 2009

Using PresentationCore in Azure requires full trust

Sometimes the answer is staring you in the face... I was trying to load an image from an URL in code. Imagine the code for that being something like this
var blobURL = "http://www.somewhere.com/image.jpg";
var multiTileImage = new BitmapImage(); 
multiTileImage.BeginInit(); 
multiTileImage.UriSource = new Uri(blobURL);
multiTileImage.CacheOption = BitmapCacheOption.None;
multiTileImage.EndInit();
This fails with an security expection, you get something like "Request for the permission of type 'System.Security.Permissions.MediaPermission failed in System.Windows.Media.Imaging.BitmapImage.EndInit" Dennis van der Stelt suggested that this may have to do something with full trust. And indeed it does. In your service definition file by default is defined
<WebRole name="WebRole" enableNativeCodeExecution="false">
I noticed that, I just failed to see the connection between "enableNativeCodeExecution" and "full trust". In fact, I still fail to see that connection ;-) but you just need to set the value for enableNativeCodeExecution in the appropriate tag to "true" and then PresentationCore classes - with apparently are not thrustworthy - can be used from Web- or Worker roles.