Debugging MAPI Problems

Posted by Hugh Ang at 12/18/2007 02:36:00 PM

I have been quiet here for the last month or so, one of the reasons being that I have been bogged down by a lot of application issues in production. The most recent one had to do with 4 Windows services on the production database server. Those services, developed in VB long time ago, run as work flow engines, polling/querying the database on a timer, changing the state of work flow items according to business rules and emailing the next person in the queue using MAPI function. Those services were developed at different times but they have very similar functionalities. Most of the source code was just copied from the very first one unfortunately.

About a week ago, those services started to hang - users are usually first to tell because the work flow items don't get routed after a couple of minutes as it is supposed to. I have been doing analysis with the hang dumps created by ADPLUS, arriving at the conclusion that MAPI call was the culprit. However, I haven't figured out exactly what in the MAPI call caused the problem due to lack of MAPI debug symbols. I am going to blog the debugging result anyway - hopefully someone with similar experiences with MAPI can point out the issue.

The following shows the stack of the main thread of the services that are hanging:


0:000> kb
ChildEBP RetAddr Args to Child
0012e64c 7c59a072 000005a4 00000000 00000000 NTDLL!ZwWaitForSingleObject+0xb
0012e674 7c57b3e9 000005a4 ffffffff 00000000 KERNEL32!WaitForSingleObjectEx+0x71
*** ERROR: Symbol file could not be found. Defaulted to export symbols for MSMAPI32.DLL -
0012e684 35ffbee7 000005a4 ffffffff 0de623a0 KERNEL32!WaitForSingleObject+0xf
WARNING: Stack unwind information not available. Following frames may be wrong.
0012e6fc 35f789e7 00000000 02dad738 02da27d8 MSMAPI32!FPropContainsProp+0x2612
*** ERROR: Symbol file could not be found. Defaulted to export symbols for MAPI32.DLL -
0012e744 61dd2d09 00000000 02da33f8 02da2228 MSMAPI32!MAPILogonEx+0xa7
*** ERROR: Symbol file could not be found. Defaulted to export symbols for CDO.DLL -
0012e76c 0dd025ea 00000000 02da33f8 02da2228 MAPI32!MAPILogonEx+0x79
00000000 00000000 00000000 00000000 00000000 CDO!DllUnregisterServer+0x10eea


To see what WaitForSingleObject() is waiting on:


0:000> !handle 5a4 f
Handle 000005a4
Type Mutant
Attributes 0
GrantedAccess 0x120001:
ReadControl,Synch
QueryState
HandleCount 6
PointerCount 12
Name \BaseNamedObjects\4D4150494C6F676F6E0070B872C47FD7101B8BEA00AA0038C699_S-1-5-21-1346851753-1016681682-1202159320-1002
Object specific information
Mutex is Owned


If the export symbols are close enough, the MAPILogonEx() is waiting on this mutex, which has a name suffixed with a SID, which belongs to the service account the services are running as. The SID suffix seems to reenforce the conjecture that MAPILogonEx() is being called.

While 3 out of the 4 services have their main threads like that, the forth one is different:


0:000> kb
ChildEBP RetAddr Args to Child
0012de34 7c59a072 00000664 00000000 00000000 NTDLL!ZwWaitForSingleObject+0xb
0012de5c 7c57b3e9 00000664 ffffffff 00000000 KERNEL32!WaitForSingleObjectEx+0x71
*** ERROR: Symbol file could not be found. Defaulted to export symbols for MSMAPI32.DLL -
0012de6c 35f98779 00000664 ffffffff 00000000 KERNEL32!WaitForSingleObject+0xf
WARNING: Stack unwind information not available. Following frames may be wrong.
0012de94 35f98691 00000201 0012deec 0012decc MSMAPI32!DDLUnwrapObjectEx+0xc65
*** ERROR: Symbol file could not be found. Defaulted to export symbols for EMSABP32.DLL -
0012dec4 35ae3c6e 00000004 00000201 00000000 MSMAPI32!DDLUnwrapObjectEx+0xb7d
0012df10 35ae3bbd 023e2144 00000001 023e2170 EMSABP32!ABProviderInit+0x2611
0012e028 35f72512 35f72570 360b6700 35f755d0 EMSABP32!ABProviderInit+0x2560
00000000 00000000 00000000 00000000 00000000 MSMAPI32!DDCS_Enter+0x16


This one is waiting on an event object:


0:000> !handle 664 f
Handle 00000664
Type Event
Attributes 0
GrantedAccess 0x1f0003:
Delete,ReadControl,WriteDac,WriteOwner,Synch
QueryState,ModifyState
HandleCount 2
PointerCount 4
Name
No object specific information available


I suspect this process is the owner of the mutex, although I didn't have a chance to create a kernel dump to verify.


0:000> !handle 370 f
Handle 00000370
Type Mutant
Attributes 0
GrantedAccess 0x1f0001:
Delete,ReadControl,WriteDac,WriteOwner,Synch
QueryState
HandleCount 6
PointerCount 12
Name \BaseNamedObjects\4D4150494C6F676F6E0070B872C47FD7101B8BEA00AA0038C699_S-1-5-21-1346851753-1016681682-1202159320-1002
Object specific information
Mutex is Owned


We have moved the 4 services from the database server (Win2K) to a different box (Win2K3) and there hasn't been any hang problems so far, which suggests that the MAPI problem is probably local to that machine, rather than having to do with the exchange server. Here is the detail of MAPI32.dll on the database server:


61dd0000 61df1000 MAPI32 (export symbols) MAPI32.DLL
Loaded symbol image file: MAPI32.DLL
Image path: C:\Program Files\Common Files\System\MSMAPI\1033\MAPI32.DLL
Image name: MAPI32.DLL
Timestamp: Wed Jan 13 11:08:14 1999 (369CC4EE)
CheckSum: 0002A798
ImageSize: 00021000
File version: 1.0.2536.0
Product version: 1.0.2536.0
File flags: 2 (Mask 3F) Pre-release
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0409.04e4
CompanyName: Microsoft Corporation
ProductName: Microsoft Exchange
InternalName: MAPI32
OriginalFilename: MAPI32.DLL
ProductVersion: 1.0
FileVersion: 1.0.2536.0
FileDescription: Extended MAPI 1.0 for Windows NT
LegalCopyright: Copyright © 1986-1999 Microsoft Corp. All rights reserved.
LegalTrademarks: Microsoft® and Windows® are registered trademarks of Microsoft Corporation.
Comments: Service Pack 3


Now back to investigating ...

Thread Pool

Posted by Hugh Ang at 10/31/2007 05:14:00 PM

I mentioned in my last post that I would cover some interesting topics that all relate to thread. Now here is the second one, on thread pool.

Thread pool is an efficient way to achieve concurrency since it saves the cost of creating new threads all the time by reusing threads in a pool. To get a good understanding of how to leverage ThreadPool class in the .NET framework, you can start by reading Jeffery Richter's good article on MSDN. However that was .NET 1.1. In .NET 2.0, the ThreadPool class supports a total of 4 types of uses as opposed to 3, which can be seen clearly from the enumeration in SSCLI2:


enum ThreadpoolThreadType

{

    WorkerThread,

    CompletionPortThread,

    WaitThread,

    TimerMgrThread

};



With the new ThreadPool class, we can


  • 1) call a method on a worker thread by QueueUserWorkItem

  • 2) call a method on an IO Completion port thread by UnsafeQueueNativeOverlapped

  • 3) call a method on an IO Completion port thread when a kernel object is signaled by RegisterWaitForSingleObject

  • 4) call a method on a worker thread by using System.Threading.Timer - note this is the API seemingly irrelevant to ThreadPool



While IO Completion Port (IOCP) is not new to native Windows, the inclusion of its API in thread pool is the latest feature added to .NET 2.0. IOCP is a mechanism on Windows to allow asynchronous IO. The IOCP threads will be woken up and start code execution if IO operation is complete. The Win32 API for this is GetQueuedCompletionStatus, which essentially doesn't return (thread back to the pool) until IO operation is done. And more interestingly, IOCP isn't just limited to being used for IO - ThreadPool.UnsafeQueueNativeOverlapped can be used just like ThreadPool.QueueUserWorkItem. Here is a code snippet for queueing a delegate to the IOCP threads via Overlapped data structure:


unsafe

{

    Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, null);

    NativeOverlapped* pOverlapped = overlapped.Pack(IocpThreadProc, null);

    ThreadPool.UnsafeQueueNativeOverlapped(pOverlapped);

}



Note that unsafe keyword is used as native pointer is created. And here is the delegate:


unsafe static void IocpThreadProc(uint x, uint y, NativeOverlapped* p)

{  

    try

    {

        Sort();

    }

    finally

    {

        Overlapped.Free(p);

    }

}



Note that Free must be called in the finally block to ensure that memory is not leaked.

The philosophy of IOCP is that the optimal number of concurrent running threads should be equal to the number of processors, because anything more would introduce the overhead of context switches between different threads. Peeking into the win32threadpool.cpp file of SSCLI2, one can find that while both the number of worker threads and the number of IOCP threads can grow under the ceiling of upper limits set by ThreadPool.SetMaxThreads, IOCP has constraints from CPU utilization also. In other words, even if you set the max of IOCP threads to a number much higher than the number of processros, there won't be more concurrent threads than the number of processors if there is very high CPU utilization. On the other hand, the number of worker threads, under the situation of high CPU utilitzation, will likely grow under the ceiling with requests queued up. This blog has shown empirical results proving this. The example is a bit of extreme in that a large number of highly computation-intensive requests are being queued to the thread pool. However it shouldn't be viewed that IOCP is always the better one to use. Remember now you can still call ThreadPool.SetMaxThreads to throttle the number of concurrent worker threads to achieve good results too. Measuring and tuning would be required in real world situations. While it's great that we have an additional option to be able to queue any requests to IOCP through UnsafeQueueNativeOverlapped, keep in mind that IOCP was designed to be a great mechanism to handle IO asynchronously. Examples, such as System.IO.FileStream, System.Net.Sockets.Socket, System.ServiceModel.Channels.MsmqQueue, etc. can be found in the FCL. So I'd conjecture that while using a custom IO device, if asynchronous IO is desired, the same pattern can be followed by passing the handle of the IO object to ThreadPool.BindHandle to associate the IO device to the IOCP of the ThreadPool.

As to using System.Threading.Timer, this great MSDN Article discusses it pretty well in comparison with System.Timers.Timer and System.Windows.Forms.Timer. It's important to remember that System.Timers.Timer is a wrapper of System.Threading.Timer. System.Windows.Forms.Timer uses a completely different mechanism, which is SetTimer Win32 API, posting WM_TIMER message to the application queue. This means that your delegate added to the Tick event will be running on the same UI thread that created the main application windows forms. As the UI thread processes a lot of messages, including mouse and keyboard messages, this mechanism will surely not get you a lot of mileage for concurrency if that's what you're looking for.

As server apps like ASP.NET, WCF already have concurrency built in, ThreadPool should not be overly used in there. ThreadPool can be ideal in UI applications, Windows service, and batch applications, etc, if they need a lot of concurrency.

.NET Code Instrumentation That Is More Accurate?

Posted by Hugh Ang at 10/31/2007 03:24:00 PM

I recently ran into a few interesting topics that all relate to Thread and I will share them with you here.

Someone asked an interesting question to our company's community on how to instrument for just the time spent only in the thread when it is executing the code. Thread switching, thread idling/sleeping while waiting for IO, etc should not be counted.

This is indeed pretty interesting as on a machine where a lot of threads are running concurrently, using the elapsed time (e.g. the Tracer in EntLib) approach, may give you inaccurate results if you just want to focus on measuring algorithm of your code. It will be further skewed if the thread running your code is given lower priorities than the other ones as thread scheduling on Windows is priority-driven and preemptive.

After digging around a bit, I found a reasonable good approach to this problem, with the help of BCL of .NET framework. The Process type in System.Diagnostics namespace has a Threads property, which is a collection that corresponds to the Win32 threads in the process. The .NET type that represents the underlying Win32 thread is ProcessThread. It turns out that ProcessThread has properties for processor time, which is key to the solution. Specifically, the property I want to use is UserProcessorTime. Here is a simple wrapper class that I wrote, following the Tracer class pattern from EntLib. I have only kept necessary code to show the point – email me (hugh dot ang at gmail dot com) if you want to have my Visual Studio project that has the complete source code.


public class ThreadTimer : IDisposable

{

    private const string LOG_CATEGORY = "General";

 

    [ThreadStatic()]

    private ProcessThread _processThread;

 

    private int _threadId;

    private TimeSpan _start;

 

    [DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]

    private static extern Int32 GetCurrentWin32ThreadId();

 

    public ThreadTimer()

    {

        _threadId = ProcessThread.Id;

        _start = ProcessThread.UserProcessorTime;

 

        Logger.Write("ThreadTimer started", LOG_CATEGORY);

    }

 

    public void Dispose()

    {

        double duration = ProcessThread.UserProcessorTime.Subtract(_start).TotalSeconds;

        Logger.Write(

            String.Format("ThreadTimer ended with elapsed time of {0} seconds processor user time.",

            duration),

            LOG_CATEGORY);

    }

 

    private ProcessThread ProcessThread

    {

        get

        {

            if (_processThread == null)

            {

                int id = GetCurrentWin32ThreadId();

                foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)

                {

                    if (thread.Id == id)

                    {

                        _processThread = thread;

                        return _processThread;

                    }

                }

            }

 

            return _processThread;

        }

    }

}



Here is how we can instrument a method called SortOperation:


using (ThreadTimer threadTimer = new ThreadTimer())

{

    // simulate an operation that needs to be instrumented

    SortOperation(i);

}



To see how this works out in comparison to instrumentation of EntLib, I implemented the SortOperation() as in the following:


static void SortOperation(int x)

{

    SortedList<int, int> slist = new SortedList<int, int>();

    for (int i = x * 10000; i >= 0; i--)

    {

        slist.Add(i, i);

    }

}



To make it interesting, I first instrumented this method using both Tracer and my ThreadTimer and then instrumented the same method plus another method that does just IO, e.g. read from a file on disk. The IO method takes about 200 milliseconds. The following table summarizes the results:



Without the IO method, both Tracer and ThreadTimer produce almost identical results. Based on the empirical results, it’s not hard to figure out that the algorithm of looping with SortedList <> is O(N2). When the IO method is included, EntLib reports the extra 200 milliseconds while ThreadTimer reports pretty much unchanged results.

So you see this ThreadTimer can be a reasonable solution for instrumentation in the scenario where you want to just focus on measuring your algorithm. However, as EntLib captures the start to end performance, which is what end user will experience, this solution shouldn’t replace that. Another caveat is that since there is no fixed relationship between a Win32 native thread and a managed thread, there is no guarantee that this solution will work for any CLR host.

Debugging Without Source Code Using the Right Tools

Posted by Hugh Ang at 10/26/2007 09:11:00 PM

When it comes to debugging without source code, there are two categories of debugging tools for this purpose:


  • deassemblers/debuggers such as IDA Pro, windbg, etc. If the running application is written in .NET, using windbg with SOS is really handy. This kind of tools are helpful if you need to track and understand program flow and execution state, such as stack and memory for subtle issues. These tools also tend to be favorites of crackers who want to crack/bypass license schemes.


  • tracing tools. There are those that trace network traffic such as tcpTrace, ethereal, Fiddler and of course netmon. For monitoring process, file and registry activities on the OS itself, nothing beats the tools from Sysinternals, now Microsoft. The top two I recommend are Process Monitor and Process Explorer. The tools in this category are your friends in many debugging scenarios, especially during the initial stage of understanding the issues at hand.


Here I will go over the debugging experience I just had this week with a legacy financial software, with a file-based database (no it's not Access or any of the Microsoft products). For anonymity reasons I will just not name this software.

Anyway, the database file used by this software is installed on a network share so that the client on users desktops can all use it. You'd probably guess by now that locking has been a common issue but that's not what I plan to cover here.

There is a custom built web application (classic ASP app hosted on IIS 5) in house that has to look up data from this database, which are files on the network share as I have mentioned. I was told that when the web app was being designed, the developer had found that although a VB Winform application could access the database through ODBC just fine, ASP application couldn't. Without investigating and further pursuit, a separate ETL program was developed to transfer the needed data to the SQL database used by the ASP application. The data fortunately doesn't change that much so this ETL program is run once every night. Suffice to say that such a moving piece has had its moments with IT operations although it is not the worst pet peeve.

I came to know this application and the ETL program recently and when I asked why we can't query and cache the data from the file based database in the ASP app, the answer was that the ODBC connection didn't work in ASP although it worked in the ETL program written in VB. I was told that the developer hadn't really debugged the application but rather called the help desk of the software vendor, which was not at all helpful like most of the tier 1 support of those vendors. Intuition was telling me that this problem had to do with the security context, such as impersonation and logon sessions. Question I would ask right away when facing this type of issue: does the context in ASP have permission or other issue accessing this share?

Determined to fix this problem and get rid of the ETL program, I started on the developer machine by configuring the IIS application with high isolation process model. This would cause a server COM+ application to be created - remember I had to deal with IIS 5! :-) Then I set the identity of the COM+ application to a domain service account that would have proper permission to the share, where the database files are located. With IIS directory security configured to do integrated windows authentication, the ASP app worked! But the production server has basic auth to allow users access this app from the Internet. Alas when basic auth was configured, it stopped working even when I typed in the same domain user name and password as the developer logged onto the desktop. As IIS 5 impersonates when either windows auth or basic auth is turned on, there must be a difference between the logged on session associated with the impersonation token in the two authentication types. Using a tool called TokenDump from Keith Brown, that I downloaded long time ago, I was able to confirm that 1) with windows auth, the ASP impersonation token is using the same logon session as the interactive user 2) with basic auth, the impersonation token, however, uses a different logon session than the desktop's although they are both for the same domain user account. This is probably by design as I conjecture that IIS may have done a LogonUser() call using the passed in user name and password, which would result in a different logon session.

But why was a different logon session encountering the problem? I used the Process Monitor for two captures, one for each auth type. When I compared the two, I noticed that the basic auth one didn't even have any trace showing attempts to access the network share. Going further, I found out from the developer that during ODBC and client setup, the legacy financial software used a mapped drive to point to the network share, where the database files reside. This is where the answer to the puzzle lies. As you may know, mapped drive is tied to the logon session and therefore not global. Here is the official documentation on MSDN. We should avoid using it, especially for enterprise server applications.

Finally I would need to change the drive letter to UNC. Alas the legacy software UI explicitly disallows it. Not wanting to give up at this point, I asked the developer to use Process Monitor to find out where (registry or configuration files) the software is keeping the data that contains the drive letter. Sure enough, we found a handful in the registry under the hives created by the software installation. I went ahead and manually changed all relevant registry settings. I then ran the ASP application with basic auth. Voila it worked! So the software must already be using the Win32 IO API that supports UNC, when its UI still disallows it.

This experience shows you how handy the right tools can be in hairy situations such as this. I do caution you though that you need to be extra careful when changing registry settings like this as it may cause unexpected behavior and/or breach license agreement.

EntLib 3.1 Configuration - Part II

Posted by Hugh Ang at 10/05/2007 11:13:00 PM

All EntLib versions come with source code, which is a great place to start digging around and understanding the framework. For configuration, since we are planning to write a custom configuration section, we will need to look at the Configuration and Configuration.Design sub namespaces as each block has them. For example, look for Microsoft.Practices.EnterpriseLibrary.Logging.Configuration and Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.Design in the Logging block. Given all the overwhelming number of types defined in those namespaces, it can seem daunting first to tackle this.

It's actually not too difficult. I will illustrate the approach by just doing a custom configuration section with simple attributes, instead of a complicated configuration schema with nested hierarchies.

Consider an example where we need to connect to an external web service, which needs a configuration section with URL, User ID and Password.

1) First of all we will need to create a type that corresponds to the section in the configuration XML file. Note that this type extends the EntLib's SerializableConfigurationSection. All we need to do in this type is defining the section name and attribute names. And of course we need to define read/write properties for those attributes to read/persist from the configuration file.


 

public class FooSettings : SerializableConfigurationSection

{

    // Defines the section name

    public const string SectionName = "FooConfiguration";

 

    // Defines attributes for the section

    private const string URL_ATTR = "url";

    private const string UID_ATTR = "userID";

    private const string PASSWORD_ATTR = "password";

 

    [ConfigurationProperty(URL_ATTR, IsRequired = true)]

    public string Url

    {

        get { return (string)base[URL_ATTR]; }

        set { base[URL_ATTR] = value; }

    }

 

    [ConfigurationProperty(UID_ATTR, IsRequired = true)]

    public string UID

    {

        get { return (string)base[UID_ATTR]; }

        set { base[UID_ATTR] = value; }

    }

 

    [ConfigurationProperty(PASSWORD_ATTR, IsRequired = true)]

    public string Password

    {

        get { return (string)base[PASSWORD_ATTR]; }

        set { base[PASSWORD_ATTR] = value; }

    }

}



2) Secondly, we will need to create a type that represents the node on the EntLib console. This type extends the EntLib's ConfigurationSectionNode. Note that It's very similar to the FooSettings type defined above, in that there are three read/write properties that correspond to the Url, UID and Password.

 

[Image(typeof(FooNode), "ConfigNode_d.bmp")]

[SelectedImage(typeof(FooNode), "ConfigNode_h.bmp")]

public class FooNode : ConfigurationSectionNode

{

    private string _url;

    private string _uid;

    private string _password;

 

    public FooNode()

        : base("Foo Configuration")

    {}

 

    [ReadOnly(true)]

    public override string Name

    {

        get { return base.Name; }

    }

 

    [Required()]

    [Browsable(true)]

    public string Url

    {

        get { return _url; }

        set { _url = value; }

    }

 

    [Required()]

    [Browsable(true)]

    public string UID

    {

        get { return _uid; }

        set { _uid = value; }

    }

 

    [Required()]

    [Browsable(true)]

    public string Password

    {

        get { return _password; }

        set { _password = value; }

    }

}


What is interesting here is that this class as well as its propeties have some attributes attached to them. The SelectedImage() and Image() attributes simply define the bitmap images shown when the node is in selected or deselected state. The two bitmap images are embedded resources within the same VS.NET project. The Required() and Browsable() attributes at the properties are telling the EntLib UI that those properties are required and browsable(visible) on the UI. If you don't put a value for the property, a UI validation error will occur when you try to save the configuration.

3) So far so good. Now we need to have a way to let EntLib UI become aware of our custom configuration node. Here is where we need to extend EntLib's ConfigurationDesignManager to have our FooConifgurationDesignManager.

 

public class FooConfigurationDesignManager : ConfigurationDesignManager

{

    public override void Register(IServiceProvider serviceProvider)

    {

        (new FooCommandRegistrar(serviceProvider)).Register();

    }

 

    protected override void OpenCore(IServiceProvider serviceProvider,

        ConfigurationApplicationNode rootNode,

        ConfigurationSection section)

    {

        if (section != null)

        {

            FooSettings settings = section as FooSettings;

            Debug.Assert(settings != null,

                "Check config section - not of the FooSettings type");

 

            FooNode node = new FooNode();

            // sync data on UI and in config file

            node.Url = settings.Url;

            node.UID = settings.UID;

            node.Password = settings.Password;

 

            SetProtectionProvider(section, node);

 

            rootNode.AddNode(node);

        }

    }

 

    protected override ConfigurationSectionInfo GetConfigurationSectionInfo(

        IServiceProvider serviceProvider)

    {

        ConfigurationNode rootNode = ServiceHelper.GetCurrentRootNode(serviceProvider);

        FooNode node = null;

        if (rootNode != null)

            node = (FooNode)rootNode.Hierarchy.FindNodeByType(rootNode, typeof(FooNode));

 

        FooSettings settings = null;

        if (node == null)

        {

            settings = null;

        }

        else

        {

            settings = new FooSettings();

 

            // sync data on UI and in config file

            settings.Url = node.Url;

            settings.UID = node.UID;

            settings.Password = node.Password;

        }

        string protectionProviderName = GetProtectionProviderName(node);

 

        return new ConfigurationSectionInfo(node,

            settings, FooSettings.SectionName, protectionProviderName);

    }

}


The two overridden methods OpenCore() and GetConfigurationSectionInfo() are the hooks for EntLib UI to load and save from/to configuration file. You will notice the code in the two methods to sync up data held by FooNode and FooSettings - just remember that FooNode represents the UI view and FooSettings represents the configuration file. The remaining function, Register(), is the hook for us to provide the command in the EntLib context menu. Here we will use the following CommandRegistrar class to add the command "Foo Configuration":

 

public class FooCommandRegistrar : CommandRegistrar

{

    public FooCommandRegistrar(IServiceProvider serviceProvider)

        : base(serviceProvider)

    {

    }

 

    public override void Register()

    {

        ConfigurationUICommand cmd = ConfigurationUICommand.CreateSingleUICommand(ServiceProvider,

            "Foo Configuration",

            "Foo Configuration",

            new AddChildNodeCommand(ServiceProvider, typeof(FooNode)),

            typeof(FooNode));

        AddUICommand(cmd, typeof(ConfigurationApplicationNode));

    }

}


With all these in place, we need to add the following to the AssemblyInfo.cs file:

[assembly: ConfigurationDesignManager(typeof(FooConfigurationDesignManager))]


EntLib UI, when being loaded, will use reflection API to query the assemblies in its folder ("c:\Program Files\Microsoft Enterprise Library 3.1 - May 2007\Bin\" in my case) and find out all the ConfigurationDesignManager types through this assembly attribute. So after the project is compiled, we need to drop the dll into the same folder as the EntLibConfig.exe file.

Whew, now we can see how this works in the EntLib UI. The following figure shows that the "Foo Configuration" command is in the context menu.



One cool feature of EntLib 3.1 configuration is that it works integrated with VS.NET 2005 IDE. The following figure shows just that.



You see that a Foo Configuration is created besides the standard logging application block. In the properties window on the lower-right corner, the values for Url, UID and Password are set. I have also defined two environments, QA and Prod. For QA, override is chosen for the foo configuration and you can also see that it's a different set of values. Note that you can encrypt this section with the standard providers. If you have gone through the code I listed above, you will realize that these two functions are provided by EntLib without us writing any code!

Here is what the app.config file looks like (I have ommitted the logging section for clarity):


<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <configSections>

    <section name="FooConfiguration" type="CustomEntLibConfig.FooSettings, CustomEntLibConfig, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

  </configSections>

  <FooConfiguration url="http://foo.com/test.asmx" userID="test"

    password="test123" />

</configuration>



In case you're curious, here is what the QA delta file looks like.


<configuration>

    <configSections>

        <section name="EnvironmentMergeData" type="Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides.Configuration.EnvironmentMergeSection, Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

    </configSections>

    <EnvironmentMergeData environmentName="QA" environmentDeltaFile="app.qa">

        <mergeElements>

            <override nodePath="/Foo Configuration" overrideProperties="true">

                <overridddenProperties>

                    <add name="Password" value="qa123" />

                    <add name="UID" value="qa" />

                    <add name="Url" value="http://qa.foo.com/test.asmx" />

                </overridddenProperties>

            </override>

        </mergeElements>

    </EnvironmentMergeData>

</configuration>


4) To use the configuration programmatically, here is a code snippet:

 

FooSettings node = ConfigurationManager.GetSection(FooSettings.SectionName) as FooSettings;

 

if (node != null)

    Console.WriteLine("Url: {0}, UID: {1}, Password: {2}",

        node.Url, node.UID, node.Password);

else

    Console.WriteLine("Custom section not found");

 

Console.ReadLine();



I hope you find this helpful. Email me at hugh dot ang @ gmail dot com if you need the source code for the sample I have used here.

EntLib 3.1 Configuration - Part I

Posted by Hugh Ang at 9/23/2007 09:36:00 PM

Recently, when an application that my team had built was deployed to production, an external web service's URL was forgotten to have been set from its test site's to the production site's. So the transactions thought to have completed actually never happened. This caused some interruptions to the business.

We had to rush this deployment one month ahead of schedule because of a business issue. While the rush was partly to blame, I think since the application uses Enterprise Library 3.1 for quite a few of its blocks, one feature could have helped us avoid this hiccup.

Since 3.0, Enterprise Library introduced the environment overrides for configuration. This blog had a good overview of this feature. In a nutshell, the configuration files for the most part are the same between different environments, DEV, Staging, QA and Prod, etc. There are only a few minor things that might be different, such as database connection string, logging threshold, etc. This new Enterprise Library configuration feature saves the differentials in delta config files. And the merge function overrides the original (usually DEV) application config file with the delta to produce the config file for the target environment.

Of course, this feature works out of box for any configuration setting if it can be done through the Enterprise Library configuration console tool, which is also available from Visual Studio .NET 2005 IDE. The list includes the "Application Settings", "Caching", "Logging", etc. "Application Settings" is great for independent name/value pairs but for a set of values and more complicated configuration data schema, a separate configuration section is required. In the next blog, I will show how to create custom EntLib 3.1 configuration sections so that not only can we leverage the environment overrides, but also we can easily use the EntLib config UI to protect sensitive config data with cryptography.

Sync Active Item in VS.NET Solution Explorer

Posted by Hugh Ang at 8/21/2007 10:22:00 PM

Opening a big VS.NET solution and having a lot of source files can be very disorienting. I've found it especially so when I am tracking deep in the types that are referred by other types, which are referred by others, and so on. And it's pretty difficult to find out which Visual Studio project the type is defined in. I was so desperate that I almost wrote an addin to help me synchronizing the active source file in the solution explorer window. Alas when I was almost done, I found that Visual Studio 2005 already offers such function. To use it, just follow these steps:


  • Go to "Tools" menu, click "Options"

  • Under "Projects and Solutions", click "General"

  • Check the "Track Active Item in Solution Explorer" checkbox on the right side



That is it! Now no matter which source file you end up burying your head into, the solution explorer window always selects and scrolls to that file for you. I guess my lesson learned is that I should always look hard first because Visual Studio may just have that built in already. And it was also interesting to learn the VS.NET automation APIs that have to do with finding the solution item and manipulating the solution explorer window.

Commoditization of Business Applications

Posted by Hugh Ang at 8/09/2007 12:19:00 PM

I have been quiet here for the last couple of months. The main reason is that I stepped into the position of vice president of app dev department and became heavily involved in organization management as well as project management at a client. I am also busy collaborating with a colleague on a WCF article that we hope to publish soon.

Being in this particular management position has given me a different perspective on application development. I have been involved in a couple of projects where "buy vs. build" decision was made. Dollars and benefits (ROI) always took precedence over anything else. And it seems obvious that the industry trend is going towards the direction where building everything from scratch is less favored and we see needs for product knowledge and configuration management skills. You can see that with the slew of products like BizTalk, MOSS, Commerce Server 2007, Dynamics, etc. coming out of Microsoft assembly line in a pace like never before.

The trade-off for the product knowledge will be fundamentals and technical skills. An unfortunate effect of this will be that for certain technical issues, the root problems don't get resolved but rather awkward workarounds are contrived at the product level, which could result in convoluted business processes for end users.

For developers, this may not be good news as the creativity aspect (the fun part) of application development is being gradually taken away and it is a big challenge to keep on top of the ever growing list of products.

EntLib 3.1 Is Coming

Posted by Hugh Ang at 5/25/2007 02:08:00 PM

It looks like that p&p is addressing the implementation issue of interception for Policy Injection by making the interception mechanism configurable. Here is the blog that talks about this.

A Simple Design Pattern for Extensible Enumeration Types

Posted by Hugh Ang at 5/15/2007 12:50:00 PM

In .NET, custom enum types are of value type so they cannot be extended. This can create an issue if you want to include an enum in your framework API, where you wish that the enum could be extended by the applications that are using the framework. After examining the implementation of System.Enum, I came up with the following implementation. I haven't googled thoroughly yet so please no flames if someone has done something similar :-) Also note the code posted is POC quality and I am looking to improve it.

First I will start off with a base class EnumEx. I am using generics to allow different underlying enum types:

 

[Serializable()]

public abstract class EnumEx<T>

    where T : struct

{

    // holds the actual value

    protected T _t;

 

    // default constructor

    protected EnumEx()

    {

        _t = default(T);

    }

 

    // constructor that takes the enum value

    protected EnumEx(T t)

    {

        _t = t;

    }

 

    // performs an implicit conversion to the underlying value

    public static implicit operator T(EnumEx<T> obj)

    {

        return obj._t;

    }

 

    // parses a string to the specified type, returns null if no string match is defined

    // this is a case-sensitive version

    public static object Parse(string s, Type type)

    {

        FieldInfo[] fis = type.GetFields(BindingFlags.Static | BindingFlags.Public);

        foreach (FieldInfo fi in fis)

        {

            if (s.Equals(fi.Name))

            {

                object obj = fi.GetValue(null);

                return obj;

            }

        }

 

        return null;

    }

 

    // System.Object overrides

    public override int GetHashCode()

    {

        return _t.GetHashCode();

    }

 

    public override string ToString()

    {

        FieldInfo[] fis = this.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);

        foreach (FieldInfo fi in fis)

        {

            object obj = fi.GetValue(this);

            T t = ((EnumEx<T>)obj)._t;

            if (_t.Equals(t))

                return fi.Name;

        }

 

        return string.Empty;

    }

}


This can be how a framework enum is defined:


 

public class LogType : EnumEx<int>

{

    protected LogType()

        : base()

    {

    }

 

    protected LogType(int value)

        : base(value)

    {

    }

 

    public static implicit operator LogType(int i)

    {

        return new LogType(i);

    }

 

    public static LogType Info = 1;

    public static LogType Warning = 2;

    public static LogType Error = 3;

}



And if the application wishes to extend the enum:


 

public class LogTypeEx : LogType

{

    public static LogType Verbose = 4;

}



If I write the following test code:


 

LogType logType = LogType.Error;

Console.WriteLine(logType.ToString());

 

LogType logType2 = LogType.Parse("Warning", typeof(LogType)) as LogType;

if (logType2.Equals(LogType.Warning))

    Console.WriteLine("Parsing succeeds");

 

int i = logType2;

if (i == 2)

    Console.WriteLine("Implicit conversion to underlying type succeeds");



I will get the following result in the console:


Error
Parsing succeeds
Implicit conversion to underlying type succeeds


So you see that this extensible enum type is pretty straightforward to use, extending the enum is very easy and it achieves pretty much what the native enum type has to offer. One thing left to be desired though is an issue using switch statement with C# compiler. Only the following works:

 

switch (logType2)

{

    case 2:

        Console.WriteLine("Do logic based on LogType.Info");

        break;

}


while this doesn't compile (it fails at the case statement):


 

switch (logType2)

{

    case LogType.Info:

        Console.WriteLine("Do logic based on LogType.Info");

        break;

}



The C# compiler requires a constant in the case statement. It's also picky about what's in the switch statement. Without the implicit operator, the first switch code snippet wouldn't even have compiled either.