.NET Workload Indirection with Managed Extensibility Framework and Task Parallel Library

by Jeffrey Juday

Jeffrey Juday shows you how to bring Task Parallel Library (TPL) and Managed Extensibility Framework (MEF) together to manage a workload on the .NET platform.

Applications like Windows Services and Web Services often have a demanding workload and sophisticated extensibility needs. Managing a workload on the .NET platform often means utilizing the Task Parallel Library (TPL) classes. .NET extensibility capabilities span many components, but increasingly popular extensibility features are found in the Managed Extensibility Framework (MEF). Bringing TPL and MEF together is this article's focus. Walking through a sample application, I'll demonstrate a loosely coupled and extensible TPL and MEF solution.

MEF - CompositonContainers, Catalogs, and Attributes

A complete MEF introduction is beyond the scope of this article. So the overview will center on some main ideas. You'll find a more complete MEF introduction in the Resources section at the end of the article.

MEF includes classes and attributes that support component discovery and extensibility. MEF allows applications to load components without baking references into the compiled application. Two simple ideas underlie MEF solutions.

  • Components providing functionality are called "Exports".
  • Components "consuming" an "Export" are called "Imports".

So, for example, a class within an assembly may "export" functionality that another class in another assembly "imports".

Some core MEF components are described below:

  • Import and Export attributes designate the components a developer will consume or provide.
  • A CompositionContainer gathers the exports and matches exports to imports. CompositionContainers can, for example, instantiate class instances and apply the instance on a class Property.
  • CompositionContainers read from Catalogs. MEF components can be housed in Directories and Assemblies. A CompositionContainer works through, for example, a DirectoryCatalog to gather all MEF components in a Directory.

The following code from the sample solution demonstrates how CompositionContainers, Catalogs, and Attributes work together.

private IEnumerable<ITaskInstanceFactory> Instances { get; set; }
public Host(string extLocation)
    this.Instances = null;
    var catalog = new DirectoryCatalog(extLocation);
    using (var container = new CompositionContainer(catalog))
            //This will populate the Instance Import
        catch (CompositionException compositionException)
public class SupplyTaskInstances2 : ITaskInstanceFactory

ITaskInstanceFactory and IRequest interfaces follow below.

public interface ITaskInstanceFactory 
    Task<TReply> StartNewOne<TRequest, TReply>(TRequest request, CancellationToken token) where TRequest : IRequest;
    /// <summary>
    /// An instance may support more than one
    /// </summary>
    List<int> IDs { get; }
public interface IRequest
    int ID { get; }

The Host class Instances Property Imports an ITaskInstanceFactory collection and the Import is satisfied from the Exported SupplyTaskInstance class. CompositionContainer ComposeParts method applies the instances to the Instances Property on the Host class.

MEF's role in the solution may seem obvious. A highly decoupled solution could not exist if applications had to maintain references to one another. The role TPL plays in the solution is more subtle.

TPL Overview

The core of TPL is embodied in the Task. A complete Task overview can be found in the resources at the end of this article. I like to think of Tasks as the chunks of work an application performs. If you're familiar with Threading and the Thread Pool; think of Tasks as an extension on the Thread Pool concept. Tasks are a context for an Action or Funct delegate. Tasks encapsulate the operation Result and the operation failure. Tasks can be chained together in Continuations. Tasks also support Cancellation. Task Parallel Library (TPL) includes TaskSchedulers that apply heuristics orchestrating a Task collection workload.

Developers who want to embrace all the power on a modern CPU need compose a workload into Tasks. Future Language feature enhancements will make developing with Tasks easier, but the enhancements will not eliminate the need to think about problems like, for example, shared memory.

Following is Task usage code from the sample application.

if (typeof(TRequest) == typeof(Request3))
    funct = new Func<TReply>(() =>
        Console.WriteLine("Starting " + request.ID.ToString());
        SpinWait.SpinUntil(() => { return false; }, 3000);
        Console.WriteLine("Completed 3 second Task");
        return (TReply)(object)new Reply3();
task = new Task<TReply>(funct);
return task;

The code demonstrates allocating and Starting a Task. As stated earlier, Tasks are queued to a Scheduler and run Asynchronously. In the following example; a Task consumer waits for the multiple Tasks to complete.

Task<Reply1> t1 = null;
Task<Reply2> t2 = null;
Task<Reply3> t3 = null;
int itr = 3;
if (Directory.Exists(extLocation))
    for (int i = 0; i < itr; ++i)
        t1 = host.StartNewOne<Request1, Reply1>(new Request1(), src.Token);
        t2 = host.StartNewOne<Request2, Reply2>(new Request2(), src.Token);
        t3 = host.StartNewOne<Request3, Reply3>(new Request3(), src.Token);
        var tList = new Task[3] { t1, t2, t3 };
        Console.WriteLine("Completed iteration " + i.ToString());

At first glance, Tasks may appear to be overkill for this simple solution. To understand the compositional power within Tasks it may help to contrast it with a Method based solution.

Tasks vs. Methods

Why even consider using Tasks in the first place? This solution could have easily been implemented with delegates or purely generic methods. Most likely, a Windows Service or Web Service would've required some sort of Threading construct. That could mean a number of options. A Windows Service could have used the Thread Pool and a WCF Web Service could have relied on WCF instancing. So, once a developer begins to think about Threads; a pure Method solution begins looking like a Task based solution.

Taking the Web Service example; ideally a developer should be using WCF's Asynchronous Programming Model (APM). Synchronous Web Services tie up IO resources waiting for operations to complete. APM solutions interleave IO resources consuming fewer server resources. Tasks support the APM model. In fact a Task nicely encapsulates an IAsyncResult.

An application requiring MEF would not be trivial. Instead of a handful of operations; a likely solution would have hundreds of operations. Many of these operations may be interdependent on one another. So, for example, a developer may submit multiple operations and wait for them all to complete. Operations may impose time limits with varying values. Anticipating all the overload options on a method is not feasible. Most of what is needed is provided in a Task. What is not provided in a Task can be implemented using, for example, Continuations or Cancellations.


MEF provides some simple, but powerful extensibility options. TPL has been built for managing workloads on modern CPUs. Together they're a potent workload indirection solution.


MEF Introductions

A Peek into The Managed Extensibility Framework (MEF) in .NET Framework 4.0

Managed Extensibility Framework Overview

Task Parallel Library

Understanding Tasks in .NET Framework 4.0 Task Parallel Library

Advanced Task Parallel Library Continuations

This article was originally published on Wednesday Feb 15th 2012
Mobile Site | Full Site