Posts Tagged ‘C#’
The Service Locator pattern is the new global variable
Mark Seeman, author of an upcoming book about dependency injection, writes that Service Locator is an anti-pattern. He shows several code examples illustrating the difficulty of configuring and troubleshooting various implementations of the Service Locator pattern. His observations tally with my thoughts about the awkwardness of service locator implementations.
As I was wrestling with yet another third-party software component that made heavy use of an inversion-of-control (IoC) container, I realized that service locators are the new global variable.
Global variables are a code smell and should be used sparingly.
This means that you should use a service locator only as a last resort, not as the default way of wiring bits of your application together.
And if you’re using an IoC container, make sure that you are using it to inject dependencies through your object constructors, rather than calling its static Resolve methods from within your classes.
An Outlook Conversation
One of the things that I had to do in Outlook this week was to determine if an outlook MailItem is part of a conversation.
After much googlework, I discovered two properties on the Outlook MailItem – ConversationIndex and ConversationTopic.
To determine if an Outlook Item is part of a Conversation, you need to look at the first 22 bytes of the hex string reported for ConversationIndex. If they are the same, then the message is part of the same conversation.
-
-
public static bool SameConversation(MailItem item1, MailItem item2)
-
-
{
-
return item1.ConversationIndex.Substring(0, 22) ==
-
item2.ConversationIndex.Substring(0, 22);
-
}
That’s all well and good, but note that this property is somewhat unreliable. For starters, in versions of outlook prior to 2003, it returned binary data, instead of a hex string (but if you’re working with versions of Outlook prior to 2003, you probably have other problems…) The other reason this property is unreliable is because it is set by the client – Outlook appends a 5 byte timestamp to the ConversationIndex when you reply. Which is cool, as long as you reply through Outlook.
But – our Infovark mail server is hosted by Google, and I occasionally use the gmail web client to reply to mail, instead of Outlook. For these conversations, when the replies were eventually retrieved into Outlook via IMAP, they ended up with unique conversationindexes, and so I couldn’t identfy them as being part of the same conversation.
In these cases, that’s where the ConversationTopic Property can help give you a clue. The ConversationTopic is the normalized subject of the message, that is, the subject without all the prefix strings (“Re:Re:” etc.) By comparing ConversationTopics, you can usually piece together the conversation, even if the ConversationIndex is not correct.
Converting IEnumerable to a Comma-Delimited String
I’m not sure whether it’s the fastest way to convert an enumerable collection of longs or ints to a comma-delimited list in C#, but it might be the shortest.
-
IEnumerable<long> ids = new long[]{1,3,4,5};
-
string delimitedIds = string.Join(",", ids.Select(x => x.ToString()).ToArray());
If you need a LINQ-free version for backward compatibility, check out Missing Functions on IEnumerable on Steve Cooper’s blog.
Handling COM Error Codes
Sometimes COM Objects return a HRESULT that is outside of the bounds of a C# integer.
Unfortunately, the only way to correctly handle a COM Exception in .NET is to use the ComException Class. But if the HRESULT isn’t an Int, and the ErrorCode Property on the ComException class is an Int, how are you supposed to ever be able to catch that specific HRESULT?
Fear not! Here’s how to handle a COM ErrorCode that can’t be converted to an Int (in this example, it’s unsigned)
-
{
-
_PropertyHandler.Open(filePath, false, dsoFileOpenOptions.dsoOptionDefault);
-
}
-
catch (COMException comEx)
-
{
-
if (comEx.ErrorCode == unchecked((int)0x800300FC))
-
{
-
throw new FileNotFoundException("Could not find file:");
-
}
-
}
The magic happens in the ‘unchecked’ statement – which tells the compiler not to perform the overflow-checking context for integral-type arithmetic operations and conversions.
More on the Unchecked Operator over on MSDN.
256 Character Filenames Should be Enough for Anybody
One of the key components of Infovark is a file crawler. We monitor specified folders for additions, updates and deletes, so that we can let users know what changes have occurred. I figured that making a recursive descent through files and folders in Windows would be a snap. And it would be, if not for the details.
Walking a file hierarchy is one of those basic examples included in just about every programming book, just like “Hello World!”. You can find sample code everywhere, but here’s the MSDN article on Iterating Through a Directory Tree. Notice how it recommends that you read about how NTFS works, at the end of the article? That’s where the important details hide.
Inconstant Constants
Implement the naive version of file recursion, and you’ll likely get a System.IO.PathTooLongException in fairly short order. This is because Windows filenames have a maximum limit of 260 characters. Most of the time. There are a few gotchas. Check out the Naming a File article. After reading it, you’ll probably have similar reactions to the folks on this Joel on Software forum thread about Windows MAX_PATH.
Here’s the gist: The Windows shell has a 260 character limit on its filenames. This is the MAX_PATH constant. However, the OS Kernel itself supports filenames with up to 32,000 characters (for compatibility with UNIX systems). So it’s trivially easy to work around this “constant” using a variety of hacks. For example:
- Sometimes you can squeeze in a few extra characters by using the DOS 8.3 short name format. This gives your files bizarre names like
C:\PROGRA~1\DOCUME~1\LongName.txt. - You can drop down into Win32 API calls and unmanaged code. Certain file-handling functions accept the “\\?\” prefix, which lets you use the UNIX-style names. Naturally, this comes with additional baggage that I can’t even begin to describe.
- You can map a drive to a folder deep in your tree. This effectively fakes out the Windows shell into thinking the path is much shorter than it really is.
- You can create a shared folder and bypass the length restriction. This works for the same reason that mapping a drive does.
The most common case where these hacks crop up is when a Windows server administrator maps network drives. While end users can create file hierarchies nested right up to the 260 character limit on their H: drives, the administrator of the file server can’t actually navigate that deeply. That’s right: The file server administrator can’t actually reach the deepest files on the machine because he sees C:\File Shares\Shared Drives\ where end users see H:. As you can imagine, this makes backing up network drives no fun at all.
But there’s a fix, right?
Not really. You’ll have to figure out how to deal with all these exceptions and hacks yourself. The Base Class Library (BCL) Team at Microsoft is working on both temporary and long-term solutions for the .NET Framework. You can read Part 1, Part 2 and Part 3 on the BCL Team Blog for all the gory details.
The core issue is the trade-off between consistency and backward compatibility. It’s a challenge that becomes tougher every year, both for Microsoft itself and for developers using the MS platform. It’s amazing how backward-compatible Microsoft is, given its quarter century accumulation of legacy code. It’s great for businesses and consumers, but from a developer’s perspective, all those gotchas add up over time. I don’t want to have the institutional memory of Raymond Chen just to navigate the filesystem. And is 256 characters a reasonable limit for filenames in a modern OS?
Oh, in case you were wondering, the maximum URL length is 2,083 characters in Internet Explorer.