Question

I have code that is in a managed C# dll that I'm trying to load from other C# code. The situation is that the C# code this is to call is built inside another application, so I have limited control over the build environment and it must use .NET 3.5. I have already been successful at loading assemblies for C code. Now I'm trying to load a managed assembly. It all almost works, except then it gets an exception looking for a dll that the prebuilt dll was "using". My question is if it is possible to include a managed dll that is fully built (clearly to be a dll) when it includes other dlls?

Here is my code that loads the external dll (built for .NET 3.5), "RESTClientClass.dll". It then tries to run the method, "Run". This part all works until I go into the debugger and get to the execution of "Run", where it then can't load "RestSharp.dll" which is the dll included within the already built RESTClientClass.dll (and is the .NET 3.5 version).

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using TChannelBase;
using TChannelRel;
using System.Reflection;
using System.ServiceModel.Web;

public class RestClientDLL{
    Assembly externAsm;
    Type externType;
    object externObj;

    public RestClientDLL(){
        Assembly externAsm = Assembly.LoadFile(@"C:\Users\daniel\Documents\Visual Studio 2010\Projects\RESTClientClass\RESTClientClass\bin\Debug\RESTClientClass.dll");
        externType = externAsm.GetType("RESTClientClass.RESTClient");
        externObj = Activator.CreateInstance(externType);
    }
    public string Run(){
        string val = (string)externType.InvokeMember("Run", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, 
                null, externObj, null);
        string newval = val;
        return( newval );
    }

}

Later in the code I instantiate an instance of RESTClientClass and then call the Run method. This is where an exception is trapped for RestSharp.dll not found. Is there a way I can load RestSharp.dll or some other solution? I looked at many posts about reflection and AppDomain but couldn't see how to apply anything.

Here is some of the RESTClientClass.dll code (to be clear this is only a section of the code as it builds and runs correctly when not included as a dll):

using RestSharp;

namespace RESTClientClass
{

    class RESTClient
    {            public string Run()
        {

            string retVal;

            Type externType;
            object externObj;
            Assembly externAsm = Assembly.LoadFile(@"c:\users\daniel\documents\visual studio 2010\Projects\RestClient\packages\RestSharp.104.4.0\lib\net35\RestSharp.dll");
            externType = externAsm.GetType("RESTClientClass.RESTClient");
            externObj = Activator.CreateInstance(externType);

            try
            {

            var client = new RestClient("http://tradetree2.dnsapi.info:8080/");
            var request = new RestRequest("hello/world", Method.GET);
            RestResponse response = (RestResponse)client.Execute(request);
            var content = response.Content; // raw content as string
            Console.Out.WriteLine(content);
            RestResponse<resultJSON> res = (RestResponse<resultJSON>)client.Execute<resultJSON>(request);
            Console.WriteLine("Result: " + res.Data.result);

            request = new RestRequest("todos", Method.GET);
            //           request = new RestRequest("todos/{id}", Method.GET);
            //           request.AddUrlSegment("id", "2");
            RestResponse response2 = (RestResponse)client.Execute(request);
            var content2 = response2.Content; // raw content as string
            Console.Out.WriteLine(content2);
            RestResponse<List<Todo>> res2 = (RestResponse<List<Todo>>)client.Execute<List<Todo>>(request);
            //            RestResponse<TodoList> res2 = (RestResponse<TodoList>)client.Execute<TodoList>(request);
            Console.WriteLine("Result: " + res2.Data[2].id + " = " + res2.Data[2].content);
            retVal = res2.Data[2].content;
            //           request.AddParameter("Content", "myFirstTodo");
            // execute the request




            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.Read();
                retVal = e.Message;
            }
            return (retVal);


        }
    }
}
Was it helpful?

Solution

Linking to an assembly that links to another assembly that... yeah, it can be a problem. Fortunately there are lots of solutions:

The first solution is to copy all of the relevant assembly DLLs to the same folder as your executable, rather than have them sitting in a different location. When one of the assemblies is referenced for the first time .NET can find it easily. You can add a reference to the DLLs in your project and they'll be copied to your output folder when you build the project.

Second option is to add the folder where those DLLs live to your search path. There are a few places that .NET will look for assemblies, and adding to the search path (either at the OS level or during your program's startup) will help.

Third, and most versatile in some ways, is to write a handler for the event that is raised when .NET fails to locate an assembly and load it yourself. When .NET fails to load an assembly it raises an event that you can trap. Do a search on AssemblyResolve here on Stack Overflow for lots and lots of examples of how to - and sometimes how not to - do this, or click here for the MSDN article.

@garthb has already covered off the final option I had for you, so I'll stop typing now :)

OTHER TIPS

Try using Assembly.LoadFrom instead of Assembly.LoadFile. This should also include all dependencies required by the managed dll.

http://msdn.microsoft.com/en-us/library/b61s44e8.aspx

Use the LoadFile method to load and examine assemblies that have the same identity, but are located in different paths. LoadFile does not load files into the LoadFrom context, and does not resolve dependencies using the load path, as the LoadFrom method does. LoadFile is useful in this limited scenario because LoadFrom cannot be used to load assemblies that have the same identities but different paths; it will load only the first such assembly.

http://msdn.microsoft.com/en-us/library/1009fa28.aspx

The load-from context allows an assembly to be loaded from a path not included in probing, and yet allows dependencies on that path to be found and loaded because the path information is maintained by the context.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top