4

在我的C#應用​​程序中,我有一個插件機制,可以根據配置XML文件中指定的不同路徑加載插件DLL。我的應用程序是本地化的。主程序集(* .exe)以標準.NET方式(例如,.\en\en-US\main.resources.dll; .\de\de_DE\main.resources.dll等)爲exe旁邊的本地化語言提供了附屬程序集。c#插件DLL本地化資源的路徑

我開始本地化一個插件,必須發現衛星組件必須放在EXE旁邊的文件夾中。將它放在插件DLL旁邊時,資源管理器找不到它。

但是,由於我的插件是可互換的,可能位於不同的文件夾中,我非常希望將本地化的資源程序集放在插件旁邊,並且不是到exe。

這可能嗎?!?!

我可以忍受的另一種選擇是將本地化資源嵌入到DLL中。這可能嗎??

乾杯, 菲利克斯

+0

這種方法適用於我們。我只是想知道你的satellite-assemblies在子文件夾中,我只看到過這樣的'。\ de-DE \ Assembly.resources.dll'等。 –

+0

糟糕,你可能是對的。我只有一個「de」資源,但我一直認爲它是「de-DE」的子文件夾。無論如何,你使用插件/外部DLL在不同的文件夾比可執行文件? – Felix

+0

是插件位於可執行文件的子文件夾中。 '.'是指應用程序的目錄,那麼結構如下。 '。\ Plugins \ PluginX.dll'及其資源存儲就像'。\ Plugins \ de-DE \ PluginX.resources.dll','。\ Plugins \ us-GB \ PluginX.resources.dll'等等。 。 –

回答

0

確定,如果你想「分離」從非標準本地化資源yoursefl結合,並希望有能夠從任何位置加載程序集自由,其中一個選項是

一)實現一個接口,裝配

b)在與翻譯交互使用Assembly.Load函數加載你的位置要.NET程序集你想

+0

我不認爲這回答了這個問題。如果有,請詳細說明。 –

+0

@亨克,它已更新。 – Tigran

+1

我仍然懷疑這適用於資源DLL。 –

0

我就遇到了這個問題,WO時爲我們公司購買產品。我沒有在任何地方找到答案,所以我會在這裏發佈我的解決方案,以防其他人發現自己處於相同的情況。

從.NET 4.0開始,有一個解決此問題的方法,因爲衛星程序集現在傳遞給AssemblyResolve處理程序。如果你已經有一個插件系統,可以從遠程目錄加載程序集,你可能已經有了一個程序集解析處理程序,你只需要擴展它就可以對衛星資源程序集使用不同的搜索行爲。如果你沒有一個,那麼這個實現就不是微不足道的,因爲你基本上對所有的程序集搜索行爲負責。我會發布完整的代碼以獲得工作解決方案,無論您採用何種方式進行覆蓋。首先,你需要的地方勾你的AssemblyResolve處理程序,如:

AppDomain.CurrentDomain.AssemblyResolve += ResolveAssemblyReference; 

然後假定你有一對夫婦的變量來保存路徑信息的主應用程序和插件目錄,如下所示:

string _processAssemblyDirectoryPath; 
List<string> _assemblySearchPaths; 

然後,你需要看起來有點像這樣一個小的輔助方法:

static Assembly LoadAssembly(string assemblyPath) 
{ 
    // If the target assembly is already loaded, return the existing assembly instance. 
    Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); 
    Assembly targetAssembly = loadedAssemblies.FirstOrDefault((x) => !x.IsDynamic && String.Equals(x.Location, assemblyPath, StringComparison.OrdinalIgnoreCase)); 
    if (targetAssembly != null) 
    { 
     return targetAssembly; 
    } 

    // Attempt to load the target assembly 
    return Assembly.LoadFile(assemblyPath); 
} 

最後,你需要的所有重要事件AssemblyResolve HANDL呃,看起來有點像這樣:

Assembly ResolveAssemblyReference(object sender, ResolveEventArgs args) 
{ 
    // Obtain information about the requested assembly 
    AssemblyName targetAssemblyName = new AssemblyName(args.Name); 
    string targetAssemblyFileName = targetAssemblyName.Name + ".dll"; 

    // Handle satellite assembly load requests. Note that prior to .NET 4.0, satellite assemblies didn't get 
    // passed to AssemblyResolve handlers. When this was changed, there is a specific guarantee that if null is 
    // returned, normal load procedures will be followed for the satellite assembly, IE, it will be located and 
    // loaded in the same manner as if this event handler wasn't registered. This isn't sufficient for us 
    // though, as the normal load behaviour doesn't correctly locate satellite assemblies where the owning 
    // assembly has been loaded using Assembly.LoadFile where the assembly is located in a different folder to 
    // the process assembly. We handle that here by performing the satellite assembly search process ourselves. 
    // Also note that satellite assemblies are formally documented as requiring the file name extension of 
    // ".resources.dll", so detecting satellite assembly load requests by comparing with this known string is a 
    // valid approach. 
    if (targetAssemblyFileName.EndsWith(".resources.dll")) 
    { 
     // Retrieve the owning assembly which is requesting the satellite assembly 
     string owningAssemblyName = targetAssemblyFileName.Replace(".resources.dll", ".dll"); 
     Assembly owningAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((x) => x.Location.EndsWith(owningAssemblyName)); 
     if (owningAssembly == null) 
     { 
      return null; 
     } 

     // Retrieve the directory containing the owning assembly 
     string owningAssemblyDirectory = Path.GetDirectoryName(owningAssembly.Location); 

     // Search for the required satellite assembly in resource subdirectories, and load it if found. 
     CultureInfo searchCulture = System.Threading.Thread.CurrentThread.CurrentCulture; 
     while (searchCulture != CultureInfo.InvariantCulture) 
     { 
      string resourceAssemblyPath = Path.Combine(owningAssemblyDirectory, searchCulture.Name, targetAssemblyFileName); 
      if (File.Exists(resourceAssemblyPath)) 
      { 
       Assembly resourceAssembly = LoadAssembly(resourceAssemblyPath); 
       if (resourceAssembly != null) 
       { 
        return resourceAssembly; 
       } 
      } 
      searchCulture = searchCulture.Parent; 
     } 
     return null; 
    } 

    // If the target assembly exists in the same directory as the requesting assembly, attempt to load it now. 
    string requestingAssemblyPath = (args.RequestingAssembly != null) ? args.RequestingAssembly.Location : String.Empty; 
    if (!String.IsNullOrEmpty(requestingAssemblyPath)) 
    { 
     string callingAssemblyDirectory = Path.GetDirectoryName(requestingAssemblyPath); 
     string targetAssemblyInCallingDirectoryPath = Path.Combine(callingAssemblyDirectory, targetAssemblyFileName); 
     if (File.Exists(targetAssemblyInCallingDirectoryPath)) 
     { 
      try 
      { 
       return LoadAssembly(targetAssemblyInCallingDirectoryPath); 
      } 
      catch (Exception ex) 
      { 
       // Log an error 
       return null; 
      } 
     } 
    } 

    // If the target assembly exists in the same directory as the process executable, attempt to load it now. 
    string processDirectory = _processAssemblyDirectoryPath; 
    string targetAssemblyInProcessDirectoryPath = Path.Combine(processDirectory, targetAssemblyFileName); 
    if (File.Exists(targetAssemblyInProcessDirectoryPath)) 
    { 
     try 
     { 
      return LoadAssembly(targetAssemblyInProcessDirectoryPath); 
     } 
     catch (Exception ex) 
     { 
      // Log an error 
      return null; 
     } 
    } 

    // Build a list of all assemblies with the requested name in the defined list of assembly search paths 
    Dictionary<string, AssemblyName> assemblyVersionInfo = new Dictionary<string, AssemblyName>(); 
    foreach (string assemblyDir in _assemblySearchPaths) 
    { 
     // If the target assembly doesn't exist in this path, skip it. 
     string assemblyPath = Path.Combine(assemblyDir, targetAssemblyFileName); 
     if (!File.Exists(assemblyPath)) 
     { 
      continue; 
     } 

     // Attempt to retrieve detailed information on the name and version of the target assembly 
     AssemblyName matchAssemblyName; 
     try 
     { 
      matchAssemblyName = AssemblyName.GetAssemblyName(assemblyPath); 
     } 
     catch (Exception) 
     { 
      continue; 
     } 

     // Add this assembly to the list of possible target assemblies 
     assemblyVersionInfo.Add(assemblyPath, matchAssemblyName); 
    } 

    // Look for an exact match of the target version 
    string matchAssemblyPath = assemblyVersionInfo.Where((x) => x.Value == targetAssemblyName).Select((x) => x.Key).FirstOrDefault(); 
    if (matchAssemblyPath == null) 
    { 
     // If no exact target version match exists, look for the highest available version. 
     Dictionary<string, AssemblyName> assemblyVersionInfoOrdered = assemblyVersionInfo.OrderByDescending((x) => x.Value.Version).ToDictionary((x) => x.Key, (x) => x.Value); 
     matchAssemblyPath = assemblyVersionInfoOrdered.Select((x) => x.Key).FirstOrDefault(); 
    } 

    // If no matching assembly was found, log an error, and abort any further processing. 
    if (matchAssemblyPath == null) 
    { 
     return null; 
    } 

    // If the target assembly is already loaded, return the existing assembly instance. 
    Assembly loadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((x) => String.Equals(x.Location, matchAssemblyPath, StringComparison.OrdinalIgnoreCase)); 
    if (loadedAssembly != null) 
    { 
     return loadedAssembly; 
    } 

    // Attempt to load the target assembly 
    try 
    { 
     return LoadAssembly(matchAssemblyPath); 
    } 
    catch (Exception ex) 
    { 
     // Log an error 
    } 
    return null; 
} 

與衛星資源集合該事件處理程序的第一部分是,然後我用常規組件的搜索行爲遵循。這應該足以幫助任何人從頭開始這樣的系統。