Reading MEF code
Okay, here is the deal. There is a feature in MEF that I find interesting, the ability to dynamically recompose the imports that an instance have. Well, that is not accurate. that doesn't really interest me. What does interest me is some of the implementation details. Let me explain a bit better.
As I understand the feature, MEF can load the imports from an assembly, and if I drop another file into the appropriate location, it will be able to update my imports collection. Now, what I am interested in is to know whatever MEF allow me to update file itself and update it on the fly. The reason that I am interested in that is to know how this is done without locking the file (loading an assembly usually locks the file, unless you use shadow copy assemblies, which means that you have to use a separate AppDomain).
As you can imagine, this is a very specific need, and I want to go in, figure out if this is possible, and go away.
I started by checking out the MEF code:
svn co https://mef.svn.codeplex.com/svn mef
I just love the SVN integration that CodePlex has.
Now, the only way that MEF can implement this feature is by watching the file system, and that can be done using a FileSystemWatcher. Looking for that, I can see that it appears that DirectoryPartCatalog is using it, which isn't really surprising.
But, going there and reading the code gives us this:
Note what isn't there. there is no registration to Changed. This is likely not something that MEF supports.
Okay, one more try. Let us see how it actually load an assembly. We start from Export<T> and GetExportedObject() which calls to GetExportedObjectCore() which shell out to a delegate. Along the way I looked at CompositionException, just to make sure that it doesn't have the same problem as TypeLoadException and the hidden information, it doesn't.
I tried to follow the reference chain, but I quickly got lost, I then tried to figure out how MEF does delayed assembly loading, to see if it is doing anything special there, but I am currently hung at ComposablePartDefinition.Create, which seems promising, but it is accepting a delegate and no one is calling this.
So this looks like it for now.
Comments
How about in constructor of AttributedAssemblyPartCatalog(string codeBase):
var assemblyName = new AssemblyName();
assemblyName.CodeBase = codeBase;
Assembly assembly = Assembly.Load(assemblyName);
this._assembly = assembly;
Steve,
You are probably right, I hoped for some fancy work there, though
Do you think it would be possible to support dynamic recomposition with Windsor ?
Steve,
Sure, it is pretty easy, you need to write a facility that keeps track on that, though, and respond to changes to ComponentStatusChanged.
The problem is that MEF doesn't have the notion of lifetimes, and Windsor does, so you need to do some fancy footwork there to get it to work in all situations
Interesting, I was thinking about components or sub-systems that can be started / stopped on the fly (as long as they are not a vital part of the application => a component exists that has a mandatory dependency to it) ... considering that most applicative components / services are singletons.
Steve,
Check my post about components about a week ago, it talks about that.
Exactly ! Have you seen the presentation of Juval Lowy touting WCF as a better .NET ? As he says, WCF offers you process isolation at the class level ... maybe an interesting option?
I heard of that, I think that he is being grossly exgagerating. WCF is really slow.
Something like five orders of magnitudes compare to plain .NET
That's the main downside, which might be adressed by in-process transport like www.codeproject.com/.../NullTransportForWCF.aspx. Haven't tested it extensively but when you think of it, WCF has all the infrastructure (and more) that you need to implement what you describe in your post.
The fundamental problem here is that .NET doesn't support dynamic assembly unloading. You could reload the assembly, but you would never be able to recover the memory used by the old one. One of the main use cases of such as feature is live updating of a long-running application and gradually leaking memory in the form of unreferenced assemblies, JIT'd code, and related data structures doesn't seem like an acceptable story to me. So work needs to be done at the CLR level before a framework like MEF can implement this for the in-process case. WCF or a cross-app-domain plug-in system are possible solutions, but - as Oren mentions - they're orders of magnitude slower than in-process and therefore aren't usable for general composition.
You can achieve the functionality by setting an app domain to shadow copy (I just tested it). With shadow copying the assemblies won't be locked and you can update in place. The caveat is this won't remove any types that are loaded in memory, BUT it will allow you to update which types are available to the container as when the catalog changes, recomposition will occur. Ping me if you want to chat on this.
Comment preview