简体   繁体   English

MEF +插件没有更新

[英]MEF + Plug-In not updating

I asked this on the MEF Codeplex forum already, but I haven't gotten a response yet, so I figured I'd try StackOverflow. 我已经在MEF Codeplex论坛上问了这个,但我还没有得到回复,所以我想我会尝试StackOverflow。 Here's the original post if anyone's interested (this is just a copy from it): 如果有人感兴趣,这是原始帖子(这只是它的副本):

MEF Codeplex MEF Codeplex

"Let me first say that I'm completely new to MEF (just discovered it today) and am very happy with it so far. However, I've ran in to a problem that is very frustrating. I'm creating an app that will have a plugin architecture and the plugins will only be stored in a single DLL file (or coded into the main app). The DLL file needs to be able to be recompiled during run-time and the app should recognize this and re-load the plugins (I know this is difficult, but it's a requirement). To accomplish this I took the approach covered http://blog.maartenballiauw.be/category/MEF.aspx there (look for WebServerDirectoryCatalog). Basically the idea is to "monitor the plugins folder, copy the new/modified assemblies to the web application's /bin folder and instruct MEF to load its exports from there." This is my code, which is probably not the correct way to do it but it's what I found in some samples around the net: “首先我要说的是,我对MEF完全不熟悉(今天才发现它),到目前为止我对此非常满意。但是,我遇到了一个非常令人沮丧的问题。我正在创建一个应用程序,将有一个插件架构,插件将只存储在一个DLL文件中(或编码到主应用程序中。)DLL文件需要能够在运行时重新编译,应用程序应该识别这个并重新加载插件(我知道这很困难,但这是一个要求)。为了实现这个目的,我采取了http://blog.maartenballiauw.be/category/MEF.aspx的方法(寻找WebServerDirectoryCatalog)。基本上我的想法是“监视插件文件夹,将新的/修改过的程序集复制到Web应用程序的/ bin文件夹,并指示MEF从那里加载其导出。”这是我的代码,这可能不是正确的方法,但它是我发现的在网周围的一些样本中:

        main()...
    string myExecName = Assembly.GetExecutingAssembly().Location;
        string myPath = System.IO.Path.GetDirectoryName(myExecName);
        catalog = new AggregateCatalog();
        pluginCatalog = new MyDirectoryCatalog(myPath + @"/Plugins");
        catalog.Catalogs.Add(pluginCatalog);


        exportContainer = new CompositionContainer(catalog);

        CompositionBatch compBatch = new CompositionBatch();
        compBatch.AddPart(this);
        compBatch.AddPart(catalog);
        exportContainer.Compose(compBatch);

and

    private FileSystemWatcher fileSystemWatcher;
    public DirectoryCatalog directoryCatalog;
    private string path;
    private string extension;

    public MyDirectoryCatalog(string path)
    {
        Initialize(path, "*.dll", "*.dll");
    }

    private void Initialize(string path, string extension, string modulePattern)
    {
        this.path = path;
        this.extension = extension;
        fileSystemWatcher = new FileSystemWatcher(path, modulePattern);
        fileSystemWatcher.Changed += new FileSystemEventHandler(fileSystemWatcher_Changed);
        fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created);
        fileSystemWatcher.Deleted += new FileSystemEventHandler(fileSystemWatcher_Deleted);
        fileSystemWatcher.Renamed += new RenamedEventHandler(fileSystemWatcher_Renamed);
        fileSystemWatcher.IncludeSubdirectories = false;
        fileSystemWatcher.EnableRaisingEvents = true;
        Refresh();
    }
    void fileSystemWatcher_Renamed(object sender, RenamedEventArgs e)
    {
        RemoveFromBin(e.OldName);
        Refresh();
    }
    void fileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
    {
        RemoveFromBin(e.Name);
        Refresh();
    }
    void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
    {
        Refresh();
    }
    void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
    {
        Refresh();
    }
    private void Refresh()
    {
        // Determine /bin path 
        string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
        string newPath = "";
        // Copy files to /bin 
        foreach (string file in Directory.GetFiles(path, extension, SearchOption.TopDirectoryOnly))
        {
            try
            {
                DirectoryInfo dInfo = new DirectoryInfo(binPath);
                DirectoryInfo[] dirs = dInfo.GetDirectories();
                int count = dirs.Count() + 1;
                newPath = binPath + "/" + count;
                DirectoryInfo dInfo2 = new DirectoryInfo(newPath);
                if (!dInfo2.Exists)
                    dInfo2.Create();

                File.Copy(file, System.IO.Path.Combine(newPath, System.IO.Path.GetFileName(file)), true);
            }
            catch
            {
                // Not that big deal... Blog readers will probably kill me for this bit of code :-) 
            }
        }
        // Create new directory catalog 
        directoryCatalog = new DirectoryCatalog(newPath, extension);
        directoryCatalog.Refresh();
    }
    public override IQueryable<ComposablePartDefinition> Parts
    {
        get { return directoryCatalog.Parts; }
    }
    private void RemoveFromBin(string name)
    {
        string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "");
        File.Delete(Path.Combine(binPath, name));
    }

So all this actually works, and after the end of the code in main my IEnumerable variable is actually filled with all the plugins in the DLL (which if you follow the code is located in Plugins/1 so that I can modify the dll in the plugins folder). 所以这一切实际上都有效,并且在主要代码结束后,我的IEnumerable变量实际上填充了DLL中的所有插件(如果您按照代码位于Plugins / 1中,那么我可以修改dll中的插件文件夹)。 So now at this point I should be able to re-compile the plugins DLL, drop it in to the Plugins folder, my FileWatcher detect that it's changed, and then copy it into folder "2" and directoryCatalog should point to the new folder. 所以现在在这一点上,我应该能够重新编译插件DLL,将其放入Plugins文件夹,我的FileWatcher检测到它已被更改,然后将其复制到文件夹“2”中,directoryCatalog应该指向新文件夹。 All this actually works! 这一切实际上都有效! The problem is, even though it seems like every thing is pointed to the right place, my IEnumerable variable is never updated with the new plugins. 问题是,即使看起来每个东西都指向正确的位置,我的IEnumerable变量也永远不会使用新的插件进行更新。 So close, but yet so far! 如此接近,但到目前为止! Any suggestions? 有什么建议? I know the downsides of doing it this way, that no dll is actually getting unloaded and causing a memory leak, but it's a Windows App and will probably be started at least once a day, and the plugins are un-likely to change that often, but it's still a requirement from the client that it does this without re-loading the app. 我知道这样做的缺点,没有dll实际上是卸载并导致内存泄漏,但它是一个Windows应用程序,可能每天至少启动一次,并且插件不太可能经常更改,但客户仍然要求它在不重新加载应用程序的情况下执行此操作。 Thanks! 谢谢!

Thanks for any help you all can provide, it's driving me crazy not being able to figure this out." 感谢你们所能提供的任何帮助,这让我发疯,无法解决这个问题。“

There is no trigger for recomposition, because your catalog implementation doesn't provide notifications. 没有重构的触发器,因为您的目录实现不提供通知。 Implement INotifyComposablePartCatalogChanged to fix this. 实现INotifyComposablePartCatalogChanged来解决这个问题。

我相信MEF只能加载同一个程序集的一个版本(我尝试使用Silverlight)

I was having a similar issue- after copying discovered Plugins to the application's directory, a DirectoryCatalog wouldn't see them, even after calling .refresh() on the DirectoryCatalog. 我遇到了类似的问题 - 在将发现的插件复制到应用程序的目录后,即使在DirectoryCatalog上调用.refresh()之后,DirectoryCatalog也看不到它们。

I found that stepping through the code resolved the issue- my best guess is that the filesystem still needs a moment after the FileSystemWatcher kicks off it's notification before MEF can scan the new assembly (perhaps to finish some obscure copy operation) and see the parts inside. 我发现通过代码解决了这个问题 - 我最好的猜测是文件系统仍然需要片刻,之后FileSystemWatcher启动它的通知,然后MEF可以扫描新的程序集(可能完成一些模糊的复制操作)并查看里面的部件。

System.Threading.Thread.Sleep(1000), lame as it is, solved the issue. System.Threading.Thread.Sleep(1000),实际上很蹩脚,解决了这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM