4

私のC#アプリケーションでは、構成XMLファイルで指定されているように、さまざまなパスからDLLを読み込むプラグインメカニズムがあります。私のアプリケーションはローカライズ可能です。メインアセンブリ(* .exe)には、標準の.NET方法でexeの隣にローカライズされた言語用の衛星アセンブリがあります(.\en\en-US\main.resources.dll; .\de\de_DE\main.resources.dllなど)。c#プラグインDLLのローカライズされたリソースのパス

私はプラグインのローカライズを開始し、衛星アセンブリをexeの隣のフォルダに配置する必要があることを発見しなければなりませんでした。プラグインDLLの隣に置くと、リソースマネージャーはDLLを見つけられません。

しかし、私のプラグインは互換性があり、潜在的に異なるフォルダにありますので、ローカライズされたリソースアセンブリをプラグインの隣に置き、ではなく、をexeに置きます。

これは可能ですか?!?!

私が住むことのできる別の方法は、ローカライズされたリソースをDLLに埋め込むことです。これは可能ですか?

乾杯、 フェリックス

+0

このアプローチは私たちにとってうまく機能します。私はちょうどあなたの衛星アセンブリがサブフォルダにあるのか疑問に思っています。私はこの '。\ 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

[OK]をあなたはスタンダールのローカライズリソースからyourseflが結合し、任意の場所からアセンブリをロードするために自由を持ちたい「切り離す」したい場合は、オプションのいずれかを

にありますあなたはWO私はこの問題に遭遇した

+0

私はこれが質問に答えるとは思わない。もしそうなら、詳しく教えてください。 –

+0

@Henk、更新されました。 – Tigran

+1

これはリソースDLLにも当てはまりません。 –

0

をする場所からあなたが望む.NETアセンブリをロードするためにAssembly.Load機能を使用))は、そのアセンブリ内の翻訳

Bと対話するためのインターフェイスを実装弊社の製品を使用しています。私はどこにでも答えは見つからなかったので、他の誰かが同じ状況で自分自身を見つけた場合には、ここに私の解決策を投稿します。

.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; 
} 

サテライトリソースアセンブリとそのイベントハンドラのお得な情報の最初の部分は、その後、私は定期的なアセンブリのために使用する検索行動はそれを次の:えー、これは、このような小さなものになります。これは誰でもこのようなシステムをゼロから始めるのを助けるのに十分であるはずです。

関連する問題