Thursday, April 08, 2010

GetSmarx C# vs. Ruby (and something about Shaving a Yak)

Steve Marx, of Windows Azure fame, recently posted “annoy.smarx.com: Letting the Internet Choose My Wallpaper”, on how he allows the Internet to choose his wallpaper using Windows Azure and Service Bus.  Somewhat cool use of the technology showcased in a very easy to follow manner. 

Of course, the little devil in me thought how easy it would be to write a snippet of code to create an Azure Worker role to randomly change his wallpaper – anything worth doing is worth automating, right? 

The requirements were pretty simple. 

  1. http GET http://annoysmarx.cloudapp.net/
  2. Parse the xhtml response (thanks, Steve!)
  3. Identify the wall paper links
  4. Randomly select a single link resource
  5. https GET of the resource (e.g. https://annoysmarx.servicebus.windows.net/AnnoySmarx/SetWallpaper?id=ac21c047-f437-4e01-a0d1-25ee47e128b3)

Then I realized I don’t have the money to shell out just to poke Steve Marx, whom I don’t know.  Then I thought, well, I *do* have VS2010 Ultimate RC1 running, including the Testers edition (which rocks, btw), so then I thought I’d just plopped the code into a virtual user (VU) and let it (or multiple VU’s!) run every hour. 

But, you see, I’ve been hearing so much about Ruby, and how what an awesome language it is.  I’ve even started noodling with it on the side (shhh….don’t tell C#).  I do kind of like Ruby, but it can be raw.  Kinda of like how I view Linux – on the surface it looks great, especially now, but it can get rough quick if your anything more than just a casual user.

Anywayz….I then got distracted with creating a snippet of Ruby code to do the same thing I did in C# just to see if life was better. 

So, just like your optometrist…which do you like better?

1)  GetSmarx.cs

or

2) GetSmarx.rb

Of course, the C# version took about as long as it took to type it.  The Ruby version took much longer as I had to consult the almighty Google for much of it.  Its times like these (Foo Fighters FTW!) that makes the heart all warm when you realize what a rich ecosystem Ruby has underneath it.

And that is how Steve Marx was saved from being sent into an epileptic coma by his constantly changing desktop background due to my being so worn out by Shaving a Yak tonight that I just plain lost interest.

Good night, Steve.  Thanks for the Azure content.  Keep it coming!

Organize XAML Namespace Declarations with XmlnsDefinitionAttribute

Microsoft does it and you can do it, too!

Whenever you need to use a control from an assembly you need to provide an xml namespace for it to avoid any collisions with existing types. By default, you need to specifically reference the namespace for each control you need access to in your XAML.

This might lead to declarations like this in your XAML:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:treeView="clr-namespace:MaryKay.SamPortal.Common.UI.TreeView.Views;assembly=MaryKay.SamPortal.Common.UI"
xmlns:infoBar="clr-namespace:MaryKay.SamPortal.Common.UI.InfoBar.Views;assembly=MaryKay.SamPortal.Common.UI"
</UserControl>


This can get ugly pretty fast if you have lots of controls in your XAML view!

However, notice how clean the Microsoft xml namespaces are? You get a lot of controls brought into scope by leveraging those simple namespaces. This is accomplished by using the assembly XmlnsDefinitionAttribute.

From MSDN


Specifies a mapping in an assembly between an XML namespace and a CLR namespace.


Which means it allows us to provide a facade, or an alias, for a namespace, or group of namespaces within an assembly. This makes it much easier to bring all the controls in a control library into scope.

For example, in the MaryKay.SamPortal.Common.UI library, all of the controls are surfaced through the namespace alias “urn:marykay-samportal-common-ui” using XmlnsDefinition in the assemblies AssemblyInfo.cs:

[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.InfoBar.Views")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.RoleGroupPicker.Views")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.BetterPopup")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.TextEditor")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.Converters")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.Documents")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.SplashScreen")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.TemplateSelector")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.ModalDialog")]
[assembly: XmlnsDefinition("urn:marykay-samportal-common-ui", "MaryKay.SamPortal.Common.UI.ConsultantSearch.Views")]

and so forth..

This cleans up our required XAML declarations to simply:

<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:commonUI="urn:marykay-samportal-common-ui">
<commonUI:InformationBar DataContext="{Binding InfoBar}"/>
</UserControl>

Which makes our XAML much cleaner and easier to work with. It even supports intellisense!