Migrated to Azure Web Sites

I’ve been thinking about moving this blog over to Windows Azure for a while, but I’ve finally got around to it, and it has to be said the experience was pretty simple. Previously I’d experimented with Windows Azure Cloud Services, specifically packaging it up as a web role. However, this blog is powered by WordPress, which is PHP and MySql based, so this wasn’t the simplest process in the world, and left quite a lot to be desired when it came to enabling and using all the WordPress features, like being able to use plugins without having to repackage the web role. But then Windows Azure Web Sites comes along, and migrating was simple.

In case anyone else is looking to do the same, here’s the steps I followed:

  • Backed up all the files from my blog at my existing hosting provider (in this case copied everything locally via FTP)
  • Exported the MySql database at my existing hosting provider to a local SQL file using MySql Workbench (yes, I know I could do this with a command line, but I like GUIs!)
  • Logged into the Windows Azure Management Portal and created a new Windows Azure Web Site from the gallery, and selected WordPress as the template
  • I didn’t bother setting up WordPress as I was going to copy over everything
  • Connected to the new Windows Azure Web Site via FTP, and copied over all the files I backed up from my existing provider
  • At this point the site mostly worked as it was connecting back to my existing MySql database
  • Logged into the WordPress Dashboard to reconfigure the site URL to the Windows Azure Web Site URL
  • Connected to the new MySql database created by the Windows Azure Web Site WordPress template with MySql Workbench, and imported the export I took earlier
  • Opened up the wp-config.php file in the root of the web site, and reconfigured the MySql database connection information
  • All done!

Well, when I say all done, I mean that WordPress, with all my content and options, is running in Windows Azure. However, I also had to move all the DNS for phazed.com over too, and that’s where I tripped over a little. You can certainly do this with Windows Azure Web Sites, you just need to use a reserved instance, add a CNAME in your domain for the Windows Azure Web Site hostname, and then add a custom domain to your Windows Azure Web Site. This is all explained quite well here:

http://social.msdn.microsoft.com/Forums/en-US/windowsazurewebsitespreview/thread/2a22b012-dc80-4f7a-9500-2a5ff628b5c4

There’s a caveat however. At the moment you can only add custom domains using CNAMEs, which is practice means I can add www.phazed.com for phazed.azurewebsites.net, but not phazed.com (without the www). Apparently it’s coming, but this was a problem for this blog as all the permalinks used phazed.com, not www.phazed.com. I won’t bore you with the details of how, but I got around it by adding some redirection at my DNS hoster for phazed.com to www.phazed.com, and bulk editing the contents of the database export before importing back into the new MySql database.

Anyway, it’s all done, and I’m quite pleased that’s the blog is finally on Windows Azure. It’s even a little faster I think!

Current WordPress Plugins

Seeing as a certain member of the team expressed an interest (you know who you are @Plip!), I thought it worth sharing the current set of plugins I have installed on this WordPress blog. Yes, I know, I could be opening up this blog to all sorts of attacks, but I’d prefer to help others than get all paranoid about security. If I get attacked, I’m sure it’ll be the subject of a future blog post!

AddThis Social Bookmarking Widget

Help your visitor promote your site! The AddThis Social Bookmarking Widget allows any visitor to bookmark your site easily with many popular services. Sign up for an AddThis.com account to see how your visitors are sharing your content–which services they’re using for sharing, which content is shared the most, and more. It’s all free–even the pretty charts and graphs.

Version 2.2.1 | By The AddThis Team | Visit plugin site

Akismet

Used by millions, Akismet is quite possibly the best way in the world to protect your blog from comment and trackback spam. It keeps your site protected from spam even while you sleep. To get started: 1) Click the “Activate” link to the left of this description, 2) Sign up for an Akismet API key, and 3) Go to your Akismet configuration page, and save your API key.

Version 2.5.3 | By Automattic | Visit plugin site

FD Feedburner Plugin

Redirects all feeds to a Feedburner feed

Version 1.45 | By John Watson | Visit plugin site

Google Analyticator

Adds the necessary JavaScript code to enable Google’s Analytics. After enabling this plugin visit the settings page and enter your Google Analytics’ UID and enable logging.

Version 6.2 | By Ronald Heft | Visit plugin site

Google XML Sitemaps

This plugin will generate a special XML sitemap which will help search engines like Google, Yahoo, Bing and Ask.com to better index your blog.

Version 3.2.5 | By Arne Brachhold | Visit plugin site

SEO Ultimate

This all-in-one SEO plugin gives you control over title tags, noindex/nofollow, meta tags, rich snippets, slugs, canonical tags, autolinks, 404 errors, rich snippets, and more.

Version 6.9.4 | By SEO Design Solutions | Visit plugin site

Simple Lightbox

Customizable Lightbox for WordPress

Version 1.5.5.1 | By Archetyped | Visit plugin site

Smart 404

Rescue your viewers from site errors! When content cannot be found, Smart 404 will use the current URL to attempt to find matching content, and redirect to it automatically. Smart 404 also supplies template tags which provide a list of suggestions, for use on a 404.php template page if matching content can’t be immediately discovered.

Version 0.5 | By Michael Tyson | Visit plugin site

Spam Free WordPress

Comment spam blocking plugin that uses anonymous password authentication to achieve 100% automated spam blocking with zero false positives, plus a few more features.

Version 1.5.1 | By Todd Lahman, LLC | Visit plugin site

Twitter for WordPress

Displays your public Twitter messages for all to read. Based on Pownce for WordPress by Cavemonkey50.

Version 1.9.7 | By Ricardo González | Visit plugin site

W3 Total Cache

The highest rated and most complete WordPress performance plugin. Dramatically improve the speed and user experience of your site. Add browser, page, object and database caching as well as minify and content delivery network (CDN) to WordPress.

Version 0.9.2.4 | By Frederick Townes | Visit plugin site

WP SyntaxHighlighter

This plugin is code syntax highlighter based on SyntaxHighlighter ver. 3.0.83 and ver. 2.1.382. Supported languages: Bash, C++, CSS, Delphi, Java, JavaScript, Perl, PHP, Python, Ruby, SQL, VB, XML, XHTML and HTML etc.

Version 1.4.4 | By redcocker | Visit plugin site

Auto-generating XML serialization classes – NuGet Edition

A while back I posted about automatically generating the XML serialization classes from schemas referenced in BizTalk or other projects. This was a relatively simple T4 template that essentially does the same job as the XML Schema Definition tool (XSD.exe).

Since then I’ve also been really enjoying NuGet. If you’ve not heard about NuGet then I suggest heading over to the NuGet project on Codeplex, where there’s a good overview in the documentation.

Well, to cut a long story short, I’ve packaged up the T4 template into a NuGet package, XsdClassGen, and published it in the main NuGet feed. So now it’s really simple to add to your projects. Enjoy!

101 LINQ Samples

OK, I’ve just discovered this. If, like me, you’re always struggling to remember the name of that LINQ extension method, or precisely how it’s supposed to work, then this is really useful.

http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx

Every single LINQ extension method, categorized, and all on one page without all the method overload signatures that just end up confusing you. Then, once you’ve identified the one you need a single click will take you to a concise yet precise example of how to use it, and what result you can expect.

Simply brilliant! I’ve no idea who did this, but thank you.

Exposing Squeezebox Web UI on Windows Home Server

At home I use a number of Logitech Squeezebox Receivers and a Squeezebox Controller to listen to and distribute my digital music around the house. All the actual music is stored on my Windows Home Server, which also runs the Squeezebox Server software. The trouble is the web UI for the Squeezebox Server runs under its own web server, not integrated with the Home Server’s web UI. This means I have to use a nasty looking URL (like http://machinename:9000) to access the UI, which isn’t hugely memorable, and it’s also not easily available remotely from the internet. What I’d like to have is this UI available under the usual Home Server remote URL, something like http://yourname.homeserver.com/squeezebox/.

Enter ISAPI_Rewrite from HeliconTech. Essentially this is an IIS ISAPI filter that implements the same functionality that you get in Apache mod_rewrite to rewrite IIS request URLs. If I were running IIS7 or above I could use URLRewrite, but Home Server is IIS6 so I don’t have that option.

Once installed, all I needed to do was configure the URL rewriting rules. I’m not sure if this is the optimal set of rules, but this seems to work for me (just replace machinename for the local machine name of your Home Server):

# Squeezebox
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{REQUEST_URI} !/squeezebox/.*
RewriteCond %{HTTP_REFERER} .*/squeezebox/.*
RewriteRule (.*) /squeezebox$1 [R,I,O]
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{HTTP_REFERER} .*/squeezebox/.*
RewriteRule (.*) http://machinename:9000$1 [P,I,U]
RewriteRule /squeezebox(.+) http://machinename:9000$1 [P,I,U]

I hope other people will find this useful, and if anyone finds any problems with this or improvements then I’d be interested in hearing about them.

Auto-generating XML serialization classes from BizTalk schemas

UPDATE: (18th February 2011) I’ve now packaged this template as a NuGet package. Read more about it here.

UPDATE: (4th October 2010) A customer of mine has just pointed out that there was a bug in the template, so I’ve updated it. Thanks Sébastien for spotting this one! The bug was caused by the template generating partial serialization classes for all the root elements defined in each schema. However, if these root elements also included simple types, like enumerations, these aren’t generated as partial classes by the XML serializer, and so you get a compile error indicating two type definitions with the same name. The fix was to ensure that the template only generates partial serialization classes for root elements that are complex types.

When building BizTalk applications you often need to generate the XML serialization classes for your schemas. Sometimes this is a more efficient and simple way gain access to data and manipulate or construct complex messages than maps, distinguished fields, or XPath expressions. The normal way to achieve this is to run the XML Schema Definition tool (XSD.exe) on your schemas to generate the classes that represent them. However, this means leaving the comfort of the Visual Studio environment for the Command Prompt, and during the early phases of projects, when schemas are often in a state of flux, this becomes a right hassle. Believe me, the last thing you want to happen in a team of BizTalk developers is for the schemas and their serialization classes to get out of step!

I’ve been looking at different ways to solve this problem, and at first I started with MSBuild calling out to XSD.exe. This approach wasn’t very satisfactory as it was a bit clunky and required editing project files and the like. So I took a different tack and decided to use a T4 template.

If you haven’t come across T4 templates in Visual Studio then they’re probably it’s best kept secret. T4 actually stands for Text Template Transformation Toolkit, and it’s a very powerful code generation tool. I won’t spend time describing it in detail in this post as Scott Hanselman has a good introduction on his blog, and Oleg Synch has a great set of tutorial articles on it. Put simply, T4 lets me write some code that will generate some code for me, in this case the XML serialization classes for some schemas.

The first step was to work out how to do the same job as XSD.exe, but from code. Fortunately Mike Hadlow had been there before me. Next, I needed to put all this in a template, but I wanted to go a step further than just creating the XML serialization classes; I also wanted to generate serialize and deserialize methods for each of the root elements in each of the schemas. To do this I’d need to create multiple output files from T4, something it doesn’t do normally. Again, someone has been here before, this time Damien Guard with his excellent T4 Manager class. Now, armed with all this I could put the template together, and here it is:

<#@ template language="C#v3.5" hostSpecific="true" debug="false" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data.Linq" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.CodeDom" #>
<#@ import namespace="System.CodeDom.Compiler" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Xml.Serialization" #>
<#@ import namespace="System.Xml.Schema" #>
<#@ import namespace="Microsoft.CSharp" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<# var manager = Manager.Create(Host, GenerationEnvironment); #>
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:<#=Environment.Version.ToString()#>
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
//
// This source code was auto-generated by XmlSerializer.tt.
//
<#
	IServiceProvider hostServiceProvider = (IServiceProvider)Host;
	EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
	EnvDTE.ProjectItem templateProjectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
	EnvDTE.Project project = templateProjectItem.ContainingProject;
	XmlSchemas xsds = new XmlSchemas();
	foreach (EnvDTE.ProjectItem projectItem in GetAllItems(project.ProjectItems.Cast<EnvDTE.ProjectItem>()))
	{
		string path = projectItem.get_FileNames(0);
		string directory = Path.GetDirectoryName(path);
		if (path.EndsWith(".xsd"))
		{
			using (FileStream stream = File.OpenRead(path))
			{
				xsds.Add(XmlSchema.Read(stream, null));
			}
		}
	}
	xsds.Compile(null, true);
	foreach(XmlSchemaElement schemaElement in xsds
		.SelectMany(xsd => xsd.Elements.Values.Cast<XmlSchemaElement>())
		.Where(e => e.ElementSchemaType is XmlSchemaComplexType))
	{
		manager.StartNewFile(schemaElement.Name + ".Serialization.cs");
#>
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace <#= project.Properties.Item("DefaultNamespace").Value.ToString() #>
{
	public partial class <#= schemaElement.Name #>
	{
		public static <#= schemaElement.Name #> Deserialize(Stream stream)
		{
			var serializer = new XmlSerializer(typeof(<#= schemaElement.Name #>));
			return (<#= schemaElement.Name #>)serializer.Deserialize(stream);
		}
		public static <#= schemaElement.Name #> Deserialize(TextReader reader)
		{
			var serializer = new XmlSerializer(typeof(<#= schemaElement.Name #>));
			return (<#= schemaElement.Name #>)serializer.Deserialize(reader);
		}
		public static <#= schemaElement.Name #> Deserialize(XmlReader reader)
		{
			var serializer = new XmlSerializer(typeof(<#= schemaElement.Name #>));
			return (<#= schemaElement.Name #>)serializer.Deserialize(reader);
		}
		public void Serialize(Stream stream)
		{
			var serializer = new XmlSerializer(typeof(<#= schemaElement.Name #>));
			serializer.Serialize(stream, this);
		}
		public void Serialize(TextWriter writer)
		{
			var serializer = new XmlSerializer(typeof(<#= schemaElement.Name #>));
			serializer.Serialize(writer, this);
		}
		public void Serialize(XmlWriter writer)
		{
			var serializer = new XmlSerializer(typeof(<#= schemaElement.Name #>));
			serializer.Serialize(writer, this);
		}
	}
}
<#
		manager.EndBlock();
	}
	XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds);
	CodeNamespace codeNamespace = new CodeNamespace(project.Properties.Item("DefaultNamespace").Value.ToString());
	XmlCodeExporter codeExporter = new XmlCodeExporter(codeNamespace);
	List<XmlTypeMapping> maps = new List<XmlTypeMapping>();
	foreach (XmlSchema xsd in xsds)
	{
		foreach(XmlSchemaType schemaType in xsd.SchemaTypes.Values)
		{
			maps.Add(schemaImporter.ImportSchemaType(schemaType.QualifiedName));
		}
		foreach(XmlSchemaElement schemaElement in xsd.Elements.Values)
		{
			maps.Add(schemaImporter.ImportTypeMapping(schemaElement.QualifiedName));
		}
	}
	foreach(XmlTypeMapping map in maps)
	{
		codeExporter.ExportTypeMapping(map);
	}
	CodeGenerator.ValidateIdentifiers(codeNamespace);
	CSharpCodeProvider codeProvider = new CSharpCodeProvider();
	using(StringWriter writer = new StringWriter(GenerationEnvironment))
	{
		codeProvider.GenerateCodeFromNamespace(codeNamespace, writer, new CodeGeneratorOptions());
	}
	manager.Process(true);
#>
<#+
private IEnumerable<EnvDTE.ProjectItem> GetAllItems(IEnumerable<EnvDTE.ProjectItem> projectItems)
{
	return projectItems.Concat(projectItems.SelectMany(i => GetAllItems(i.ProjectItems.Cast<EnvDTE.ProjectItem>())));
}
// Manager class records the various blocks so it can split them up
// From http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited
class Manager {
	private class Block {
		public String Name;
		public int Start, Length;
	}
	private Block currentBlock;
	private List<Block> files = new List<Block>();
	private Block footer = new Block();
	private Block header = new Block();
	private ITextTemplatingEngineHost host;
	private StringBuilder template;
	protected List<String> generatedFileNames = new List<String>();
	public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
		return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
	}
	public void StartNewFile(String name) {
		if (name == null)
			throw new ArgumentNullException("name");
		CurrentBlock = new Block { Name = name };
	}
	public void StartFooter() {
		CurrentBlock = footer;
	}
	public void StartHeader() {
		CurrentBlock = header;
	}
	public void EndBlock() {
		if (CurrentBlock == null)
			return;
		CurrentBlock.Length = template.Length - CurrentBlock.Start;
		if (CurrentBlock != header && CurrentBlock != footer)
			files.Add(CurrentBlock);
		currentBlock = null;
	}
	public virtual void Process(bool split) {
		if (split) {
			EndBlock();
			String headerText = template.ToString(header.Start, header.Length);
			String footerText = template.ToString(footer.Start, footer.Length);
			String outputPath = Path.GetDirectoryName(host.TemplateFile);
			files.Reverse();
			foreach(Block block in files) {
				String fileName = Path.Combine(outputPath, block.Name);
				String content = headerText + template.ToString(block.Start, block.Length) + footerText;
				generatedFileNames.Add(fileName);
				CreateFile(fileName, content);
				template.Remove(block.Start, block.Length);
			}
		}
	}
	protected virtual void CreateFile(String fileName, String content) {
		if (IsFileContentDifferent(fileName, content))
			File.WriteAllText(fileName, content);
	}
	public virtual String GetCustomToolNamespace(String fileName) {
		return null;
	}
	public virtual String DefaultProjectNamespace {
		get { return null; }
	}
	protected bool IsFileContentDifferent(String fileName, String newContent) {
		return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
	}
	private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
		this.host = host;
		this.template = template;
	}
	private Block CurrentBlock {
		get { return currentBlock; }
		set {
			if (CurrentBlock != null)
				EndBlock();
			if (value != null)
				value.Start = template.Length;
			currentBlock = value;
		}
	}
	private class VSManager: Manager {
		private EnvDTE.ProjectItem templateProjectItem;
		private EnvDTE.DTE dte;
		private Action<String> checkOutAction;
		private Action<IEnumerable<String>> projectSyncAction;
		public override String DefaultProjectNamespace {
			get {
				return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
			}
		}
		public override String GetCustomToolNamespace(string fileName) {
			return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
		}
		public override void Process(bool split) {
			if (templateProjectItem.ProjectItems == null)
				return;
			base.Process(split);
			projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
		}
		protected override void CreateFile(String fileName, String content) {
			if (IsFileContentDifferent(fileName, content)) {
				CheckoutFileIfRequired(fileName);
				File.WriteAllText(fileName, content);
			}
		}
		internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
			: base(host, template) {
			var hostServiceProvider = (IServiceProvider) host;
			if (hostServiceProvider == null)
				throw new ArgumentNullException("Could not obtain IServiceProvider");
			dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
			if (dte == null)
				throw new ArgumentNullException("Could not obtain DTE from host");
			templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
			checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
			projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
		}
		private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
			var keepFileNameSet = new HashSet<String>(keepFileNames);
			var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
			var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";
			foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
				projectFiles.Add(projectItem.get_FileNames(0), projectItem);
			// Remove unused items from the project
			foreach(var pair in projectFiles)
				if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
					pair.Value.Delete();
			// Add missing files to the project
			foreach(String fileName in keepFileNameSet)
				if (!projectFiles.ContainsKey(fileName))
					templateProjectItem.ProjectItems.AddFromFile(fileName);
		}
		private void CheckoutFileIfRequired(String fileName) {
			var sc = dte.SourceControl;
			if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
				checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
		}
	}
}
#>

Initial projectsT4 template added with output filesFor simplicity’s sake I’ve merged Damien’s T4 Manager class into this template, just so there’s a single file to drop into the project. So, how do you use this template? Well first create a BizTalk project with some schemas, and then create a C# class library project alongside it; this project is going to contain the XML serialization classes. Next, add the schemas from the BizTalk project into the C# class library project, but as a link so they don’t get copied into the project, just referred to. Now just add the template, which I’ve named XmlSerializer.tt, to the project. This will automatically generate XmlSerializer.cs, which contains the XML serialization classes, and also *.Serialization.cs for each of the root elements in each of the schema files. It couldn’t be easier! There’s only one thing to watch out for; the code generation only occurs when you save the template file or select Run Custom Tool from its context menu in Solution Explorer. So if you change your schemas you’ll need to remember to resave the template to regenerate the serialization code. This is just how T4 works out of the box, but it’s an awful lot easier than getting out a Command Prompt and remembering the syntax for XSD.exe!

Subversion and Windows Search

I’m a regular Subversion user, specifically TortoiseSVN and VisualSVN, but I’m also a big fan of Windows Search, particularly with all the improvements introduced in Windows 7. However, when Windows Search indexes areas of the file system where you’ve checked out a Subversion repository to, then by default it will index the checked out files and the base files that Subversion keeps in the hidden .svn directories. In addition it indexes all the other files in the .svn directories. This means you can get a slightly odd search experience as you often get garbage in the results and two hits for every matching file, one that’s the file you’re looking for and one that’s the base file in the .svn directory.

Search results with duplicate entries

So, what’s the solution? Well one solution is to slightly alter the query you use when searching directory hierarchies that contain Subversion managed files. Just add -folder:.svn to the end of the query.

Correct search results

It’s the correct set of results, but this isn’t ideal. What would be better is if Windows Search didn’t index the .svn directories in the first place. Unfortunately the user interface for managing Windows Search is quite basic and it’s not possible to add a rule that says exclude all directories named .svn anywhere they are encountered. You can only exclude specific .svn directories, and this isn’t practical.

I’m left wondering if there’s some way to achieve this through the Windows Search SDK? An interesting exercise for the future I think!

.NET Naming Conventions – VB.NET version

Not so long ago a colleague of mine, Josh Twist, did a post on .NET naming conventions using C# code to serve as an example. These are based on the .NET naming guidelines published on MSDN. Well, I happen to be doing a code review right now, but it’s in VB.NET. So I thought I’d do a VB.NET version and post it here for everyone’s reference. I’m sure that Eric Nelson will be very happy!

Option Explicit On
Option Strict On
Imports System
' Namespaces are PascalCased
Namespace Example.NamingConventions
    ' Class names are PascalCased
    Public Class ExampleClass
        ' All public fields, including constants are PascalCased
        Public Const PiAsAString As String = "3.14"
        ' All private fields are camelCased with an underscore prefix
        Private ReadOnly _privateMember As String
        ' All protected members are PascalCased
        Protected ProtectedField As Integer = 12
        ' All friend members are PascalCased
        Friend InternalField As Integer = 13
        ' All private methods are PascalCased
        ' *** NOTE - All parameters are camelCased
        Private Function Multiply(ByVal valueA As Double, ByVal valueB As Double) As Double
            ' local variables (scoped within a method) are camelCased (no underscore)
            Dim result As Double = valueA * valueB
            Return result
        End Function
        ' All private Properties are PascalCased
        ' *** NOTE - Acronyms of 2 characters are UPPERCASED (e.g. UI, IO)
        Private ReadOnly Property UIElementName() As String
            Get
                Throw New NotImplementedException()
            End Get
        End Property
        ' All (public and private) properties are PascalCased
        ' *** NOTE - Acronyms longer than 2 characters are PascalCased (e.g. Html, Xml)
        Public Property HtmlLength() As Integer
            Get
                Throw New NotImplementedException()
            End Get
            Set(ByVal value As Integer)
                Throw New NotImplementedException()
            End Set
        End Property
        ' All public methods are PascalCased
        ' *** NOTE - All parameters are camelCased
        ' *** NOTE - Abbreviations are not treated as Acronyms (so "Id" is Id, not ID).
        Public Sub AlignObjectById(ByVal id As String, ByVal alignment As Alignment)
            Throw New NotImplementedException()
        End Sub
        ' Nested classes are PascalCased, even private ones
        Private Class NestedClass
            Implements IDisposable
            Public Sub Dispose() Implements IDisposable.Dispose
                Throw New NotImplementedException()
            End Sub
        End Class
    End Class
    ' Enums are PascalCased and not plural (unless marked with <Flags> in which case the name should be plural)
    Public Enum Alignment
        ' Enum members are PascalCased
        Top
        Bottom
        Left
        Right
    End Enum
End Namespace

BizTalk WCF Adapter Stack

For a while now I’ve been thinking about writing a post that documents all the gritty details of how the BizTalk messaging engine hooks into the WCF stack in the various WCF adapters. Now I don’t have to as Paolo Salvatori has done a stunning job:

http://blogs.msdn.com/paolos/archive/2009/11/17/customizing-and-extending-the-biztalk-wcf-adapters.aspx

Well done mate. This is by far the best explanation of how the BizTalk WCF adapter stack actually works. It should be in the documentation!