Вы определяете метод GetAssembly
в прокси-домене, который перетаскивает загруженный Assembly
в основной домен.Это делает всю концепцию бессмысленной, потому что даже если вы выгрузите прокси-домен, ваш основной домен будет в конечном итоге загрязнен загруженной сборкой.
Вместо того, чтобы возвращать сборку, просто используйте ее внутри прокси-домена.Если вы хотите вернуть некоторую информацию в основной домен, вы должны передать простые сериализуемые типы (или удаленные объекты, полученные из MarshalByRefObject
), чтобы основной домен оставался чистым.
Вот как вы должны это сделать:
// This class provides callbacks to the host app domain.
// This is optional, you need only if you want to send back some information
public class DomainHost : MarshalByRefObject
{
// sends any object to the host. The object must be serializable
public void SendDataToMainDomain(object data)
{
Console.WriteLine($"Hmm, some interesting data arrived: {data}");
}
// there is no timeout for host
public override object InitializeLifetimeService() => null;
}
И ваш прокси должен выглядеть так:
class AssemblyLoader : MarshalByRefObject
{
private DomainHost host;
public void Initialize(DomainHost host)
{
// store the remote host here so you will able to use it to send feedbacks
this.host = host;
host.SendData("I am just being initialized.")
}
// of course, if your job has some final result you can have a return value
// and then you don't even may need the DomainHost.
// But do not return any Type from the loaded dll (not mentioning the whole Assembly).
public void DoWork()
{
host.SendData("Work started. Now I will load some dll.");
// TODO: load and use dll
host.SendData(42);
host.SendData("Job finished.")
}
}
Использование:
var domain = AppDomain.CreateDomain("SandboxDomain");
var loader = (AssemblyLoader)domain.CreateInstanceAndUnwrap(typeof(AssemblyLoader).Assembly.FullName, typeod(AssemblyLoader).FullName);
// pass the host to the domain (again, this is optional; just for feedbacks)
loader.Initialize(new DomainHost());
// Start the work.
loader.DoWork();
// At the end, you can unload the domain
AppDomain.Unload(domain);
И, наконец, для самого FileNotFoundException
:
В AppDomain
вы можете загружать только сборки, которые находятся в той же самой или подпапке основного домена.Используйте это вместо Environment.CurrentDirectory
в объекте установки:
var setup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
PrivateBinPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
};
Если вы действительно хотите загрузить сборку из любого места, загрузите ее как byte[]
:
var dll = Assembly.Load(File.ReadAllBytes(fullPathToDll));