title: assembly discovery from library code
body: <p>I have some code in a common library to support internationalization. The basic idea is that given the fully qualified name of a RESX file location, you can look up values using a markup extension:</p>
  
  <pre><code>    resx:ResxProperty.Name="SampleApp.Common.Resources.MainWindow"
      Title="{Resx Key=Window.Title}" 
      Icon="{Resx Key=Window.Icon}"
  </code></pre>
  
  <p>To find the RESX file there is a routine to search all assemblies as shown below, and it works fine when the RESX file is in the same assembly as the xaml. BUT it breaks down when it is not.</p>
  
  <p>Consider the solution structure below, where SampleApp.Wpf has the calling XAML and has a dependency on both the LocalizationLib and SampleApp.Common. </p>
  
  <p><img src="https://i.stack.imgur.com/6Ccms.jpg" alt="enter image description here"></p>
  
  <p>AppDomain.CurrentDomain.GetAssemblies() does not have SampleApp.Common at run time (although it does at design time).</p>
  
  <p>How can I modify this code so it will know about SampleApp.Common at runtime?</p>
  
  <p>Cheers,<br>
  Berryl</p>
  
  <h1>Library code</h1>
  
  <pre><code>/// &lt;summary&gt;
  /// Find the assembly that contains the type
  /// &lt;/summary&gt;
  /// &lt;returns&gt;The assembly if loaded (otherwise null)&lt;/returns&gt;
  public static Assembly FindResourceAssembly(string resxName)
  {
      // check the entry assembly first - this will short circuit a lot of searching
      //
      var assembly = Assembly.GetEntryAssembly();
      if (assembly != null &amp;&amp; HasSpecifiedResx(assembly, resxName))
          return assembly;
  
      var assemblies = AppDomain.CurrentDomain.GetAssemblies();
      foreach (var searchAssembly in assemblies)
      {
          // skip system assemblies
          var name = searchAssembly.FullName;
          if (_isSystemAssembly(name)) continue;
  
          if (HasSpecifiedResx(searchAssembly, resxName))
              return searchAssembly;
      }
      return null;
  }
  </code></pre>
  
  <h1>UPDATE</h1>
  
  <p>More details. </p>
  
  <p>SampleApp.Wpf is targeting .net 4.0. Below are the references for it as displayed in Visual Studio. </p>
  
  <p><img src="https://i.stack.imgur.com/XyNUh.jpg" alt="enter image description here"></p>
  
  <p>The only project references in there are Infralution.Localization.Wpf and SampleApp.Common, both of which also target .Net 4.0.</p>
  
  <p>Based on Metro Smurf's input I tried using assembly.GetReferencedAssemblies(). When I use this method, the VS designer does NOT find SampleApp.Common, and the following AssemblyNames are known in the debugger at runtime:</p>
  
  <pre><code>{System.Reflection.AssemblyName[6]}
      [0]: {PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
      [1]: {mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [2]: {System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [3]: {Infralution.Localization.Wpf, Version=2.1.2.0, Culture=neutral, PublicKeyToken=547ccae517a004b5}
      [4]: {System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [5]: {PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
  </code></pre>
  
  <p>And when I use the origional AppDomain.CurrentDomain.GetAssemblies(), the designer DOES know SampleApp.Common, and these assemblies are known at runtime:</p>
  
  <pre><code>?AppDomain.CurrentDomain.GetAssemblies()
  {System.Reflection.RuntimeAssembly[21]}
      [0]: {mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [1]: {Microsoft.VisualStudio.HostingProcess.Utilities, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [2]: {System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [3]: {System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [4]: {System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [5]: {Microsoft.VisualStudio.HostingProcess.Utilities.Sync, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [6]: {Microsoft.VisualStudio.Debugger.Runtime, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [7]: {vshost32, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [8]: {System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [9]: {System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [10]: {System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [11]: {Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [12]: {System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [13]: {System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [14]: {System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}
      [15]: {WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
      [16]: {PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
      [17]: {PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35}
      [18]: {SampleApp.Wpf, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
      [19]: {System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}
      [20]: {Infralution.Localization.Wpf, Version=2.1.2.0, Culture=neutral, PublicKeyToken=547ccae517a004b5}
  </code></pre>
  
  <p>In both cases, SampleApp.Common isn't known at runtime. For the fun of it, I loaded that assembly in the debugger and got:</p>
  
  <pre><code>?Assembly.Load("SampleApp.Common")
  {SampleApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
      [System.Reflection.RuntimeAssembly]: {SampleApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
      CodeBase: "file:///C:/.../SampleApp.Wpf/bin/Release/SampleApp.Common.DLL"
      EntryPoint: null
      EscapedCodeBase: "file:///C:.../SampleApp.Wpf/bin/Release/SampleApp.Common.DLL"
      Evidence: {System.Security.Policy.Evidence}
      FullName: "SampleApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
      GlobalAssemblyCache: false
      HostContext: 0
      ImageRuntimeVersion: "v4.0.30319"
      IsDynamic: false
      IsFullyTrusted: true
      Location: "C:\\...\\SampleApp.Wpf\\bin\\Release\\SampleApp.Common.dll"
      ManifestModule: {SampleApp.Common.dll}
      PermissionSet: {&lt;PermissionSet class="System.Security.PermissionSet"
  version="1"
  Unrestricted="true"/&gt;
  }
      ReflectionOnly: false
      SecurityRuleSet: Level2
  </code></pre>
  
  <p>I also tried Metro Smurf's suggestion to reference a static string from SampleApp.Common in SampleApp.Wpf. No change on that one, although I guess it further proves that SampleApp.Common is properly referenced.</p>
  
  <p>Other things to try on SampleApp.Common might include adding an EntryPoint, a SNK, or a HashAlgorithm.</p>
  
  <h1>the FIX</h1>
  
  <p>asm.GetReferencedAssemblies <em>sounds</em> like the ticket, but it only returns assemblies which are loaded in the memory, and assemblies aren't loaded if they aren't referenced <em>in the code</em> (as in it's confusing that while also quite proper to say one project has a reference to another, but that isn't the sort of reference this method returns).</p>
  
  <p>It turns out that AppDomain.CurrentDomain.GetAssemblies() works the same way.</p>
  
  <p>Metro Smurf was on the right track, but apparently a static reference won't get the assembly loaded, but creating a type instance from the assembly will. So:</p>
  
  <pre><code>Console.WriteLine(Class1.MyDummyString)  // this won't do it
  Console.WriteLine(new Class1())  // finally, the assembly is loaded
  </code></pre>
  
  <p>As much as I dislike creating a dummy class, in this case it is an easy fix; I can leave the original library code as is.</p>