MEF Runtime Plugin Update Issue
Asked Answered
S

1

10

Issue

My MEF code is not appropriately updating assemblies during runtime, from a folder associated to a DirectoryCatalog. The plugins load at run-time succesffully, but when i update the dll and call Refresh on the DirectoryCatalog, the assemblies are not getting updated.

Background

I am building a dll that has an MEF container, and uses a DirectoryCatalog to find a local plugin folder. I call this dll currently from a simple WinForm, that is setup to with a seperate project to use ShadowCopy so i can overwrite the dlls in my plugin folder. Instead of using a FileWatcher to update this folder, I am exposing a public method that calls refresh on the DirectoryCatalog, so i can update the assemblies at will instead of automatically.

Code

base class instantiates the MEF catalogs and container, and saves them as class variables for referential access later

    public class FieldProcessor
{
    private CompositionContainer _container;
    private DirectoryCatalog dirCatalog;

    public FieldProcessor()
    {
        var catalog = new AggregateCatalog();
        //Adds all the parts found in the same assembly as the TestPlugin class
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(TestPlugin).Assembly));
        dirCatalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory + "Plugin\\");
        catalog.Catalogs.Add(dirCatalog);

        //Create the CompositionContainer with the parts in the catalog
        _container = new CompositionContainer(catalog);
    }

    public void refreshCatalog()
    {
        dirCatalog.Refresh();
    }

} ...

here's the plugin i'm trying to overwrite. My test of updating, is that the stings returned are output to a text box, I change the Strings the plugin is returning, rebuild, and copy it in to the plugin folder. But it does not update for the running app, until i close and restart the app.

[Export(typeof(IPlugin))]
[ExportMetadata("PluginName", "TestPlugin2")]
public class TestPlugin2 : IPlugin
{
    public IEnumerable<IField> GetFields(ContextObject contextObject, params string[] parameters)
    {
        List<IField> retList = new List<IField>();
        //Do Work Return Wrok Results
        retList.Add(new Field("plugin.TestPlugin2", "TestPluginReturnValue2"));
        return retList;
    }
}

Edit

Import Statement
    [ImportMany(AllowRecomposition=true)]
    IEnumerable<Lazy<IPlugin, IPluginData>> plugins;

Research

I have done fairly extensive research and everywhere in articles and code samples the answer appears to be, to add a DirectoryCatalog to a container and save a reference of that catalog, then call Refresh on that reference, after a new plugin has bee added, and it will update the assemblies...which i am doing, but it's not showing updated output, from the new plugin dll.

Request

Has anyone seen this issue, or know what may be causing my problems with the assemblies not updating during runtime? Any additional information or insight would be appreciated.

Resolution

Thanks to Panos and Stumpy for their links which led me to the solution my issue. For future knowledge seekers, my main issue was that the Refresh method does not update assemblies, when the new assembly has the exact same assembly name as the overwritten dll. For my POC i just tested rebuilding with a Date appended to the assembly name and everything else the same, and it worked like a charm. their links in the comments below, were very useful, and are recommended if you have the same issue.
Single answered 22/4, 2013 at 15:19 Comment(3)
DirectoryCatalog.Refresh will not detect updated assebmlies. Only new or deleted ones. Have a look at this answer for a workaround and suggestions: https://mcmap.net/q/1168600/-facing-error-during-catalog-refresh-the-new-dll-is-not-usedHemphill
My dlls are locked down when they are loaded so I cant override them with new dlls. Did you not have this problem? did you do something that made them updatable.Antepast
yeah, i did have this issue. One of the steps i mentioned in passing was, enabling "Shadow Copy". Shadow Copy allows a program to pull make local copies of dll assemblies, and add them to a local cache, instead of locking the dlls. This has to be enabled to allow you to "hot swap" dlls during runtime, otherwise you need to stop the program, change the dlls, and then restart it. I think this is the example i looked at, but if it doesn't work for you google MEF and Shadow Copy, #12593808Single
C
3

did you set AllowRecomposition parameter to your Import attribut?

AllowRecomposition
Gets or sets a value that indicates whether the property or field will be recomposed when exports with a matching contract have changed in the container.

http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.importattribute(v=vs.95).aspx

edit:

DirectoryCatalog doesn't update assemblies, only added or removed: http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.directorycatalog.refresh.aspx

for a work around: https://mcmap.net/q/1168600/-facing-error-during-catalog-refresh-the-new-dll-is-not-used

Claus answered 22/4, 2013 at 20:58 Comment(6)
I did, sorry i didn't post the import statement code originally, i have updated the question to reflect my import statement.Single
and your refresh code? I think the problem is inside. You said not using FileSystemWatcher, how do you detect and reload your assemblies?Claus
I'm exposing it through the RefreshCatalog method seen above. I'm calling that method from a button click event on a winForm.Single
Refresh doesn't update assemblies but only add or remove them. msdn.microsoft.com/en-us/library/… see: https://mcmap.net/q/1168600/-facing-error-during-catalog-refresh-the-new-dll-is-not-usedClaus
thanks for the links i'm investigating further, may have to change the use case slightly, but those seem like they will help tremendously. I'll reply and mark it as the answer once i've got it worked out. Thanks again.Single
It was an issue of Assembly naming, once i got the code to use unique assembly names the code worked like a champ. Thanks for all your help.Single

© 2022 - 2024 — McMap. All rights reserved.