I was burning the midnight oil last night writing some samples for a project I’m working on with Azure AppFabric Service Bus Queues and Topics. In short, I was modifying some existing code I had written to defensively check for the existence of a queue so that I could avoiding entity conflicts when attempting to create the same queue name twice.
Given a queueName of “Orders”, the first thing I did was to check to see if it exists by using the Client API along with a very simple LINQ query:
1: var qs = namespaceClient.GetQueues();
2:
3: var result = from q in qs
4:
5: where q.Path == queueName
6:
7: select q;
If the result came back as empty, I’d go ahead and create the queue:
1: if (result.Count() == 0)
2: {
3:
4: Console.WriteLine("Queue does not exist");
5:
6: // Create Queue
7:
8: Console.WriteLine("Creating Queue...");
9:
10: Queue queue = namespaceClient.CreateQueue(queueName);
11:
12: }
This code worked fine the first time, since the queue did not exist, but the next time I ran the code, and each time following, Line 10 above would execute each time because the result.Count() was always zero.
Looking at the queue properties, it was clear that the queue name was stored in lower case, regardless of the case used in my queueName variable:
On the surface, this created an interesting dilemma: Even though case didn’t matter when creating the queue, when I was searching for the queue name in Line 5 of my LINQ query, it was always resulting in a false match. Could this be a bug?
My first thought was to go back and make queueName lowercase, changing to “orders”. This fixed the problem on the surface, but it felt dirty and fragile.
After reviewing the code with some colleagues (thanks @clemensv and @briannoyes) it turns out that I had made an esoteric, but key error when checking for equality of the queue path:
where q.Path == queueName
The full explanation is available on the C# Programming Guide on MSDN, but in a nutshell, I had made the error of using the “==” operator to check for equality. From MSDN: “Use basic ordinal comparisons when you have to compare or sort the values of two strings without regard to linguistic conventions. A basic ordinal comparison (System.StringComparison.Ordinal) is case-sensitive, which means that the two strings must match character for character: "and" does not equal "And" or "AND".”
The solution was to modify the where clause to use the Equals method which takes the object you are comparing to along with a StringComparison rule of StringComparison.OrdinalIgnoreCase:
1: var result = from q in qs
2: where q.Path.Equals(queueName,StringComparison.OrdinalIgnoreCase)
3: select q;
Explanation from MSDN: “A frequently-used variation is System.StringComparison.OrdinalIgnoreCase, which will match "and", "And", and "AND". StringComparison.OrdinalIgnoreCase is often used to compare file names, path names, network paths, and any other string whose value does not change based on the locale of the user's computer.”
The AppFabric team is doing exactly the right thing since the queue path corresponds to a network path.
Here is the full code, which allows me to check for the existence of the queue path ensuring that I am ignoring case and the rest is as it was:
1: var qs = namespaceClient.GetQueues();
2:
3: var result = from q in qs
4: where q.Path.Equals(queueName,StringComparison.OrdinalIgnoreCase)
5: select q;
6:
7: if (result.Count() == 0)
8: {
9: Console.WriteLine("Queue does not exist");
10:
11: // Create Queue
12: Console.WriteLine("Creating Queue...");
13: Queue queue = namespaceClient.CreateQueue(queueName);
14: }
When you’ve been programming for a while, it’s sometimes easy to forget the little things, and it is often the least obvious things that create the nastiest bugs.
Hope this saves someone else from having a Doh! moment like I did