Thursday, May 19, 2011

Thursday Quickie - Mocking Events with Moq

There are times when the code under test depends on an event being fired by a component we're mocking. You can explicitly fire a mocked object's event using the following code
            var authService = new Mock<IAuthenticationService>();
authService.Raise(m => m.LoggedIn += null, null as AuthenticationEventArgs);
You can also raise an event on the mock as part of a callback - i.e. fire the event when a method or property on the mock is triggered.
            var authService = new Mock<IAuthenticationService>();
authService.Setup(a => a.LoadUser(null, null))
.Returns(null as LoadUserOperation)
.Callback(() => authService.Raise(m => m.LoggedIn += null, null as AuthenticationEventArgs));
To call a delegate passed into a mocked handler, you just need to do exactly that - the magic is in getting the generics right
            var worker = new Mock<IWorker>();             worker.Setup(w => w.DoWork(It.IsAny<EventHandler<WorkCompletedEventArgs>>()))                   .Callback<EventHandler<WorkCompletedEventArgs>>(c => c(worker.Object, new WorkCompletedEventArgs()))                   .Verifiable();

Monday, February 21, 2011

Tricks & Tips: ListBoxes, TextBoxes and SelectedItems

I ran across this today and thought it was worth sharing. The problem is one that's been found in both Silverlight and WPF, but there doesn't seem to be a nice simple solution for either.

The issue involves a control that can accept focus (e.g. a TextBox) being part of the ItemTemplate of a ListBox control. In this scenario, you can select one ListBoxItem by clicking on the whitespace within the ItemTemplate, but when you click on the focusable control (the TextBox) of another ListBoxItem, then the selection does NOT move along with the focus.

The solution is a dinky little behavior that walks up the Visual tree from the TextBox when it gets focus and selects the parent ListBoxItem.

namespace MyProject.Behaviors

{
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;

///
/// Behaviour that allows a control to cause a parent ListBox to become focused.
///

public sealed class ListBoxItemFocusBehaviour : Behavior<Control>
{
///
/// Called after the behaviour is attached to an AssociatedObject.
///

/// Override this to hook up functionality to the AssociatedObject.
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.GotFocus += OnControlFocused;
}

///
/// Called when the behaviour is being detached from its AssociatedObject, but before it has actually occurred.
///

/// Override this to unhook functionality from the AssociatedObject.
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.GotFocus -= OnControlFocused;
}

///
/// Called when [control focused].
///

/// "sender">The sender.
/// "e">The "System.Windows.RoutedEventArgs"/> instance containing the event data.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "By design - p is re-used for multiple control types.")]
private static void OnControlFocused(object sender, RoutedEventArgs e)
{
var control = sender as Control;
DependencyObject p = control;
while (p != null && !(p is ListBoxItem))
{
p = VisualTreeHelper.GetParent(p);
}

if (p == null)
{
return;
}

((ListBoxItem)p).IsSelected = true;
}
}
}

Alll you have to do is attach this behavior to your focusable control and when it receives focus, its associated ListBoxItem gets selected.
                <TextBox x:Name="MyTextBox>

<Interactivity:Interaction.Behaviors>
<Behaviours:ListBoxItemFocusBehaviour />
<Interactivity:Interaction.Behaviors>
TextBox>
Not forgetting of course to register the appropriate namespaces and reference the System.Windows.Interactivity assembly from the Blend SDK.
xmlns:Behaviours="clr-namespace:MyProject.Behaviors;assembly=MyProject" 
xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Nothing too it!

Monday, February 07, 2011

RIA Services and NHibernate Recipes - Introduction

For the last few weeks I've been working on a new system at work that implements a Silverlight MVVM UI on top of RIA Services. The back end is a SQL Server database that is accessed via NHibernate using LINQ4NHibernate and FluentNHibernate to configure everything.

There has been a fair amount of pain in the process, so prompted by a tweet from @SLColinBlair I've decided to start blogging a series of recipes for using RIA Services and NHibernate together.

As I go, I'm going to create a simple "Client / Project" management application to use throughout which will allow me to blog about each recipe within a common context.

The diagram to the right shows the data structures we'll be starting with.
  • A Client has zero or more Contacts and Projects.
  • A Contact belongs to just one client and has zero or more Responsibilities, each of which is to just one Project.
I will expand the scope of the sample application as we introduced more recipes - any requests will be most welcome on Twitter.

Next time: Getting started - The Clients object.

Friday, January 28, 2011

Quickie: Unwrapping Invocation Exceptions

If you work with dynamic invocation in any way, shape or form you're bound to catch a TargetInvocationException at some time or another. However, the fact that the real exception has been wrapped into a TargetInvocationException can hide a multitude of sins - potentially all sorts of different exception types can get wrapped from all sorts of sources.

One further problem is that it's entirely possible to get nested TargetInvocationExeptions as the call stack unwinds - again masking what the real problem is. This was the precise situation I found myself in with my nicely crafted n-tier WCF-based system.

So to make life just a little easier on myself when dealing with the exceptions thrown whilst performing a dynamic invocation I put together the following extension methods - one that re-wraps an exception and one that un-wraps nested TargetInvocationExceptions.

To use it, we just catch and re-throw, except using the extension methods.
try
{
// Do something dangerous with dynamic invocation
}
catch (TargetInvocationException ex)
{
throw ex.UnwrapTargetInvocationExceptions().ForRethrowing();
}
What you'll get is an exception throw of the same type as the actual fault, regardless of how many nested TargetInvocationExceptions it is wrapped in. Because we're nicely wrapping the exception we also maintain the call stacks to let you trace what's really going on.

Finally, here's the source - use it at your own risk - I've found it handy!

public static class ExceptionExtensions
{
///
/// Returns an exception wrapping an exception, but of the same type a
/// that's exception's INNER exception.
///

///
/// This allows us to write code like
/// throw ex.InnerException.ForRethrowing()
/// to re-throw an inner exception type without losing the stack trace.
///
public static T ForRethrowing(
this T innerException, Exception outerException)
where T: Exception
{
var actualType = innerException.GetType();

var ctorParams = new object[] {
innerException.Message, outerException
};
var result = (T)Activator.CreateInstance(actualType, ctorParams);
return result;
}

///
/// Unwraps an exception from any wrapping target invocation exceptions.
///

public static Exception UnwrapTargetInvocationExceptions(
this Exception exception)
{
var innerException = exception.InnerException;

// not a TargetInvocationException, or no inner exception? Then
// just return the exception itself
if ((innerException == null) ||
(!(exception is TargetInvocationException)))
{
return exception;
}

return innerException.UnwrapTargetInvocationExceptions();
}
}

Monday, January 24, 2011

Getting it right - filming DDD WP7

OK, now they're all available I want describe how I filmed the Developer Developer Developer - WP7 event that was held back in October 2010 at The Printworks in Manchester.

As an entirely community driven event, the day provided 9 sessions that gave a really good introduction to WP7 development - including Andy Wigley's excellent talk on Tombstoning - with NO Microsoft presenters.

The videos are now all up on Channel 9, courtesy of Mike Ormond - and are all in HD to boot.
And now for the trumpet-blowing bit - I was the lunatic that volunteered to film, edit and produce all 6 hours of final video output.

Filming

I filmed the presenter using a Canon XM camera placed at the front of the auditorium - this gave me good footage of the presenter (although Rob Miles enthusiasm as he bounds around the stage makes tracking him a challenge!) as well as a master wide shot against which to synchronise the slide graphics.

A second, smaller Sony HD Handycam was placed in the middle of the back row of the cinema to get a "god's eye view" of proceedings, and to record the screens during demo's. This worked well, but I do think that a camera that has manual focus would have been better, and a direct feed recorded from the screen best of all. Unfortunately that last option requires a £500 converter and some kind of SDI recorder - well beyond the budget of this kind of community event.

Finally I had a second Sanyo HD Handycam for quick pick-up shots of the audience - this really needs a dedicated cameraman / interviewer to make best use of it. I used it in the breaks to get some shots of the outside area where Mike Ormond was running his XAPathon, but the light levels were really too low for any of the footage to be useful. Some of the in-auditorium shots were used as cut-aways in the final edit tho'.

Each presenter was given a second radio pack (in addition to the one for the venue SR system) that was recorded by the Canon - I had two packs, so there was no rushing to swap between presenters. These recorded a good clean audio track against the close-up video which would allow me to sync the recordings from both camera in the edit more easily.

The Sony camera's front stereo mics recorded a good "wild-track" of the audience (and the presenter's voice played through the SR speakers), but regretably the audience levels were never enough to get a clean recording of any questions. This audio did get used at low-levels in the mix to provide some room ambience.

I think the only way to improve the recording of audience questions would be to have 2 or 3 runners with radio stick mics ready to hand them out, or else use a couple of shotgun mics on long booms. That would also allow the question to be piped through the SR system so everyone could hear it clearly as well as allowing it to be recorded.

After the success of filming the Guathon, I wanted to once again get a really clean audio recording of the presenter. As the portable digital recorder I used before wasn't available I used a stereo 1/4" jack to USB audio interface to record the mix audio directly from the Sends of the SR mixing desk into a netbook running Sony Sound Forge Audio Studio. This worked superbly, giving a perfectly clear recording without having to worry about batteries or filling the CF card - seeing "196 hours available" gives a nice warm feeling!

Post Production

After the event, the footage from the Cannon was ingested into my Vaio laptop using a Sony HDV deck over Firewire. Footage from the handycams was pulled straight from the SD cards, and the audio files were just copied over the network from the Netbook onto the Vaio. Then came the hard work - editing in Sony Vegas.

I started by pulling in the master audio files - these were full-length for each session, so gave me a good place to start. Laying the Canon video/audio tracks alongside synchronised the audio for each clip, then did the same for the Sony Handycam footage. This gave me two video tracks (the close-up of the presenter and the "God's eye" view to work with whilst adding the slide graphics exported from Powerpoint as Png's.

Once each session was prepared, the video and slides were merged down into a "Multi-Camera Edit Track". This is a superb feature in Vegas, and lets you easily cut between the three shots as the video is playing. Once the cuts were finalised, it was just a matter of putting a 16 frame cross-fade between each shot, adding top and tail titles and rendering out as a Windows Media file.

Final file sizes were ranged from 700Mb to 1.5Gb per session - 720p targetting a 3.5Mb data rate.

Distribution

This was where Mike Ormond came in - he'd most graciously offered to get the final videos up onto Channel 9 for distribution, and provided access to Microsoft's "big-file-upload" service. He then took each one, uploaded it to C9 for conversion and authored the associated blog posts that are linked above.

Final Thoughts

Was it worth doing?

Absolutely. The DDD sessions are always a superb resource on their subject matter, so allowing those that couldn't be there on the day to see them is highly valuable.

What would you do differently?

First, take a week off from my day-job to do the edit! Fitting this level of complex editing into late-nights and weekends when you've got a young family is hard.

Second, given a larger budget I'd have at least one other cameraman, a second Canon, boom operater / mic runners and record the screen output directly.

Thirdly, I'd try and have Rob Miles tied to the desk! His exuberance makes it damn hard to film as be bounds around and even harder to edit - but that's what makes him such an engaging presenter.

Thanks to everyone involved in setting up this event and letting me record it - may there be many more.

Another New Start

There are a couple of the reasons I've been so quiet on this blog. Firstly, Blogger was (until recently) blocked entirely at my workplace, making ad-hoc posts a pain; and secondly because Chris Alcock has done such a sterling job with "The Morning Brew" that my musings on .Net tidbits were entirely superflous (he well deserved his MVP for that).

But it's another New Year, Blogger has been unblocked at work, so I should really get on and post about some of the technical nuggets that have been stuck in limbo for the last year or more.

Time to dig into the internal blogs and wikis and pull out some nuggets.

Friday, July 02, 2010

What no posts?

I've been guilty of lapsing on my blogging before, but six full months without a Nugget is probably a personal record.

This time, however, I've got an excuse. No, really! Corporate policy.

Much as I can see the need to restrict access to Facebook and YouTube in the corporate environment, I've been torn over just how much technical content I've been missing since Twitter was blocked along with the major blog engines.

The block serves it's purpose - as an employee, I'm not idly browsing blogs, and nor am I posting drivel throughout the day. But whilst there are ways around the restrictions (go-go-gadget iPhone!) the pain of having to forward links or full articles to myself via email means that in general I don't.

So until I find an efficient way of blogging can I humbly point you to Chris (@calcock) Alcock's "The Morning Brew" - essential reading every day.

Friday, November 13, 2009

Friday Quickie: The *other* TemplateBinding syntax

Setting up the template for a new custom control in Silverlight is fraught at the best of times – the Silverlight runtime invariably swallows any error in the template and gives just a cryptic exception.

But stranger still is a limitation on how the {TemplateBinding ...} syntax can be used and the exception that is thrown when in error.

The {TemplateBinding ...} syntax provides a quick and simple way to bind properties within a control’s template to the properties of the control itself. According to the MSDN documentation, it’s a shortcut to the more full-featured {Binding ...} syntax. But what’s not clear from the documentation is that {TemplateBinding ...} can only bind a control property to a DependencyProperty on the control class.

If you try and use {TemplateBinding ...} against a normal property on the control, you get the strange exception shown right – confusing because the target control (WizardActionButton in the example) absolutely does have a State property.

The solution is to use the {Binding ...} syntax where the source property isn’t a DependencyProperty, and to use the {RelativeSource ...} syntax to specify that you’re actually binding to the control within its template.

Wrong:

<i4tControls:WizardActionButton x:Name="RetreatButtonPart"

Style="{StaticResource ActionButtonStyle}"

State="{TemplateBinding CanRetreat}"

Content="{TemplateBinding RetreatButtonContent}"

ContentTemplate="{TemplateBinding RetreatButtonContentTemplate}"

/>

Correct:

<i4tControls:WizardActionButton x:Name="RetreatButtonPart"

Style="{StaticResource ActionButtonStyle}"

State="{Binding Path=CanRetreat,RelativeSource={RelativeSource TemplatedParent}}"

Content="{TemplateBinding RetreatButtonContent}"

ContentTemplate="{TemplateBinding RetreatButtonContentTemplate}"

/>

Monday, September 14, 2009

Cometh The Gu

This should be old news to most readers (it was announced all of 3 days ago!), but bears re-posting.

Scott Guthrie is presenting in Manchester
on 29th September!

Why haven’t you registered already?

Gu’dness: http://developerdeveloperdeveloper.com/guathon/Default.aspx

Wednesday, September 09, 2009

Wednesday Quickie: Forcing event un-subscription

This is another really simple and obvious code snippet, but one well worth remembering – posted this morning by Fabrice MARGUERIE.

The crux is that event subscriptions can cause memory leaks – so ensuring they are un-subscribed is essential. The code snippet is designed to be used in the Dispose or Cleanup method on the publishing object, and forcibly disconnects any subscribers just before the publishing object is disposed.

if (SomeEvent != null)
{
foreach (EventHandler handler in SomeEvent.GetInvocationList())
SomeEvent -= handler;
}

Simple. Clean. Elegant. Use it!

Force your subscribers away: http://weblogs.asp.net/fmarguerie/archive/2009/09/09/forcing-event-unsubscription.aspx

Wednesday, August 05, 2009

Wednesday Quickie: Why Rounded Corners Work...

Came across this little article this afternoon via a tweet from @DaveSussman giving some background and justification for using rounded corners in your UI design. Well worth a read - I particularly like the examination of Apple hardware from a rounded corner point of view.

Round your rectangles: http://www.uiandus.com/2009/07/27/theories/realizations-of-rounded-rectangles/

Wednesday Tidbit: Smoooooooth scrolling a ScrollViewer

Spotted this great little article today on how to use the Mediator pattern to allow you to bind an animation to a scroll-viewer to get really slick scrolling.

Smooth as butter on a muffin: http://blogs.msdn.com/delay/archive/2009/08/04/scrolling-so-smooth-like-the-butter-on-a-muffin-how-to-animate-the-horizontal-verticaloffset-properties-of-a-scrollviewer.aspx

Monday, August 03, 2009

Monday Quickie: CSS Resources

This morning, @DaveSussman (http://blogs.ipona.com/davids) posted a link on Twitter to an excellent set of CSS resources:

http://is.gd/20qgs

This post is just an aide-memoire... and to share the CSS goodness.

Thursday, June 11, 2009

Thursday Quickie: Using the NULL pattern for event delegates

This little tweet turned up this morning in response to Mike Taulty wanting“the ability to fire an event without having to check it for null”.

richardblewett @mtaulty you can use the null pattern for this Mike, just do = delegate{}; on the event declaration
Thu, Jun 11 09:27:36 from Witty in reply to mtaulty


It’s pretty obvious when you think about it tho’...

public event EventHandler CriteriaChanged = delegate{};

Easy-peasey.

Update: Richard credits Andy Clymer the original idea (see comments). How far will the chain go?!

Thursday, May 21, 2009

Path animations in Silverlight

I attended the most-excellent NxtGenUG Manchester Launch event last night, where Richard Costall (@costall) gave a great overview of some of the new features in Silverlight 3.0.

One of the questions that came up was whether visuals could be animated on a non-circular path using the new Perspective 3D features. The answer was “No”, because the projection features just give rotation and offset in 2.5D space. I piped up that it MIGHT be possible to take a visual moving along a 2D animation path that is itself projected to give the required effect. Richard pointed out that Silverlight doesn’t have any PathAnimation support. 

A quick Google this morning, however, came up with an intriguing CodeProject post from  “Ineir” where he presents a PathAnimation framework for Silverlight that flattens the path into a set of line-segments suitable for use as Storyboard keyframes. With this, I think it WOULD be possible to have a complex path for visuals in 2.5D space. I’ll just have to try it at some point - this post is really just a “note-to-self”.

Moving in circles along curves: http://www.codeproject.com/KB/silverlight/PathAnimation.aspx

 

Tuesday, April 07, 2009

Getting Started with the Managed Extensibility Framework

Updated 2009-04-08 11:48: 

Thanks to Eric Nelson who included this as the Feature Article in today's MSDN UK Newsletter. (updated on the web soon, I hope!).

Also, and with perfect timing, the MEF Team have just released MEF Preview 5. Enjoy.

Joel


In this article, I will provide a basic overview of the Managed Extensibility Framework (MEF), and detail a practical sample of providing extensibility in your application.

But what is it? And why is using it a good idea?

According to its project web site, MEF is “a new library in .Net that enables greater reuse of applications and components.”[1]

MEF provides an engine that will dynamically extend your .NET application with plug-ins at run-time. You define the requirements to extend your application by decorating the classes in your core application with MEF’s attributes. Plug-ins can then be created as classes that will satisfy these requirements, again using MEF’s attributes to indicate what requirements the plug-in class will satisfy.

Currently in open development, the January 2009 release (Preview 4) is licensed under the MS-PL – which means you can use it right away for real projects. There is already a strong community grown up around MEF, including a Contrib project and plenty of articles on the web – but getting started with MEF can be a daunting prospect.

Glenn Block put it very succinctly:

“In MEF everything is an extension, everything is extensible (extensions themselves included).”[2]

Let’s look at a simple sample (download the code here) - a Login processing module which needs to allow extentions to the processing of a login request with custom code, without re-writing the login code and without the login module referencing the extensions.

To implement the extensibility for the login module, we define an interface that describes the functionality that a Login Extension should provide (ILoginExtension), an “extension point” in login code at the point where logically the checks should occur (in the sample this is in the LoginHelper class), and finally a LoginExtensions property (again in the LoginHelper) that will contain the extensions that MEF provides.

What makes MEF so easy is that the interface (ILoginExtension) exposed by the requirement is the only piece of shared information. MEF scans all assemblies in your application (and / or specific directories as you choose) for plug-ins that will satisfy the requirement and calls the setter for the LoginExtensions property, “injecting” the list of extensions so that the code at the extension point merely has to iterate the list and call the implementation method on each extension.

This magic happens when, in the LoginHelper’s constructor, we use MEF to generate a catalog of all extensions (classes decorated with an Export attribute) and requirements (classes with properties decorated with an Import attribute). Better still, the catalog can watch the file system for new plug-ins being added on the fly.

This catalog is then passed to the composition engine (an instance of the MEF CompositionContainer class) and the container statisfies all the requirements (Imports) found with the matching extensions (Exports).

Now we’ve looked at MEF in overview, let’s dive into our sample code, starting with the ILoginExtension interface:

    public interface ILoginExtension

    {

        void LoginEx(ref Session session);

    }

So our extension point will call the LoginEx method of any extensions, passing in a reference to the current user’s session. The LoginEx method can then do any additional checks it needs and throw an exception (or modify the session information) based on whatever its own requirements are.

Next the extension point itself:


public Session Login(string username, string password)

        {

            // Get a session - this is abstracted via MEF too.

            var session = SessionProvider.GetSession(username, password);


            // =============================================

            // EXTENSION POINT

            // =============================================


            // process all the extensions

            if (LoginExtensions != null)

            {

                Console.WriteLine(string.Format("LoginHelper: Found {0} extensions...",
LoginExtensions.Count()));


                foreach (var extension in LoginExtensions)

                {

                    extension.LoginEx(ref session);

                }

            }


            // =============================================

            // END EXTENSION POINT

            // =============================================


            return session;

        }

This code is as simple as it comes – after we do our initial login check and have a session, just iterate the extensions, calling them each in turn.

The LoginExtensions property is the point at which MEF will inject the extension instances:

        [Import(AllowRecomposition = true)]

        public IEnumerable<ILoginExtension> LoginExtensions { get; set; }

Note that MEF automatically understands that if a module requires an IEnumerable of a type, then it is to inject a list of class instances that satisfy that requirement into the property. If the requirement is for a single instance, then just the first matching extension will get injected. So we could also abstract how a session is created (for example, from a database, or via a web service), and the LoginHelper can indicate its need for a provider with a property for that:

        [Import]

        public ISessionProvider SessionProvider { get; set; }

In the sample, this composition logic is encapsulated in a static ExtensionHelper class that provides a single container of all the Imports and Exports, as well as a simple method to allow a module to compose itself.

    public static class ExtensionHelper

    {

...


        public static void Compose(object compositionTarget)

        {

            // configure our Imports so that we've loaded any plugins.

            var batch = new CompositionBatch();

            batch.AddPart(compositionTarget);


            using (var container = GetCompositionContainer())

            {

                container.Compose(batch);

            }

        }


...

    }

The Compose method is the heart of the helper – it retrieves the composition container from a helper method, then instructs that container to satisfy any requirements of the object passed into it.

We centralise our container generation so that the catalog of imports and exports is generated only once – parsing all the assemblies in a large project can take a little time.

    public static class ExtensionHelper

    {

        private static AggregateCatalog _catalog;


        private static object _padlock = new object();


        public static CompositionContainer GetCompositionContainer()

        {

            if (_catalog == null)

            {

                lock (_padlock)

                {

                    _catalog = new AggregateCatalog();

 

                    // Add the current executable

                    _catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));


                    // Add all the assemblies in the executable's directory

                    _catalog.Catalogs.Add(new DirectoryCatalog(".", false, "*.dll"));


                    // add any plugins assemblies

                    if (PlugInsDirectoryExists)

                    {

                        _catalog.Catalogs.Add(new DirectoryCatalog(PlugInsDirectory, true, "*.dll"));

                    }

                }

            }


            // finally, build the composition container

            var container = new CompositionContainer(_catalog);


            return container;

        }


...

    }

You will notice that we add three “sub-catalogs” to our application’s plug-in catalog:

  1. A catalog containing any imports and exports found in the current executing assembly
  2. A catalog containing imports and exports from any other assemblies found in the current working directory. This is a “static” catalog.

    Note: For windows services & ASP.Net, the working directory is NOT the executable’s installation directory, so you may need to compensate!.

  3. A catalog containing imports and exports from any assemblies found in a specific “plug-ins” directory.

    This catalog is “dynamic”, indicated by the true flag passed into its constructor, and will “watch” the plug-ins directory for any assemblies being added or removed. The next composition that happens would then automatically pick up any new plug-ins – a really powerful feature.

We cache the catalog so that the assembly resolution happens only once, but create a new composition container each time just to be on the safe side and avoid any interactions between objects being composed.

With this helper class available, the LoginHelper’s constructor becomes about as simple as you could hope for:

        public LoginHelper()

        {

            ExtensionHelper.Compose(this);

        }

Finally, we can implement an extension in a completely separate assembly if required, just by implementing the requirement interface (e.g. ILoginExtension) and decorating the class appropriately. So we can implement a FooLoginCheckExtension plug-in class thus:

    [CompositionOptions(CreationPolicy = CreationPolicy.NonShared)]

    [Export(typeof(ILoginExtension))]

    public class FooLoginCheckExtension : ILoginExtension

    {


        public void LoginEx(ref Session session)

        {

            Console.WriteLine(string.Format(" Foo: Processing {0}", session.Guid));

        }

    }

MEF also is recursive – if any extensions need providers, or have other extension points themselves, these too will be satisfied when the MEF composes the LoginHelper. This means you COULD write a completely interface-driven system, where every component is bound in dynamically using MEF.

Even for this simple case, the MEF provides an elegant and above all SIMPLE way of defining and implementing extensibility within your application. Use it once, and you’ll be using it again and again to implement extension points in your code that will make it much more flexible.

On a final note, it should be stressed that MEF is NOT an Inversion of Control container[3] - it targets purely one goal: Dependency Management. But it does this well, and as such is a worthy addition to any developer’s toolset.


[1] http://www.codeplex.com/MEF

[2] http://codebetter.com/blogs/glenn.block/archive/2008/09/25/what-is-the-managed-extensibility-framework.aspx

[3] http://ayende.com/Blog/archive/2008/09/25/the-managed-extensibility-framework.aspx