none
CLR host and partial binding RRS feed

  • Question

  • Hi,

    I'm trying to write a CLR host (.NET 4) to run an existing .NET product from C++.

    I've implemented IHostAssemblyStore::ProvideAssembly and it works most of time.

    However, I can't make it work in the following scenario:

    Suppose there is an assembly called TestDep.

    Running:

    Assembly.Load("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

    from my hosted code works (TestDep.dll is resolved by my ProvideAssembly(..) implementation).

    However, running:

    Assembly.Load("TestDep, Culture=neutral");

    does not. ProvideAssembly is not even called.

    This is from the fusion log:

    LOG: Fusion is hosted. Check host about this assembly. LOG: Assembly is not in CLR Loaded list. Asking host assembly store. LOG: Input is partial name. Skip host assembly store lookup. ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).

    I tried to fix this by registering to AppDomain.AssemblyResolve event with this code:

    if (args.name == "TestDep, Culture=neutral") {

    return Assembly.Load("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nulll");

    }

    But it still doesn't work. Now fusion log contains this:

    LOG: The same bind was seen before, and was failed with hr = 0x80070002. ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).

    I tried to disable binding caching by putting:

    <runtime>
        <disableCachingBindingFailures>1</disableCachingBindingFailures>
      </runtime>

    In my app.config but it had no affect.

    Adding

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <qualifyAssembly partialName="TestDep" fullName="TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </assemblyBinding>

    did not help either.

    The only workaround I found was to call

    Assembly.Load("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

    Before running the hosted code.

    Is there a better solution? How am I supposed to support partial binding in my CLR host?
    Is it possible to disable binding caching from code?
    Of course I can't modify the application I'm trying to host (change partial to full bindings).

    Thanks!

    • Edited by _olegz Monday, March 17, 2014 11:20 PM
    Monday, March 17, 2014 11:07 PM

Answers

  • Hi Olegz,

    CLR use its algorithm to find the required assembly. You can see on the above picture. According the algorithm, put the TestDep assembly in application directory or GAC can easily solve this problem.

    > My appdomain is initialized with "DisallowApplicationBaseProbing=true" to force CLR to load assemblies only through the host.

    Set this property to true will tell CLR do not probe assembly in the directories specified by the ApplicationBase property. Did you have some misunderstanding? http://msdn.microsoft.com/en-us/library/system.appdomainsetup.disallowapplicationbaseprobing(v=vs.110).aspx.

    Regards,


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, March 24, 2014 9:48 AM
    Moderator

All replies

  • Hi Olegz,

    >Is there a better solution? How am I supposed to support partial binding in my CLR host?

    I don’t know if this is a better solution, but you can try to use Assembly.LoadWithPartialName method. For more information, refer to http://msdn.microsoft.com/en-us/library/12xc5368(v=vs.110).aspx. The binder simply tries to load in application directory and if it fails then picks up the highest version of the assembly in GAC.

    As you has found, I recommend to use Assembly.Load method. The CLR is responsible for locating and binding the assemblies in code. In order to work assembly binding efficiently you need to always use fully specified assembly names.

    Here is an article about understanding the CLR Binder.

    http://msdn.microsoft.com/en-us/magazine/dd727509.aspx.

    Hope useful.

    Regards,


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Wednesday, March 19, 2014 3:16 AM
    Moderator
  • Hi, thank you for your reply.

    > you can try to use Assembly.LoadWithPartialName method

    As I said, I can't modify the application I'm trying to host.

    All the partial bindings are made in WPF XAML files. I think it's the default work method in the "pack://" URI type.

    ----------

    Just to clarify, this is the test code I'm trying to run:

    static void Main()
            {
                Console.WriteLine("Start");
    
                try
                {
                    Assembly.Load("TestDep, Culture=neutral");
                    Console.WriteLine("Partial loaded");
                }
                catch(Exception)
                {
                    Console.WriteLine("!!! Partial failed");
                }
    
                try
                {
                    Assembly.Load("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
                    Console.WriteLine("Full loaded");
                }
                catch (Exception)
                {
                    Console.WriteLine("!!! Full failed");
                }
            }

    When I run it directly (double click on the compiled EXE), it works as expected with this output:

    Start
    Partial loaded
    Full loaded

    When I run it using my host, I get this output

    Start
    !!! Partial failed
    !!! Full failed

    and this fusion log messages:

    first load ("TestDep, Culture=neutral.htm"):

    LOG: Input is partial name. Skip host assembly store lookup.
    ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).

    second load ("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.htm"):

    LOG: The same bind was seen before, and was failed with hr = 0x80070002.
    ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).

    In both cases, my IHostAssemblyStore::ProvideAssembly() was not called.

    Since it's probably impossible to make CLR call my ProvideAssembly with partial binding, I need to disable binding caching to make the second Assembly.Load work.

    2 more (relevant?) things:

    1. Changing:

    Assembly.Load("TestDep, Culture=neutral")

    to:

    Assembly.Load("TestDep")

    makes the second assembly.Load (with the full type name: TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null) work.

    Could this whole thing be a bug in CLR? If not, why removing the culture part makes this work?

    2. My appdomain is initialized with "DisallowApplicationBaseProbing=true" to force CLR to load assemblies only through the host.

    Thanks again.





    • Edited by _olegz Wednesday, March 19, 2014 6:24 PM
    Wednesday, March 19, 2014 5:30 PM
  • Hi Olegz,

    CLR use its algorithm to find the required assembly. You can see on the above picture. According the algorithm, put the TestDep assembly in application directory or GAC can easily solve this problem.

    > My appdomain is initialized with "DisallowApplicationBaseProbing=true" to force CLR to load assemblies only through the host.

    Set this property to true will tell CLR do not probe assembly in the directories specified by the ApplicationBase property. Did you have some misunderstanding? http://msdn.microsoft.com/en-us/library/system.appdomainsetup.disallowapplicationbaseprobing(v=vs.110).aspx.

    Regards,


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Monday, March 24, 2014 9:48 AM
    Moderator
  • Hi,

    I'm trying to solve this without using GAC.

    I can't understand from your post/graph why this won't work:

    Assembly.Load("TestDep, Culture=neutral"); // excpetion is thornw - OK
    Assembly.Load("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); // excpetion is thrown - NOT OK!!!!

    while this works (culture is not specified now):

    Assembly.Load("TestDep"); // exception is thrown - OK
    Assembly.Load("TestDep, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); // the assembly is loaded - OK

    I'm trying to make my code work, even when an assembly is requested with partial binding with culture specified.

    Set this property to true will tell CLR do not probe assembly in the directories specified by the ApplicationBase property. Did you have some misunderstanding?

    I think there is no misunderstanding. I want all my assemblies to be loaded by my host, using my implementation of IHostAssemblyStore::ProvideAssembly. I don't want CLR to probe ApplicationBase. Anyway, changing this property to false doesn't solve the above bug.

    Thanks!




    • Edited by _olegz Thursday, March 27, 2014 10:36 AM
    Thursday, March 27, 2014 10:34 AM