I've found a lot of similar questions but couldn't find any solution.
I have following code:
string file = "c:\\abc.dll";
AppDomainSetup ads = new AppDomainSetup();
ads.PrivateBinPath = Path.GetDirectoryName(file);
AppDomain ad2 = AppDomain.CreateDomain("AD2", null, ads);
ProxyDomain proxy = (ProxyDomain)ad2.CreateInstanceAndUnwrap(typeof(ProxyDomain).Assembly.FullName, typeof(ProxyDomain).FullName);
Assembly asm = proxy.GetAssembly(file); // exception File.IO assembly not found is thrown here after succesfully running the funktion GetAssembly.
public class ProxyDomain : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
try
{
Assembly asm = Assembly.LoadFile(assemblyPath);
//...asm is initialized correctly, I can see everything with debugger
return asm;
}
catch
{
return null;
}
}
}
The most Interesting thing that then my GetAssembly funktion returns some other type, even my custom serializable class, everything is fine. Does someone know what I'm missing? Or It's just impossible to return loaded assembly to another domain?
Thank you
I imagine File.IO is sitting in your main application's bin directory? If so, your abc.dll will not know where to find it (unless your main application is also sitting in C:\\).
You need to do one of
Bind to the AppDomain.AssemblyResolve event and manually load the referenced dll
Change the AppDomainSetup's base directory (which is one of the places .NET knows to look for dlls)
Install File.IO to the GAC (which is another one of the places .NET knows to look for dlls)
Add the location of File.IO to your AppDomainSetup's private probing path (which is another one of the places .NET will try to look for dlls).
Related
I'm developing a module for an external application, which is a dll that is loaded.
However in order to develop, you have to restart the application to see the results of your code.
We have built a piece of code that loads a dll dynamically from a startassembly:
startassembly
var dllfile = findHighestAssembly(); // this works but omitted for clarity
Assembly asm = Assembly.LoadFrom(dllFile);
Type type = asm.GetType("Test.Program");
MethodInfo methodInfo = type.GetMethod("Run");
object[] parametersArray = new object[] { };
var result = methodInfo.Invoke(methodInfo, parametersArray);
Effectively we have a solution with a startassembly which will be static and a test assembly which will be invoked dynamically, which allows us to swap the assembly during runtime.
The problem
This piece of code will load a new dll every time and search for the highest version at the end of the assembly name. e.g. test02.dll will be loaded instead of test01.dll, because the application locks both startassemly.dll as well as test01.dll. Now we have to edit the properties > assembly name all the time.
I want to build a new dll while the main application still runs. However for now I get the message
The process cannot access the file test.dll because it is being used
by another process
I have read that you can unload a .dll using AppDomains however the problem is that I don't know how to properly unload an AppDomain and where to do this.
The goal is to have to reload the new test.dll everytime the window is re-opened (by a button click from the main application).
You cannot unload a single assembly, but you can unload an Appdomain. This means you need to create an app domain and load the assembly in the App domain.
Exmaple:
var appDomain = AppDomain.CreateDomain("MyAppDomain", null, new AppDomainSetup
{
ApplicationName = "MyAppDomain",
ShadowCopyFiles = "true",
PrivateBinPath = "MyAppDomainBin",
});
ShadowCopyFiles property will cause the .NET runtime to copy dlls in "MyAppDomainBin" folder to a cache location so as not to lock the files in that path. Instead the cached files are locked. For more information refer to article about Shadow Copying Assemblies
Now let's say you have an class you want to use in the assembly you want to unload. In your main app domain you call CreateInstanceAndUnwrap to get an instance of the object
_appDomain.CreateInstanceAndUnwrap("MyAssemblyName", "MyNameSpace.MyClass");
However, and this is very important, "Unwrap" part of CreateInstanceAndUnwrap will cause the assembly to be loaded in your main app domain if your class does not inherit from MarshalByRefObject. So basically you achieved nothing by creating an app domain.
To solve this problem, create a 3rd Assembly containing an Interface that is implemented by your class.
For example:
public interface IMyInterface
{
void DoSomething();
}
Then add reference to the assembly containing the interface in both your main application and your dynamically loaded assembly project. And have your class implement the interface, and inherit from MarshalByRefObject. Example:
public class MyClass : MarshalByRefObject, IMyInterface
{
public void DoSomething()
{
Console.WriteLine("Doing something.");
}
}
And to get a reference to your object:
var myObj = (IMyInterface)_appDomain.CreateInstanceAndUnwrap("MyAssemblyName", "MyNameSpace.MyClass");
Now you can call methods on your object, and .NET Runtime will use Remoting to forward the call to the other domain. It will use Serialization to serialize the parameters and return values to and from both domains. So make sure your classes used in parameters and return values are marked with [Serializable] Attribute. Or they can inherit from MarshalByRefObject in which case the you are passing a reference cross domains.
To have your application monitor changes to the folder, you can setup a FileSystemWatcher to monitor changes to the folder "MyAppDomainBin"
var watcher = new FileSystemWatcher(Path.GetFullPath(Path.Combine(".", "MyAppDomainBin")))
{
NotifyFilter = NotifyFilters.LastWrite,
};
watcher.EnableRaisingEvents = true;
watcher.Changed += Folder_Changed;
And in the Folder_Changed handler unload the appdomain and reload it again
private static async void Watcher_Changed(object sender, FileSystemEventArgs e)
{
Console.WriteLine("Folder changed");
AppDomain.Unload(_appDomain);
_appDomain = AppDomain.CreateDomain("MyAppDomain", null, new AppDomainSetup
{
ApplicationName = "MyAppDomain",
ShadowCopyFiles = "true",
PrivateBinPath = "MyAppDomainBin",
});
}
Then when you replace your DLL, in "MyAppDomainBin" folder, your application domain will be unloaded, and a new one will be created. Your old object references will be invalid (since they reference objects in an unloaded app domain), and you will need to create new ones.
A final note: AppDomains and .NET Remoting are not supported in .NET Core or future versions of .NET (.NET 5+). In those version, separation is achieved by creating separate processes instead of app domains. And using some sort of messaging library to communicate between processes.
Not the way forward in .NET Core 3 and .NET 5+
Some of the answers here assume working with .NET Framework. In .NET Core 3 and .NET 5+, the correct way to load assemblies (with ability to unload them) in the same process is with AssemblyLoadContext. Using AppDomain as a way to isolate assemblies is strictly for .NET Framework.
.NET Core 3 and 5+, give you two possible ways to load dynamic assemblies (and potentially unload):
Load another process and load your dynamic assemblies there. Then use an IPC messaging system of your choosing to send messages between the processes.
Use AssemblyLoadContext to load them in the same process. Note that the scope does NOT provide any kind of security isolation or boundaries within the process. In other words, code loaded in a separate context is still able to invoke other code in other contexts within the same process. If you want to isolate the code because you expect to be loading assemblies that you can't fully trust, then you need to load it in a completely separate process and rely on IPC.
An article explaining AssemblyLoadContext is here.
Plugin unloadability discussed here.
Many people who want to dynamically load DLLs are interested in the Plugin pattern. The MSDN actually covers this particular implementation here:
https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support
2021-9-12 UPDATE
Off-the-Shelf Library for Plugins
I use the following library for plugin loading. It has worked extremely well for me:
https://github.com/natemcmaster/DotNetCorePlugins
what you're trying to do in the code you posted is unload the default app domain which your program will run in if another isn't specified. What you're probably wanting is to load a new app domain, load the assembly into that new app domain, and then unloaded the new app domain when the user destroys the page.
https://learn.microsoft.com/en-us/dotnet/api/system.appdomain?view=netframework-4.7
the reference page above should give you a working example of all of this.
Here is an example for loading and unloading an AppDomain.
In my example I have 2 Dll's: DynDll.dll and DynDll1.dll.
Both Dll's have the same class DynDll.Class and a method Run (MarshalByRefObject is required):
public class Class : MarshalByRefObject
{
public int Run()
{
return 1; //DynDll1 return 2
}
}
Now you can create a dynamic AppDomain and load a Assembly:
AppDomain loDynamicDomain = null;
try
{
//FullPath to the Assembly
string lsAssemblyPath = string.Empty;
if (this.mbLoad1)
lsAssemblyPath = Path.Combine(Application.StartupPath, "DynDll1.dll");
else
lsAssemblyPath = Path.Combine(Application.StartupPath, "DynDll.dll");
this.mbLoad1 = !this.mbLoad1;
//Create a new Domain
loDynamicDomain = AppDomain.CreateDomain("DynamicDomain");
//Load an Assembly and create an instance DynDll.Class
//CreateInstanceFromAndUnwrap needs the FullPath to your Assembly
object loDynClass = loDynamicDomain.CreateInstanceFromAndUnwrap(lsAssemblyPath, "DynDll.Class");
//Methode Info Run
MethodInfo loMethodInfo = loDynClass.GetType().GetMethod("Run");
//Call Run from the instance
int lnNumber = (int)loMethodInfo.Invoke(loDynClass, new object[] { });
Console.WriteLine(lnNumber.ToString());
}
finally
{
if (loDynamicDomain != null)
AppDomain.Unload(loDynamicDomain);
}
Here is an idea, instead of loading the DDL directly (as is), let the application rename it, then load the renamed ddl (e.g. test01_active.dll). Then, just check for the original file (test01.dll) before loading the assembly and if exists, just delete the current one(test01_active.dll) and then rename the updated version then reload it, and so on.
Here is a code shows the idea :
const string assemblyDirectoryPath = "C:\\bin";
const string assemblyFileNameSuffix = "_active";
var assemblyCurrentFileName = "test01_active.dll";
var assemblyOriginalFileName = "test01.dll";
var originalFilePath = Path.Combine(assemblyDirectoryPath, assemblyOriginalFileName);
var currentFilePath = Path.Combine(assemblyDirectoryPath, assemblyCurrentFileName);
if(File.Exists(originalFilePath))
{
File.Delete(currentFilePath);
File.Move(originalFilePath, currentFilePath);
}
Assembly asm = Assembly.LoadFrom(currentFilePath);
Type type = asm.GetType("Test.Program");
MethodInfo methodInfo = type.GetMethod("Run");
object[] parametersArray = new object[] { };
var result = methodInfo.Invoke(methodInfo, parametersArray);
I have an in-memory assembly MyAssembly (class library) that is used in my main assembly MyApp.exe:
byte[] assemblyData = GetAssemblyDataFromSomewhere();
(For testing, the GetAssemblyDataFromSomewhere method can just do File.ReadAllBytes for an existing assembly file, but in my real app there is no file.)
MyAssembly has only .NET Framework references and has no dependencies to any other user code.
I can load this assembly into the current (default) AppDomain:
Assembly.Load(assemblyData);
// this works
var obj = Activator.CreateInstance("MyAssembly", "MyNamespace.MyType").Unwrap();
Now, I want to load this assembly into a different AppDomain and instantiate the class there. MyNamespace.MyType is derived from MarshalByRefObject, so I can share the instance across the app domains.
var newAppDomain = AppDomain.CreateDomain("DifferentAppDomain");
// this doesn't really work...
newAppDomain.Load(assemblyData);
// ...because this throws a FileNotFoundException
var obj = newAppDomain.CreateInstanceAndUnwrap("MyAssembly", "MyNamespace.MyType");
Yes, I know there is a note in the AppDomain.Load docs:
This method should be used only to load an assembly into the current application domain.
Yes, it should be used for that, but...
If the current AppDomain object represents application domain A, and the Load method is called from application domain B, the assembly is loaded into both application domains.
I can live with that. There's no problem for me if the assembly will be loaded into both app domains (because I actually load it into the default app domain anyway).
I can see that assembly loaded into the new app domain. Kind of.
var assemblies = newAppDomain.GetAssemblies().Select(a => a.GetName().Name);
Console.WriteLine(string.Join("\r\n", assemblies));
This gives me:
mscorlib
MyAssembly
But trying to instantiate the class always leads to a FileNotFoundException, because the CLR tries to load the assembly from file (despite it is already loaded, at least according to AppDomain.GetAssemblies).
I could do this in MyApp.exe:
newAppDomain.AssemblyResolve += CustomResolver;
private static Assembly CustomResolver(object sender, ResolveEventArgs e)
{
byte[] assemblyData = GetAssemblyDataFromSomewhere();
return Assembly.Load(assemblyData);
}
This works, but this causes the second app domain to load the calling assembly (MyApp.exe) from file. It happens because that app domain now needs the code (the CustomResolver method) form the calling assembly.
I could move the app domain creation logic and the event handler into a different assembly, e.g. MyAppServices.dll, so the new app domain will load that assembly instead of MyApp.exe.
However, I want to avoid the file system access to my app's directory at any cost: the new app domain must not load any user assemblies from files.
I also tried AppDomain.DefineDynamicAssembly, but that did't work either, because the return value's type System.Reflection.Emit.AssemblyBuilder is neither MarshalByRefObject nor marked with [Serializable].
Is there any way to load an assembly from byte array into a non-default AppDomain without loading the calling assembly from file into that app domain? Actually, without any file system access to my app's directory?
You first problem is the way you load the assembly into the second AppDomain.
You need some type loaded / shared between both AppDomains. You can't load assembly into the second AppDomain from the first AppDomain if the assembly is not already loaded into the first AppDomain (it also won't work if you load the assembly bytes into the first AppDomain uisng .Load(...)).
This should be a good starting point:
Lets say i have class library named Models with single class Person as follows:
namespace Models
{
public class Person : MarshalByRefObject
{
public void SayHelloFromAppDomain()
{
Console.WriteLine($"Hello from {AppDomain.CurrentDomain.FriendlyName}");
}
}
}
and console application as follows (the Models class library is NOT references from the project)
namespace ConsoleApp
{
internal class Program
{
[LoaderOptimizationAttribute(LoaderOptimization.MultiDomain)]
public static void Main(String[] args)
{
CrossAppDomain();
}
private static Byte[] ReadAssemblyRaw()
{
// read Models class library raw bytes
}
private static void CrossAppDomain()
{
var bytes = ReadAssemblyRaw();
var isolationDomain = AppDomain.CreateDomain("Isolation App Domain");
var isolationDomainLoadContext = (AppDomainBridge)isolationDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "ConsoleApp.AppDomainBridge");
// person is MarshalByRefObject type for the current AppDomain
var person = isolationDomainLoadContext.ExecuteFromAssembly(bytes);
}
}
public class AppDomainBridge : MarshalByRefObject
{
public Object ExecuteFromAssembly(Byte[] raw)
{
var assembly = AppDomain.CurrentDomain.Load(rawAssembly: raw);
dynamic person = assembly.CreateInstance("Models.Person");
person.SayHelloFromAppDomain();
return person;
}
}
}
The way it works is by creating instance of the AppDomainBridge from the ConsoleApp project which is loaded into both AppDomains. Now this instance is living into the second AppDomain. Then you can use the AppDomainBridge instance to actually load the assembly into the second AppDomain and skipping anything to do with the first AppDomain.
This is the output of the console when i execute the code (.NET Framework 4.7.2), so the Person instance is living in the second AppDomain:
Your second problem is sharing instances between AppDomains.
The main problem between AppDomains sharing the same code is the need to share the same JIT compiled code (method tables, type information ... etc).
From docs.microsoft:
JIT-compiled code cannot be shared for assemblies loaded into the
load-from context, using the LoadFrom method of the Assembly class, or
loaded from images using overloads of the Load method that specify
byte arrays.
So you won't be able to fully share the type information when you load assmebly from bytes, which means your object at this point is just MarshalByRefObject for the first AppDomain. This means that you can execute and access methods / properties only from the MarshalByRefObject type (it does not matter if you try to use dynamic / reflection - the first AppDomain does not have the type information of the instance).
What you can do is not to return the object from ExecuteFromAssembly, but to extend the AppDomainBridge class to be simple wrapper around the created Person instance and use it to delegate any method execution from the first AppDomain to the second if you really need it for those purposes.
I'm not quite sure what are you trying to achieve, but I would try the following.
In general, your approach seems OK. You have to make sure your probing paths (especially, the appbase path) for the secondary appdomain are set correctly. Otherwise, .NET Fusion will probe these locations for dependencies, and you'll have those unwanted file system access attempts, you're trying to avoid. (Well, at least make sure that these paths are configured to some temp folders with no real permissions set up).
PROPOSED SOLUTION
In any case, you can try adding to your dynamic (is this how I should call it?) assembly an entry point (ex. Main method in some Bootstrap class), and
try calling AppDomain.ExecuteAssemblyByName, after loading the assembly into the secondary AppDomain.
I would add to the Bootstrap class your CustomResolver method, and in the Main method, I would subscribe to AssemblyResolve.
This way, when the Main method is called (and hopefully it works as expected), the subscription to AppDomain's AssemblyResolve won't trigger fusion.
I didn't test this solution, and it could be a long shot, but worse trying.
P.S.:
I do see that documentation on this method does state, that the runtime will try to load the assembly first (by probably using regular probing logic), but it doesn't say anything about situation in which the assembly was pre-loaded into the AppDomain before the call was made.
Remarks
The ExecuteAssemblyByName method provides similar functionality to the ExecuteAssembly method, but specifies the assembly by display name or AssemblyName rather than by file location. Therefore, ExecuteAssemblyByName loads assemblies with the Load method rather than with the LoadFile method.
The assembly begins executing at the entry point specified in the .NET Framework header.
This method does not create a new process or application domain, and it does not execute the entry point method on a new thread.
Load method documentation doesn't provide a clear answer either.
P.P.S:
Calling the Unwrap method, may trigger the fusion in your main AppDomain, since a proxy is created for your class. I would think, that at this point your main AppDomain would try to locate that dynamically loaded assembly. Are you sure it's the secondary AppDomain that throws the exception?
My aim is to make a missing dependency check between 2 given folders.
Imagine the following setup.
Root\DirA\A.dll
Root\DirB\B.dll
B depends on A.
So given these folders, I want to create a new AppDomain, load B.dll and have the dependency from DirA(A.dll) automatically resolved and isolated in that new AppDomain.
Isolation is key here given that when I unload this AppDomain I want to create a new one with potentially DirA as a dependency again but DirC libraries that require it so in the case that DirC has a dependency on DirB as well I want it to throw an exception.
Edit: Adding a code example in case that it helps describe my question better.
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = #"C:\Root";
setup.ApplicationName = "Isolated Domain"
setup.PrivateBinPath = #"DirA;DirB";
setup.PrivateBinPathProbe = "";//disable search in AppBase..
var domain = AppDomain.CreateDomain(Guid.NewGuid().ToString(),
AppDomain.CurrentDomain.Evidence,
setup,
AppDomain.CurrentDomain.PermissionSet);
//The following statement in theory should pick B.dll's dependency from DirA.
var assembly = domain.Load(AssemblyName.GetAssemblyName(#"C:\Root\DirB\B.dll").Name);
//Do the same in a different domain for C.dll
Thanks for any help on that.
This looks like a job for the ResolveEventHandler (more detail on MSDN regarding resolving unknown assemblies)
So, you can write something like
class MyResolver
{
public static Assembly MyResolveEventHandler( Object sender, ResolveEventArgs args )
{
// confirm args.Name contains A.dll
String dllName = args.Name.Split({','}, SplitStringOptions.None)[0];
if (dllName == "A")
{
return Assembly.LoadFile(#"C:\Root\DirA\A.dll")
}
return null;
}
}
and in the domain you created, you'd do a:
domain.AssemblyResolve += new ResolveEventHandler(MyResolver.MyResolveEventHandler);
Make sure you bind the event before you reference A in B.
AppDomain's cannot probe for dll's outside of their initial folder. They can probe in the GAC, and in the PrivateBinPath deeper into the folder, but they cannot probe into other folders.
We implement a plugin framework for our application and load plugin assemblies using Assembly.Loadfrom. We then use GetTypes() and further examine the types with each plugin file for supported Interfaces.
A path for the plugins is provided by the user and we cycle through each of the files in the folder to see if it (the plugin) supports our plugin interface. If it does, we create an instance, if not we move onto the next file.
We build two versions of software from the one code base (appA_1 and appA_2).
Loading the plugins works well when the plugins are loaded by the application that was built at the same time as the plugin file. However if we build appA_2 and point to the plugin folder of appA_1, we get an exception when GetTypes() is called.
A basic version of our code is;
var pluginAssembly = Assembly.LoadFrom(FileName);
foreach (var pluginType in pluginAssembly.GetTypes())
{
We get a "ReflectionTypeLoadException" exception.
This is concerning because we want our application to be able to load the types of any plugin, built by anyone. Is there something we are missing?
EDIT:
After iterating through the LoaderExceptions we have discovered that there is a single file libPublic.dll that generates a System.IO.FileNotFoundException exception. The strange thing is that this file resides in the application directory and the plugin is referenced to the project file.
EDIT 2:
In the exception log we find the following
"Comparing the assembly name resulted in the mismatch: Revision Number"
A few things:
Make sure you don't have duplicate assemblies in the plugin directory (i.e. assemblies that you're already loading in your main app from your app directory.) Otherwise, when you load your plugin, it may load an additional copy of the same assembly. This can lead to fun exceptions like:
Object (of type 'MyObject') is not of type 'MyObject'.
If you're getting the exception when instantiating a type, you may need to handle AppDomain.AssemblyResolve:
private void App_Startup(object sender, StartupEventArgs e)
{
// Since we'll be dynamically loading assemblies at runtime,
// we need to add an appropriate resolution path
// Otherwise weird things like failing to instantiate TypeConverters will happen
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain) sender;
foreach (var assembly in domain.GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
}
I realize it's a bit strange to have to tell the CLR that, in order to resolve an assembly, find the assembly with the name we're using to resolve, but I've seen odd things happen without it. For example, I could instantiate types from a plugin assembly, but if I tried to use TypeDescriptor.GetConverter, it wouldn't find the TypeConverter for the class, even though it could see the Converter attribute on the class.
Looking at your edits, this is probably not what's causing your current exception, though you may run into these issues later as you work with your plugins.
Thanks to this post I could solve the ReflectionTypeLoadException that I was getting in a UITypeEditor. It's a designer assembly (a winforms smart-tag used at design-time) of a custom class library, that scan for some types.
/// <summary>
/// Get the types defined in the RootComponent.
/// </summary>
private List<Type> getAssemblyTypes(IServiceProvider provider)
{
var types = new List<Type>();
try
{
IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
foreach (var assembly in ((AppDomain)sender).GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
};
Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
types = rootComponentType.Assembly.GetTypes().ToList();
}
catch
{
}
return types;
}
You are getting an assembly version mismatch. Since your plugins refer to this libPublic.dll, you must version it carefully and in particular not bump its revision/build/etc. numbers at every compile.
I have written the following Utility class to get an instance of any class of name "className".
public class AssemblyUtils
{
private AssemblyUtils()
{
}
public static T GetInstance<T>(string assemblyName, string className)
{
T classInstance = default(T);
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assemblyName);
object o = assembly.CreateInstance(className);
if (o is T)
{
classInstance = (T)o;
}
else
{
o = null;
}
return classInstance;
}
I have called this like:
IMyInterface ins = AssemblyUtils.GetInstance<IMyInterface>(#"MyNamespace.DA.dll", "MyClassDA");
But I am getting the following error message:
Could not load file or assembly 'MyNamespace.DA.dll' or one of its dependencies. The system cannot find the file specified.
Note that, I called the AssemblyUtils.GetInstance() from separate assemblies which are in the same sln.
How can I resolve the assembly path???
My guess is that it cannot find assembly because it's not in the same folder and not in the GAC, or other directories where the system is looking for.
You need either move them in the same folder where an executing assembly. You can change the folder where assembly is loaded from by using AppDomainSetup.PrivateBinPath Property.
I think, the assembly you want to load (MyNamespace.DA.dll) is dependent to another assembly which is not located in you folder you're looking for. Copy the dependent assemblies into the folder where you located MyNamespace.DA.dll assembly.
Check your bin\Debug folder, is the MyNamespace.DA.dll in that folder? If not you're going to have to move it in there manually. Maybe add a postcondition so that its copied in automatically. Also try using the full assembly strong name.
Also JMSA, how about some upvotes and accepting answers on your other thread?
As Vadim mentioned Assembly.Load will only look in a limited set of places. Assembly.LoadFrom might be a better bet for you. It takes a path (with filename) to the assembly.
Assembly.Load works off the assembly name, not the path.