簡體   English   中英

從子文件夾解析裝配的正確方法

[英]Proper way to resolving assemblies from subfolders

這是我的應用程序文件夾的外觀:

Application:
+ App.exe
+ App.exe.config
Application/Plugins:
+ Plugin1 (folder)
Application/Plugins/Plugin1:
+ Plugin1.dll
+ SomeDll.dll

因此,主應用程序App.exe查找plugins文件夾並將{PluginName} .dll加載到內存中以運行它。 此插件通常使用它自己的相關程序集,必須對其進行加載(例如SomeDll.dll)。 看來有時會造成嚴重的麻煩。 我收到一個例外,例如找不到依賴程序集的依賴程序集,我也不知道為什么。

例如,我的插件必須加載許多其他dll,因為插件運行OwinSelfHost服務。

因此它必須加載例如:

System.Web.Http.Owin
Owin
Microsoft.Owin
Microsoft.Owin.Host.HttpListener
Microsoft.Owin.Hosting

並且在加載Microsoft.Owin.Hosting時引發無法加載Microsoft.Owin的異常

異常看起來像:

Could not load file or assembly 'Microsoft.Owin, Version=2.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of it's dependencies. File not found.

您可以使用“ AssemblyResolve事件”(方法3): https : //support.microsoft.com/en-us/kb/837908

我編寫了此方法來解析程序集。 根據我的需要進行了調整。

它基本上將AssemblyResolve事件掛接到當前應用程序域,以從目錄列表中檢索請求的程序集。

除了加載程序集文件並檢查其屬於哪個名稱空間之外,沒有簡單的方法來找到與命名空間匹配的程序集文件在哪里解析。

另外,它會丟棄一些不需要的程序集(例如序列化程序,資源...),並檢測非.NET程序集的dll或exe。

更好的方法是使用Global Assembly Cache ,但是我們希望我們的插件可以完全移動。 就是這樣

public static class AssemblyResolver
{
    internal static void Hook(params string[] folders)
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {
                // Check if the requested assembly is part of the loaded assemblies
                var loadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name);
                if (loadedAssembly != null)
                    return loadedAssembly;

                // This resolver is called when an loaded control tries to load a generated XmlSerializer - We need to discard it.
                // http://connect.microsoft.com/VisualStudio/feedback/details/88566/bindingfailure-an-assembly-failed-to-load-while-using-xmlserialization

                var n = new AssemblyName(args.Name);

                if (n.Name.EndsWith(".xmlserializers", StringComparison.OrdinalIgnoreCase))
                    return null;

                // http://stackoverflow.com/questions/4368201/appdomain-currentdomain-assemblyresolve-asking-for-a-appname-resources-assembl

                if (n.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
                    return null;

                string assy = null;

                // Find the corresponding assembly file
                foreach (var dir in folders)
                {
                    assy = new[] { "*.dll", "*.exe" }.SelectMany(g => Directory.EnumerateFiles(dir, g)).FirstOrDefault(f =>
                               {
                                   try { return n.Name.Equals(AssemblyName.GetAssemblyName(f).Name, StringComparison.OrdinalIgnoreCase); }
                                   catch (BadImageFormatException) { return false; /* Bypass assembly is not a .net exe */ }
                                   catch (Exception ex) { throw new ApplicationException("Error loading assembly " + f, ex); }
                               });

                    if (assy != null)
                        return Assembly.LoadFrom(assy);
                }

                throw new ApplicationException("Assembly " + args.Name + " not found");
            };
    }
}

下面是它的工作原理:

AssemblyResolver.Hook("\Plugins", "\CommonReferences");

每次需要解析某些程序集時,它將獲取一個已加載到內存中的程序集,否則它將在任何給定的文件夾中搜索。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM