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);
}
}
}
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 :)