Ask Kathleen

Getting Current on MEF

Readers explore Managed Extensibility Framework, using callback delegates and how to create the equivalent of a C# partial interface in Visual Basic.

Q: I read your article on Managed Extensibility Framework (MEF), but I heard there have been changes to the way MEF works. Can you explain these changes?

A: Microsoft's Managed Extensibility Framework in general still works the way I described in my earlier article ("Working with MEF," April 2009). That article used one of the CodePlex previews. It looks like MEF Preview 6 is getting close to the final .NET 4 feature set, so it's worth looking at how these changes affect your code. MEF continues to work in .NET 3.5 as well. There have been syntax changes and a major change to how MEF behaves when parts are missing.

I'll review a couple aspects of MEF as groundwork for explaining these enhancements, but if you're new to MEF please read my April article, which you can find on VisualStudioMagazine.com using FindIT code Dollard1009. You'll see these changes in MEF Preview 6 and beyond, and they'll also be reflected in Visual Studio 2010 starting with beta 2. While MEF is moving close to lockdown for .NET 4, additional changes may still occur.

Note that Visual Studio 2010 beta 1 is based on an older MEF preview than the one that I'm describing here. You can use MEF Preview 6 with beta 1 if you download and explicitly reference its assemblies.

Before looking at recent changes, I need to cover an aspect of MEF I touched on lightly in the earlier article. Cardinality refers to how many of something is legal-in other words, the legal count. MEF supports cardinality of zero or one, exactly one, and zero to many. Some of the recent syntax changes involve how MEF manages cardinality.

With a cardinality of zero to many, MEF returns anything that matches the request-which generally means matching a specific interface. In early previews, MEF used the target type to determine whether the intended cardinality was exactly one or zero to many. If the target was an IEnumerable, MEF assumed zero-to-many cardinality. If the target type was not an IEnumerable, MEF assumed a cardinality of exactly one. This was a flawed design. The major issue is that this excludes import of a list as a single import-it prohibits you saying, "there should be exactly one list available." In addition to being overly restrictive, it could be confusing if the target was a derived type. Because of the open source release of early MEF previews, this design issue was discovered and addressed.

The Import attribute now refers only to single imports-zero-to-one and exactly-one cardinalities. A new ImportMany attribute declares zero-to-many cardinality. If you use the Import attribute on a type declared as IEnumerable<T>, MEF will search for exactly one IEnumerable list. If you use the ImportMany attribute on an IEnumerable<T> type, MEF will supply an IEnumerable that contains all parts that export the type T. The second approach of filling the IEnumerable with matching parts is the more common case. Listing 1 illustrates this distinction.

This version of MEF also changes composition behavior with a new feature called Stable Composition when there are nested parts. A nested part is simply an import within another part. In earlier versions, if a cardinality rule with a nested part couldn't be met-for example, if a part was not available for a cardinality of exactly one-an exception occurred with a plethora of information on what was causing the issue. A nested part is simply an import on a part. This stopped composition and would generally block proper function of your application. With Stable Composition, parts that have missing nested parts won't appear in the catalog. Information about the missing part is retained, and if the nested part later becomes available through additional composition, the containing part will appear in the catalog. The reverse doesn't occur. If a part is in the catalog and may be in use, an exception occurs if you attempt to remove a required nested part.

While Stable Composition is a step forward, it's a sword that cuts two ways. It keeps systems from crashing on certain types of errors in composed parts-parts that might not be under the control of the application. On the other hand, errors that would have appeared as exceptions with full information are now silent failures with the containing part simply missing from the catalog.

If you've been working with an earlier version of MEF, including Visual Studio 2010 beta 1, the combination of changing how Import works with an IEnumerable and Stable Composition may cause some debugging headaches. The team is working on tools for tracing and debugging, but the core issue is that you'll see the failure at a high level in a missing part, while the real issue is buried rather deep in composed parts. It's important to search projects that use MEF from earlier previews and beta 1 for the combination of the Import attribute and an IEnumerable, and change these to ImportMany. You must also ensure any IEnumerable parameters on a constructor marked with the ImportingConstructor attribute have the ImportMany attribute as well.

Although it's tedious to ensure this change manually, it's easier than debugging a complex system under Stable Composition.

The updated version of MEF also has naming changes. Export<T> becomes Lazy<T> to clarify its purpose of late creation of the contained part. The GetExportedObject method is replaced with a functionally equivalent Value property.

The ExportCollection is removed in favor of the simpler approach of using an IEnumerable<Lazy<partType>>. It may at first seem odd to see a nested generic like this, and FxCop/Code Analysis has traditionally complained about the complexity of such constructs in your code. They certainly don't deserve wide use, but this is one example of where the direct inclusion of the nested generic provides more clarity than a wrapping type. If you're faced with a similar situation in your own generics, consider whether the person reading the code is aided by understanding the nested generic type-which, in this case, they are.

In my April article I demonstrated the use of custom metadata attributes. In this newest version of MEF, there's a subtle but important change that can lead to clearer code for people creating exports of parts you define. The ExportAttribute class was unsealed. If you create a custom ExportAttribute with a MetadataAttributeAttribute and a meaningful name in the context of your system, exporting classes will be marked with their actual intent. The MEF usage will be hidden. For example, if TemplateData includes the MetadataAttributeAttribute, the Export attribute is no longer needed:

   <Export(GetType(IProcessWrapper))> _
<TemplateData(Priority:=Utilities. _
DefaultPriority)> _
Partial Public Class Validation

In my April article I discussed accessing the raw metadata dictionary. This capability is gone. If you need this specific capability, you'll need to create your own dictionary.

Another exciting change in the MEF Preview 6 available on CodePlex is the inclusion of an early preview of MEF for Silverlight. The Silverlight version of MEF will probably not be released with .NET 4 but wait for Silverlight 4, which will release a bit later because they're on independent release cycles. This preview is intended for use with Silverlight 3.

One of the features of MEF for Silverlight is a Package Directory to supply MEF parts via XAP packages. If you're working with Silverlight, MEF capabilities for Silverlight 3 are an exciting addition, although there are likely to be some changes prior to the Silverlight 4 release. Most of these changes are likely to be in the Silverlight-specific pieces such as the API for the Package Catalog. If you're interested in seeing MEF run on Silverlight, you can explore a new picture viewer sample Silverlight application available with the preview.

Q: I'm creating an application using code generation and I want to add new features to a generated interface. However, interfaces don't support partial method-at least in Visual Basic. I want to do this because I'm using an IoC container in a Model-View-ViewModel design, and I want to generate the properties and known methods. However, I also need to add additional items to the interface to support custom behavior. How can I work around this limitation?

A: C# supports partial interfaces and VB does not. But in this case, you need some control of the template in either language, and the result is similar. Because C# supports partial interfaces, you can directly create a partial interface. However, because C# requires the partial keyword on each partial piece, you'll need to include the partial keyword in the generated portion of the interface-this will probably require altering the template.

You can accomplish the same thing in VB, although the approach is different. Here you can create a custom base interface and a generated interface for use, or the reverse:

Interface IFooCustom
' Put custom interface elements here
End Interface

Interface IFoo
Inherits IFooCustom
Property Name() As String
' Other properties
End Interface

Interfaces allow multiple inheritance, so this doesn't interfere with any other inheritance in your design.

There are a couple of differences with the VB approach. Primarily, the C# partial class is optional-you can include the partial or not as your needs change. In the VB approach you must include the custom interface whether or not you're using it. You also have an extra interface in your solution, which a programmer could implement or use, even though its use is inconsistent with the intention of the architecture. There's no parallel to MustInherit-abstract in C#-for interfaces.

If the interface is queried via inheritance, the partial interface in C# will appear as a single interface, while the inheritance aspect of the VB approach will be evident. This is potentially a feature. In the partial interface approach, it's impossible to determine whether a particular interface member is a custom item. Via reflection, you can make this distinction by exploring the inherited interface design. If this distinction is valuable to your overall architecture, you can also use the inheritance approach in C#.

Q: When should I use a callback delegate and when should I use an event?

A: Events and callback delegates both allow communications between elements of your application. There's also a third approach using MEF.

An event allows a subscription model. A class can inform the rest of your application that something happened without concern over how many other portions of the application actually care that the event happened-specifically not caring whether anything is listening for the event. The event generally has an argument, but the calling code can accept the argument as any base type. This is a fairly loosely coupled scenario where the listener is aware of the specific item it subscribed to, but the broadcaster is entirely unaware of who's listening.

A callback delegate provides a specific delegate that will be called in a logically consistent manner. This approach is useful when there are zero or one interested parties. Once the callback is originally passed, this delegate can be passed on with no dependencies other than the signature of the delegate. This is also a loosely coupled scenario where the dependency is only on the delegate being passed around the system, with the listener aware of the specific instance it called to pass the callback delegate.

The third approach relies on a composable system such as MEF. A MEF part can request a list of all other parts in the system that support a particular contract. The contract can contain a delegate to call when something happens. The contract effectively subscribes the listener as interested in a particular occurrence, without the formal dependencies. This is less coupled because, from a logical perspective, the listener effectively says: "Hey, if anyone out there does this, I want to know." It cares about the occurrence unrelated to the thing that caused the occurrence.

Events are a good solution when you have an item that will inherently be known by the subscriber, but the item raising the communications has no dependency on who's listening-for example, in a user interface where containers are interested in state changes of contained parts.

Callbacks are a good solution when there's generally a single listener and the relationship is predictable. For example, an asynchronous process called by an application element is generally interested in knowing that the process completes.

MEF parts are a good solution when actions will occur within the system, but the design doesn't require any details or couple. This is a good approach for decoupled systems where a logical state change can be generated by any mechanism and be recognized by any combination of parts-or no parts. MEF parts are a great approach for applications that are already using a composable system.

However, it may not in itself be sufficient reason to adopt a composable approach.

Q: I have a solution with a half dozen projects that works fine on most of my group's machines, but we get the following error when we run the application on a new development machine:

Could not load file or assembly 'MyLibraryName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.

A: This error almost always occurs because you have a mixed build environment: the selected options for building different assemblies in the application aren't compatible in the CPU they target. One way this can happen and give inconsistent results is to have most of the projects in your solution target "AnyCPU" and one or more target "x86." This combination will run without a problem when doing x86 development. However, when you run the same application on a 64-bit machine, you'll encounter this error.

You can fix this by using the same target for all projects in the solution. I've often had to make this change both in the project properties and in the build configuration. There are two things that might surprise you as you make this change. There's a check box that appears when you change the build configuration asking whether you want a new solution item. This generally needs to be unchecked because you already have the correct build defined for the solution.

When you change the target in project properties, Visual Studio assumes you're creating a new set of outputs and resets the output location to the default. If you were building into the default location, you won't notice this. However, if you're building into an alternate location and don't realize that the output path is reset, your application will remain broken because the assembly you're using hasn't been updated.

Q: I was using a local test run configuration to copy some files into my test environment. These tests began to fail and Visual Studio said there was no local test run configuration. How do I get it back?

A: If you lose your local test run configuration, you can recreate it by creating a new test project. This creates the files you need, and then you can delete the dummy project. One way this appears to happen is manually down-revving from .NET 4 to .NET 3.5.

Q: I know this is a small thing, but I find it very annoying to try to read output in the Immediate window which has /r/n embedded in it. How do I display output in the immediate window with the stupid /r/n?

A: To force formatting you should use a WriteLine method such as System.Diagnostics.Debug.WriteLine. For example, if the message in an exception is long and contains these characters, you're currently using:

? ex.Message

Instead use:

? System.Diagnostics.Debug.WriteLine(ex.Message)

Or, if you have imported (using in C#) System.Diagnostics, you can simplify this to:

? Debug.WriteLine(ex.Message)

Q: I'm getting an error in a Windows Presentation Foundation application that just says: System.ExecutionEngineException. The application was previously working.

A: Check your App.xaml for a missing TargetType. It's required in Silverlight. Rick Robinson pointed out one way this might happen in a blog post at http://tinyurl.com/l8ksth.

comments powered by Disqus
Most   Popular
Upcoming Events

.NET Insight

Sign up for our newsletter.

Terms and Privacy Policy consent

I agree to this site's Privacy Policy.