AppDomain.CurrentDomain.SetupInformation.PrivateBinPath is null

When I start my application that only has one AppDomain, AppDomain.CurrentDomain.SetupInformation.PrivateBinPath is null. Even though I have probing paths set in MyApp.exe.config as shown below.

I would have expeceted that AppDomain.CurrentDomain.SetupInformation.PrivateBinPath contains the string "Dir1;Dir2;Dir3".

How can I access the probing path as configured in the MyApp.exe.config?

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <appSettings>
    <add key="Foo" value="Bar" />
  </appSettings>
  <startup>
    <!-- supportedRuntime version="v1.1.4322" / -->
  </startup>

  <runtime>
    <gcConcurrent enabled="true" />
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <publisherPolicy apply="yes" />

      <!-- Please add your subdirectories to the probing path! -->
      <probing privatePath="Dir1;Dir2;Dir3" />
    </assemblyBinding>
  </runtime>
  <system.windows.forms jitDebugging="true" />
</configuration>

Update

As Hans Passant pointed out the comment below, SetupInformation.PrivateBinPath is not set for the primary appdomain. So the above doesn't work. What would be your suggestion to simulate the way fusion searches for assemblies in the probing path or at least take <probing privatePath="" /> from the current application configuration into account? The best thing I can come up with is to read <probing privatePath="" /> from App.config manually when the current domain is the primary appdomain (AppDomain.CurrentDomain.IsDefaultAppDomain() is true). Is there a better way?

Update 2

Here some additional background information what this is needed for: This problem occured in AppDomainAssemblyTypeScanner.GetAssemblyDirectories() of the Nancy framework.

Nancy autodiscovers and loads 3rd party modules and other "plugins". By default this is supposed to be done same way as normally linked assemblies would be loaded (i.e. as fusion would do it) by looking through the probing paths. Assemblies are loaded using Assembly.Load (as opposed to Assembly.LoadFrom) so as I understand it, all the dependent assemblies of the loaded assemblies must be reachable in the probing path of the application/appdomain too.

How can I access the probing path as configured in the MyApp.exe.config

To remain compatible what fusion will do, you can read the config file in effect to get the current probing paths:

private static string GetProbingPath()
{
    var configFile = XElement.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
    var probingElement = (
        from runtime 
            in configFile.Descendants("runtime")
        from assemblyBinding 
            in runtime.Elements(XName.Get("assemblyBinding", "urn:schemas-microsoft-com:asm.v1"))
        from probing 
            in assemblyBinding.Elements(XName.Get("probing", "urn:schemas-microsoft-com:asm.v1"))
        select probing)
        .FirstOrDefault();

    return probingElement?.Attribute("privatePath").Value;
}

Supposing the config file sample in your question it returns: "Dir1;Dir2;Dir3"

AppDomain.PrivateBinPath is null, Based on @Alexei Levenkov's comment: You need to be very careful not to "leak" references to loaded assembly outside of new AppDomain  First make sure Plugins is a subdirectory of your AppDomain base path.PrivateBinPath will only work on subdirectories as described here. If that isn't the problem then take a look at your fusion binding logs.

AppDomain.CurrentDomain.SetupInformation.PrivateBinPath is null, Как я могу получить доступ к зондирующему пути, конфигурируется в MyApp.​exe.config. Чтобы сохранить совместимость, что слияние будет делать,  Per MSDN, an App Domain "Represents an application domain, which is an isolated environment where applications execute." When you think about an ASP.Net application the root where the app resides is not the bin folder.

I've always found that the easiest thing to do is intercept the AppDomain.AssemblyResolve event. Then you can load whatever assembly you want from wherever you want and return it. You can still store your settings in the appConfig...You could even probing path section if you particularly want to use it. One thing to note is that assemblies loaded using Assembly.Load don't end up in the same load context as assemblies loaded under the default load context (https://msdn.microsoft.com/en-us/library/dd153782(v=vs.110).aspx). This has the effect of changing how type and assembly resolution occurs for subsequent resolutions (after the initial call to Assembly.Load). Accordingly, you may want to intercept AppDomain.TypeResolve as well as AssemblyResolve...and you'll want to cache the Assemblies you load from AssemblyResolve...otherwise subsequent resolutions MAY actually load the same assembly again (depending on how exactly you call Assembly.Load)

Understanding AppDomainSetup.PrivateBinDir, "test2" is null AppDomainSetup setup = AppDomain.CurrentDomain.​SetupInformation; setup.PrivateBinPath = "test"; AppDomain. Here are the examples of the csharp api class System.AppDomain.AppendPrivatePath(string) taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

If this is a problem of assemblies not loading, one method I've found to work effectively is to use the AppDomain.AssemblyResolve event which is fired whenever the appdomain fails to load an assembly...

Working with AppDomain.AssemblyResolve event

e.g.

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(LoadManually);

private Assembly LoadManually(object sender, ResolveEventArgs args)
{
   ....
    return Assembly.LoadFrom(whereEverYouLike);
}

https://social.msdn.microsoft.com/Forums/en-US/f81, The AppDomain.CurrentDomain.SetupInformation.PrivateBinPath "Plugins";. does correctly create the path, I have some more code to load the file,. Assembly​  Examples. The following example demonstrates how to use the ApplicationBase property to set the location where the assembly loader begins probing for assemblies to load into a new application domain.

Inspired by g.pickardou's solution, I have created function without necessity to reference System.Xml.Linq:

private static string GetProbingPath()
{
    var xmlDoc = new XmlDocument();
    xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

    var privatePathAttribute = xmlDoc.SelectSingleNode("/*[name()='configuration']/*[name()='runtime']/*[name()='assemblyBinding']/*[name()='probing']/@privatePath");
    return (privatePathAttribute as XmlAttribute)?.Value;
}

Visual C# >>AppendPrivatePath, I have a service that creates an app domain and starts it: this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.​Evidence  The following code example creates a new application domain. The CurrentDomain property is used to obtain an AppDomain object that represents the current application domain. The FriendlyName property provides the name of the current application domain, which is then displayed at the command line. using namespace System; int main

Getting the assembly name for a process started within an app domain, CreateDomain("New Domain", null, myAppDomainSetup);. AppDomain.​CurrentDomain.SetupInformation is used to examine properties of the App. domain.

Configuring App. domains in .NET Framework with C# |,

Comments
  • It just doesn't, a side-effect of the CLR using a different api called "Fusion" to search for assemblies. Data flow is app.config => fusion for the primary appdomain and appdomainsetup => fusion for ones you create, not the other way around.
  • This is shaping up to be a major XY question. That excessive bounty is going to produce a lot of "parse the config file" answers. Fusion is readily available in a .NET program as well, pretty unlikely that you need anything else. But we can't guess, what is the real problem, why does it matter that you know the probing path?
  • What are you trying to do this for? Why do you need the PrivateBinPath? "Is there a better way" to do what exactly?
  • I'm in agreement with Hans here, it's a pretty simple task to read the config file manually, but I'm sure there's something better you can do.
  • I have updated my question. Are your questions properly adressed?
  • Although the approach to parse App.config manually is just a hack I am accepting it as an answer because no better solution came up. It probably works correctly in most of the cases.
  • Thx for the feedback. To lower the feeling of "hack" I am using the current appdomain's SetupInformation to get the config in effect. Also: The probing mechanism and the schema of the config file is a very stable part of .NET since its advent, it is part of the specification. It should not change, because it would be a horrible breaking change.
  • Btw, that question is still open, why PrivateBinPath is not set properly for the primary AppDomain, where most probably (99.99% of the cases) the applications will try to utilize it.
  • OP asked about 'howto make nancy to load assemblies from <probing privatePath="" /> dirs?', not about 'howto override probing logic?' ; )
  • And since it is not possible to see it in AppDomainSetup, this should be an alternative solution