August 2009 - Posts
you can download the sample here
This post assume that you familiar with MEF technologies, you can fined more resources here and here.
Background
I’m currently working at Sela Group on project that demonstrate the different capabilities appended to Windows 7.
This project architecture involve plug-ins (using MEF architecture) and we needed way to instantiate only those plug-ins that support the runtime operating system.
MEF Metadata
MEF support lazy instantiation and metadata which can be inspect before the instantiation.
Plug-ins decoration
MEF support decoration by using the Metadata attribute, also you can use that attribute out of the box, we decide to have strongly metadata technique.
In order to achieve our goal we follow the next steps:
1) First we have to define how our metadata contract:
public interface ISupportedOS {
OSSupported OSSupported { get; }
}
2) Then we define our metadata attribute:
[MetadataAttribute ]
[AttributeUsage (AttributeTargets.Class)]
public class ExportWithMetaAttribute
:ExportAttribute,ISupportedOS{
public ExportWithMetaAttribute(Type exportType,
OSSupported eSupportedOS )
:base(exportType){
this.OSSupported = eSupportedOS;
}
public OSSupported OSSupported { get; set; }
}
3) Now we have to decorate our Plug-in:
[ExportWithMetaAttribute (typeof (ICommand),
OSSupported.Windows7)]
[PartCreationPolicy (CreationPolicy.Shared)]
public class Win7Command: ICommand {
Consuming the plug-ins
Getting the metadata is easy, all we have to do is to add our metadata contract (interface) after the imported type.
Property looks like:
[ImportMany]
public Lazy<ICommand,ISupportedOS> Commands{get;set;}
GetExports looks like:
var commands = container.GetExports<ICommand, ISupportedOS> ();
Loading OS aware plug-ins
The following code snippet show the final step which is to decide whether or not the plug-is compatible with out OS:
foreach (var command in commands) {
if (command.Metadata.OSSupported.IsSupported())
command.Value.Execute ();
}
Summary
MEF lazy instantiation and metadata capabilities give us great control on our plug-ins composition.
You can download the sample code and explore the concept.
You can download the code here
Wouldn’t it be nice to extend WCF just by inheriting the relevant interface (IServiceBehavior, IDispatchMessageInspector, ext…) and having it hooked without wasting your time on finding the right way of hooking it?
Well this post is all about this topic.
How does it work?
I wrote 2 helper project MEFContracts and WcfPrimitivePlugins which responsible for that magic, and you will also need reference to MEF.
For any of your WCF services or client proxy, you have to add reference to the MEFContracts project and ComponentModel project (which is the MEF CTP 6 implementation), then place the WcfPrimitivePlugins.dll under relative folder called “Plug-Ins” (you can change this place by adding MEF catalog using ).
Modify your client proxy to inherit from MefWcfProxy<TChannel> instead of ClientBase<TChannel>.
On the service side you have 2 option:
1) using MefHost for hosting your service.
2) decorate your service with [MefBehavior] attribute
Writing your WCF extensibility
Writing WCF extensibility is made simple.
Just create class library application and implement the WCF extensibility interface
- IServiceBehavior
- IEndpointBehavior
- IOperationBehavior
- IParameterInspector
- IOperationInvoker
- IInstanceContextInitializer
- IDispatchMessageInspector
- IClientMessageInspector
- IErrorHandler
optional: add reference to MEFContracts for having advance hooking for timeout, Throttling, and more
Running the sample
The solution can be compile with different compiler switches for demonstrating different scenarios:
- ByAttribute (will hook the service using [MefBehavior] attribute)
- Debug (will hook the service using MefHost)
- IgnoreInterception (will detach the hooking)
- LimitedThrottling (will cause exceptions by limiting the concurrent session and reduce the timeout – that how you see the IErrorHandler plug-in in action)
So choose the compiler switch (recommended: delete the bin folder), compile the solution and run (WcfClientConsole and WcfHostConsole projects are configure the start with F5)
Summary
Writing WCF extension should be focus on extension and the hooking should be transparent.
I just found out about the partial method existence.
You can think about partial method as virtual method for partial scope.
In case you having your own code generator like Templates, VS designers or Custom tools,
i assume that you familiar with the following scenario:
You code generating partial class and you want to give class consumer the ability to intercept (hook) the class initialization.
Traditionally we may think about one of the followings:
- one option is to avoid writing your own constructor, but what if you need one?
- you may think of virtual method? but the consumer does not inherit the class (its partial).
- so maybe having private event? ye bat haw can the consumer register to the event without having access to the constructor?
This is the place that partial method help you, and it look like this:
Your generated code:
public partial class MyClass {
public MyClass () {
OnInit (); // will compile to IL only if implement
}
partial void OnInit (); // will compile to IL only if implement
}
The consumer code:
partial class MyClass {
partial void OnInit () {
// consumer logic goes here
}
}
The MSDN definition and limitation:
A partial method has its signature defined in one part of a partial type, and its implementation defined in another part of the type. Partial methods enable class designers to provide method hooks, similar to event handlers, that developers may decide to implement or not. If the developer does not supply an implementation, the compiler removes the signature at compile time. The following conditions apply to partial methods:
-
Signatures in both parts of the partial type must match.
-
The method must return void.
-
No access modifiers or attributes are allowed. Partial methods are implicitly private.
New version of BTested is available on Codeplex (compatible with MEF CTP 6)
http://btested.codeplex.com/
Enjoy :-)