简体   繁体   中英

Loaded an assembly into Appdomain from memory, createinstance results in 'filenotfound' exception

For some context: I am already running within a "plugin" appdomain provided by a third party application. This is important because it limits what can be done when it comes to classloading. More specifically, this application relies on certain predefined core dll's to be on the classic application base path, and loads everything else dynamically from a database. Although I don't have a view into that layer, it does not appear to use the filesystem (tempfile sort of thing) so I am assuming it is loading all DLLs that are not core directly into memory as byte arrays.

I have a DLL loaded as a embedded reference which requires a certain app.config and bin directory not controllable in the plugin context, therefore I plan to use an appdomain. The DLL embedded resource in the plugin gets read as a byte array and injected into the appdomain.

The DLL appears in the AppDomain.GetAssemblies() for the appdomain created , however, when I attempt to create an instance from that DLL it complains about a "FileNotFound". I have checked that the FullNames are matching etc. This raises the first and most simple question: why is it looking for a DLL that is already loaded? It appears that it is intentionally skipping all byte-array loaded assemblies for the purpose of looking up types. I have tried disabling Base Path probing and that just changes the error from a FileNotFound to a more generic reference not found error. Here is the code which tries to use a memory injected DLL and fails.

public AdsAdapter(Context context)
        {   

            try
            {
                var adsPath = session.GetSystemSetting("SpecialConfig");
                var adsBin = Path.Combine(session.GetSystemSetting("SpecialBin"), @"special\path");

                AppDomainSetup appSetup = new AppDomainSetup()
                {
                    ApplicationName = "ExtendsProxyOC",
                    ApplicationBase = adsBin,
                    PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory,
                    ConfigurationFile = System.IO.Path.Combine(adsPath,"cs_client_app.config")
                };

                _adsDomain = AppDomain.CreateDomain("adsDomain"+Guid.NewGuid(),
                    null,appSetup);

                // add inmemory DLL

                var dll = Assembly.GetAssembly(typeof(AdsAdapter))
                       .GetManifestResourceStream(resourcespath + "ADSOCWrapper.dll");
                var dlldbg = Assembly.GetAssembly(typeof(AdsAdapter))
                    .GetManifestResourceStream(resourcespath + "ADSOCWrapper.pdb");
                Assembly asmWrapper = _adsDomain.Load(StreamToBytes(dll), StreamToBytes(dlldbg));

                 // Load a file which IS in the bin directory filesystem
                _adsDomain.Load("ads_core");

                // the DLL IS in memory  at this point and this proves it. Type definitions are there, looks fine.
                Assembly[] assm = _adsDomain.GetAssemblies();

                // error occurs here "FileNotFound" in the app base for the .DLL file. Why is it trying to load from disk when it is already loaded?
                _proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper",
                    typeof(AdsRemote).FullName, 
                    true, //case search
                    System.Reflection.BindingFlags.CreateInstance, //bindingattr
                    null, //Binder
                    new object[]{}, //args
                    null, //culture
                    null);//activationattr


            }
            catch (Exception e)
            {
                throw e;
            }
        }

        static byte[] StreamToBytes(Stream input)
        {
            var capacity = input.CanSeek ? (int)input.Length : 0;
            using (var output = new MemoryStream(capacity))
            {
                int readLength;
                var buffer = new byte[4096];

                do
                {
                    readLength = input.Read(buffer, 0, buffer.Length);
                    output.Write(buffer, 0, readLength);
                }
                while (readLength != 0);

                return output.ToArray();
            }
        }

}

My next move was to try overriding the assembly resolution process, which I believe could be the answer, but since I do not have a filesystem dll 'anchor' it seems I am unable to bootstrap my custom code.

Even when using anonymous delegate functions in my AppDomainSetup.AppDomainInitializer, it is apparently dependent on some other DLLs being available. I am only calling GAC objects in my delegate, yet it requires that the parent executing assembly (the one setting up the appdomain) is loaded into the target appdomain. In order to pass an anonymous delegate. Why?

Could not load file or assembly 'ParentAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

AppDomainInitializer = new AppDomainInitializer(delegate(string[] target)
                            {
                                AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
                                {
                                    if (args.Name.Contains("ADSOCWrapper"))
                                    {
                                        return Array.Find(AppDomain.CurrentDomain.GetAssemblies(),
                                            x => x.FullName.Contains("ADSOCWrapper"));
                                    }
                                    return null;
                                };
                            })

As a result I am stuck unable to make my appdomain look in memory for its types, it seems. Any ideas here?

The overload you are using of CreateInstanceFromAndUnwrap takes assembly file instead of assembly name.

Try overload of CreateInstanceFromAndUnwrap which takes assembly name as argument:

       _proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper",
                typeof(FeedDao).FullName);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM