首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MEF +插件未更新

MEF +插件未更新
EN

Stack Overflow用户
提问于 2010-04-13 05:09:02
回答 3查看 1.9K关注 0票数 4

我已经在MEF Codeplex论坛上问过这个问题了,但我还没有得到回应,所以我想我应该试试StackOverflow。如果任何人感兴趣,这里是原始帖子(这只是它的副本):

MEF Codeplex

“首先我要说的是,我对MEF完全陌生(今天才发现它),到目前为止我对它非常满意。然而,我遇到了一个非常令人沮丧的问题。我正在创建一个应用程序,它将具有插件架构,插件将只存储在单个DLL文件中(或编码到主应用程序中)。DLL文件需要能够在运行时重新编译,应用程序应该识别这一点并重新加载插件(我知道这很困难,但这是必需的)。为了实现这一点,我在那里采用了覆盖http://blog.maartenballiauw.be/category/MEF.aspx的方法(查找WebServerDirectoryCatalog)。基本上,这个想法是“监控插件文件夹,将新的/修改过的程序集复制到web应用程序的/bin文件夹中,并指示MEF从那里加载其导出。”这是我的代码,这可能不是正确的方法,但它是我在网上的一些示例中找到的:

代码语言:javascript
运行
复制
        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);

代码语言:javascript
运行
复制
    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));
    }

所有这些实际上都是有效的,在main中的代码结束后,我的IEnumerable变量实际上被DLL中的所有插件填充(如果您遵循这些代码,它位于Plugins/1中,这样我就可以修改插件文件夹中的dll )。所以现在我应该能够重新编译插件DLL,将它放到plugins文件夹中,我的FileWatcher检测到它发生了变化,然后将它复制到文件夹"2“中,directoryCatalog应该指向新的文件夹。所有这些实际上都是有效的!问题是,即使似乎所有的东西都指向了正确的位置,我的IEnumerable变量从来没有用新的插件更新过。如此接近,但到目前为止!有什么建议吗?我知道这样做的缺点,实际上没有dll被卸载并导致内存泄漏,但它是Windows应用程序,可能每天至少启动一次,插件不太可能经常更改,但客户端仍然要求它在不重新加载应用程序的情况下执行此操作。谢谢!

感谢你们所有人能提供的任何帮助,不能解决这个问题让我抓狂。“

EN

回答 3

Stack Overflow用户

发布于 2010-04-13 06:29:49

没有重新组合的触发器,因为您的目录实现不提供通知。实现INotifyComposablePartCatalogChanged来解决这个问题。

票数 3
EN

Stack Overflow用户

发布于 2010-04-13 16:22:38

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

票数 1
EN

Stack Overflow用户

发布于 2011-08-12 02:45:57

我遇到了一个类似的问题--在将发现的插件复制到应用程序的目录后,即使在DirectoryCatalog上调用了.refresh(),DirectoryCatalog也看不到它们。

我发现单步执行代码解决了这个问题--我最好的猜测是,在FileSystemWatcher启动通知之后,文件系统仍然需要一段时间才能扫描新的程序集(可能是为了完成一些晦涩的复制操作)并查看其中的部分。

System.Threading.Thread.Sleep(1000),尽管它很差劲,但解决了这个问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2625475

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档