Mutexes, Semaphores, Monitors, ReaderWriterLocks, AutoResetEvents & ManualResets oh my!

Mutexes, Semaphores, Monitors, ReaderWriterLocks, AutoResetEvents & ManualResets oh my!

Up until a few years ago, mainstream programming for the most part did not involve asynchrony and/or parallelism except for the most performance demanding applications. In the multi core world we live in today async and parallel programming have become common place. Libraries such as TPL which provide first class framework level support and keywords like async/await built on TPL provide language support for writing elegant asynchronous code. Win8 Metro style apps built on the WinRT programming model is inherently async to help keep Metro style UIs responsive and fluid. As easy as it might appear to write async programs using these new features we should not forget our roots and the primitive constructs in the .NET framwework that TPL uses behind the scenes. This post provides a quick primer on the synchronization primitives that exist in the framework and the use cases of ech of them.

Mutex
A mutex is a synchronization primitive that provides a "locking mechanism" so that only a single thread access to a resource.Other threads can request access to the resource by calling WaitOne() and will be blocked until the thread onwning the Mutex releases it via a call to Release(). The thread holding the Mutex can request the same Mutex multiple times(typically via recursion) by calling WaitOne() without blocking but must call Release() the same number of times. A Mutex enforces thread identity i.e. only the thread holding the Mutex can release it. Mutexes can be named or unnamed. An unnamed Mutex is scoped to the appdomain it is running in, whereas a named Mutex can span across app domain / process boundaries.

Example:

  1. class MutexSample   
  2. {   
  3.     private static void RunMutex()   
  4.     {   
  5.         Mutex mutex = new Mutex(true);   
  6.         Console.WriteLine("Main thread holds mutex");   
  7.         ThreadPool.QueueUserWorkItem(_ =>   
  8.         {   
  9.             Console.WriteLine("Thread {0} waiting to acquire mutex", Thread.CurrentThread.ManagedThreadId);   
  10.             mutex.WaitOne();   
  11.             Console.WriteLine("Thread {0} acquired mutex", Thread.CurrentThread.ManagedThreadId);   
  12.             Thread.Sleep(2000);   
  13.             Console.WriteLine("Thread {0} released mutex", Thread.CurrentThread.ManagedThreadId);   
  14.             mutex.ReleaseMutex();   
  15.         }   
  16.         );   
  17.         Thread.Sleep(5000);   
  18.         mutex.ReleaseMutex();   
  19.         Console.WriteLine("Main thread released mutex");   
  20.         Console.ReadLine();   
  21.     }   
  22.   
  23.     private static void RunNamedMutex()   
  24.     {   
  25.         Mutex mutex = new Mutex(false"MYNAMEDMUTEX");   
  26.         Console.WriteLine("Main thread waiting to acquire mutex");   
  27.         mutex.WaitOne();   
  28.         Console.WriteLine("Main thread holds mutex");   
  29.   
  30.         Thread.Sleep(8000);   
  31.         mutex.ReleaseMutex();   
  32.         Console.WriteLine("Main thread released mutex");   
  33.         Console.ReadLine();   
  34.     }   
  35.     static void Main(string[] args)   
  36.     {   
  37.      //Mutexes enforce  ThreadID, a thread  that owns a mutex can acquire it repeatedly using Waitone() without blocking but must call Release   
  38.      //same # of times   
  39.       RunMutex();   
  40.       RunNamedMutex();   
  41.     }    
  42. }  

Semaphore
A semaphore is a synchronization primitive that provides a "signalling mechanism" to control access to a pool of resources. A semaphore is count based where the count represents the maximum number of resources available which corresponds to the number of threads that can enter the Semaphore.Threads can enter a Semaphore by calling WaitOne() which decreases the count and exits it by calling Release() which increases the count. When the count reaches zero subsequent requests to WaitOne() will block.Unlike a Mutex which uses a ThreadId to maintain ownership, a Semaphore has no notion of "ownership" or ThreadIds. This can lead to situations where a programming error can cause a thread that holds on to the Semaphore to calls Release() more times than it should,so use caution! Like a Mutex, a Semaphore can be named or unnamed. An unnamed Semaphore is scoped to the appdomain it is running in, whereas a named Mutex spans across appdomain / process boundaries.

Example:

  1. class SemaphoreSample   
  2. {   
  3.     private static void RunNamedSemaphore()   
  4.     {   
  5.         Semaphore sem = new Semaphore(1, 1, "MYNAMEDSEMAPHORE");   
  6.         Console.WriteLine("Main Thread holds onto all 3 available entries");   
  7.         sem.WaitOne();   
  8.         Console.WriteLine("Acquired semaphore");   
  9.         Thread.Sleep(8000);   
  10.         sem.Release();   
  11.         Console.WriteLine("Released semaphore");   
  12.         Console.ReadLine();   
  13.     }   
  14.   
  15.     private static void RunUnNamedSemaphore()   
  16.     {   
  17.         Semaphore sem = new Semaphore(0, 3);   
  18.         Console.WriteLine("Main Thread holds onto all 3 available entries");   
  19.         for (int i = 0; i < 5; i++)   
  20.         {   
  21.   
  22.   
  23.             ThreadPool.QueueUserWorkItem(_ =>   
  24.                     {   
  25.                         Console.WriteLine("Thread {0} waiting to acquire semaphore", Thread.CurrentThread.ManagedThreadId);   
  26.                         sem.WaitOne();   
  27.                         Console.WriteLine("Thread {0} acquired semaphore", Thread.CurrentThread.ManagedThreadId);   
  28.                         Thread.Sleep(2000);   
  29.                         sem.Release();   
  30.                         Console.WriteLine("Thread {0} releases semaphore", Thread.CurrentThread.ManagedThreadId);   
  31.                     }   
  32.                 );   
  33.         }   
  34.   
  35.         Thread.Sleep(3000);   
  36.         sem.Release(3);   
  37.         Console.ReadLine();   
  38.     }   
  39.     static void Main(string[] args)   
  40.     {   
  41.        //Semaphores have no notion of ThreadID, any thread can call a release and it wil decrease the semaphore count   
  42.         RunNamedSemaphore();   
  43.         RunUnNamedSemaphore();   
  44.     }   
  45. }   

To see the RunNamedSemaphore() method in action,comment out RunUnNamedSemaphore() and run 2 isntances of the console app.

Monitor
The Monitor is one of the most commonly used synchronization primitives used in the .NET framwework, everyone in some way shape or form has used it knowingly or unknowingly using the "lock" statement which is the syntactic sugar provided by the compiler. A Monitor is used for controlling access to a critical section of code scoped to a single process by granting a lock on an object to the requesting thread.The class has no constructor and exposes it's functionality via static methods. A thread can request a lock by calling Monitor.Enter(object o) and give up the lock by calling Monitor.Exit(object o). Only private or internal objects should be used for locking on, failure to do so is an invitation to deadlocks and/or race conditions While a lock is held by a thread, all other threads requesting a lock are blocked. For each synchronised object the following information is maintained:

  • A reference to the thread that currently holds the lock.
  • A reference to a ready queue, which contains the threads that are ready to obtain the lock.
  • A reference to a waiting queue, which contains the threads that are waiting for notification of a change in the state of the locked object.

To ensure that the Monitor is released properly, wrap your code in a try block and place the Exit call in a finally block. The functionality provided by the Enter and Exit methods is identical to that provided by the C# lock statement, except that lock wraps the Enter method overload and the Exit method in a try…finally block to ensure that the Monitor is released properly. .NET 4.0 provides a TryEnter which tries to acquire a lock and atomically sets a value indicating whether the lock was acquired. A timeout paramter indicates how long to wait for the lock to become available. The benefit of using the static methods on Monitor as opposed to the lock keyword is that it provided a greater degree of control. For instance if a Thread that holds a lock needs to decides to yield control temporarily (such as when it needs to perform an I/O bound operation), it can do so by calling Wait() which puts an entry into the wait queue and allows threads that are ready to run and waiting on the lock (from the ready queue) a chance to run. The thread that gets the lock can complete it's work and call Pulse or PulseAll() to notify the threads in the wait queue so that they can attempt to get the lock back

Example

  1. class MonitorSample   
  2. {   
  3.     private static void RunMonitor()   
  4.     {           object o = new object();   
  5.         for (int i = 0; i < 3; i++)   
  6.         {   
  7.             ThreadPool.QueueUserWorkItem(_ =>   
  8.             {   
  9.                 try  
  10.                 {   
  11.                     Monitor.Enter(o);   
  12.                     Console.WriteLine("Thread {0} acquired lock...working", Thread.CurrentThread.ManagedThreadId);   
  13.                     Thread.Sleep(2000);   
  14.                     Console.WriteLine("Thread {0} performing some I/O operation so yielding the lock temporarily...", Thread.CurrentThread.ManagedThreadId);   
  15.                     Monitor.PulseAll(o);   
  16.                     Monitor.Wait(o);   
  17.                     Console.WriteLine("Thread {0} reacquired lock", Thread.CurrentThread.ManagedThreadId);   
  18.                 }   
  19.                 finally  
  20.                 {   
  21.                     Console.WriteLine("Thread {0} released lock", Thread.CurrentThread.ManagedThreadId);   
  22.                     Monitor.PulseAll(o);   
  23.                     Monitor.Exit(o);   
  24.                 }   
  25.             }   
  26.             );   
  27.         }   
  28.   
  29.         Console.ReadLine();   
  30.   
  31.     }   
  32.     static void Main(string[] args)   
  33.     {   
  34.         RunMonitor();   
  35.     }   
  36. }   

AutoResetEvent
AutoResetEvents are a signalling mechanism for obtaining exclusive access to a resource. Threads can call WaitOne() to wait for a signal to be set by a thread that currently has exclusive access and is ready to give it up. Setting the event allows a single thread from the set of blocked threads, exclusive access and automtically resets the signal. AutoResetEvents inherit from WaitHandle which is a wrapper around a native kernel object, so it does carry some overhead. It might appear that Monitor and AutoResetEvents are both a way to synchronize access to a shared resource so which do you pick and why? AutoResetEvent being a signalling mechanism is primarily used in producer/consumer scenarios where in a producer thread can signal (call Set()) to indicate that some data has been produced and written to a buffer that worker threads can consume. One of which gets to pick up and process the data, and signal to the producer agai n that it is ready for more data to be produced and written to the buffer, whereas a Monitor is used to control access to a critical section of code which if left unsynchronized would cause data corruption.

Example:

  1. class AutoResetEventSample   
  2. {   
  3.     private static void EnqueueWorkItems()   
  4.     {   
  5.         //scenario:used when a thread needs exclusive access to a resource.   
  6.         AutoResetEvent e = new AutoResetEvent(false);   
  7.         for (int i = 0; i < 5; i++)   
  8.         {   
  9.             int index = i;   
  10.             ThreadPool.QueueUserWorkItem(_ =>   
  11.             {   
  12.                 Console.WriteLine("Thread {0}: waiting for event...", Thread.CurrentThread.ManagedThreadId);   
  13.                 e.WaitOne();   
  14.                 Console.WriteLine("Thread {0}: event signalled", Thread.CurrentThread.ManagedThreadId);   
  15.             }   
  16.                 );   
  17.         }   
  18.         Thread.Sleep(2000);   
  19.         Console.WriteLine("Main thread setting event");   
  20.         e.Set();   
  21.        }   
  22.        static void Main(string[] args)   
  23.       {   
  24.           EnqueueWorkItems();   
  25.            Console.ReadLine();   
  26.       }   
  27.    }   

ManualResetEvent
A ManualReset event is similar to AutoResetEvent, the primary difference being that once it is signalled(by calling Set(), the event is not automatically reset. The closest analogy is that of a flood gate that that has been opened allowing all threads waiting on the event to be signalled, access. ManualResetEvents are typically used in fork/join scenarios where in a main thread has forked a bunch of operations for child threads to complete and the main thread Waits on a bunch of WaitHandles, each of which is associated with one child. When a child completes it sets the event. When all events are set the threads have joined and the Main thread can continue about doing it's business.

Example:

  1. class ManualResetEventSample   
  2. {   
  3.     private static void EnqueueWorkItems()   
  4.     {   
  5.         //scenario:communication concerns a task in which one thread must complete   
  6.         //before other threads can proceed.   
  7.         ManualResetEvent e = new ManualResetEvent(false);   
  8.         for (int i = 0; i < 5; i++)   
  9.         {   
  10.             ThreadPool.QueueUserWorkItem(_ =>   
  11.                 {   
  12.                     Thread.Sleep(2000);   
  13.                     Console.WriteLine("Thread {0} waiting for event...", Thread.CurrentThread.ManagedThreadId);   
  14.                     e.WaitOne();   
  15.                     Console.WriteLine("Thread {0} event signalled", Thread.CurrentThread.ManagedThreadId);   
  16.                 }   
  17.                 );   
  18.         }   
  19.         Thread.Sleep(2000);   
  20.         Console.WriteLine("Main thread setting event");   
  21.         e.Set();   
  22.         Thread.Sleep(1000);   
  23.         Console.WriteLine("Main thread re-setting event");   
  24.         e.Reset();   
  25.         Thread.Sleep(1000);   
  26.         Console.WriteLine("Main thread setting event again");   
  27.         e.Set();   
  28.        }   
  29.        static void Main(string[] args)   
  30.       {   
  31.           EnqueueWorkItems();   
  32.            Console.ReadLine();   
  33.       }   
  34.    }   

ReaderWriterLock
A ReaderWriterLock is used to synchronize access to a resource where reads are more frequent than writes. It allows for a single thread (writer) exclusive access to the resource or allows multiple threads (readers) concurrent access to the resource. It is much more performant than a Monitor which does not distinguish between readers and writers thus providing better throughput. Multiple readers alternate with single writers, so that neither readers nor writers are blocked for long periods. Most of the methods for acquiring reader or writer locks accept a timeout parameter so that threads do not deadlock in cases when a thread holding a reader lock requests a writer lock whereas another thread holding the writer lock requests a reader lock.

Example:

  1. class ReaderWriterLockSample   
  2. {   
  3.     private static void Read(ReaderWriterLock readerWriterLock)   
  4.     {   
  5.         Console.WriteLine("Thread {0} waiting for reader lock", Thread.CurrentThread.ManagedThreadId);   
  6.         readerWriterLock.AcquireReaderLock(8000);   
  7.         // AcquireReaderLock can be called multiple times by the same thread,    
  8.         //it bumps up the lock count for this thread   
  9.         if (readerWriterLock.IsReaderLockHeld)   
  10.         {   
  11.             Console.WriteLine("Thread {0} acquired reader lock", Thread.CurrentThread.ManagedThreadId);   
  12.             Console.WriteLine("Thread {0} reading", Thread.CurrentThread.ManagedThreadId);   
  13.             Thread.Sleep(1000);   
  14.             Console.WriteLine("Thread {0} releasing reader lock", Thread.CurrentThread.ManagedThreadId);   
  15.   
  16.             //reduces lock count to 0 immediately, useful if the same thread has acquired the lock multiple   
  17.             //times and increased the lock count. Call "ReleaseReaderLock" to decrement   
  18.             //the lock count by one.                   
  19.             readerWriterLock.ReleaseLock();   
  20.         }   
  21.     }   
  22.   
  23.     private static void Write(ReaderWriterLock readerWriterLock)   
  24.     {   
  25.         Console.WriteLine("Thread {0} waiting for writer lock", Thread.CurrentThread.ManagedThreadId);   
  26.         //blocks  if another thread holds a reader or writer lock.   
  27.         readerWriterLock.AcquireWriterLock(3000);   
  28.         if (readerWriterLock.IsWriterLockHeld)   
  29.         {   
  30.             Console.WriteLine("Thread {0} acquired writer lock", Thread.CurrentThread.ManagedThreadId);   
  31.             Console.WriteLine("Thread {0} writing", Thread.CurrentThread.ManagedThreadId);   
  32.             Thread.Sleep(1000);   
  33.             Console.WriteLine("Thread {0} releasing writer lock", Thread.CurrentThread.ManagedThreadId);   
  34.   
  35.             //reduces lock count to 0 immediately, useful if the same thread has acquired the lock multiple   
  36.             //times and increased the lock count. Call "ReleaseWriterLock" to decrement   
  37.             //the lock count by one.                   
  38.             readerWriterLock.ReleaseLock();   
  39.         }   
  40.     }   
  41.   
  42.     private static void ReadUpgradeToWrite(ReaderWriterLock readerWriterLock)   
  43.     {   
  44.         try  
  45.         {   
  46.             Console.WriteLine("Thread {0} waiting for reader lock", Thread.CurrentThread.ManagedThreadId);   
  47.             //blocks  if another thread holds a reader or writer lock.   
  48.             readerWriterLock.AcquireReaderLock(3000);   
  49.             if (readerWriterLock.IsReaderLockHeld)   
  50.             {   
  51.                 Console.WriteLine("Thread {0} acquired reader lock", Thread.CurrentThread.ManagedThreadId);   
  52.                 Console.WriteLine("Thread {0} reading", Thread.CurrentThread.ManagedThreadId);   
  53.                 Thread.Sleep(1000);   
  54.                 //release reader lock and request write lock,if it times out the exception   
  55.                 //will not be thrown until the thread reacquires the reader lock   
  56.                 Console.WriteLine("Thread {0} waiting to upgrade to writer lock...", Thread.CurrentThread.ManagedThreadId);   
  57.                 LockCookie cookie = readerWriterLock.UpgradeToWriterLock(2000);   
  58.                 try  
  59.                 {   
  60.                     Console.WriteLine("Thread {0} upgraded to writer lock...writing", Thread.CurrentThread.ManagedThreadId);   
  61.   
  62.                 }   
  63.                 finally  
  64.                 {   
  65.                     Console.WriteLine("Thread {0} releasing writer lock and downgraded to reader lock...", Thread.CurrentThread.ManagedThreadId);   
  66.                     //restores reader lock right away ,even if other threads are waiting to write(or read as I understand)   
  67.                     readerWriterLock.DowngradeFromWriterLock(ref cookie);   
  68.                 }   
  69.             }   
  70.         }   
  71.         finally  
  72.         {   
  73.             Console.WriteLine("Thread {0} releasing reacquired reader lock", Thread.CurrentThread.ManagedThreadId);   
  74.             readerWriterLock.ReleaseLock();   
  75.         }   
  76.     }   
  77.   
  78.     private void AnyWritersSince(ReaderWriterLock readerWriterLock)   
  79.     {   
  80.         Console.WriteLine("Thread {0} waiting for reader lock", Thread.CurrentThread.ManagedThreadId);   
  81.         readerWriterLock.AcquireReaderLock(3000);   
  82.         if (readerWriterLock.IsReaderLockHeld)   
  83.         {   
  84.             try  
  85.             {   
  86.                 Console.WriteLine("Thread {0} acquired reader lock", Thread.CurrentThread.ManagedThreadId);   
  87.                 Thread.Sleep(1000);   
  88.                 var seq = readerWriterLock.WriterSeqNum;   
  89.                 var cookie = readerWriterLock.ReleaseLock();   
  90.                 Console.WriteLine("Thread {0} released reader lock", Thread.CurrentThread.ManagedThreadId);   
  91.                 Thread.Sleep(1000);   
  92.                 readerWriterLock.RestoreLock(ref cookie);   
  93.                 Console.WriteLine("Thread {0} restored reader lock", Thread.CurrentThread.ManagedThreadId);   
  94.                 if (readerWriterLock.AnyWritersSince(seq))   
  95.                 {   
  96.                     Console.WriteLine("data invalid due to writer writing");   
  97.                 }   
  98.                 else  
  99.                 {   
  100.                     Console.WriteLine("data still valid, no writers have written");   
  101.                 }   
  102.             }   
  103.             finally  
  104.             {   
  105.                 Console.WriteLine("Thread {0} releasing restored reader lock", Thread.CurrentThread.ManagedThreadId);   
  106.                 readerWriterLock.ReleaseLock();   
  107.             }   
  108.         }   
  109.     }   
  110.   
  111.     private static void Run()   
  112.     {   
  113.         ReaderWriterLock readerWriterLock = new ReaderWriterLock();   
  114.         for (int i = 0; i < 5; i++)   
  115.         {   
  116.             if (i == 2)   
  117.             {   
  118.                 ThreadPool.QueueUserWorkItem(_ =>   
  119.                     {   
  120.                         Write(readerWriterLock);   
  121.                     }   
  122.                     );   
  123.             }   
  124.             else  
  125.             {   
  126.                 ThreadPool.QueueUserWorkItem(_ =>   
  127.                 {   
  128.                     Read(readerWriterLock);   
  129.                 }   
  130.                 );   
  131.             }   
  132.         }   
  133.        }   
  134.   
  135.        static void Main(string[] args)   
  136.        {   
  137.            Run();   
  138.            Console.ReadLine();   
  139.        }       
  140.   


.NET 4 introduced "Slim" verisions of some of the primitives above which are lightweight counterparts

SemaphoreSlim
SemaphoreSlim is similar to a Semaphore except that it cannot be used for cross process synchronization and does not use a windows kernel semaphore.

Example:

  1.   class SemaphoreSlimSample   
  2.   
  3. private static void RunSemaphoreSlim()   
  4. {   
  5.     SemaphoreSlim sem = new SemaphoreSlim(0, 3);   
  6.     Console.WriteLine("Main Thread holds onto all 3 available entries");   
  7.   
  8.     for (int i = 0; i < 5; i++)   
  9.     {   
  10.   
  11.   
  12.         ThreadPool.QueueUserWorkItem(_ =>   
  13.         {   
  14.             Console.WriteLine("Thread {0} waiting to acquire semaphore", Thread.CurrentThread.ManagedThreadId);   
  15.             if (sem.Wait(2000))   
  16.             {   
  17.                 Console.WriteLine("Thread {0} acquired semaphore", Thread.CurrentThread.ManagedThreadId);   
  18.                 Thread.Sleep(2000);   
  19.                 sem.Release();   
  20.                 Console.WriteLine("Thread {0} released semaphore", Thread.CurrentThread.ManagedThreadId);   
  21.             }   
  22.             else  
  23.             {   
  24.                 Console.WriteLine("Thread {0} timed out while waiting to acquire semaphore", Thread.CurrentThread.ManagedThreadId);   
  25.             }   
  26.         }   
  27.             );   
  28.     }   
  29.     Thread.Sleep(2000);   
  30.     sem.Release(3);   
  31.     Console.ReadLine();   
  32. }   
  33.   
  34.   static void Main(string[] args)   
  35.   {   
  36.        RunSemaphoreSlim();   
  37.   }    
  38.   

ManualResetEventSlim
ManualResetEventSlim is intended to be used when the wait time will be extremenly short. It resorts to spinning for the specified spin count before resorting to a kernel based wait operation. The Kernel object is not allocated unless needed making this more performant than a ManualResetEvent

Example:

  1.     class ManualResetEventSlimSample   
  2.     {   
  3.         private static void EnqueueWorkItems()   
  4.         {   
  5.             //scenario:communication concerns a task in which one thread must complete   
  6.             //before other threads can proceed.   
  7.             //Use when wait times are short, uses spinning before resorting to using a wait    
  8.             //handle, this is less expensive than waiting.Also provides a mechanism for   
  9.             //cancellation and timeouts.   
  10.             ManualResetEventSlim e = new ManualResetEventSlim(false);   
  11.             for (int i = 0; i < 5; i++)   
  12.             {   
  13.                 ThreadPool.QueueUserWorkItem(_ =>   
  14.                 {   
  15.                     Thread.Sleep(2000);   
  16.                     Console.WriteLine("Thread {0} waiting for event...", Thread.CurrentThread.ManagedThreadId);   
  17.                     e.Wait();   
  18.                     Console.WriteLine("Thread {0} event signalled", Thread.CurrentThread.ManagedThreadId);   
  19.                 }   
  20.                     );   
  21.             }   
  22.             Thread.Sleep(2000);   
  23.             Console.WriteLine("Main thread setting event");   
  24.             e.Set();   
  25.             Thread.Sleep(1000);   
  26.             Console.WriteLine("Main thread re-setting event");   
  27.             e.Reset();   
  28.             Thread.Sleep(1000);   
  29.             Console.WriteLine("Main thread setting event again");   
  30.             e.Set();   
  31.         }   
  32.   
  33.         static void Main(string[] args)   
  34. {   
  35.            EnqueueWorkItems();   
  36.             Console.ReadLine();   
  37. }   
  38.     }   

ReaderWriterLockSlim
ReaderWriterLockSlim is a more performant version of ReaderWriterLock. ReaderWriterLockSlim does not suffer from writer starvation which can can occur with ReaderWriterLock. By default, it does not allow recursion when requesting locks. It also avoids potential deadlocks that can occur with ReaderWriterLock such as when a thread is holding a read lock and wants to acquire a write lock but another thread is already waiting to acquire a write lock but it cannot until the read lock is released. To achieve this,the ReaderWriterLockSlim allows a thread to enter in one of 3 modes: - Read: Multiple threads can enter the lock in read mode as long as there is no thread currently holding a write lock or waiting to acquire a write lock; if there are any such threads,the threads waiting to enter in read mode are blocked. -Upgradeable: This mode is intended for cases where a thread usually performs reads and might occassionally perform writes. A thread that holds an upgradeable lock on a resource can read and request a promotion to write by calling (Enter/TryEnter)WriteLock. Only one thread can be in this mode at a time. A thread waiting to enter the lock in this mode will block if there is a thread currently holding a lock in write mode of waiting to enter write mode. If there are threads in read mode, the thread that is upgrading to write will block. While the thread is blocked, other threads trying to enter read mode are blocked. When all threads have exited from read mode, the blocked upgradeable thread enters write mode. If there are other threads waiting to enter write mode, they remain blocked, because the single thread that is in upgradeable mode prevents them from gaining exclusive access to the resource. When the thread in upgradeable mode exits write mode, if there are any threads waiting to enter write mode, they get a chance to go first before any threads that are waiting to enter in read mode. - Write: A thread can enter the lock in write mode if no threads hold the lock in any mode,in which case it will block. While a thread is holding a write lock, no threads can enter the lock in any mode.

Example:

  1. class ReaderWriterLockSlimSample   
  2. {   
  3.     private static void Read(ReaderWriterLockSlim readerWriterLock)   
  4.     {   
  5.         Console.WriteLine("Thread {0} waiting for reader lock", Thread.CurrentThread.ManagedThreadId);   
  6.         try  
  7.         {   
  8.             readerWriterLock.EnterReadLock();   
  9.             if (readerWriterLock.IsReadLockHeld)   
  10.             {   
  11.                 Console.WriteLine("Thread {0} acquired reader lock", Thread.CurrentThread.ManagedThreadId);   
  12.                 Console.WriteLine("Thread {0} reading", Thread.CurrentThread.ManagedThreadId);   
  13.                 Thread.Sleep(1000);   
  14.                 Console.WriteLine("Thread {0} releasing reader lock", Thread.CurrentThread.ManagedThreadId);   
  15.             }   
  16.         }   
  17.         finally  
  18.         {   
  19.                 readerWriterLock.ExitReadLock();   
  20.         }   
  21.     }   
  22.   
  23.     private static void ReadWithUpgrade(ReaderWriterLockSlim readerWriterLock)   
  24.     {   
  25.         Console.WriteLine("Thread {0} waiting for upgradeable read lock", Thread.CurrentThread.ManagedThreadId);   
  26.         //only 1 thread can enter upgradeable mode, threads in read mode cannot enter    
  27.         //upgradeable mode or write modedue to probability of deadlock.   
  28.         readerWriterLock.EnterUpgradeableReadLock();   
  29.         try  
  30.         {                  
  31.             if (readerWriterLock.IsUpgradeableReadLockHeld)   
  32.             {   
  33.                 Console.WriteLine("Thread {0} acquired upgradeable read lock", Thread.CurrentThread.ManagedThreadId);   
  34.                 Console.WriteLine("Thread {0} reading", Thread.CurrentThread.ManagedThreadId);   
  35.                 Thread.Sleep(1000);   
  36.                 Console.WriteLine("Thread {0} waiting to acquire write lock", Thread.CurrentThread.ManagedThreadId);   
  37.                 readerWriterLock.EnterWriteLock();   
  38.                 try  
  39.                 {   
  40.                     Console.WriteLine("Thread {0} to acquired write lock", Thread.CurrentThread.ManagedThreadId);   
  41.                 }   
  42.                 finally  
  43.                 {   
  44.                     Console.WriteLine("Thread {0} releasing write lock", Thread.CurrentThread.ManagedThreadId);   
  45.                     readerWriterLock.ExitWriteLock();   
  46.                 }   
  47.             }   
  48.         }   
  49.         finally  
  50.         {   
  51.             Console.WriteLine("Thread {0} releasing upgradeable read lock", Thread.CurrentThread.ManagedThreadId);   
  52.             //downgrade to read mode before leaving upgradeable mode.   
  53.             readerWriterLock.EnterReadLock();   
  54.             readerWriterLock.ExitUpgradeableReadLock();   
  55.             Console.WriteLine("Thread {0} IsReadLockHeld:{1}", Thread.CurrentThread.ManagedThreadId,readerWriterLock.IsReadLockHeld);   
  56.             Console.WriteLine("Thread {0} releasing read lock", Thread.CurrentThread.ManagedThreadId);   
  57.             readerWriterLock.ExitReadLock();   
  58.         }   
  59.     }   
  60.   
  61.     private static void Write(ReaderWriterLockSlim readerWriterLock)   
  62.     {   
  63.         Console.WriteLine("Thread {0} waiting for writer lock", Thread.CurrentThread.ManagedThreadId);   
  64.         try  
  65.         {   
  66.             readerWriterLock.EnterWriteLock();   
  67.             if (readerWriterLock.IsWriteLockHeld)   
  68.             {   
  69.                 Console.WriteLine("Thread {0} acquired writer lock", Thread.CurrentThread.ManagedThreadId);   
  70.                 Console.WriteLine("Thread {0} writing", Thread.CurrentThread.ManagedThreadId);   
  71.                 Thread.Sleep(1000);   
  72.                 Console.WriteLine("Thread {0} releasing readewriterr lock", Thread.CurrentThread.ManagedThreadId);   
  73.             }   
  74.         }   
  75.         finally  
  76.         {   
  77.             readerWriterLock.ExitWriteLock();   
  78.         }   
  79.     }   
  80.   
  81.     private static void Run()   
  82.     {   
  83.         ReaderWriterLockSlim readerWriterLock = new ReaderWriterLockSlim();   
  84.         for (int i = 0; i < 3; i++)   
  85.         {   
  86.             if (i == 1)   
  87.             {   
  88.                 ThreadPool.QueueUserWorkItem(_ =>   
  89.                 {   
  90.                     ReadWithUpgrade(readerWriterLock);   
  91.                 }   
  92.                     );   
  93.             }   
  94.             else  
  95.             {   
  96.                 ThreadPool.QueueUserWorkItem(_ =>   
  97.                 {   
  98.                     Read(readerWriterLock);   
  99.                 }   
  100.                 );   
  101.             }   
  102.         }   
  103.        }               
  104.        static void Main(string[] args)   
  105.        {   
  106.            Run();   
  107.            Console.ReadLine();   
  108.        }   
  109.    }   

AutoResetEvent does not have a "Slim" counterpart since AutoResetEvent is typically used when a thread need exclusive access to a resource for a period of time and wait times are not expected to be short. ManualResetEventSlim, is intended when you know, in advance that wait time will be very short and it uses spinning for a a period of time before waiting, hence there is no "Slim" counterpart. Unless you are on an older version of the framework there is no good reason to choose ReaderWriterLock over ReaderWriterLockSlim.

As the adage goes, "with great power comes great responsibility", use the above with care, writing thread synchronization code is easy, writing bug free and performant thread synchronization code is non trivial. Use libraries like TPL which have done the hard work and encapsulated common patterns of parallelism and asynchrony and exposed them as tasks, but keep the above in mind and konw that they are available for those niche cases when you need fine grained control. This post turned out longer than I anticipated but it serves a one stop shop (at least for me) to come to at those times when I need a quick refresher.


MEF 101 - Part2

This is part 2 of a 2 part series exploring the MEF.We covered some of the basics in Part 1 In this part we'll cover the following:

  • Catalogs
  • Recomposition
  • Export Providers

Catalogs:
Catalogs provide one way for MEF to discover components that it can compose. In it's most basic form it contains a registration of types. A container by itself is just an empty repository. The catalog is the one that collects and returns ComposablePartDefinitions i.e (objects of types that you have registered with MEF) to the container which in turn uses this for satifying imports on a specified object. We've seen AssemblyCatalog previously as a means for finding and satisfying imports. The following catalogs are built into the framework: TypeCatalog, AssemblyCatalog, DirectoryCatalog and AggregateCatalog. Each of these catalogs are derived from ComposablePartCatalog which is the abstract base class for all catalogs.

TypeCatalog
A type catalog is an immutable catalog that lets you register one or more type names.When this catalog is provided to the container it will use the types specified in this catalog for resolving imports and exports. You can specify types directly using 'typeof' (less useful since you are coupled to concrete types) or read type information from a configuration file instead.

 
  1. [Export(typeof(ILogger))]   
  2. public class ConsoleLogger : ILogger   
  3. {   
  4.     [Import]   
  5.     public ITextFormatter Formatter   
  6.     {   
  7.         get;   
  8.         set;   
  9.     }   
  10.   
  11.     public void Log(string str)   
  12.     {   
  13.         string formattedString = Formatter.Format(str);   
  14.         Console.WriteLine(formattedString);   
  15.     }   
  16.   
  17.     public string Name   
  18.     {   
  19.         get  
  20.         {   
  21.             return "Console Logger";   
  22.         }   
  23.     }   
  24. }   
  25.   
  26. [Export(typeof(ITextFormatter))]   
  27. public class TextFormatter : ITextFormatter   
  28. {   
  29.     public string Name   
  30.     {   
  31.         get  
  32.         {   
  33.             return "Text Formatter";   
  34.         }   
  35.     }   
  36.   
  37.     public string Format(string str)   
  38.     {   
  39.         return string.Format("Formatted Message:{0}", str);   
  40.     }   
  41. }   
  42.   
  43. class Program   
  44. {   
  45.   
  46.     [Import]   
  47.     public ILogger Logger { getset; }   
  48.   
  49.   
  50.     static void Main(string[] args)   
  51.     {   
  52.         Program p = new Program();   
  53.         ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(ConsoleLogger), typeof(TextFormatter));    
  54.         CompositionContainer container =   
  55.             new CompositionContainer(typeCatalog);               
  56.         container.ComposeParts(p);   
  57.         p.Logger.Log("Hello world");   
  58.   
  59.     }   
  60. }  
To avoid coupling to specific type names (and by extension an assembly holding a concrete implementation) you could use 'Type.GetType(string typename)' instead where the typename could come from a config file. TypeCatalog gives you fine grained control over each type that you would like to register and make available to the container.

Assembly Catalog
If all the types that you would like to register are contained in an assembly you can use the AssemblyCatalog which scans the assembly and identifies the types that expose Import and Export attributes and registers them in one fell swoop into the catalog.This is useful when you have an application which is broken down into components by say feature areas or you have an on demand download for performance reasons or you have a pay as you go model for features available to your application as is typical in plugin based applications which is what MEF is all about anyways.
The AssemblyCatalog lets you register the types defined in such assemblies and make them available to the rest of the host application via the container.
 

 
  1. class Program   
  2. {   
  3.   
  4.     [Import]   
  5.     public ILogger Logger { getset; }   
  6.   
  7.   
  8.     static void Main(string[] args)   
  9.     {   
  10.         Program p = new Program();   
  11.         Assembly assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), "MEF101.Implementations.dll"));   
  12.         //you could also load the assembly on the fly from over the wire by using Assemly.Load(byte[] bytes)   
  13.         ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(assembly);               
  14.         CompositionContainer container =  new CompositionContainer(assemblyCatalog);               
  15.         container.ComposeParts(p);   
  16.         p.Logger.Log("Hello World");   
  17.   
  18.     }   
  19. }  

DirectoryCatalog
If all your types are contained in a specific directory (such as the current directory your exe is running from) you could use the DirectoryCatalog specifying a directory name and an optional search pattern to have MEF scan all assemblies in the specified directory and automatically register all types that it finds into the catalog like so:
 

 
  1. class Program   
  2.    {   
  3.   
  4.        [Import]   
  5.        public MEF101.Interfaces.ILogger Logger { getset; }   
  6.   
  7.   
  8.        static void Main(string[] args)   
  9.        {   
  10.            Program p = new Program();               
  11.            ComposablePartCatalog dirCatalog = new DirectoryCatalog(Directory.GetCurrentDirectory());   
  12.            CompositionContainer container =  new CompositionContainer(dirCatalog);               
  13.            container.ComposeParts(p);   
  14.            p.Logger.Log("Hello World");   
  15.   
  16.        }   
  17.    }  

AggregateCatalog
You can all combine all the above catalog types into an aggregate catalog type using the AggregateCatalog. As the name implies this takes in one or more ComposablePartCatalogs and exposes the the type registrations contained in all of them to the container as one whole. This is great when you have your types spread out over multiple locations. For example your applcation can start with a barebones set of features loaded from an assembly running in the current directory and you can asynchronously download updates/feature assemblies in the background. You can then compose your application using a combination of AssemblyCatalog and DirectoryCatalog
The following code shows a simplified example wherein ILogger implementations come from an AssemblyCatalog and a TypeCatalog .The TypeCatalog is added after the AggregateCatalog is constructed .

 
  1. [Export(typeof(MEF101.Interfaces.ILogger))]   
  2. class DebugLogger : MEF101.Interfaces.ILogger   
  3. {   
  4.        public string Name   
  5.        {   
  6.            get { return "Debug Logger"; }   
  7.        }   
  8.   
  9.        [Import]   
  10.        public MEF101.Interfaces.ITextFormatter Formatter   
  11.        {   
  12.            get;   
  13.            set;   
  14.        }   
  15.   
  16.        public void Log(string str)   
  17.        {   
  18.            Debug.Write(str);   
  19.        }   
  20.    }   
  21.   
  22. class Program   
  23. {   
  24.     [ImportMany]   
  25.     public IEnumerable<MEF101.Interfaces.ILogger> Loggers { getset; }   
  26.   
  27.   
  28.     static void Main(string[] args)   
  29.     {   
  30.         Program p = new Program();               
  31.         ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(DebugLogger));   
  32.         ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(Assembly.LoadFile(   
  33.                                 Path.Combine(Directory.GetCurrentDirectory(),   
  34.                                     "MEF101.Implementations.dll")));   
  35.         AggregateCatalog aggCatalog = new AggregateCatalog(assemblyCatalog);   
  36.         aggCatalog.Catalogs.Add(typeCatalog);   
  37.         CompositionContainer container =  new CompositionContainer(aggCatalog);               
  38.         container.ComposeParts(p);   
  39.         foreach (var logger in p.Loggers)   
  40.         {   
  41.             logger.Log("Hello");   
  42.         }              
  43.     }   
  44. }  

Whereas all the other catalog types are immutable, the AggregateCatalog lets you add and subract ComposablePartCatalogs from it's internal "Catalog" collection facilitating recomposition of the container on the fly.

Recomposition
MEF provides a facility to allow a composable application to change it's behavior when composable parts can change on the fly via a mechanism called recomposition.
Let's re-write the example such that the call to "Catalogs.Add" is made after we compose the instance of Program
 

 
  1. [Export(typeof(MEF101.Interfaces.ILogger))]   
  2. class DebugLogger : MEF101.Interfaces.ILogger   
  3. {   
  4.        public string Name   
  5.        {   
  6.            get { return "Debug Logger"; }   
  7.        }   
  8.   
  9.        [Import]   
  10.        public MEF101.Interfaces.ITextFormatter Formatter   
  11.        {   
  12.            get;   
  13.            set;   
  14.        }   
  15.   
  16.        public void Log(string str)   
  17.        {   
  18.            Debug.Write(str);   
  19.        }   
  20.    }   
  21.   
  22. class Program   
  23. {   
  24.     [ImportMany]   
  25.     public IEnumerable<MEF101.Interfaces.ILogger> Loggers { getset; }   
  26.   
  27.   
  28.     static void Main(string[] args)   
  29.     {   
  30.         Program p = new Program();               
  31.         ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(DebugLogger));   
  32.         ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(Assembly.LoadFile(   
  33.                                 Path.Combine(Directory.GetCurrentDirectory(),   
  34.                                     "MEF101.Implementations.dll")));   
  35.         AggregateCatalog aggCatalog = new AggregateCatalog(assemblyCatalog);   
  36.            CompositionContainer container =  new CompositionContainer(aggCatalog);               
  37.            container.ComposeParts(p);   
  38.         aggCatalog.Catalogs.Add(typeCatalog);   
  39.             foreach (var logger in p.Loggers)   
  40.             {   
  41.                logger.Log("Hello");   
  42.             }              
  43.     }   
  44. }  

This causes the following exception to be thrown:
Change in exports prevented by non-recomposable import 'MEF.LazyImports.Program.Loggers (ContractName="MEF101.Interfaces.ILogger")' on part 'MEF.LazyImports.Program'
This happens because the container changed after the instance of Program was already composed. The error indicates that the part being imported on the instance of Program i.e Loggers does not support recomposition and hence the change was prevented. We can easily enable this by changing the [Import] declaration on the Loggers property to
[ImportMany(AllowRecomposition=true)]. This allows for the program to dynamically obtain another instance of logger in it's Loggers collection and continue working normally
i.e. recompose itself
Similar to adding catalogs on the fly, we can also remove catalogs from the container and this will cause recomposition and update the Import on the instance of the Program automatically like so:
 
  1. [Export(typeof(MEF101.Interfaces.ILogger))]   
  2. class DebugLogger : MEF101.Interfaces.ILogger   
  3. {   
  4.        public string Name   
  5.        {   
  6.            get { return "Debug Logger"; }   
  7.        }   
  8.   
  9.        [Import]   
  10.        public MEF101.Interfaces.ITextFormatter Formatter   
  11.        {   
  12.            get;   
  13.            set;   
  14.        }   
  15.   
  16.        public void Log(string str)   
  17.        {   
  18.            Debug.Write(str);   
  19.        }   
  20.    }   
  21.   
  22. class Program   
  23. {   
  24.     [ImportMany]   
  25.     public IEnumerable<MEF101.Interfaces.ILogger> Loggers { getset; }   
  26.   
  27.   
  28.     static void Main(string[] args)   
  29.     {   
  30.         Program p = new Program();               
  31.         ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(DebugLogger));   
  32.         ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(Assembly.LoadFile(   
  33.                                 Path.Combine(Directory.GetCurrentDirectory(),   
  34.                                     "MEF101.Implementations.dll")));   
  35.         AggregateCatalog aggCatalog = new AggregateCatalog(assemblyCatalog);   
  36.            CompositionContainer container =  new CompositionContainer(aggCatalog);               
  37.            container.ComposeParts(p);   
  38.         aggCatalog.Catalogs.Add(typeCatalog);   
  39.             foreach (var logger in p.Loggers)   
  40.             {   
  41.                logger.Log("Hello");   
  42.             }   
  43.         aggCatalog.Catalogs.Remove(typeCatalog);   
  44.             foreach (var logger in p.Loggers)   
  45.             {   
  46.                 logger.Log("Hello");   
  47.             }              
  48.     }   
  49. }  

Notifications of Recomposition
MEF can notify you whenever a recomposition happens in case you need to perform some action such as cleanup/housekeeping. It does this via an interface called IPartImportSatisfiedNotification
You implement this interface in any of your parts in which you need that a recomposition(or more generally a composition) has occured.The interface has a single method called OnImportSatisfied
that you need to provide an implementation for.

 

 
  1. [Export(typeof(MEF101.Interfaces.ILogger))]   
  2. class DebugLogger : MEF101.Interfaces.ILogger   
  3. {   
  4.        public string Name   
  5.        {   
  6.            get { return "Debug Logger"; }   
  7.        }   
  8.   
  9.        [Import]   
  10.        public MEF101.Interfaces.ITextFormatter Formatter   
  11.        {   
  12.            get;   
  13.            set;   
  14.        }   
  15.   
  16.        public void Log(string str)   
  17.        {   
  18.            Debug.Write(str);   
  19.        }   
  20.    }   
  21.   
  22. class Program : IPartImportsSatisfiedNotification   
  23. {   
  24.     [ImportMany]   
  25.     public IEnumerable<MEF101.Interfaces.ILogger> Loggers { getset; }   
  26.     
  27.     public void OnImportsSatisfied()   
  28.     {   
  29.         Console.WriteLine("Import satisfied");   
  30.     }   
  31.     static void Main(string[] args)   
  32.     {   
  33.         Program p = new Program();               
  34.         ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(DebugLogger));   
  35.         ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(Assembly.LoadFile(   
  36.                                 Path.Combine(Directory.GetCurrentDirectory(),   
  37.                                     "MEF101.Implementations.dll")));   
  38.         AggregateCatalog aggCatalog = new AggregateCatalog(assemblyCatalog);   
  39.            CompositionContainer container =  new CompositionContainer(aggCatalog);               
  40.            container.ComposeParts(p);   
  41.         aggCatalog.Catalogs.Add(typeCatalog);   
  42.             foreach (var logger in p.Loggers)   
  43.             {   
  44.                logger.Log("Hello");   
  45.             }   
  46.         aggCatalog.Catalogs.Remove(typeCatalog);   
  47.             foreach (var logger in p.Loggers)   
  48.             {   
  49.                 logger.Log("Hello");   
  50.             }              
  51.     }   
  52. }  

In the above example, recomposition occurs thrice. Once for the initial composition: container.ComposeParts(p); and then once each for the calls to Catalogs.Add and Catalogs.Remove

Export Providers
Up until now we have used catalogs to initialize the CompositionContainer.We can also use one or more Export Providers to initialize the container. The difference is that by providing one or more export providers, MEF will search for exports matching an import in the order in which the exports providers are set on the CompositionContainer. This helps in situations where more than one catalog has part definitions that could satisfy an Import. Let's change the code above to illustrate this
 

 
  1. [Export(typeof(MEF101.Interfaces.ILogger))]   
  2.     class DebugLogger : MEF101.Interfaces.ILogger   
  3.     {   
  4.   
  5.         public string Name   
  6.         {   
  7.             get { return "Debug Logger"; }   
  8.         }   
  9.   
  10.         [Import]   
  11.         public MEF101.Interfaces.ITextFormatter Formatter   
  12.         {   
  13.             get;   
  14.             set;   
  15.         }   
  16.   
  17.         public void Log(string str)   
  18.         {   
  19.             Debug.Write(str);   
  20.         }   
  21.     }   
  22.        
  23.     class Program    
  24.     {   
  25.          [Import(AllowRecomposition=true)]   
  26.         public MEF101.Interfaces.ILogger Logger { getset; }   
  27.   
  28.         static void Main(string[] args)   
  29.         {   
  30.             Program p = new Program();               
  31.             ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(DebugLogger));   
  32.             ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(Assembly.LoadFile(   
  33.                                               Path.Combine(Directory.GetCurrentDirectory(),   
  34.                                               "MEF101.Implementations.dll")));   
  35.             AggregateCatalog aggCatalog = new AggregateCatalog(typeCatalog,assemblyCatalog);   
  36.             CompositionContainer container =  new CompositionContainer(aggCatalog);               
  37.             container.ComposeParts(p);             
  38.         }         
  39.     }  
The call to ComposeParts causes the following error.
More than one export was found that matches the constraint . The reason for this is because there are 2 parts (ConsoleLogger and DebugLogger) that are exported as ILogger and the Program has a single import for a logger instead of a collection of loggers. In this case MEF does not know which export to use for satisfying the import and hence the exception.
By using ExportProviders you can control the resolution order for satisying imports.

 
  1. [Export(typeof(MEF101.Interfaces.ILogger))]   
  2. class DebugLogger : MEF101.Interfaces.ILogger   
  3. {   
  4.   
  5.        public string Name   
  6.        {   
  7.            get { return "Debug Logger"; }   
  8.        }   
  9.   
  10.        [Import]   
  11.        public MEF101.Interfaces.ITextFormatter Formatter   
  12.        {   
  13.            get;   
  14.            set;   
  15.        }   
  16.   
  17.        public void Log(string str)   
  18.        {   
  19.            Debug.Write(str);   
  20.        }   
  21.    }   
  22.   
  23. class Program   
  24. {   
  25.      [Import(AllowRecomposition=true)]   
  26.     public MEF101.Interfaces.ILogger Logger { getset; }   
  27.           
  28.     static void Main(string[] args)   
  29.     {   
  30.         Program p = new Program();               
  31.         ComposablePartCatalog typeCatalog = new TypeCatalog(typeof(DebugLogger));   
  32.         ComposablePartCatalog assemblyCatalog = new AssemblyCatalog(Assembly.LoadFile(   
  33.                                           Path.Combine(Directory.GetCurrentDirectory(),   
  34.                                           "MEF101.Implementations.dll")));   
  35.            CatalogExportProvider assemblyProvider = new CatalogExportProvider(assemblyCatalog);   
  36.            CatalogExportProvider typeProvider = new CatalogExportProvider(typeCatalog);   
  37.            AggregateExportProvider aggProvider = new AggregateExportProvider(   
  38.                assemblyProvider, typeProvider);               
  39.            CompositionContainer container = new CompositionContainer(aggProvider);   
  40.            typeProvider.SourceProvider = container;   
  41.            assemblyProvider.SourceProvider = container;   
  42.         container.ComposeParts(p);   
  43.         p.Logger.Log("Hello");   
  44.        }          
  45.    }  

Since the AggregateExportProvider contains the assemblyProvider first followed by typeProvider, the call to ComposeParts checks the assemblyProvider(and by extension the assemblyCatalog) first and notices that it can satisfy the import defined on Program, stops there and ends up using the ConsoleLogger. If no export was defined in the assemblyProvider then MEF would continue looking into the typeProvider for satisfying the import. Vice-versa, if the order was reversed and typeProvider was set before assemblyProvider then DebugLogger would have been used instead. You can also buid your own export providers by deriving from ExportProvider. This wraps up the coverage of MEF.

MEF 101 - Part1

The Managed Extensibility framework or MEF is a framework released as part of .NET 4 and Silverlight that provides a mechanism to dynamically compose an application at runtime out of loosely coupled parts and provides a variety of mechanisms to discovering these parts. You can think of this as an implementation of a plugin framework that enables plugging in functionality into a container, based on information available at runtime. The most notable example of a MEF client is the Visual Studio 2010 editor which uses MEF to plugin in 3rd party extensions into it's shell proving an easy to use programming model to customize and/or extend the behavior of the IDE.

To wrap my head around MEF and how to leverage the framework to write extensible apps,I'll be going over some of the key features and APIs in MEF over the next several posts. This is the first in the series, and covers the nuts and bolts that MEF is made up of:

Imports and Exports

Imports and Exports is how MEF discovers and marries components that provide a service with components needing a service. The discovery is based on attributes.
A type decorated with the [Export] attribute indicates to MEF that the type is available to any type that needs it's services. Similarly a type needing a service is decorated with the [Import] attribute which conveys to MEF that it is in need of some type which provides the service.

Using Concrete classes

To make things a bit concrete, let's say we have a Logger which uses a TextFormatter to format messages before they are logged.

  1. [Export]  
  2. public class TextFormatter  
  3. {  
  4.     public string Format(string str)  
  5.     {  
  6.         return string.Format("Formatted Message:{0}", str);  
  7.     }  
  8. }  
  9.   
  10. [Export]  
  11. public class ConsoleLogger  
  12. {  
  13.     [Import]  
  14.     TextFormatter Formatter  
  15.     {  
  16.         get;  
  17.         set;  
  18.     }  
  19.   
  20.     public void Log(string str)  
  21.     {  
  22.         string formattedString = Formatter.Format(str);  
  23.         Console.WriteLine(formattedString);  
  24.     }  
  25. }  

The [Export] attribute on the TextFormatter class indicates that the services of this type are available to any type that needs them. The [Import] attribute on the ConsoleLogger indicates that it needs a TextFormatter in order for it to log messages.
Similarly the [Export] attribute on the ConsoleLogger indicates that it's services are available to any type that needs a ConsoleLogger.

  1. class Program  
  2. {  
  3.     [Import]  
  4.     public ConsoleLogger Logger { getset; }  
  5.   
  6.     static void Main(string[] args)  
  7.     {  
  8.         Program p = new Program();  
  9.         CompositionContainer container =   
  10.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));  
  11.           
  12.         container.ComposeParts(p);  
  13.         p.Logger.Log("This is a test");  
  14.     }  
  15. }  

Nowhere in the code above do you see a new TextFormatter() or new ConsoleLogger().
MEF handles the creation for you. In order to do this it needs to discover the types available so that it can satify the imports. It does this using a CompositionContainer which holds onto catalogs of various types. A catalog itself is a container holding types. In the code above we are using one type of catalog called AssemblyCatalog which wraps around a specified assembly and holds onto the types available in the assembly which exports services that can be used for satisfying imports(more on catalogs later). The main program imports the ConsoleLogger, in order to satisfy this import and have MEF create a ConsoleLogger for us we need to tell MEF to go through a composition on the instance of the Program so that it can satify it's imports. This is achieved via the call to container.Composeparts(p). At the end of this step MEF has inspected the current assembly, discovered that TextFormatter exports it's services which are needed in turn by the ConsoleLogger and injected an instance of the TextFormatter into the ConsoleLogger.
Furthermore, it then creates an instance of the ConsolLogger(since it also is an [Export]) and has injected an intance of the ConsoleLogger into the intance of the main program we created.

You might say "Why can't I just use new...?" which is a valid question, considering that everything is currently in one code file/assembly, this will become clearer as we progress further along where not all types are available in the same assembly and there is no static dependency between assemblies(via add ref).

Injecting dependencies via Constructor Injection

Imports can also be specified on constructors so that dependencies can be auto injected into a type. This is specified by using the [ImportingConstructor] attribute on the constructor of the type into which the dependency needs to be injected.

  1. [Export]  
  2.    public class TextFormatter  
  3.    {  
  4.        public string Format(string str)  
  5.        {  
  6.            return string.Format("Formatted Message:{0}", str);  
  7.        }  
  8.    }  
  9.   
  10.    [Export]  
  11.    public class ConsoleLogger  
  12.    {  
  13.        TextFormatter _formatter;  
  14.   
  15.        [ImportingConstructor]  
  16.        public ConsoleLogger(TextFormatter formatter)  
  17.        {  
  18.            _formatter = formatter;  
  19.        }  
  20.   
  21.        public void Log(string str)  
  22.        {  
  23.            string formattedString = _formatter.Format(str);  
  24.            Console.WriteLine(formattedString);  
  25.        }  
  26.    }  
  27.   
  28.    class Program  
  29.    {  
  30.        [Import]  
  31.        public ConsoleLogger Logger { getset; }  
  32.   
  33.        static void Main(string[] args)  
  34.        {  
  35.            Program p = new Program();  
  36.            CompositionContainer container =   
  37.                new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));  
  38.              
  39.            container.ComposeParts(p);  
  40.            p.Logger.Log("This is a test");  
  41.        }  
  42.    }  

In the above code,the TextFormatter is specified as a constructor parameter to the ConsoleLogger. the [ImportingConstructor] attribute indicates to MEF that the TextFormatter needs to be injected into the ConsoleLogger.
As before, the ConsoleLogger has an [Export] attribute and is imported into the main Program as an Import. When the Program is composed, MEF finds the TextFormatter in the AssemblyCatalog (since it's in the current assembly) and uses that to satisfy the import for the ConsoleLogger's constructor.

Exporting types from a Factory class

In the previous examples we've specified the [Export] attribute on the type itself such as on the TextFormatter and ConsoleLogger classes, which in turn causes MEF to instantiate these types for satisfying imports. Instead, if we wanted to have a factory class in charge of creating instances of a type so that you have more control, and specify these types as the ones to use for satisfying an import, we can do something like so:

  1. class FormatterFactory  
  2.    {  
  3.        [Export]  
  4.        public TextFormatter Formatter  
  5.        {  
  6.            get  
  7.            {  
  8.                return new TextFormatter();  
  9.            }  
  10.        }        
  11.    }  

The Formatter property of the FormatterFactory provides a valid export to MEF. If another type needs to Import a TextFormatter, MEF is prepared to instantiate the FormatterFactory and invoke the "Formatter" property in order to satisy the import.

  1. public class TextFormatter   
  2. {  
  3.     public string Format(string str)  
  4.     {  
  5.         return string.Format("Formatted Message:{0}", str);  
  6.     }  
  7. }  
  8.   
  9. [Export]  
  10. public class ConsoleLogger  
  11. {  
  12.     [Import]  
  13.     TextFormatter Formatter  
  14.     {  
  15.         get;  
  16.         set;  
  17.     }               
  18.   
  19.      public void Log(string str)  
  20.     {  
  21.      string formattedString = Formatter.Format(str);  
  22.      Console.WriteLine(formattedString);                                
  23.     }  
  24. }  
  25.   
  26. class Program  
  27. {  
  28.     [Import]  
  29.     public ConsoleLogger Logger { getset; }  
  30.   
  31.     static void Main(string[] args)  
  32.     {  
  33.         Program p = new Program();  
  34.         CompositionContainer container =   
  35.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  36.         container.ComposeParts(p);  
  37.         p.Logger.Log("This is a test");  
  38.     }  
  39. }  

Notice that the [Export] atribute is no longer present on the TextFormatter, and the import in ConsoleLogger is satisfied by the FormatterFactory.

In addition to exporting a type from a property we can also have function exports. i.e the [Export] attribute is tagged onto a method

  1. class FormatterFactory  
  2.     {  
  3.         [Export]  
  4.         public TextFormatter Formatter  
  5.         {  
  6.             get  
  7.             {  
  8.                 return new TextFormatter();  
  9.             }  
  10.         }  
  11.   
  12.         [Export]  
  13.         public TextFormatter GetTextFormatter()  
  14.         {  
  15.             return new TextFormatter();  
  16.         }  
  17.          
  18.         [Export]  
  19.         public void WriteFormattedOutput(string str, Stream stream)  
  20.         {  
  21.             System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();  
  22.             var bytes = encoding.GetBytes(str);  
  23.             stream.Write(bytes,0,bytes.Length);  
  24.         }  
  25.     }  

This enables some interesting scenarios for import, such as lazy evaulation.The function export can be imported into a type by specifying a delegate type that matches the function signature, The signatures of GetTextFormatter() and WriteFormattedOutput(string str, Stream stream) match the delegates Func<TextFormatter> and Action<string, Stream> respectively. We can use these delegates to import these exports into the ConsoleLogger.

  1. public class TextFormatter   
  2. {  
  3.     public string Format(string str)  
  4.     {  
  5.         return string.Format("Formatted Message:{0}", str);  
  6.     }  
  7. }  
  8.   
  9. [Export]  
  10. public class ConsoleLogger  
  11. {  
  12.     [Import]  
  13.     TextFormatter Formatter  
  14.     {  
  15.         get;  
  16.         set;  
  17.     }  
  18.   
  19.     [Import]  
  20.     public Func<TextFormatter> FormatterFunc  
  21.     {  
  22.         get;  
  23.         private set;  
  24.     }         
  25.   
  26.     [Import]  
  27.     public Action<string, Stream> FormatterAction  
  28.     {  
  29.         get;  
  30.         private set;  
  31.     }  
  32.      
  33.     public void Log(string str)  
  34.     {  
  35.         string formattedString = Formatter.Format(str);  
  36.         Console.WriteLine(formattedString);                     
  37.         formattedString = FormatterFunc().Format(str);  
  38.         FormatterAction(str, Console.OpenStandardOutput());  
  39.         Console.WriteLine(formattedString);  
  40.     }  
  41. }  
  42.   
  43. class Program  
  44. {  
  45.     [Import]  
  46.     public ConsoleLogger Logger { getset; }  
  47.   
  48.     static void Main(string[] args)  
  49.     {  
  50.         Program p = new Program();  
  51.         CompositionContainer container =   
  52.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  53.         container.ComposeParts(p);  
  54.         p.Logger.Log("This is a test");  
  55.     }  
  56. }  

Notice the following 2 lines in the Log method
formattedString = FormatterFunc().Format(str);
FormatterAction(str, Console.OpenStandardOutput());
FormatterFunc() invokes the GetTextFormatter() of the Export which gives us a TextFormatter on which we then invoke the Format method.
FormatterAction(str, Console.OpenStandardOutput()) invokes the WriteFormattedOutput method we exported passing in a string and the standard console stream.
This is immensely useful when you don't necessarily want MEF to materialize a value up front but rather provide a handle to a method which on invocation yields a value, but there are other ways to be lazy.

Using Interfaces instead of concrete classes

This far we've been using concrete classes for all exports and imports, i.e we've used ConsoleLogger and TextFormatter. This limits us to working only with these types. To promote loose coupling to any type, MEF also supports importing and exporting via interfaces. We can extract out the following interfaces from the ConsoleLogger and TextFormatter

  1. public interface ITextFormatter  
  2. {  
  3.     string Name { get;}  
  4.     string Format(string str);  
  5. }  
  6.   
  7. public interface ILogger  
  8. {  
  9.     string Name { get;}  
  10.     ITextFormatter Formatter {  getset;}  
  11.     void Log(string str);  
  12. }  

and have both classes implement the respective interface

  1. [Export(typeof(ITextFormatter))]  
  2. public class TextFormatter : ITextFormatter  
  3. {  
  4.     public string Name  
  5.     {  
  6.         get  
  7.         {  
  8.             return "Text Formatter";  
  9.         }  
  10.     }  
  11.   
  12.     public string Format(string str)  
  13.     {  
  14.         return string.Format("Formatted Message:{0}", str);  
  15.     }  
  16. }  
  17.   
  18. [Export(typeof(ILogger))]  
  19. public class ConsoleLogger : ILogger  
  20. {  
  21.     [Import]  
  22.     public ITextFormatter Formatter  
  23.     {  
  24.         get;  
  25.         set;  
  26.     }  
  27.   
  28.     public void Log(string str)  
  29.     {  
  30.         string formattedString = Formatter.Format(str);  
  31.         Console.WriteLine(formattedString);  
  32.     }  
  33.    
  34.     public string Name  
  35.     {  
  36.         get  
  37.         {  
  38.             return "Console Logger";  
  39.         }              
  40.     }  
  41.      
  42. }  

Notice that the Export attributes now export the respective interface types and not the concrete types anymore and the Import attributes are applied on properties of interface types

  1. class Program  
  2. {  
  3.     [Import]  
  4.     public ILogger Logger { getset; }  
  5.   
  6.     static void Main(string[] args)  
  7.     {  
  8.         Program p = new Program();  
  9.         CompositionContainer container =   
  10.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));  
  11.           
  12.         container.ComposeParts(p);  
  13.         p.Logger.Log("This is a test");  
  14.     }  
  15. }  

The main program now just works since MEF resolves the import by instantiating the concrete type on which the Export attribute is defined, types it to the specified interface type and uses the interface type to satisfy imports.

Lazy Imports

It's great that MEF instantiates and injects types to satisfy imports but there are times when you just don't need an import to be satisfied until the point in time at which you need the imported type. The default behavior with the Import attribute is that when a part is composed, imports are satisified and MEF has already created an instance of the type and injected them into your type. Based on the dynamics of how your type is used, the satisifed import may never get used, this means that you paid for something that you did not need but paid for it in anticipation of it's use. It could very well be that the export might be a type which consumes expensive resources, or needs to make a cross domain/ cross process call as part of it's construction, or pull data from a database to initialize itself to a usable state, which means that we paid a "lot" for anticipation. To alleviate this, MEF leverages the Lazy<T> type which is new in .NET 4.0 to allow for lazy instantiaion of types. Using Lazy<T> for an import instead of T, causes MEF to delay the instantiation of the type T until the Value property of the Lazy<T> is accessed.

If we replace the Import in the main Program to use Lazy<ILogger> instead of ILogger, we effectively delay the creation of the ConsoleLogger until the Value property is accessed for the first time.

  1. [Export(typeof(ILogger))]  
  2. public class ConsoleLogger : ILogger  
  3. {  
  4.     [Import]  
  5.     public ITextFormatter Formatter  
  6.     {  
  7.         get;  
  8.         set;  
  9.     }  
  10.   
  11.     public void Log(string str)  
  12.     {  
  13.         string formattedString = Formatter.Format(str);  
  14.         Console.WriteLine(formattedString);  
  15.     }  
  16.    
  17.     public string Name  
  18.     {  
  19.         get  
  20.         {  
  21.             return "Console Logger";  
  22.         }              
  23.     }  
  24.      
  25. }  
  26.   
  27. class Program  
  28. {  
  29.       
  30.   
  31.     [Import]  
  32.     public Lazy<ILogger> Logger { getset; }  
  33.   
  34.     static void Main(string[] args)  
  35.     {  
  36.         Program p = new Program();  
  37.         CompositionContainer container =   
  38.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));  
  39.           
  40.         container.ComposeParts(p);  
  41.         p.Logger.Value.Log("This is a test");  
  42.     }  
  43. }  

If you were to add a watch to the p.Logger.IsValueCreated, you would observe that it returns false.Once the Value property is accessed, IsValueCreated would return true.

Part Creation Policy

By default when MEF satisfies imports for a type(note the pluralization), it shares the instance that it creates from the export across all imports(i.e. it creates a singleton) and this is the default behvior. You can change this behavior on the importing side or the exporting side.

On the exporting side you can specify a PartCreationPolicy attribute on the type being exported indicating that a new instance should be created for satisying an import, by specifying a value of CreationPolicy.NonShared (the default that MEF uses is CreationPolicy.Shared)

  1. [Export(typeof(ILogger))]      
  2. [PartCreationPolicy(CreationPolicy.NonShared)]  
  3. public class ConsoleLogger : ILogger  
  4. {  
  5.     [Import]  
  6.     public ITextFormatter Formatter  
  7.     {  
  8.         get;  
  9.         set;  
  10.     }  
  11.   
  12.     public void Log(string str)  
  13.     {  
  14.         string formattedString = Formatter.Format(str);  
  15.         Console.WriteLine(formattedString);  
  16.     }  
  17.    
  18.     public string Name  
  19.     {  
  20.         get  
  21.         {  
  22.             return "Console Logger";  
  23.         }              
  24.     }  
  25.      
  26. }  

Now, whenever MEF satisfies an import it will create a new instance of the ConsoleLogger instead of a singleton.
You can also specify a value of CreationPolicy.Any which effectively means that the importer decides the creation policy.
This is accomplished by using an overload of the Import attribute which accepts a RequiredCreationPolicy enum,which can have values of Shared,NonShared or Any. This is best illustrated with an example:

  1. [Export(typeof(ILogger))]  
  2. [PartCreationPolicy(CreationPolicy.Any)]  
  3. public class ConsoleLogger : ILogger  
  4. {  
  5.     [Import]  
  6.     public ITextFormatter Formatter  
  7.     {  
  8.         get;  
  9.         set;  
  10.     }  
  11.   
  12.     public void Log(string str)  
  13.     {  
  14.         string formattedString = Formatter.Format(str);  
  15.         Console.WriteLine(formattedString);  
  16.     }  
  17.    
  18.     public string Name  
  19.     {  
  20.         get  
  21.         {  
  22.             return "Console Logger";  
  23.         }              
  24.     }  
  25.      
  26. }  
  27.   
  28. class Program  
  29. {  
  30.     [Import]  
  31.     public ILogger Logger1 { getset; }        
  32.   
  33.     [Import(RequiredCreationPolicy=CreationPolicy.Shared)]          
  34.     public ILogger Logger2 { getset; }  
  35.      
  36.     [Import(RequiredCreationPolicy=CreationPolicy.Shared)]  
  37.     public ILogger Logger3 { getset; }  
  38.   
  39.     [Import(RequiredCreationPolicy=CreationPolicy.NonShared)]  
  40.     public ILogger Logger4 { getset; }  
  41.   
  42.     static void Main(string[] args)  
  43.     {  
  44.         Program p = new Program();  
  45.         CompositionContainer container =   
  46.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));  
  47.           
  48.         container.ComposeParts(p);              
  49.     }  
  50. }  

Since Logger2 and Logger3 have a CreationPolicy of CreationPolicy.Shared, they will share an instance of a ConsoleLogger that MEF creates, Logger1 will also share this instance since the default behavior is Shared if nothing is specified.
Logger4 on the other hand uses a CreationPolicy of CreationPolicy.NonShared, which will cause MEF to create a new instance of the ConsolLogger4 for satisfying the import for Logger4. This instance is not shared with any other import.

Default Values

There may be times where there is no available export to satisfy an import and it might be feasible to settle with a default value for an import (null for a reference type and the default value for a value type).
If a Formatter is not available, the logger can still perform logging like so:

  1. public struct LogInfo  
  2.     {  
  3.         private string _loggedBy ;  
  4.   
  5.         public string LoggedBy  
  6.         {  
  7.             get { return _loggedBy; }  
  8.               
  9.         }  
  10.   
  11.         public LogInfo(string loggedBy)  
  12.         {  
  13.             _loggedBy = loggedBy;  
  14.         }         
  15.     }  
  16.   
  17.     [Export(typeof(ILogger))]  
  18.     public class ConsoleLogger : ILogger  
  19.     {  
  20.         [Import(AllowDefault=true)]  
  21.         public ITextFormatter Formatter  
  22.         {  
  23.             get;  
  24.             set;  
  25.         }  
  26.   
  27.         [Import(AllowDefault = true)]  
  28.         public LogInfo Info  
  29.         {  
  30.             get;  
  31.             set;  
  32.         }         
  33.   
  34.         public void Log(string str)  
  35.         {  
  36.   
  37.             if (Formatter != null)  
  38.             {  
  39.                 string formattedString = Formatter.Format(!string.IsNullOrEmpty(Info.LoggedBy)?  str + " logged by" + Info.LoggedBy: str);  
  40.                 Console.WriteLine(formattedString);  
  41.             }  
  42.         }  
  43.        
  44.         public string Name  
  45.         {  
  46.             get  
  47.             {  
  48.                 return "Console Logger";  
  49.             }              
  50.         }         
  51.     }  
  52.   
  53.     class Program  
  54.     {  
  55.         [Import]  
  56.         public ILogger Logger { getset; }              
  57.   
  58.         static void Main(string[] args)  
  59.         {  
  60.             Program p = new Program();  
  61.             CompositionContainer container =   
  62.                 new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  63.             container.ComposeParts(p);              
  64.         }  
  65.     }  
Note that the [Import] ttribute sets "AllowDefault" to true which causes the Formatter property to be set to null since there are no types which export IFormatter and hence the Formatter is set to null.
Also note that for kicks we have included a struct (LogInfo) and the ConsoleLogger imports this struct. Since this struct is not explicitly exported and "AllowDefault = true", MEF creates a default instance of the struct and sets the "Info" property to this default instance.

Named Exports

Since multiple types can export the same contract you can provide a name for each export so that you can uniquely identify an export on the importing side like so:
  1. [Export("Console Loger",typeof(ILogger))]  
  2. public class ConsoleLogger : ILogger  
  3. {  
  4.     [Import]  
  5.     public ITextFormatter Formatter  
  6.     {  
  7.         get;  
  8.         set;  
  9.     }  
  10.   
  11.     public void Log(string str)  
  12.     {  
  13.         string formattedString = Formatter.Format(str);  
  14.         Console.WriteLine(formattedString);  
  15.     }  
  16.    
  17.     public string Name  
  18.     {  
  19.         get  
  20.         {  
  21.             return "Console Logger";  
  22.         }              
  23.     }         
  24. }  
  25.   
  26. [Export("Debug Logger",typeof(ILogger))]  
  27. public class DebugLogger : ILogger  
  28. {  
  29.     [Import(AllowDefault = true)]  
  30.     public ITextFormatter Formatter  
  31.     {  
  32.         get;  
  33.         set;  
  34.     }  
  35.   
  36.     public void Log(string str)  
  37.     {  
  38.         string formattedString = Formatter.Format(str);  
  39.         Debug.WriteLine(formattedString);              
  40.     }  
  41.   
  42.     public string Name  
  43.     {  
  44.         get  
  45.         {  
  46.             return "Debug Logger";  
  47.         }  
  48.     }  
  49. }  
  50. class Program  
  51. {  
  52.     [Import("Debug Logger")]  
  53.     public ILogger Logger { getset; }              
  54.   
  55.     static void Main(string[] args)  
  56.     {  
  57.         Program p = new Program();  
  58.         CompositionContainer container =   
  59.             new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  60.         container.ComposeParts(p);             
  61.         p.Logger.Log(DateTime.UtcNow.ToString());             
  62.     }  
  63. }  
The main drawback here is that we are now rely on strings for identifying a particular export. There are better ways to achieve the same end effect using attributes as we'll soon see.

Import Many

The main advantage of MEF is building wholes out of parts and building functionality by assembling parts. Multiple types can implement the same contract and export it. You are not limited to importing a single implementation of an export,multiple implementations of a contract can be imported using [ImportMany] You could have different types of loggers,a ConsoleLogger to log to the console, a DebugLogger to log to the debug output and so on. These loggers can all export the ILogger interface. A client application can import many such ILoggers which causes MEF to look for all matching available exports in the configured catalogs to satisfy the import. This is specified using an ImportMany attribute an IEnumerable<ILogger> like so:

  1. [Export(typeof(ITextFormatter))]  
  2.     public class TextFormatter : ITextFormatter  
  3.     {  
  4.         public string Name  
  5.         {  
  6.             get  
  7.             {  
  8.                 return "Text Formatter";  
  9.             }  
  10.         }  
  11.   
  12.         public string Format(string str)  
  13.         {  
  14.             return string.Format("Formatted Message:{0}", str);  
  15.         }  
  16.     }  
  17.   
  18.     [Export(typeof(ILogger))]  
  19.     public class ConsoleLogger : ILogger  
  20.     {  
  21.         [Import]  
  22.         public ITextFormatter Formatter  
  23.         {  
  24.             get;  
  25.             set;  
  26.         }  
  27.   
  28.         public void Log(string str)  
  29.         {  
  30.             string formattedString = Formatter.Format(str);  
  31.             Console.WriteLine(formattedString);  
  32.         }  
  33.        
  34.         public string Name  
  35.         {  
  36.             get  
  37.             {  
  38.                 return "Console Logger";  
  39.             }              
  40.         }         
  41.     }  
  42.   
  43.     [Export(typeof(ILogger))]  
  44.     public class DebugLogger : ILogger  
  45.     {  
  46.         [Import(AllowDefault = true)]  
  47.         public ITextFormatter Formatter  
  48.         {  
  49.             get;  
  50.             set;  
  51.         }  
  52.   
  53.         public void Log(string str)  
  54.         {  
  55.             string formattedString = Formatter.Format(str);  
  56.             Debug.WriteLine(formattedString);              
  57.         }  
  58.   
  59.         public string Name  
  60.         {  
  61.             get  
  62.             {  
  63.                 return "Debug Logger";  
  64.             }  
  65.         }  
  66.     }  
  67.     class Program  
  68.     {  
  69.         [ImportMany]  
  70.         public IEnumerable<ILogger> Loggers { getset; }              
  71.   
  72.         static void Main(string[] args)  
  73.         {  
  74.             Program p = new Program();  
  75.             CompositionContainer container =   
  76.                 new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  77.             container.ComposeParts(p);  
  78.             foreach (var logger in p.Loggers)  
  79.             {  
  80.                 logger.Log(DateTime.UtcNow.ToString());  
  81.             }  
  82.         }  
  83.     }  

Exporting Metadata

So now you've imported multiple exports,great!, you can use these exports as they are, but what if you needed to get a handle to a particular export you've imported. This is where metadata comes in. Each export can be annotated with export metadata which can be used to query the export.The metadata is made available on the import side as a Dictionary<string,object> which can be queried for the attribute name which is the dictionary key, and the value can be checked for the value of interest.
We can mark the ConsoleLogger as the default logger to use by specifying an ExportMetatdata attribute with key name "IsDefault" and value true.

  1. [Export(typeof(ITextFormatter))]  
  2.     public class TextFormatter : ITextFormatter  
  3.     {  
  4.         public string Name  
  5.         {  
  6.             get  
  7.             {  
  8.                 return "Text Formatter";  
  9.             }  
  10.         }  
  11.   
  12.         public string Format(string str)  
  13.         {  
  14.             return string.Format("Formatted Message:{0}", str);  
  15.         }  
  16.     }  
  17.   
  18.     [Export(typeof(ILogger))]  
  19.     [ExportMetadata("IsDefault"true)]  
  20.     public class ConsoleLogger : ILogger  
  21.     {  
  22.         [Import]  
  23.         public ITextFormatter Formatter  
  24.         {  
  25.             get;  
  26.             set;  
  27.         }  
  28.   
  29.         public void Log(string str)  
  30.         {  
  31.             string formattedString = Formatter.Format(str);  
  32.             Console.WriteLine(formattedString);  
  33.         }  
  34.        
  35.         public string Name  
  36.         {  
  37.             get  
  38.             {  
  39.                 return "Console Logger";  
  40.             }              
  41.         }         
  42.     }  
  43.   
  44.     [Export(typeof(ILogger))]  
  45.     [ExportMetadata("IsDefault"false)]  
  46.     public class DebugLogger : ILogger  
  47.     {  
  48.         [Import(AllowDefault = true)]  
  49.         public ITextFormatter Formatter  
  50.         {  
  51.             get;  
  52.             set;  
  53.         }  
  54.   
  55.         public void Log(string str)  
  56.         {  
  57.             string formattedString = Formatter.Format(str);  
  58.             Debug.WriteLine(formattedString);              
  59.         }  
  60.   
  61.         public string Name  
  62.         {  
  63.             get  
  64.             {  
  65.                 return "Debug Logger";  
  66.             }  
  67.         }  
  68.     }  

The client can query for the default logger like so:
  1. class Program  
  2.     {  
  3.         [ImportMany]  
  4.         public IEnumerable<Lazy<ILogger,Dictionary<string,object>>> Loggers { getset; }  
  5.   
  6.         public void LogUsingDefaultLogger(string message)  
  7.         {  
  8.             foreach (var logger in Loggers)  
  9.             {  
  10.                 if (logger.Metadata.ContainsKey("IsDefault"))  
  11.                 {  
  12.                     bool isdefault = (bool)logger.Metadata["IsDefault"];  
  13.                     if (isdefault)  
  14.                     {  
  15.                         logger.Value.Log(message);  
  16.                     }  
  17.                 }  
  18.             }  
  19.         }  
  20.   
  21.         static void Main(string[] args)  
  22.         {  
  23.             Program p = new Program();  
  24.             CompositionContainer container =   
  25.                 new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  26.             container.ComposeParts(p);  
  27.             p.LogUsingDefaultLogger("test");  
  28.         }  
  29.     }  

Note that in order to get to the metadata the Loggers property is of type IEnumerable<Lazy<ILogger,Dictionary<string,object>>>, Lazy<T> exposes a Metadata property which allows us to get to our metadata as shown in LogUsingDefaultLogger

Exporting Metadata the strongly typed way

Working with strings tends to be error prone.Wouldn't it be nicer to export metadata using strong types instead of strings. The good news is you can.You can write a custom attribute class derived from ExportAttribute and includes properties in the derived class which you can then use for finding exports matching your filter criteria
  1. [MetadataAttribute]  
  2. [AttributeUsage(AttributeTargets.Class,AllowMultiple=false)]  
  3. public class LogExportAttribute : ExportAttribute  
  4. {  
  5.     public LogExportAttribute() : base(typeof(ILogger))  
  6.     {  
  7.   
  8.     }  
  9.   
  10.     public bool IsDefault { getset; }  
  11. }  

You can then decorate the loggers with this attribute and set one as the default
  1. [Export(typeof(ILogger))]  
  2. [LogExport(IsDefault=true)]  
  3. public class ConsoleLogger : ILogger  
  4. {  
  5.     [Import]  
  6.     public ITextFormatter Formatter  
  7.     {  
  8.         get;  
  9.         set;  
  10.     }  
  11.   
  12.     public void Log(string str)  
  13.     {  
  14.         string formattedString = Formatter.Format(str);  
  15.         Console.WriteLine(formattedString);  
  16.     }  
  17.    
  18.     public string Name  
  19.     {  
  20.         get  
  21.         {  
  22.             return "Console Logger";  
  23.         }              
  24.     }         
  25. }  
  26.   
  27. [Export(typeof(ILogger))]  
  28. [LogExport(IsDefault=false)]  
  29. public class DebugLogger : ILogger  
  30. {  
  31.     [Import(AllowDefault = true)]  
  32.     public ITextFormatter Formatter  
  33.     {  
  34.         get;  
  35.         set;  
  36.     }  
  37.   
  38.     public void Log(string str)  
  39.     {  
  40.         string formattedString = Formatter.Format(str);  
  41.         Debug.WriteLine(formattedString);              
  42.     }  
  43.   
  44.     public string Name  
  45.     {  
  46.         get  
  47.         {  
  48.             return "Debug Logger";  
  49.         }  
  50.     }  
  51. }  

In order to query for the attribute and reach into it's properties we need to also define an interface with properties corresponding to that of the custom attribute class like so:
  1. public interface ILogExportMetdata  
  2.    {  
  3.        bool IsDefault { get; }  
  4.    }  

We can then consume the metadata(strongly typed) like so:
  1. class Program  
  2.    {  
  3.        [ImportMany]  
  4.        public IEnumerable<Lazy<ILogger,ILogExportMetdata>> Loggers { getset; }  
  5.   
  6.        public void LogUsingDefaultLogger(string message)  
  7.        {  
  8.            foreach (var logger in Loggers)  
  9.            {  
  10.                if (logger.Metadata.IsDefault)  
  11.                {                      
  12.                    logger.Value.Log(message);                      
  13.                }  
  14.            }  
  15.        }  
  16.   
  17.        static void Main(string[] args)  
  18.        {  
  19.            Program p = new Program();  
  20.            CompositionContainer container =   
  21.                new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));              
  22.            container.ComposeParts(p);  
  23.            p.LogUsingDefaultLogger("test");  
  24.        }  
  25.    }  

Behind the scenes MEF performs some clever mapping of the attribute's properties to the interface's properties so that we can access the metadata in a strongly typed way.
This post is getting longer than I anticipated but we've covered the heart of what MEF is about.
In part 2 we'll look at Catalogs.

A simple Dynamic Proxy

Frameworks such as EF4 and MOQ do what most developers consider "dark magic". For instance in EF4, when you use a POCO for an entity you can opt-in to get behaviors such as "lazy-loading" and "change tracking" at runtime merely by ensuring that your type has the following characteristics:

  • The class must be public and not sealed.
  • The class must have a public or protected parameter-less constructor.
  • The class must have public or protected properties
Adhere to this and your type is magically endowed with these behaviors without any additional programming on your part.
Behind the scenes the framework subclasses your type at runtime and creates a "dynamic proxy" which has these additional behaviors and when you navigate properties of your POCO, the framework replaces the POCO type with derived type instances.

The MOQ framework does simlar magic. Let's say you have a simple interface:

 
  1. public interface IFoo  
  2.    {  
  3.        int GetNum();  
  4.    }  

We can verify that the GetNum() was invoked on a mock like so:
 
  1. var mock = new Mock<IFoo>(MockBehavior.Default);  
  2. mock.Setup(f => f.GetNum());  
  3. var num = mock.Object.GetNum();  
  4. mock.Verify(f => f.GetNum());  

Beind the scenes the MOQ framework is generating a dynamic proxy by implementing IFoo at runtime. the call to moq.Object returns the dynamic proxy on which we then call "GetNum" and then verify that this method was invoked.

No dark magic at all, just clever programming is what's going on here, just not visible and hence appears magical!

Let's create a simple dynamic proxy generator which accepts an interface type and dynamically creates a proxy implementing the interface type specified at runtime.

 

 
  1. public static class DynamicProxyGenerator  
  2. {  
  3.     public static T GetInstanceFor<T>()  
  4.     {  
  5.         Type typeOfT = typeof(T);  
  6.         var methodInfos = typeOfT.GetMethods();  
  7.         AssemblyName assName = new AssemblyName("testAssembly");  
  8.         var assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);  
  9.         var moduleBuilder = assBuilder.DefineDynamicModule("testModule""test.dll");  
  10.         var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "Proxy", TypeAttributes.Public);  
  11.   
  12.         typeBuilder.AddInterfaceImplementation(typeOfT);  
  13.         var ctorBuilder = typeBuilder.DefineConstructor(  
  14.                   MethodAttributes.Public,  
  15.                   CallingConventions.Standard,  
  16.                   new Type[] { });  
  17.         var ilGenerator = ctorBuilder.GetILGenerator();  
  18.         ilGenerator.EmitWriteLine("Creating Proxy instance");  
  19.         ilGenerator.Emit(OpCodes.Ret);  
  20.         foreach (var methodInfo in methodInfos)  
  21.         {  
  22.             var methodBuilder = typeBuilder.DefineMethod(  
  23.                 methodInfo.Name,  
  24.                 MethodAttributes.Public | MethodAttributes.Virtual,  
  25.                 methodInfo.ReturnType,  
  26.                 methodInfo.GetParameters().Select(p => p.GetType()).ToArray()  
  27.                 );  
  28.             var methodILGen = methodBuilder.GetILGenerator();               
  29.             if (methodInfo.ReturnType == typeof(void))  
  30.             {  
  31.                 methodILGen.Emit(OpCodes.Ret);  
  32.             }  
  33.             else  
  34.             {  
  35.                 if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum)  
  36.                 {  
  37.                     MethodInfo getMethod = typeof(Activator).GetMethod(/span>"CreateInstance",new Type[]{typeof((Type)});                          
  38.                     LocalBuilder lb = methodILGen.DeclareLocal(methodInfo.ReturnType);  
  39.                     methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);  
  40.                     methodILGen.Emit(OpCodes.Call, typeofype).GetMethod("GetTypeFromHandle"));  ));  
  41.                     methodILGen.Emit(OpCodes.Callvirt, getMethod);  
  42.                     methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);  
  43.                                           
  44.                 }  
  45.                  else  
  46.                 {  
  47.                     methodILGen.Emit(OpCodes.Ldnull);  
  48.                 }  
  49.                 methodILGen.Emit(OpCodes.Ret);  
  50.             }  
  51.             typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);  
  52.         }  
  53.          
  54.         Type constructedType = typeBuilder.CreateType();  
  55.         var instance = Activator.CreateInstance(constructedType);  
  56.         return (T)instance;  
  57.     }  
  58. }  

Dynamic proxies are created by calling into the following main types: AssemblyBuilder, TypeBuilder, Modulebuilder and ILGenerator. These types enable dynamically creating an assembly and emitting .NET modules and types in that assembly, all using IL instructions.
Let's break down the code above a bit and examine it piece by piece

 

 
  1.            Type typeOfT = typeof(T);  
  2.            var methodInfos = typeOfT.GetMethods();  
  3.            AssemblyName assName = new AssemblyName("testAssembly");  
  4.            var assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);  
  5.            var moduleBuilder = assBuilder.DefineDynamicModule("testModule""test.dll");  
  6.            var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "Proxy", TypeAttributes.Public);  

We are instructing the runtime to create an assembly caled "test.dll"and in this assembly we then emit a new module called "testModule". We then emit a new type definition of name "typeName"Proxy into this new module. This is the definition for the "dynamic proxy" for type T

 

 
  1.             typeBuilder.AddInterfaceImplementation(typeOfT);  
  2.             var ctorBuilder = typeBuilder.DefineConstructor(  
  3.                       MethodAttributes.Public,  
  4.                       CallingConventions.Standard,  
  5.                       new Type[] { });  
  6.             var ilGenerator = ctorBuilder.GetILGenerator();  
  7.             ilGenerator.EmitWriteLine("Creating Proxy instance");  
  8.             ilGenerator.Emit(OpCodes.Ret);  

The newly created type implements type T and defines a default parameterless constructor in which we emit a call to Console.WriteLine. This call is not necessary but we do this so that we can see first hand that when the proxy is constructed, when our default constructor is invoked.

 

  1. var methodBuilder = typeBuilder.DefineMethod(  
  2.                    methodInfo.Name,  
  3.                    MethodAttributes.Public | MethodAttributes.Virtual,  
  4.                    methodInfo.ReturnType,  
  5.                    methodInfo.GetParameters().Select(p => p.GetType()).ToArray()  
  6.                    );  

We then iterate over each method declared on type T and add a method definition of the same name into our "dynamic proxy" definition

 

 
  1. if (methodInfo.ReturnType == typeof(void))  
  2. {  
  3.     methodILGen.Emit(OpCodes.Ret);  
  4. }  

If the return type specified in the method declaration of T is void we simply return.

 

 
  1. if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum)  
  2. {                          
  3.     MethodInfo getMethod = typeof(Activator).GetMethod("CreateInstance",  
  4.                                                       new Type[]{typeof(Type)});                          
  5.     LocalBuilder lb = methodILGen.DeclareLocal(methodInfo.ReturnType);                                                
  6.     methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);  
  7.     methodILGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));  
  8.     methodILGen.Emit(OpCodes.Callvirt, getMethod);  
  9.     methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);  
  10. }  

If the return type in the method declaration of T is either a value type or an enum, then we need to create an instance of the value type and return that instance the caller. In order to accomplish that we need to do the following:
1) Get a handle to the Activator.CreateInstance method
2) Declare a local variable which represents the Type of the return type(i.e the type object of the return type) specified on the method declaration of T(obtained from the MethodInfo) and push this Type object onto the evaluation stack.
In reality a RuntimeTypeHandle is what is pushed onto the stack.
3) Invoke the "GetTypeFromHandle" method(a static method in the Type class) passing in the RuntimeTypeHandle pushed onto the stack previously as an argument, the result of this invocation is a Type object (representing the method's return type) which is pushed onto the top of the evaluation stack.
4) Invoke Activator.CreateInstance passing in the Type object from step 3, the result of this invocation is an instance of the value type boxed as a reference type and pushed onto the top of the evaluation stack.
5) Unbox the result and place it into the local variable of the return type defined in step 2

 

  1. methodILGen.Emit(OpCodes.Ldnull);  

If the return type is a reference type then we just load a null onto the evaluation stack

 

  1. methodILGen.Emit(OpCodes.Ret);  

Emit a a return statement to return whatever is on top of the evaluation stack(null or an instance of a value type) back to the caller

 

 
  1. Type constructedType = typeBuilder.CreateType();  
  2. var instance = Activator.CreateInstance(constructedType);  
  3. return (T)instance;  

Now that we have a definition of the "dynamic proxy" implementing all the methods declared on T, we can now create an instance of the proxy type and return that out typed as T.

The caller can now invoke the generator and request a dynamic proxy for any type T.
In our example when the client invokes GetNum() we get back "0". Lets add a new method on the interface called DayOfWeek GetDay()

 
  1. public interface IFoo  
  2.    {  
  3.        int GetNum();  
  4.        DayOfWeek GetDay();  
  5.    }  

When GetDay() is invoked, the "dynamic proxy" returns "Sunday" since that is the default value for the DayOfWeek enum

A client would consume this as follows:

 
  1. static void Main(string[] args)  
  2. {                
  3.     var instance = DynamicProxyGenerator.GetInstanceFor<IFoo>();  
  4.     int num = instance.GetNum();  
  5.     var day = instance.GetDay();
  6.      Console.WriteLine(num);
  7.     Console.WriteLine(day);  
  8.  }  

This is a very trivial example of dynamic proxies, frameworks like MOQ have a way more sophisticated implementation of this paradigm where in you can instruct the framework to create proxies which return specified values for a method implementation as part of Setup.

CLR via C# 3rd Edition is out

Time for some book news update. CLR via C#, 3rd Edition seems to have been out for a little while now. The book was released in early Feb this year, and needless to say my copy is on it’s way. I can barely wait to dig in and chew on the goodies that one of the best technical authors and software professionals I respect has in store. The 2nd edition of the book was an absolute treat and this edition promises to be no less.

Here is a brief description of what’s new and updated from the 2nd edition.

Part I – CLR Basics

Chapter 1-The CLR’s Execution Model

Added about discussion about C#’s /optimize and /debug switches and how they relate to each other.

Chapter 2-Building, Packaging, Deploying, and Administering Applications and Types

Improved discussion about Win32 manifest information and version resource information.

Chapter 3-Shared Assemblies and Strongly Named Assemblies

Added discussion of TypeForwardedToAttribute and TypeForwardedFromAttribute.

Part II – Designing Types

Chapter 4-Type Fundamentals

No new topics.

Chapter 5-Primitive, Reference, and Value Types

Enhanced discussion of checked and unchecked code and added discussion of new BigInteger type. Also added discussion of C# 4.0’s dynamic primitive type.

Chapter 6-Type and Member Basics

No new topics.

Chapter 7-Constants and Fields

No new topics.

Chapter 8-Methods

Added discussion of extension methods and partial methods.

Chapter 9-Parameters

Added discussion of optional/named parameters and implicitly-typed local variables.

Chapter 10-Properties

Added discussion of automatically-implemented properties, properties and the Visual Studio debugger, object and collection initializers, anonymous types, the System.Tuple type and the ExpandoObject type.

Chapter 11-Events

Added discussion of events and thread-safety as well as showing a cool extension method to simplify the raising of an event.

Chapter 12-Generics

Added discussion of delegate and interface generic type argument variance.

Chapter 13-Interfaces

No new topics.

Part III – Essential Types

Chapter 14-Chars, Strings, and Working with Text

No new topics.

Chapter 15-Enums

Added coverage of new Enum and Type methods to access enumerated type instances.

Chapter 16-Arrays

Added new section on initializing array elements.

Chapter 17-Delegates

Added discussion of using generic delegates to avoid defining new delegate types. Also added discussion of lambda expressions.

Chapter 18-Attributes

No new topics.

Chapter 19-Nullable Value Types

Added discussion on performance.

Part IV – CLR Facilities

Chapter 20-Exception Handling and State Management

This chapter has been completely rewritten. It is now about exception handling and state management. It includes discussions of code contracts and constrained execution regions (CERs). It also includes a new section on trade-offs between writing productive code and reliable code.

Chapter 21-Automatic Memory Management

Added discussion of C#’s fixed state and how it works to pin objects in the heap. Rewrote the code for weak delegates so you can use them with any class that exposes an event (the class doesn’t have to support weak delegates itself). Added discussion on the new ConditionalWeakTable class, GC Collection modes, Full GC notifications, garbage collection modes and latency modes. I also include a new sample showing how your application can receive notifications whenever Generation 0 or 2 collections occur.

Chapter 22-CLR Hosting and AppDomains

Added discussion of side-by-side support allowing multiple CLRs to be loaded in a single process. Added section on the performance of using MarshalByRefObject-derived types. Substantially rewrote the section on cross-AppDomain communication. Added section on AppDomain Monitoring and first chance exception notifications. Updated the section on the AppDomainManager class.

Chapter 23-Assembly Loading and Reflection

Added section on how to deploy a single file with dependent assemblies embedded inside it. Added section comparing reflection invoke vs bind/invoke vs bind/create delegate/invoke vs C#’s dynamic type.

Chapter 24-Runtime Serialization

This is a whole new chapter that was not in the 2nd Edition.

Part V – Threading

Chapter 25-Threading Basics

Whole new chapter motivating why Windows supports threads, thread overhead, CPU trends, NUMA Architectures, the relationship between CLR threads and Windows threads, the Thread class, reasons to use threads, thread scheduling and priorities, foreground thread vs background threads.

Chapter 26-Performing Compute-Bound Asynchronous Operations

Whole new chapter explaining the CLR’s thread pool. This chapter covers all the new .NET 4.0 constructs including cooperative cancelation, Tasks, the aralle class, parallel language integrated query, timers, how the thread pool manages its threads, cache lines and false sharing.

Chapter 27-Performing I/O-Bound Asynchronous Operations

Whole new chapter explaining how Windows performs synchronous and asynchronous I/O operations. Then, I go into the CLR’s Asynchronous Programming Model, my AsyncEnumerator class, the APM and exceptions, Applications and their threading models, implementing a service asynchronously, the APM and Compute-bound operations, APM considerations, I/O request priorities, converting the APM to a Task, the event-based Asynchronous Pattern, programming model soup.

Chapter 28-Primitive Thread Synchronization Constructs

Whole new chapter discusses class libraries and thread safety, primitive user-mode, kernel-mode constructs, and data alignment.

Chapter 29-Hybrid Thread Synchronization Constructs

Whole new chapter discussion various hybrid constructs such as ManualResetEventSlim, SemaphoreSlim, CountdownEvent, Barrier, ReaderWriterLock(Slim), OneManyResourceLock, Monitor, 3 ways to solve the double-check locking technique, .NET 4.0’s Lazy and LazyInitializer classes, the condition variable pattern, .NET 4.0’s concurrent collection classes, the ReaderWriterGate and SyncGate classes.

Chunking a List - .NET vs Python

Chunking a List

As I mentioned last time, I'm knee deep in python these days. I come from a statically typed background so it's definitely a mental adjustment. List comprehensions is BIG in Python and having worked with a few of them I can see why. Let's say we need to chunk a list into sublists of a specified size.
Here is how we'd do it in C#

  1.  static class Extensions  
  2.  {  
  3.      public static IEnumerable<List<T>> Chunk<T>(this List<T> l, int chunkSize)  
  4.      {  
  5.          if (chunkSize <0)  
  6.          {  
  7.              throw new ArgumentException("chunkSize cannot be negative""chunkSize");  
  8.          }  
  9.          for (int i = 0; i < l.Count; i += chunkSize)  
  10.          {  
  11.              yield return new List<T>(l.Skip(i).Take(chunkSize));  
  12.          }  
  13.      }   
  14.  }  
  15.   
  16. static void Main(string[] args)  
  17. {  
  18.          var l = new List<string> { "a""b""c""d""e""f","g" };  
  19.   
  20.          foreach (var list in l.Chunk(7))  
  21.          {  
  22.              string str = list.Aggregate((s1, s2) => s1 + "," + s2);  
  23.              Console.WriteLine(str);  
  24.          }  
  25.  }  

A little wordy but still pretty concise thanks to LINQ.We skip the iteration number plus chunkSize elements and yield out a new List of chunkSize elements on each iteration.

The python implementation is a bit more terse.

  1. def chunkIterable(iter, chunkSize):  
  2.     '''Chunks an iterable 
  3.         object into a list of the specified chunkSize 
  4.     '''    
  5.     assert hasattr(iter, "__iter__"), "iter is not an iterable"  
  6.     for i in xrange(0, len(iter), chunkSize):  
  7.         yield iter[i:i + chunkSize]  
  8.   
  9. if __name__ == '__main__':  
  10.     l = ['a', 'b', 'c', 'd', 'e', 'f']  
  11.     generator = chunkIterable(l,2)  
  12.     try:  
  13.         while(1):  
  14.             print generator.next()  
  15.     except StopIteration:  
  16.         pass  
xrange generates elements in the specified range taking in a seed and returning a generator. which can be used in a for loop(much like using a C# iterator in a foreach loop)
Since chunkIterable has a yield statement, it turns this method into a generator as well.
iter[i:i + chunkSize] essentially slices the list based on the current iteration index and chunksize and creates a new list that we yield out to the caller one at a time.
A generator much like an iterator is a state machine and each subsequent call to it remembers the state at which the last call left off and resumes execution from that point.

The caveat to keep in mind is that since variables are not explicitly typed we need to ensure that the object passed in is iterable using hasattr(iter, "__iter__").This way we can perform chunking on any object which is an "iterable", very similar to accepting an IEnumerable in the .NET land

Showing Progress in a .NET Console Application

 

 

Showing the progress of an operation is trivial in rich client applications using a progress bar control of some sort. But what about .NET console apps? The Console class offers 2 static methods Console.Write and Console.WriteLine to write out to the Console, but any subsequent calls to these methods will write the content out at the current location of the cursor.This doesn't really help when you want the progress percentage to refresh in place instead. The trick is to write out the "\r" character in the call to Console.Write so that the cursor is repositioned to the begining of the line after the content is written out. Following is quick implementation of a method which shows percentage of progress, refreshing the percent value in place.

 

 
  1. static void ShowPercentProgress(string message, int currElementIndex, int totalElementCount)   
  2. {   
  3.     if (currElementIndex < 0 || currElementIndex >=totalElementCount)   
  4.     {   
  5.            throw new InvalidOperationException("currElement out of range");   
  6.     }   
  7.     int percent =  (100 * (currElementIndex + 1)) / totalElementCount;   
  8.     Console.Write("\r{0}{1}% complete",message, percent);   
  9.     if (currElementIndex == totalElementCount-1)   
  10.     {   
  11.         Console.WriteLine(Environment.NewLine);   
  12.     }   
  13. }  

and the caller of course.
 

 
  1. static void Main(string[] args)   
  2. {   
  3.   
  4.     for (int i = 0; i < 100; i++)   
  5.     {   
  6.         ShowPercentProgress("Processing...", i, 100);   
  7.         Thread.Sleep(100);   
  8.     }   
  9. }  

That's all there is to it. Happy coding.

UPDATE: This example wouldn't be complete unless I provide an Python implmentation since that's what I'm living and breathing these days.

 

 
  1. def showProgress(message, it = [], currElement = 0):   
  2.     percent = (100 * (currElement + 1)) / len(it)   
  3.     sys.stdout.write("\r")   
  4.     sys.stdout.write("%s %i complete" % (message, percent))   
  5.     sys.stdout.flush()   
  6.   
  7. def process(it, notifyCompletion = showProgress):   
  8.     for item in it:   
  9.         time.sleep(0.5)   
  10.         notifyCompletion("Processing", it, it.index(item))            
  11.   
  12. if __name__ == "__main__":      
  13.     process(range(10));   

UPDATE(4/27/11): I received a comment requesting a precise usage example of the above for copying files
The code below has been adapted to achieve that.
Disclamer: If you use this code, please add proper error handling as you see fit.

 

 
  1. class Program   
  2. {    
  3.        static void Copyfiles(   
  4.             string[] sourceFiles,   
  5.             string destPath,                
  6.             Action<string,long,long> reportProgress,   
  7.             int blockSizeToRead = 4096)   
  8.         {               
  9.             if(!Directory.Exists(destPath))   
  10.             {   
  11.                throw new DirectoryNotFoundException(destPath);   
  12.             }   
  13.             foreach (var sourceFile in sourceFiles)   
  14.             {   
  15.                 if (!File.Exists(sourceFile))   
  16.                 {   
  17.                     Console.WriteLine("{0} not found.. skipping",sourceFile);   
  18.                 }   
  19.                 FileInfo sourceFileInfo = new FileInfo(sourceFile);   
  20.                 string message = string.Format("Copying {0} ", sourceFileInfo.Name);   
  21.                 string destFilePath = Path.Combine(destPath, sourceFileInfo.Name);   
  22.                 byte[] buffer = new byte[blockSizeToRead];   
  23.                 using (var destfs = File.OpenWrite(destFilePath))   
  24.                 {   
  25.                     using (var sourcefs = File.OpenRead(sourceFile))   
  26.                     {                           
  27.                         int bytesRead,totalBytesRead = 0;   
  28.                         while ((bytesRead = sourcefs.Read(buffer, 0, buffer.Length - 1)) > 0)   
  29.                         {   
  30.                             destfs.Write(buffer, 0, bytesRead);   
  31.                             totalBytesRead += bytesRead;   
  32.                             if (reportProgress != null)   
  33.                             {   
  34.                                 reportProgress(message, totalBytesRead, sourceFileInfo.Length);   
  35.                             }   
  36.                         }   
  37.                     }   
  38.                 }   
  39.             }   
  40.         }   
  41.   
  42.         static void ShowPercentProgress(string message, long processed, long total)   
  43.         {   
  44.                
  45.             long percent = (100 * (processed + 1)) / total;   
  46.             Console.Write("\r{0}{1}% complete", message, percent);   
  47.             if (processed >= total - 1)   
  48.             {   
  49.                 Console.WriteLine(Environment.NewLine);   
  50.             }   
  51.         }     
  52.         static void Main(string[] args)   
  53.         {   
  54.             var files = Directory.GetFiles(@"C:\temp\source");   
  55.             Copyfiles(files, @"C:\temp\dest", ShowPercentProgress);   
  56.         }   
  57. }  

 

 

Covariance and Contravariance in C# 4.0

C# 4.0 introduces the notion of Covariance and Contravariance of generic type parameters for interfaces and delegate types. Eric Lippert has put together a bunch of posts that goes into details of the why and how, an excellent read but not for the faint of heart. I would strongly suggest reading these posts to get a firm grounding and a better appreciation of this feature. It took me a while to get my head wrapped around this, especially since none of the VS2010 Betas were not out at the time and there was no way to try out any code. Now that I have Beta2 of VS2010 at hand I decided to try out some code samples first hand and solidify my understanding of the feature.

Suppose we have the following inheritance hierarchy:

 
  1. interface IAnimal  
  2. {  
  3.     void Speak();  
  4. }  
  5.   
  6. class Whale : IAnimal  
  7. {  
  8.      public void  Speak()  
  9.     {  
  10.          Console.WriteLine("I'm a Whale");  
  11.     }  
  12. }  
  13.   
  14. class Giraffe : IAnimal  
  15. {  
  16.     public  void Speak()  
  17.     {  
  18.         Console.WriteLine("I'm a Giraffe");  
  19.     }  
  20. }  

 

and a processor to process animals:

 
  1. interface IProcessor<T>  
  2. {  
  3.     void Process(IEnumerable<T> ts);     
  4. }  
  5.   
  6. class Processor<T> : IProcessor<T> where T:IAnimal  
  7. {  
  8.     public void Process(IEnumerable<T> ts)  
  9.     {  
  10.         foreach (var t in ts)  
  11.         {  
  12.             t.Speak();  
  13.         }  
  14.     }          
  15. }  

 

It would be natural to be able to create a Processor to process any kind of animal, but the following code does not compile today on the C# 3.0 compiler

 
  1. List<Giraffe> giraffeList = new List<Giraffe> { new Giraffe() };  
  2. IProcessor<IAnimal> proc = new Processor<IAnimal>();  
  3. proc.Process(giraffeList);  
We have to add a silly"OfType<IAnimal>" cast to make it work:
 
  1. List<Giraffe> giraffeList = new List<Giraffe> { new Giraffe() };  
  2. IProcessor<IAnimal> proc = new Processor<IAnimal>();  
  3. proc.Process(giraffeList.OfType<IAnimal>());  

 

In C# 4.0 no such cast is needed and everything just works as expected. Why? because in .NET 4.0 IEnumerable<T> is covariant in it's type parameter T, this is what the definition looks like

 
  1. public interface IEnumerable<out T> : IEnumerable  
  2. {  
  3. ....  
  4. ....  
  5. }   
The "out" keyword is what makes the "T" covariant; which means that you can pass in any type which is more derived than "T" as the type argument, hence we can pass in IEnumerable<Giraffe> or IEnumerable<Whale> to the Process method which accepts an IEnumerable<IAnimal> and everything just works as expected in a type safe way.

 

You can define your own covariant types to allow for such conversions.
Consider the following generic class definition to create instances of a specified type
 
  1. interface IFactory<out T>  
  2. {  
  3.     T CreateInstance();  
  4. }  
  5.   
  6. class Factory<T> : IFactory<T> where T: new()  
  7. {  
  8.     public T CreateInstance()  
  9.     {  
  10.         return new T();  
  11.     }          
  12. }  
IFactory<T> is covariant in T so we can treat a Factory<Giraffe> as an IFactory<IAnimal>. This allows us to treat factories of types in the same inheritance chain uniformly like so:
 
  1. IFactory<IAnimal> giraffeFactory = new Factory<Giraffe>();  
  2. IFactory<IAnimal> whaleFactory = new Factory<Whale>();  
  3.   
  4. List<IFactory<IAnimal>> factories = new List<IFactory<IAnimal>>{ giraffeFactory, whaleFactory };  
  5. foreach (var factory in factories)  
  6. {  
  7.     factory.CreateInstance().Speak();  
  8. }  

Note that it is illegal for a covariant type parameter to occur in an input position, it can only occur in output positions such as return type of a method in the type. This restriction is key in making covariance work,allowing the type parameter in an input position would break covariance. How you might ask. Imagine if the following illegal code were legal and you could specify T in an input position.

 
  1. interface IFactory<out T>    
  2. {  
  3.     T CreateInstance();  
  4.     T CreateInstanceFrom(T t);  
  5. }  
  6.   
  7. class Factory<T> : IFactory<T>  
  8.     where T : new()  
  9.     where T : ICloneable  
  10. {  
  11.     public T CreateInstance()  
  12.     {  
  13.         return new T();  
  14.     }  
  15.     public T CreateInstanceFrom(T t)  
  16.     {  
  17.         return (T)t.Clone();  
  18.     }  
  19.   
  20. }  
We added a constraint to the factory class to constrain the type parameter to support ICloneable and added a new method CreateInstanceFrom which accept the instance to clone. Now what happens if we do the following:
 
  1. IFactory<IAnimal> giraffeFactory = new Factory<Giraffe>();  
  2. giraffeFactory.CreateInstanceFrom(new Whale())  
Oh my! we just passed in a Whale to clone a Giraffe, and we'd bomb a runtime.
It is precisely for this reason that a covariant type parameter can only occur in output positions(hence the keyword out) and the runtime error is now a compile time error.

 

But what if we wanted to have the type paramter in an input position to get the benefits variance has to offer, enter contrvariance which is the dual of covariance. In that a type argument can be safely replaced by a more derived type but only in an input position.

If T appears ONLY in an input position (such as a parameter in methods of IProcessor) then we can mark T as contravariant using the in keyword, allowing us to substitute any sub type of T.

 
  1. interface IProcessor<in T>  
  2. {  
  3.     void Process(IEnumerable<T> ts);  
  4. }  

This makes assignments such as the following legal.

 
  1. List<Giraffe> giraffes = new List<Giraffe> { new Giraffe() };  
  2. List<Whale> whales = new List<Whale> { new Whale() };  
  3. IProcessor<IAnimal> animalProc = new Processor<IAnimal>();  
  4. IProcessor<Giraffe> giraffeProcessor = animalProc;  
  5. IProcessor<Whale> whaleProcessor = animalProc;  
  6. giraffeProcessor.Process(giraffes);  
  7. whaleProcessor.Process(whales);  

 

Finally let's look at variance in delegate types. Consider the following delegate definition and it's subsequent usage

 
  1. public delegate void MyAction<in T>(T t);  
  2. ........  
  3. .......  
  4. .........  
  5.  MyAction<IAnimal> animalAction = a => a.Speak();  
Since T is contravariant, we can treat MyAction<IAnimal> as MyAction<Giraffe> since Giraffe is more derived than IAnimal
  1. MyAction<Giraffe> rafAction = animalAction;  

 

Now let's combine both co and contravariance, consider the following delegate

 
  1. public delegate T2 MyFunc<in T1,out T2>(T1 t1);  
T2 is covariant and T1 is contravariant and hence we can use T1 or any subtypes of T1 as the first generic type paramter and T2 or any of its base types as the second generic type parameter, allowing us to use assignments such as the following with full type safety
 
  1. Func<IAnimal, Giraffe> func = a => a as Giraffe;  
  2. Func<Giraffe, IAnimal> funcG = func;  

 

Covariance and Contravariance may sound like a mouthful and daunting to understand but at its core it's quite simple to grasp once you understand its purpose, it enables writing generic code more naturally and allows safe type coercions. That's it for today. Happy coding.

T4 template consuming a WCF service

It’s been a while since I’ve blogged since things have been crazy busy. I finally decided to kick myself and do a post so without further ado, the problem at hand:
A co-worker of mine asked me whether its possible to dynamically create a type from some data he is receiving from a WCF service (over HTTP).
My natural response was, why would you need to do that since Visual Studio creates a proxy from the metadata exposed by the service and the return types would typically be DataContracts.
Well, it turns out that instead of returning a strongly typed domain specific object, the service is returning a Dictionary<string,string> where the Key represents an attribute and the Value represents the value of the attribute.

This has obvious problems:

 

  • Nothing is strongly typed
  • No contract versioning
  • The service could return a variable number of fields
A naive approach is to inspect the data returned by the service and hand code a class with properties based on the type of each key in the Dictionary.
For example, if the Dictionary contained the following KeyValuePairs.
{“Name”,”Jon Smith”}
{“Age”,”20”}
{“Zip”,”90876”}

The class definition would look something like this:
 
  1. public class User  
  2. {  
  3.   public string Name {get;set;}  
  4.   public int Age {get;set;}  
  5.   public int Zip {get;set;}  
  6. }  

That’s fine when you have a couple of KeyValuePairs but what if you had 10 or 20, it gets unwieldy very quickly.
Enter T4 templates, a slick way to generate code for repetitive tasks. I'd never written a T4 template before so I figured this would be a nice excuse to dabble in it a little.
 

Let’s create a simple service to simulate some data, nothing too fancy
 

 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Runtime.Serialization;  
  5. using System.ServiceModel;  
  6. using System.Text;  
  7.   
  8. namespace T4WCFService  
  9. {  
  10.     [ServiceContract]  
  11.     public interface IT4WCFService  
  12.     {  
  13.   
  14.         [OperationContract]  
  15.         Dictionary<string,string> GetUser(string userID);         
  16.     }  
  17. }  
and its implementation...
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Runtime.Serialization;  
  5. using System.ServiceModel;  
  6. using System.Text;  
  7.   
  8. namespace T4WCFService  
  9. {  
  10.     public class T4Service : IT4WCFService  
  11.     {  
  12.  
  13.         #region IT4WCFService Members  
  14.   
  15.         public Dictionary<stringstring> GetUser(string userID)  
  16.         {  
  17.             if (userID == "jsmith")  
  18.             {  
  19.                 return new Dictionary<stringstring>   
  20.                         {   
  21.                             { "Name""Jack smith" },  
  22.                             { "Age""30" },   
  23.                             { "City""San francisco" },  
  24.                             { "State""CA"  },   
  25.                             { "Zip""94061"  },  
  26.                             { "Country""USA"  }   
  27.   
  28.   
  29.                         };    
  30.             }  
  31.             if (userID == "jasmith")  
  32.             {  
  33.                 return new Dictionary<stringstring>   
  34.                         {   
  35.                             { "Name""Jane smith" },  
  36.                             { "Age""28" },   
  37.                             { "City""Portland" },  
  38.                             { "State""OR"  },   
  39.                             { "Zip""98685"  },  
  40.                             { "Country""USA"  }   
  41.                         };  
  42.             }  
  43.             return new Dictionary<stringstring>();              
  44.         }  
  45.  
  46.         #endregion  
  47.     }  
  48. }  

The service just simulates returning some dummy users based on a userID and returns an empty Dictionary if no matching user is found, and it’s exposed using
WSHttpBinding

The <system.servicemodel> looks as follows:
 
  1. <system.serviceModel>  
  2.   <services>  
  3.     <service behaviorConfiguration="T4WCFService.Service1Behavior"  
  4.       name="T4WCFService.T4Service">  
  5.       <endpoint address="WsHttpT4Service" binding="wsHttpBinding" name="WsHttpT4Service"  
  6.         contract="T4WCFService.IT4WCFService">  
  7.         <identity>  
  8.           <dns value="localhost" />  
  9.         </identity>  
  10.       </endpoint>  
  11.       <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />  
  12.       <endpoint address="basicHttpTService" binding="basicHttpBinding"  
  13.         name="basicHttpTService" contract="T4WCFService.IT4WCFService" />  
  14.       <host>  
  15.         <baseAddresses>  
  16.           <add baseAddress="http://WCFServices" />  
  17.         </baseAddresses>  
  18.       </host>  
  19.     </service>  
  20.   </services>  
  21.   <behaviors>  
  22.     <serviceBehaviors>  
  23.       <behavior name="T4WCFService.Service1Behavior">  
  24.         <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->  
  25.         <serviceMetadata httpGetEnabled="true"/>  
  26.         <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->  
  27.         <serviceDebug includeExceptionDetailInFaults="false"/>  
  28.       </behavior>  
  29.     </serviceBehaviors>  
  30.   </behaviors>  
  31. </system.serviceModel>  

If you(like me) have never created a T4 template before, I’d strongly suggest reading this article first.

Welcome back, now that you know how to create a simple T4 template, let’s get started.
T4 enables writing reusable modules that can be consumed from other T4 modules. For the purpose of this exercise I decided to create a template which encapsulates invoking a WCF service and returning the result back to the caller.

Create a new Console Application and add a service reference to the service we created above, also add a new T4 file to your project called WCFServiceInvoker.tt

T4_WCFServiceInvoker

Double click on WCFServiceInvoker.tt and the file should open up in markup mode.Delete the default code in the .tt file and add the following code:

 

 
  1. <#@ template language="C#v3.5"#>  
  2. <#@ output extension=".cs"#>   
  3. <#@ assembly name ="System.ServiceModel" #>   
  4. <#@ import namespace="System.Collections.Generic"#>  
  5. <#@ import namespace="System.Reflection"#>  
  6. <#@ import namespace="System.ServiceModel.Channels"#>  
  7. <#@ import namespace="System.ServiceModel"#>  
  8.   
  9. <#+  
  10.     public class WCFServiceInvoker<TInterfaceType,TReturnType> where TReturnType:class  
  11.     {  
  12.       public string EndPointAddress {get;set;}  
  13.       public string EndPointName {get;set;}  
  14.       public Type ServiceInterfaceType {get;set;}        
  15.       public Binding Binding {get;set;}  
  16.       public string MethodName {get;set;}  
  17.       public object[] Parameters {get;set;}  
  18.       public TReturnType InvokeMethod()  
  19.       {  
  20.             EndpointAddress endpoint = new EndpointAddress(EndPointAddress);  
  21.             Type typeDef = typeof(ChannelFactory<>).MakeGenericType(typeof(TInterfaceType));  
  22.             var typeInst = Activator.CreateInstance(typeDef,new object[]{Binding,endpoint});  
  23.             var channel = typeInst.GetType().InvokeMember("CreateChannel", BindingFlags.InvokeMethod,null, typeInst, null);  
  24.             var results = channel.GetType().InvokeMember(MethodName, BindingFlags.InvokeMethod, null,channel, Parameters);  
  25.             return results as TReturnType;  
  26.       }  
  27.         
  28.     }  
  29. #>  

There is a lot going on here.

  • The template and output directives indicate that the code is written in C# and the generated file needs to be have an extension of .cs.
     
  • The <#@assembly> directive is similar to an “Add Reference” in Visual Studio, it allows for referencing external assemblies.
  • The <#@import> directive is similar to a “using” statement, in that it brings the types in the specified namespace in scope so that the template can avail of them.
  • The <#+ #> directive is called Class feature block and it allows for writing class definitions within the template.
    This allows for encapsulating reusable logic.
    NOTE: The class definitions in this block are not emitted out to the final .cs file.
  • The WCFServiceInvoker class contains a bunch of properties, whose values(when set) are used for invoking a specified service dynamically.
  • The type parameters “TInterfaceType” represents the type of the interface on which the method specified in the "MethodName" parameter will be invoked.
  • The type parameter “TReturnType” represents the type of the result returned from the method call.

Using “TInterfaceType” we dynamically create a type definition for ChannelFactory<T> using reflection, and then create an instance of it, on which we then call CreateChannel which in turns returns us an instance of a type which implements TInterfaceType. Once we have a “TInterfaceType” instance we then go ahead and invoke the specified “MethodName” with the parameters specified in the “Parameters” object[] property and get the result back which is typed to “TReturnType” and returned to the caller.

Phew! that’s a mouthful and we are not done yet. For now just keep in mind that this template is merely a helper which encapsulates the details on dynamically invoking a WCF service in a strongly typed manner.

Now onto the main task of writing a template to solve our problem.

Add another T4 template to the project and call it UserClass.tt
T4_UserClass

As before delete the code from the .tt file and add the following:
 

 
  1. <#@ assembly name ="System.ServiceModel" #>   
  2. <#@ assembly name ="T4WCFService.dll" #>   
  3. <#@ assembly name ="System.ServiceModel" #>   
  4. <#@ import namespace="System.Collections.Generic"#>  
  5. <#@ import namespace="System.Reflection"#>  
  6. <#@ import namespace="System.ServiceModel.Channels"#>  
  7. <#@ import namespace="System.ServiceModel"#>  
  8. <#@ import namespace="T4WCFService"#>  
  9. <#@ include file="WCFServiceInvoker.tt" #>  
  10. using System.Collections.Generic;  
  11. namespace T4ClassFromDict  
  12. {  
  13.     public class User  
  14.     {  
  15.         <#  
  16.         WCFServiceInvoker<IT4WCFService,Dictionary<string,string>> invoker = new WCFServiceInvoker<IT4WCFService,Dictionary<string,string>>();  
  17.         invoker.EndPointAddress = "http://localhost:24551/Service1.svc/WsHttpT4Service";  
  18.         invoker.EndPointName = "WsHttpT4Service";  
  19.         invoker.ServiceInterfaceType = typeof(IT4WCFService);  
  20.         invoker.Binding = new WSHttpBinding();  
  21.         invoker.MethodName = "GetUser";  
  22.         invoker.Parameters = new object[]{"jsmith"};      
  23.         Dictionary<string,string> result = invoker.InvokeMethod();  
  24.         #>  
  25.          <#foreach(KeyValuePair<string,string> item in result){  
  26.          #>  
  27.            
  28.          public <#= item.Key.GetType().Name.ToLower()#> <#=item.Key#>  
  29.          {  
  30.              get;         
  31.              set;  
  32.          }  
  33.          <#}#>  
  34.            
  35.          public static User GetUser(Dictionary<string,string> dict)  
  36.          {  
  37.              var user = new User();  
  38.              foreach(KeyValuePair<string,string> kvp in dict)  
  39.              {  
  40.                 typeof(User).GetProperty(kvp.Key).SetValue(user,kvp.Value,null);                  
  41.              }  
  42.              return user;  
  43.          }  
  44.     }  
  45. }  

We've included the template file we created before so that we can reuse it to invoke any WCF Service.
We then proceed to create an instance of WCFServiceInvoker and set it's properties to invoke the WCF service we've created.
The result of "invoker.InvokeMethod()" is a Dictionary<string,string> which we then loop through creating public properties.

We use the type of the Key as the type of the property and the Key itself as the property name.
 

We've also created the definition of factory method which accepts a Dictionary<string,string> and returns a User object.

Note that we've added a direct reference to the service assembly in this template so that we can get a reference to IT4WCFService.
This is just to keep the example simple, ideally you would want to seperate the interface and implementation assemblies and have a reference to just the interface assembly.

T4 templates are executed typically when saved or by right clicking on the .tt file and selecting "Run Custom Tool".
Before running the template, ensure that the WCF service is up and running.

On running/saving the template, the following class definition is generated.
 

 

 
  1. using System.Collections.Generic;  
  2. namespace T4ClassFromDict  
  3. {  
  4.     public class User  
  5.     {  
  6.                            
  7.          public string Name  
  8.          {  
  9.              get;         
  10.              set;  
  11.          }  
  12.                    
  13.          public string Age  
  14.          {  
  15.              get;         
  16.              set;  
  17.          }  
  18.                    
  19.          public string City  
  20.          {  
  21.              get;         
  22.              set;  
  23.          }  
  24.                    
  25.          public string State  
  26.          {  
  27.              get;         
  28.              set;  
  29.          }  
  30.                    
  31.          public string Zip  
  32.          {  
  33.              get;         
  34.              set;  
  35.          }  
  36.                    
  37.          public string Country  
  38.          {  
  39.              get;         
  40.              set;  
  41.          }  
  42.                    
  43.          public static User GetUser(Dictionary<string,string> dict)  
  44.          {  
  45.              var user = new User();  
  46.              foreach(KeyValuePair<string,string> kvp in dict)  
  47.              {  
  48.                 typeof(User).GetProperty(kvp.Key).SetValue(user,kvp.Value,null);                  
  49.              }  
  50.              return user;  
  51.          }  
  52.     }  
  53. }  

A client can then use the generates class as follows:
 

 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net;  
  6. using System.IO;  
  7. using System.ServiceModel;  
  8. using T4WCFService;  
  9. using System.Reflection;  
  10.   
  11.   
  12. namespace T4ClassFromDict  
  13. {    
  14.   
  15.     class Program  
  16.     {  
  17.   
  18.         public string Foo { getset; }  
  19.         static void Main(string[] args)  
  20.         {            
  21.             var client = new T4Service.T4WCFServiceClient("WsHttpT4Service");  
  22.             var data = User.GetUser(client.GetUser("jsmith"));  
  23.         }  
  24.     }  
  25. }  

 

NOTE: The console app hosting the project has a direct project reference to WCF service project since it needs the IT4WCFService definition. and since T4 engine is running inside Visual studio it locks the assembly, so rebuilding the WCF service after template generation does not work.
As mentioned previously the solution to this is to have seperate assemblies for the interface and service implementation.
Download Code

Why no Anonymous Iterators in C#

Yes I’m a language geek and yes the awesome  Eric Lippert is my idol when it comes to anything C# and the CLR, I’ve been following his blog for a long time and recently Eric wrote an awesome series on the how and why of Iterator Blocks. The entire series is very well worth a read, but then again I’d read almost anything Eric writes from why the sky is blue to why the Falkirk Wheel has horns.

I had posed a question on this post about why there are no anonymous iterators in C#. Eric provided a very good answer to that comment and I was highly flattered when he did a follow up post on this very question here.

Thanks Eric!