Sunday, December 19, 2010

Introduction to InterceptingCatalog – Part II – Open Generics Support

In the previous post I have described how to setup interception using the InterceptingCatalog and InterceptionConfiguration class. Just to remind you, the interception allows you to take control over the exported instances thanks to the IExportedValueInterceptor interface. Although this is the primary functionality, there is other bunch of stuff possible to do with the catalog. In this post I am going to show how to enable open-generics support for MEF using both the InterceptingCatalog and the decorating GenericCatalog. I will then introduce the IExportHandler interface which gives the ability to do some nice filtering based on a given criteria as well as to add new exports on the fly. The open generics support implementation is based on the on the fly export creation (thanks to the IExportHandler interface) as well as thing called part rewriting. Keep reading to find out more!

The problem

One of the biggest problem people complain about is the lack of open-generics support in MEF. You can read about this issue here, here and here (I advise you see these entries!). The canonical example folks use concerns IRepository<T>. Imagine the following code:

public interface IRepository<T>
{
T Get(int id);

void Save(T instance);
}

[Export(typeof(IRepository<>))]
public class Repository<T> : IRepository<T>
{
public T Get(int id)
{
return (...);
}

public void Save(T instance)
{
Console.WriteLine("Saving {0} instance.", instance.GetType().Name);
}
}

/// <summary>
/// Fake customer.
/// </summary>
public class Customer { }

[Export]
public class CustomerViewModel
{
[Import]
public IRepository<Customer> Repository { get; set; }
}

So what happens here ? We simply export a generic implementation of the generic interface IRepository<T> with an open-generic contract type, and we import a closed-generic part based on the open generic contract. Unfortunately, this isn’t supported out of the box in MEF. However, thanks to MefContrib, it is!

How can I get it ?

Open generics support shipped initially in the MefContrib 1.0 release. However, it had limited capabilities as the open generics worked only when generic types were exported using the InheritedExport attribute. To get the updated version, which enables to do things like the above, you have to download MefContrib repo and compile the sources yourself. Updated samples, including those presented here, are available in the MefContrib-Samples repo. Go and get them =)

Container setup

There are two ways of enabling open generics support. You can either use more verbose syntax using the InterceptingCatalog, or you can leverage the GenericCatalog. The GenericCatalog is noting more than a convenient decorating catalog which internally uses the InterceptingCatalog.

The first thing to do is to provide mapping between open generic interface and its implementation. This step is mandatory since the underlying infrastructure requires to produce export based on the concrete implementation. This export is produced on the fly, which means it is not contained in any composable catalog, but is created when it is needed. To map the contract type to its implementation you can either implement IGenericContractRegistry interface or inherit the GenericContractRegistryBase class. The implementation which supports the above example is presented below.

[Export(typeof(IGenericContractRegistry))]
public class MyGenericContractRegistry : GenericContractRegistryBase
{
protected override void Initialize()
{
Register(typeof(IRepository<>), typeof(Repository<>));
}
}

Important: the mapping is required only when you export the generic class with explicitly given contract type (like in the example). If you export generic class with its default contract type, no mapping is required!

Next is what you have probably expected – the catalog setup.

// Create source catalog
var typeCatalog = new TypeCatalog(typeof(CustomerViewModel), typeof(MyGenericContractRegistry));

// Create the interception configuration and add support for open generics
var cfg = new InterceptionConfiguration()
.AddHandler(new GenericExportHandler());

// Create the InterceptingCatalog and pass the configuration
var interceptingCatalog = new InterceptingCatalog(typeCatalog, cfg);

// Create the container
var container = new CompositionContainer(interceptingCatalog);

// Get the repository
var repository = container.GetExportedValue<CustomerViewModel>().Repository;
After creating the interception configuration, we add the GenericExportHandler instance which is responsible for creating closed generic parts. This class implements the IExportHandler interface, which I will introduce in a moment. Meanwhile, let’s see the less verbose and cleaner setup routine.

// Create source catalog
var typeCatalog = new TypeCatalog(typeof(CustomerViewModel));

// Create catalog which supports open-generics, pass in the registry
var genericCatalog = new GenericCatalog(new MyGenericContractRegistry());

// Aggregate both catalogs
var aggregateCatalog = new AggregateCatalog(typeCatalog, genericCatalog);

// Create the container
var container = new CompositionContainer(aggregateCatalog);

// Get the repository
var repository = container.GetExportedValue<CustomerViewModel>().Repository;

Instead of creating the InterceptingCatalog, the GenericCatalog is created. This concludes how to setup MEF to support open generics. Next sections explain how stuff works, without digging into implementation details though. If you are curious, keep reading!

How does it work ?

You are maybe asking yourself – given the export definition below – how does MEF know that when importing say IRepository<Order>, it should inject Repository<Order> ?!
[Export(typeof(IRepository<>))]
public class Repository<T> : IRepository<T>
{
}

In fact MEF only knows there is an export Repository<T> which is NOT the required one! And this is not the only question! Attentive reader will also observe the the contract type (which is a string) of the given export will be ‘SomeCleverNamespace.IRepository()’ which is an open generic. But the import’s contract type will be ‘SomeCleverNamespace.IRepository(SomeOtherCleverNamespace.Order)’ which is a closed generic. So even though MEF somehow knew the export Repository<Order>, the contract types wouldn’t match resulting in ImportCardinalityMismatchException.

The answer to the first question is on the fly export creation. Earlier I have introduced the concept of mapping contract type to its implementation(s). So when we import IRepository<>, MEF knows its implementation is Repository<>. But of course we import closed generic, like I said IReposiotry<Order>, so MEF knows the implementing type is Repository<Order>. Of course there is no export Repository<Order>, only Repository<T>. So it have to be introduced in runtime! This is where IExportHandler comes to play. The open generics support is all implemented in the GenericExportHandler class which is responsible for creating closed generic exports on the fly.

Finally, the answer to the second question is part rewriting. When we create Repository<Order> export on the fly (I mean in runtime), the export’s contract type will remain ‘SomeCleverNamespace.IRepository()’. So we have to rewrite the part so that the contract type and optionally contract name will be set properly. To do the part rewriting, special catalog is used – GenericTypeCatalog. It accepts two types – the concrete type being exported (e.g. Repository<Order>) and the open-generic contract type (e.g. IRepository<>). What the catalog does in its internals is to rewrite all open-generic exports which match the contract type to be closed-generic. In our example, the contract type will be rewritten from ‘SomeCleverNamespace.IRepository()’ to ‘SomeCleverNamespace.IRepository(SomeOtherCleverNamespace.Order)’. Same for contract name.

Meet the IExportHandler interface

The purpose of this interface is to filter out exports based on any criteria you want, as well as to dynamically create new exports. Let’s have a look at the IExportHandler signature.

public interface IExportHandler
{
void Initialize(ComposablePartCatalog interceptedCatalog);

IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>>
GetExports(
ImportDefinition definition,
IEnumerable<Tuple<ComposablePartDefinition,ExportDefinition>> exports);
}

Wow! This looks complicated! Hopefully, it is not :) The initialize method gets called once when the export handler is initialized. Within this method you get a reference to the catalog being intercepted. The main player here is the GetExports method which has the exact same signature as the GetExports method in the ComposablePartCatalog class. It is called whenever an InterceptingCatalog is asked for exports which match the given import. The import definition is passed as the first argument. The second argument is a collection of matching export definitions along with theirs ComposablePartDefinition instances. The initial collection is the collection of exports from the intercepted catalog. Because the method returns the collection of matching exports, we can filter out the original exports we don’t want to show up, or what is more interesting, we can add our own export definitions!

Known limitations

Although support for open-generics in MefContrib is pretty amazing, it is not perfect. The first and probably the biggest limitation is the lack of support for recomposition. The other problem is that type being imported is inferred from the language construct rather than the import itself. Consider the following two imports.

[Import]
public IRepository<Order> OrderRepository { get; set; }

[Import(typeof(IRepository<Order>))]
public object OrderRepository { get; set; }

Both imports are perfectly legal. But only the former works as expected. This is because the type being imported is inferred from the property’s type, which is IRepository<Order>. In the latter example, the contract type is explicitly given in the Import attribute, but the property’s type is object, hence the inferred type will be object, which is not the case. You may want to know why is that. As you probably know, the import in MEF is represented by the ImportDefinition class. Unfortunately, it is NOT possible to get the Type instance representing the import from the ImportDefinition instance, only the defining construct (like property, field, etc.) and only for those ImportDefinition instances created by MEF’s Reflection Model.

Conclusion

In this post I have presented MefContrib’s approach to enable open-generic type composition. Hope you like it!

Tuesday, December 14, 2010

MEF Deep Dive Talk

Recently, I gave 2 talks about Managed Extensibility Framework. One on KGD.NET, which is our local .NET group (on Nov 24th 2010), and one on IT Academic Day at Uniwersytet Jagielloński in Kraków (Dec 14th 2010). Both of my talks went good! I do enjoy spreading knowledge about MEF and MefContrib! When it comes to the presentations, both were mostly the same, although on ITAD I was speaking more about MEF itself and less about hard stuff, so it was kind a MEF Deep Dive Light Edition =) I covered the following:

  1. Basics of developing loosely coupled components
  2. MEF basics (parts, exports, imports, composition)
  3. Catalogs
  4. Metadata
  5. Custom export attributes
  6. Recomposition
  7. Stable composition
  8. Debugging MEF
  9. MefContrib
  10. MEF Extensibility

You can find all the materials (slides + source code) from the KGD.NET meeting here and from the ITAD here. If you haven’t attended any of the talks, you might still want to go through the slides (these are nice!) and run the demos (VS 2010). Finally, I want thank Mike Taulty for letting me use some of the slides from his MEF talk =)

Saturday, December 4, 2010

MatrixAnimation for WPF

Windows Presentation Foundation has a powerful animation system. It comes with various classes which enable dependency properties’ values to be animated, i.e. to be automatically changed during a given period of time. WPF supports four types of animations:

  • Linear animation – a value of a property linearly changes from a starting value (referred as From) to a destination value (referred as To).
  • Key frame animation – animation is specified using key frames, each key frame specifies the time and the desired value. The animated property will be assigned once the timeline hits the give time.
  • Path-based animation – property value is given by a geometric path.
  • Frame-based animation – this is the most powerful animation approach, the CompositionTarget class is used to create custom animations based on a per-frame callback.

The first three animation types are supported by <Type>Animation, <Type>AnimationUsingKeyFrames and <Type>AnimationUsingPath classes, respectively. For example, consider the double type. Its animation is supported by DoubleAnimation, DoubleAnimationUsingKeyFrames and DoubleAnimationUsingPath classes.

WPF also supports matrix animations. However, out of the box, only key frame and path-based animations are supported for the Matrix type. This post introduces MatrixAnimation class, which performs linear, smooth animation of the Matrix type. The animation supports translation, scaling and rotation along with easing functions. The following 14 sec-length video shows an early preview of a multi-touch MDI interface whose windows are being animated using the MatrixAnimation class.

The following code snippet represents the MatrixAnimation class.
public class MatrixAnimation : MatrixAnimationBase
{
public Matrix? From
{
set { SetValue(FromProperty, value); }
get { return (Matrix)GetValue(FromProperty); }
}

public static DependencyProperty FromProperty =
DependencyProperty.Register("From", typeof(Matrix?), typeof(MatrixAnimation),
new PropertyMetadata(null));

public Matrix? To
{
set { SetValue(ToProperty, value); }
get { return (Matrix)GetValue(ToProperty); }
}

public static DependencyProperty ToProperty =
DependencyProperty.Register("To", typeof(Matrix?), typeof(MatrixAnimation),
new PropertyMetadata(null));

public IEasingFunction EasingFunction
{
get { return (IEasingFunction)GetValue(EasingFunctionProperty); }
set { SetValue(EasingFunctionProperty, value); }
}

public static readonly DependencyProperty EasingFunctionProperty =
DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(MatrixAnimation),
new UIPropertyMetadata(null));

public MatrixAnimation()
{
}

public MatrixAnimation(Matrix toValue, Duration duration)
{
To = toValue;
Duration = duration;
}

public MatrixAnimation(Matrix toValue, Duration duration, FillBehavior fillBehavior)
{
To = toValue;
Duration = duration;
FillBehavior = fillBehavior;
}

public MatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration)
{
From = fromValue;
To = toValue;
Duration = duration;
}

public MatrixAnimation(Matrix fromValue, Matrix toValue, Duration duration, FillBehavior fillBehavior)
{
From = fromValue;
To = toValue;
Duration = duration;
FillBehavior = fillBehavior;
}

protected override Freezable CreateInstanceCore()
{
return new MatrixAnimation();
}

protected override Matrix GetCurrentValueCore(Matrix defaultOriginValue, Matrix defaultDestinationValue, AnimationClock animationClock)
{
if (animationClock.CurrentProgress == null)
{
return Matrix.Identity;
}

var normalizedTime = animationClock.CurrentProgress.Value;
if (EasingFunction != null)
{
normalizedTime = EasingFunction.Ease(normalizedTime);
}

var from = From ?? defaultOriginValue;
var to = To ?? defaultDestinationValue;

var newMatrix = new Matrix(
((to.M11 - from.M11) * normalizedTime) + from.M11,
((to.M12 - from.M12) * normalizedTime) + from.M12,
((to.M21 - from.M21) * normalizedTime) + from.M21,
((to.M22 - from.M22) * normalizedTime) + from.M22,
((to.OffsetX - from.OffsetX) * normalizedTime) + from.OffsetX,
((to.OffsetY - from.OffsetY) * normalizedTime) + from.OffsetY);

return newMatrix;
}
}

The code is actually quite simple. The class is derived from the abstract MatrixAnimationBase class. Firstly, three dependency properties are defined, namely From, To and EasingFunction. Next comes a bunch of useful constructors. The interesting part resides in the GetCurrentValueCore method. At first, the current animation time is retrieved. Also, the animation time is eased with the easing function if it is available. Lastly, new matrix is calculated based on the From and To values. Each matrix cell is linearly scaled with the time value. And that’s it! This provides smooth animation for the matrix type!