Wednesday, December 30, 2009

Controlling Personal Projects with TDD/BDD

Last night, a friend and I were discussing our ever growing list of personal projects and tasks that we strive to find/make time to whittle away. The items on our list ranged from reading a simple blog post, asking a mentor a question, or working on a personal, pet project. I don't know any developer who doesn't have a similar list to be honest.

Though the conversation, we began to talk about an issue we were both sharing about our pet projects getting drawn out. While there are true reasons (i.e. time constraints being the most prevalent), the one that plagued us was the concept of scope creep. As a developer, we battle with scope creep during our day jobs (usually) but to experience such at home leads to only a single person to put the blame on; ourselves.

This really got me thinking and reflecting on my project and my own scope creep issues. I began to realize that every time I had scope creep, it was a spot where I hadn't written unit tests first. In many cases I focus on a test-first strategy of TDD; however, there are a few times when I get in the flow and just write the code. This works sometimes but the times in which I can identify as scope creep all fell into these moments. If I had stayed focus on a test-first strategy, would these moments of scope creep been prevented? Probably not; however, it would have probably allowed me to be more conscience of the decision and possibly move it to some form of feature list for another iteration.

I only use standard NUnit-based unit tests and haven't fully tried out writing specs associated with BDD. Using something like a full spec like BDD would have been able to control the feature list a bit better but, again, not fully prevent scope creep. Regardless of the method, staying focused on a test-first approach does have a habit of controlling and identifying scope creep. It's easier to finishing a single iteration and enhance/refactor than it is to always go with the flow and allow the scope to continue to grow.

Tuesday, December 22, 2009

Using MEF and Custom Configuration Sections

Up to this point, I've dove into some of the core fundamentals of using the Managed Extensibility Framework.  Starting with this post, we're going to dive into how to apply it under certain circumstances.  Some of the scenarios in the upcoming posts will focus on using MEF with different .Net technologies, applications that use MEF, or tricks in .Net that can assist when working with MEF.  In this post, we'll start with this last category of scenarios by looking at how to utilize a custom configuration section defined in an assembly used as a MEF part and not located in the same directory as the executable.  Using this method, it will allow even greater power to your application and freedom to the parts consumed by such.

Setting the Stage

For this post, we'll look at a simple code base we worked on earlier in the series which imported MEF parts from a separate assembly.  Let's extend the code base by defining our simple custom configuration section from within the same assembly that define our external part.  For simplicity sake, let's call the custom configuration section MEFCustomConfigSection.  Below is the code for our custom configuration section:

   1:  public class MEFCustomConfigSection : ConfigurationSection
   2:  {
   3:      private static MEFCustomConfigSection settings = ConfigurationManager.GetSection("MEFCustomConfigSection") as MEFCustomConfigSection;
   4:   
   5:   
   6:      public static MEFCustomConfigSection Settings
   7:      {
   8:          get { return settings; }
   9:      }
  10:   
  11:      [ConfigurationProperty("message", IsRequired = true)]
  12:      public string Message
  13:      {
  14:          get { return this["message"].ToString(); }
  15:          set { this["message"] = value; }
  16:      }
  17:  }

This configuration section is very simple in that it only defines one property/attribute called Message.  This property will contain a string value in which we'll be displaying on the screen when the application consumes our part.

Consuming Our Section

Now that our configuration section has been defining, let's go ahead and create the code to consume such.  In previous examples, each of our parts had a property called HelpText that is used by the consuming application to display command line help documentation for each part.  What we will do with this new part is using our configuration section's Message property to define what the value of the HelpText property should be.  Thankfully, the code for this is extremely simple as shown below:

   1:  [Export("command", typeof(IHelp))]
   2:  public class CustomCommand : IHelp
   3:  {
   4:      public string CommandName
   5:      {
   6:          get { return "Custom"; }
   7:      }
   8:   
   9:      public string HelpText
  10:      {
  11:          get { return MEFCustomConfigSection.Settings.Message; }
  12:      }
  13:  }

Setting Up the Configuration File

Now that we have the custom configuration section created and code that needs it, we're now ready to update our consuming application's App.config file.

   1:  <configuration>
   2:      <configSections>
   3:          <section name="MEFCustomConfigSection" 
   4:                   type="MEFExample7.Commands.MEFCustomConfigSection, MEFExample7.Commands" />
   5:      </configSections>
   6:   
   7:      <MEFCustomConfigSection message="Hello From a Custom Section" />
   8:   
   9:      <runtime>
  10:          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  11:              <probing privatePath="Plug-ins;" />
  12:          </assemblyBinding>
  13:      </runtime>    
  14:  </configuration>

Setting up the custom configuration section is the same as any other configuration section that would need to be setup.  We first define our section within the <configSections> node and then we're able to insert our section; however, what's that last section?

The <runtime> section in the above snippet is needed to tell .Net to scan the Plug-ins subdirectory for the assembly that contains our configuration section.  There are two ways of doing this.  The example above uses the <probing> node which is great for little examples like this; however, can lead to performance issues since it will scan all assemblies in the paths that are provided.  Another issue with the <probing> node is that it doesn't provide a way for targeting specific, strongly named assemblies nor specific assembly versions.  If you need stronger control of what assemblies gets loaded, you can use the <codeBase> node instead.

For more information on using the <probing> and <codeBase> nodes for loading assemblies this way, feel free to check out the following links:

NOTE: One final item I need to mention about using <probing>, it can only look in subdirectories of the location the executable is in.  So if the assembly is in /bin, your path to probe for assemblies cannot be in a parent directory.

Once the configuration section is setup, and the Plug-ins directory is a child directory of the location of the executable, our new command is now displayed when the application runs.

Summary

In this post, we briefly looked at some things to be aware of when defining a custom configuration section from with in an assembly used as an external MEF part.  In future posts, we'll be looking at other scenarios on using MEF including consuming parts written in F# by a C# application as well as take a look at an open source project that will soon be releasing a new version that uses MEF.

Resources

kick it on DotNetKicks.comShout it

Tuesday, December 1, 2009

Managing Composition Through Lazy Loading Parts

So far in this post series, we've been looking at various aspects of working with MEF in the context of a single level of composition.  One interesting thing about MEF is that its composition is recursive based on the assemblies and types identified in the catalogs within the container.  What this means is that if one of our parts also has imports defined for parts of its own, the composition container will continue loading parts for the initial type as well as all parts loaded until no more parts are found or all imports are fulfilled.  This is a really nice feature since it will ensure everything is ready for you once compose the initial type; however, this eager loading can greatly cause a performance issue if the parts are not constructed properly.  In this post on our ongoing series about MEF, we'll look into the concept of parts of parts and how to apply lazy loading principles towards them.

Putting the Pieces of Pieces Together

To start this example off, we'll add to the code we last used in the fourth post of this series (Playing Nice with Other Assemblies using MEF Catalogs).  In order to enhance the code to illustrate a part of parts, let's add a new field to our IHelp interface that will represent subcommands of our parts.  Since we're going to assume that any of our commands could have multiple subcommands, let's make it of type IEnumerable<IHelp>.  Since it's an enumeration of IHelp, the amount of embedding could be infinite in theory (which sounds like fun but maybe another time).  After we update our IHelp interface and our current commands, let's mark only our ExampleCommand class to have its Subcommands property to be a MEF Import point as shown below.

IHelp.cs

   1:  public interface IHelp
   2:  {
   3:      string CommandName { get; }
   4:      string HelpText { get; }
   5:      IEnumerable<IHelp> Subcommands { get; set; }
   6:  }

ExampleCommand.cs

   1:  [Export("Commands", typeof(IHelp))]
   2:  public class ExampleCommand : IHelp
   3:  {
   4:      private string _helpText = "Lorem ipsum dolor sit amet, c ..." +
   5:                                      "Nulla molestie erat rhon ..." +
   6:                                      "amet dolor. Aliquam rhon ..." +
   7:                                      "vel est. Vestibulum et u ..." +
   8:                                      "id tellus. Fusce lectus  ..."
   9:   
  10:      public string CommandName
  11:      {
  12:          get { return AppName + " Example1"; }
  13:      }
  14:   
  15:      public string HelpText
  16:      {
  17:          get { return _helpText; }
  18:      }
  19:   
  20:      [ImportMany("Subcommands", typeof(IHelp))]
  21:      public IEnumerable<IHelp> Subcommands { get; set; }
  22:   
  23:      [Import("AppName")]
  24:      public string AppName { get; set; }
  25:  }

With this done, let's modify our Program.cs code slightly as well.  In order to ensure the we can infinitely loop through our subcommands, let's change our output information slightly by using recursion as shown below.

   1:  void Run()
   2:  {
   3:      Compose();
   4:   
   5:      OutputHelp(Commands, 0);
   6:      Console.ReadKey();
   7:  }
   8:   
   9:  private void OutputHelp(IEnumerable<IHelp> helpCommands, int padding)
  10:  {
  11:      foreach (var help in helpCommands)
  12:      {
  13:          Console.WriteLine(string.Empty.PadLeft(padding, '-') + FormatCommandOutput(help));
  14:   
  15:          if (help.Subcommands != null && help.Subcommands.Count() > 0)
  16:          {
  17:              OutputHelp(help.Subcommands, ++padding);
  18:          }
  19:      }
  20:  }

In the above code, we're passing our recursive function, OutputHelp, two parameters.  The first parameter represent the collection of IHelp instances to be outputted to the screen while the second is to provide depth of the recursion.  On line 13 of the snippet above we use this depth parameter to append our formatted command name with hyphens equal to the depth.  Lastly, we check to see if the Subcommands collection has values and call our OutputHelp method again passing the collection and incrementing the depth.

Next, let's create a new class called ExampleSubcommand.cs.  This will represent a subcommand for our ExampleCommand.cs class.  Once our ExampleSubcommand is all set, we can run the application to see the following output.

Example6-OutputTest1

In the above image, we can see our Subcommand being displayed after the Example1 command as expected.  In addition, we've applied the hyphens prior to the command name to indicate the depth correctly.  Alternatively, we could have added an export to our ExampleCommand class similar to that of our AppName property to send the "MEFExample6 Example1" down the tree as well.

Working with Lazing Parts

Now that we have our example prepped, it's time to see what we can do to optimize the code slightly through lazy loading.  For those who may not be familiar with the concept, lazy loading ultimately means that you do not load the objects or data until they are needed.  What this translates to is that when we call container.ComposeParts(this) in our Program.cs class, we want only our initial commands to be instantiated but not any subcommands it has in order to ensure only the objects that are currently being used are the ones currently in memory.

in order to accomplish lazy loading of exports in MEF, we need to use the System.Lazy<T> type in place of the contract type of our exports.  This type (built into the MEF assembly for .Net 3.5)  tells MEF to delay the instantiation of the value until it's actually called.  This is exactly what we're looking for to prevent a full line of instances from being created as we compose our parts.  Before we dive into the nuances of Lazy<T>, let's look at a simplified snippet below:

   1:  public class LazyExample
   2:  {
   3:      [Import()]
   4:      public System.Lazy<IHelp> command { get; set; }
   5:  }

In the above code, we created an example class called LazyExample which contains a singular import of type IHelp.  Because we wanted to delay the instantiation of this instance, we changed the type from IHelp to System.Lazy<IHelp> and we are all set from a definition standpoint.  While this looks easy, there are two things to be aware of when working with Lazy<T>.

  1. System.Lazy<T> requires you to grab instances of the underlying type using the Value property.  In the example snippet above, we would need to call command.Value in order to get the instance of IHelp instead of just calling the command property like we've been doing up to this point.
  2. System.Lazy<T> is not a collection type.  System.Lazy<T> does not implement nor inherit any class that implement IEnumerable<T>.  What this means is that just wrapping Lazy<T> around your currently defined properties that are decorated with ImportMany() won't work.  In order to apply lazy loading to collections of parts, you must change the type to IEnumerable<Lazy<IHelp>>, keeping inline with the above example.  This means any looping within the collection must be item.Value now instead of just item.

Applying Lazy Loading to Our Exports

Since we now see how to apply lazy loading to our exports, let's modify our code to implement such.  To do this, we'll need to modify our IHelp interface to change the Subcommands property we added to be of type IEnumerable<Lazy<IHelp>> and propagate such between the various parts.  Next, we need to copy our recursive OutputHelp command to create a new method called OutputSubcommandHelp which will address the output.  Once this is done, our code should look something like this:

IHelp.cs

   1:  public interface IHelp
   2:  {
   3:      string CommandName { get; }
   4:      string HelpText { get; }
   5:      IEnumerable<Lazy<IHelp>> Subcommands { get; set; }
   6:  }

ExampleCommand.cs

   1:  [ImportMany("Subcommands", typeof(IHelp))]
   2:  public IEnumerable<Lazy<IHelp>> Subcommands { get; set; }

Program.cs

   1:  [ImportMany("Commands", typeof(IHelp))]
   2:  public IEnumerable<IHelp> Commands { get; set; }
   3:   
   4:  [Export("AppName")]
   5:  public string AppName { get { return "MEFExample6"; } }
   6:   
   7:  void Run()
   8:  {
   9:      Compose();
  10:   
  11:      OutputHelp(Commands, 0);
  12:      Console.ReadKey();
  13:  }
  14:   
  15:  private void OutputHelp(IEnumerable<IHelp> helpCommands, int padding)
  16:  {
  17:      foreach (var help in helpCommands)
  18:      {
  19:          Console.WriteLine(string.Empty.PadLeft(padding, '-') + FormatCommandOutput(help));
  20:   
  21:          if (help.Subcommands != null && help.Subcommands.Count() > 0)
  22:          {
  23:              OutputSubcommandHelp(help.Subcommands, ++padding);
  24:          }
  25:      }
  26:  }
  27:   
  28:  private void OutputSubcommandHelp(IEnumerable<Lazy<IHelp>> helpCommands, int padding)
  29:  {
  30:      foreach (var help in helpCommands)
  31:      {
  32:          Console.WriteLine(string.Empty.PadLeft(padding, '-') + FormatCommandOutput(help.Value));
  33:   
  34:          if (help.Value.Subcommands != null && help.Value.Subcommands.Count() > 0)
  35:          {
  36:              OutputSubcommandHelp(help.Value.Subcommands, ++padding);
  37:          }
  38:      }
  39:  }

Adding Another Subcommand Layer

The last thing we will do in this example is to further extend the recursion tree by adding a new subcommand onto our current ExampleSubcommand.  We'll call it ExampleSubcommand2 and give the contract a label of "Subcommands2".  We'll decorate our ExampleSubcommand class to apply Import such into its own Subcommand collection and we'll run our application to see the following:

Example6-OutputTest2

Summary:

Hopefully after this post you can see the benefits of lazy loading exports as well as how easy it is to implement such.  Given the pattern that we have outlined above, the true depth can open a number of possibilities without over-utilizing our memory.  In the next section, we're going to mix things up a bit by looking at what it may take to have an export be used to defined and interact with a custom configuration section while the assembly is not in the same directory as the calling assembly.

Resources:


kick it on DotNetKicks.comShout it

Wednesday, November 25, 2009

Looking Around at Circular References in MEF

In the last post of this series, we created a new example code base used to display help text for various "commands".  This was a simple code base that extended previous examples by using external assemblies and different catalogs to identify all of the parts that can be imported and mapped.  This example covers a lot of scenarios when applied beyond the means of console-based text output since each imported "command" could literally be a functional piece of code by itself.  However, what happens when the imports require something from our main application?  When one object has a dependency with another object of another type; only for the dependent have a dependency towards the initial type; this is called a circular dependency.  In this post, we're going to look at the condition of a circular dependency and see how MEF encounters such issues.

A Closer Look at Circular Dependencies in General

To reiterate what was said a moment ago, a circular dependency is where two objects depend on each other for different things in somewhat of a symbiotic relationship.  Let's look at an example.  Let's say we have an application that contains two special types.  One type is used to read configuration information and implements the IConfig interface.  The second type is used to log any errors that may occur in the system and implements the IErrorManager interface. 

Example5 - CircularReference

In this illustration, our configuration manager requires an instance of an error manager in case there was an error reading the configuration information.  In addition, our error manager requires an instance of a configuration manager to know how the system is configured for logging errors.  Since each type has a required dependency on the other, a common pattern is to place the required dependencies into a constructor so that the proper dependencies are provided and the type is instantiated in a valid state.  Below is an example what our constructors may look like.

   1:  class ConfigurationManager : IConfig
   2:  {
   3:      private IErrorManager _errMgr;
   4:   
   5:      public ConfigurationManager (IErrorManager errorManager)
   6:      {
   7:          _errMgr = errorManager;
   8:      }
   9:  }
  10:   
  11:  class ErrorManager: IErrorManager
  12:  {
  13:      private IConfig _configMgr;
  14:   
  15:      public ErrorManager(IConfig configManager)
  16:      {
  17:          _configMgr = configManager;
  18:      }
  19:  }

If we have to pass in a valid instance of IErrorManager to our configuration manager, we would first have to instantiate an instance of IConfig for our error manager.  Since there's not a way based on the above code to instantiate a type without the other, the code has to be changed to allow for each to be created in an invalid state and the dependency to be passed to it via a property like below.

   1:  class ConfigurationManager : IConfig
   2:  {
   3:      public IErrorManager ErrMgr { get; set; }
   4:   
   5:      public ConfigurationManager() { }
   6:  }
   7:   
   8:  class ErrorManager : IErrorManager
   9:  {
  10:      public IConfig ConfigMgr { get; set; }
  11:   
  12:      public ErrorManager() { }
  13:  }

The issue with this pattern is that it requires the developer to now remember to always inject the proper dependencies after the types have been instantiated through their constructors.  Ultimately, it's risky because we're all human and tend to forget from time to time.   IoC containers help here a little bit, but can still confuse people.  An alternative solution which many people prefer is to used a bootstrapped version of one of the two objects that doesn't depend on the other.  This pattern also has issues due to what may not be available in a bootstrapped version.  In our example, a bootstrapped IConfig object may not contain any error management code with in it.

Looking At a Simple MEF Circular Reference

Now that we, hopefully, understand a bit more about what a circular reference is and where it can occur, let's see about recreating our example with MEF.   Let's create a program that has a property for a IErrorManager and IConfigMgr instances.  To build the circular reference, let's inject the dependencies through the constructors of our ErrorManager and ConfigManager classes and mark the constructors as Imports.  Below is our Circular Reference implementation.

Program.cs

   1:  namespace MEFExample5
   2:  {
   3:      class Program
   4:      {
   5:          [Import(typeof(IConfigManager))]
   6:          public IConfigManager ConfigurationManager { get; set; }
   7:   
   8:          [Import(typeof(IErrorManager))]
   9:          public IErrorManager ErrorManager { get; set; }
  10:   
  11:          static void Main(string[] args)
  12:          {
  13:              var prog = new Program();
  14:              prog.Run();
  15:          }
  16:   
  17:          void Run()
  18:          {
  19:              Compose();
  20:              Console.WriteLine(ConfigurationManager.TestText);
  21:              Console.WriteLine(ErrorManager.TestText);
  22:              Console.ReadKey();
  23:          }
  24:   
  25:          void Compose()
  26:          {
  27:              var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  28:              var container = new CompositionContainer(catalog);
  29:              container.ComposeParts(this);
  30:          }
  31:      }
  32:  }

ConfigMgr.cs

   1:  namespace MEFExample5
   2:  {
   3:      public interface IConfigManager
   4:      {
   5:          string TestText { get; set; }
   6:      }
   7:   
   8:      [Export(typeof(IConfigManager))]
   9:      public class ConfigMgr : IConfigManager
  10:      {
  11:   
  12:          public string TestText { get; set; }
  13:   
  14:          public ConfigMgr()
  15:          {
  16:              TestText = "Config";
  17:          }
  18:   
  19:          [ImportingConstructor]
  20:          public ConfigMgr(IErrorManager errorManager) : this()
  21:          {
  22:              _errorManager = errorManager;
  23:          }
  24:      }
  25:  }

ErrorManager.cs

   1:  namespace MEFExample5
   2:  {
   3:      public interface IErrorManager
   4:      {
   5:          string TestText { get; set; }
   6:      }
   7:   
   8:      [Export(typeof(IErrorManager))]
   9:      public class ErrorManager : IErrorManager
  10:      {
  11:          public string TestText { get; set; }
  12:   
  13:          public ErrorManager ()
  14:          {
  15:              TestText = "Error";
  16:          }
  17:   
  18:          [ImportingConstructor]
  19:          public ErrorManager(IConfigManager configManager) : this()
  20:          {
  21:              _configManager = configManager;
  22:          }
  23:      }
  24:  }

When we try to run this, we get the following error message:

Example5-Error1

As we can see, MEF doesn't completely remove issues inherit from constructor injection-based circular references.  Like we discussed above though, we can move our dependencies into properties instead of a constructor.  What's nice about doing such with MEF though is that we can don't have to truly remember to wire up the dependencies manually.  With the ability to declaratively set our dependent properties as Imports, we won't need any additional code.  Below is the updated code to that addresses the circular reference.

ConfigMgr.cs

   1:  namespace MEFExample5
   2:  {
   3:      public interface IConfigManager
   4:      {
   5:          string TestText { get; set; }
   6:      }
   7:   
   8:      [Export(typeof(IConfigManager))]
   9:      public class ConfigMgr : IConfigManager
  10:      {
  11:          private IErrorManager _errorManager;
  12:   
  13:          public string TestText { get; set; }
  14:   
  15:          [Import(typeof(IErrorManager))]
  16:          public IErrorManager ErrorMngr
  17:          {
  18:              get { return _errorManager; }
  19:              set { _errorManager = value; }
  20:          }
  21:   
  22:          public ConfigMgr()
  23:          {
  24:              TestText = "Config";
  25:          }
  26:   
  27:          public ConfigMgr(IErrorManager errorManager) : this()
  28:          {
  29:              _errorManager = errorManager;
  30:          }
  31:      }
  32:  }

ErrorManager.cs

   1:  namespace MEFExample5
   2:  {
   3:      public interface IErrorManager
   4:      {
   5:          string TestText { get; set; }
   6:      }
   7:   
   8:      [Export(typeof(IErrorManager))]
   9:      public class ErrorManager : IErrorManager
  10:      {
  11:          private IConfigManager _configManager;
  12:   
  13:          public string TestText { get; set; }
  14:   
  15:          [Import(typeof(IConfigManager))]
  16:          public IConfigManager ConfigManager
  17:          {
  18:              get { return _configManager; }
  19:              set { _configManager = value; }
  20:          }
  21:   
  22:          public ErrorManager ()
  23:          {
  24:              TestText = "Error";
  25:          }
  26:   
  27:          public ErrorManager(IConfigManager configManager) : this()
  28:          {
  29:              _configManager = configManager;
  30:          }
  31:      }
  32:  }

Summary:

So in this post we looked at Circular References and and how they are handled through MEF.  In the next post of this series, we'll dive into how we can use lazy loading towards imported parts and where they could be applied at.

Resources:


kick it on DotNetKicks.comShout it

Monday, November 23, 2009

Playing Nice with Other Assemblies using MEF Catalogs

Looking over the previous three posts, we have been working within a single assembly for managing our extensibility parts.  While this works well if we want to use MEF more as an IoC container, it really limits the extensibility of our application.  In the single assembly model that we've been using, every update would require a new build of the application.  To overcome this limitation, we'll create a new example project that builds on what we've covered and branch it out into multiple assemblies.

Building a Console's Help Information

In the new example, we'll be creating a new console application whose sole purpose is to output help documentation on various fake commands.  We aren't going to be implementing any of the actual command functionality; however, each extension will represent a new command and is responsible for its own help documentation.  Given our scenario, it isn't very practical for an application to do nothing without any extensions.  Because of this, our example will be importing in the various parts from both inside of its own assembly (like we've done previously) as well as assemblies located in a Plug-Ins directory.

Defining Our Project Structure

Given the scenario that we are going to be working on, there are a couple of different ways we can structure our solution.  In an attempt to make this a bit more practical, we'll split out our extensibility contract into a separate assembly.  This assembly we'll reference into our hosting application as well as any external plug-in assemblies so that they aren't directly referencing our executable. While this extra assembly that contains our extensibility contract will be very simple, it also provides a point to branch out with other core functionality in a real world scenario.

For the sake of this example, let's start a new Windows Console application project named MEFExample4. Once the solution was created, we need to add a Class Library Project named MEFExample4.Core.  Below is an image of the possible solution explorer window inside of Visual Studio.

Example4-SolutionExplorerStart

Creating Our Extensibility Contract

Now that we have the project structure established, let's go ahead and add a new Interface to the MEFExample4.Core project named IHelp.  This interface will be used by our various "commands" and define a CommandName and HelpText property.  Below is the code for IHelp.

   1:  namespace MEFExample4.Core
   2:  {
   3:      public interface IHelp
   4:      {
   5:          string CommandName { get; }
   6:          string HelpText { get; }
   7:      }
   8:  }

Building the Hosting Application

Now that we have our contract by means of the MEFExample4.Core.IHelp type, let's create our extensible application that imports multiple instances of IHelp types.  In this first iteration, we'll setup the application in the same way as our initial, simple example from earlier posts. We'll use the AssemblyCatalog which is used to instantiate types of a given assembly, and like our previous examples, will use Reflection to get the currently executed assembly. 

In addition to the catalog we're currently choosing, we need to make sure that we have our collection property to hold our imported parts and decorate it with the ImportMany(typeof(IHelp)) attribute. Once that's in place, the only thing left is to setup our console output for displaying the CommandName and HelpText properties of our imports.  Below is first iteration of our Program.cs file.

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel.Composition;
   4:  using System.ComponentModel.Composition.Hosting;
   5:  using System.Reflection;
   6:  using System.Text;
   7:  using MEFExample4.Core;
   8:   
   9:  namespace MEFExample4
  10:  {
  11:      class Program
  12:      {
  13:          static void Main(string[] args)
  14:          {
  15:              Program p = new Program();
  16:              p.Run();
  17:          }
  18:   
  19:          [ImportMany("command", typeof(IHelp))]
  20:          public IEnumerable<IHelp> Commands { get; set; }
  21:   
  22:          void Run()
  23:          {
  24:              Compose();
  25:   
  26:              foreach(IHelp cmd in Commands)
  27:              {
  28:                  Console.WriteLine(FormatCommandOutput(cmd));
  29:              }
  30:   
  31:              Console.ReadKey();
  32:          }
  33:   
  34:          void Compose()
  35:          {
  36:              var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
  37:              var container = new CompositionContainer(catalog);
  38:              container.ComposeParts(this);
  39:          }
  40:   
  41:          string FormatCommandOutput(IHelp command)
  42:          {
  43:              StringBuilder sb = new StringBuilder();
  44:              sb.AppendLine(command.CommandName);
  45:              sb.AppendLine(string.Empty); //empty line
  46:   
  47:              List<string> splitText = SplitText(command.HelpText);
  48:   
  49:              splitText.ForEach(t => sb.AppendLine(t));
  50:   
  51:              return sb.ToString();
  52:          }
  53:   
  54:          List<string> SplitText(string text)
  55:          {
  56:              const int LINE_LENGTH = 55;
  57:              int length = text.Length;
  58:              List<string> output = new List<string>();
  59:   
  60:              for (int i = 0; i * LINE_LENGTH < length; i++)
  61:              {
  62:                  if (i*LINE_LENGTH + LINE_LENGTH <= length)
  63:                  {
  64:                      output.Add(text.Substring(i * LINE_LENGTH, LINE_LENGTH).PadLeft(60, ' '));
  65:                  }
  66:                  else
  67:                  {
  68:                      output.Add(text.Substring(i * LINE_LENGTH).PadLeft(55, ' '));
  69:                  }
  70:              }
  71:   
  72:              return output;
  73:          }
  74:      }
  75:  }

Writing the First Command

Now that we have our contract and hosting application defined, we need to create our first "command".  We started our application to look inside of it's own assembly for our various types that will be imported.  Because of this, we need to add a new class called TestCommand and have it implement our IHelp interface.  Let's set the CommandName property to "Test" and the HelpText property to some random text.  Once we decorate the class with our Export(typeof(IHelp)) attribute, we can compile and run the application and see our text.

Example4-OutputTest1

Preparing the Application For External Plug-ins

We've tested our application in the same fashion as the previous posts in this series and we're almost ready to work with external assemblies.  Before we do that, we need to add a new folder to our console application project named Plug-Ins.  This folder will be our holding area for the external assemblies that house additional "commands". 

The second thing we need to do is change our AssemblyCatalog to a DirectoryCatalog object.  Unlike an AssemblyCatalog which accepts an assembly as a constructor parameter, the DirectoryCatalog accepts a file path (relative or absolute) to the location where any number of the assemblies are found.  In addition to that difference, the DirectoryCatalog will review all assemblies located in the supplied directory.  This means that once we point our DirectoryCatalog to our Plug-Ins folder, we can just start dropping assemblies into there without having to recompile the console app. Note: Since the project uses the default build location of /bin/Debug, the path we supply will traverse up the directory tree once again. In practice, the Plug-Ins directory should probably be in the same directory as the executable application or the path configurable via an App.config file.  Below is the updated Program.Compose() method.

   1:  void Compose()
   2:  {
   3:      var catalog = new DirectoryCatalog(@"..\..\Plug-ins\");
   4:      var container = new CompositionContainer(catalog);
   5:      container.ComposeParts(this);
   6:  }

Adding Another Assembly

With our folder/repository ready to be used by our DirectoryCatalog, it's time for us to create a new "command" that implements IHelp from a new/separate assembly. Let's add a new class library project called MEFExample4.Commands.  Before we write any code for our new command, let's update the project properties a little bit.  Since we are working on our Commands assembly in the same solution as the application, let's add a Post-Build Event script that will copy our built Commands assembly to the Plug-Ins directory we made in the previous section.  To do this, we need to open the Project's Property window and click on the Build Events tab.  In the Post-Build Event Command Line textbox, we need to add the following:

copy $(TargetPath) $(SolutionDir)\MEFExample4\Plug-ins\$(TargetFileName)

If you are not familiar with Pre/Post-Build events and the macros, feel free to check out this link since they can be used to do some pretty interesting things.  As for the above script, it tells the build manager to copy the TargetPath (the built .dll file) and copy it to the application's Plug-ins directory using the same name.

Now that we have the project setup, we can write the code for our next "command".  We are going to rename Class1.cs to ExampleCommand.cs and add the below code into it.

   1:  using System.ComponentModel.Composition;
   2:  using MEFExample4.Core;
   3:   
   4:  namespace MEFExample4.Commands
   5:  {
   6:      [Export("command", typeof(IHelp))]
   7:      public class ExampleCommand : IHelp
   8:      {
   9:          private string _helpText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
  10:                                          "Nulla molestie erat rhoncus sapien volutpat rhoncus sed sit " +
  11:                                          "amet dolor. Aliquam rhoncus sem et neque elementum lacinia ut " +
  12:                                          "vel est. Vestibulum et urna sit amet nibh feugiat imperdiet ac " +
  13:                                          "id tellus. Fusce lectus risus, congue et.";
  14:   
  15:          public string CommandName
  16:          {
  17:              get { return "Example1"; }
  18:          }
  19:   
  20:          public string HelpText
  21:          {
  22:              get { return _helpText; }
  23:          }
  24:      }
  25:  }

After that, let's build the solution and test everything out.  When we run the application we should now see Example1 and the Ipsum text that we designated for the HelpText property like the image below.

Example4-OutputTest2

In addition, if we take a look in the Plug-Ins directory, we can also see our MEFExample4.Commands.dll is listed.

Working with Internal and External Assemblies

Now that we've seen how to work with the currently executing assembly as well a directory containing multiple different assemblies, there's one last thing for this post.  What if we wanted to look both internally and externally for our Commands?  An application like this without any native commands is just a shell and provides little initial value.  Sure we can create all of our commands in a separate assembly so we never have to touch the application; however, this allows for our initial commands to be deleted.  In order to cultivate both internal commands and external commands, we need to use an AggregateCatalog object.

An AggregateCatalog differs from an AssemblyCatalog or a DirectoryCatalog in that it's, in essence, a catalog of catalogs.  Looking at the intellisense, we're shown that the AssemblyCatalog constructor accepts either an IEnumerable<ComposablePartCatalog> object or a parameter array of ComposablePartCatalogs.  For the example, we'll use the parameter array version of the constructor to add new instances of an AssemblyCatalog and DirectoryCatalog into our new AggregateCatalog as shown by the updated code below.

   1:  void Compose()
   2:  {
   3:      var catalog = new AggregateCatalog(new DirectoryCatalog(@"..\..\Plug-ins\"),
   4:                                         new AssemblyCatalog(Assembly.GetExecutingAssembly()));
   5:      var container = new CompositionContainer(catalog);
   6:      container.ComposeParts(this);
   7:  }

Once we do this, we can test the application and see that the output has changed to the following:

Example4-OutputTest3

Summary

In this post we really looked at starting a more applicable console application using MEF.  We looked at how you can use a couple different catalogs in order to obtain the assemblies that contain parts for our application.  There are additional catalogs available that allow other ways to import assemblies and types and can also be used with an AggregateCatalog.  In the next post for this series, we'll dive into how MEF handles Circular References real quick and then further expand our example.

Resources:



kick it on DotNetKicks.comShout it