AppDomain执行程序集

本文关键字:程序集 执行程序 执行 AppDomain | 更新日期: 2023-09-27 18:21:58

我正在尝试将程序集(dll)加载到AppDomain并调用入口点。(本质上是将包引导到Azure环境中)我一直在关注这篇SO文章(我如何创建应用程序域并在其中运行我的应用程序?)我认为我做得对,但我遇到了一些问题。

我已经在这里用了几篇文章来了解我的情况,但我一直遇到FileNotFoundException,如Unable to load executing assembly into new AppDomain,FileNotFoundException中所述。我的问题是解决方案不起作用。我试图执行的程序集存在于其他位置。所以ApplicationBase需要是我试图执行的程序集的文件夹。

var otherType = typeof(BootstrapProxy);
var domaininfo = new AppDomainSetup
    {
        ConfigurationFile = executingAssembly + ".config",
        ApplicationBase = _root
    };
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
_domain = AppDomain.CreateDomain(_type.ToString(), adevidence, domaininfo);
_domain.AssemblyResolve += (sender, args) =>
    {
        var lookupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (lookupPath == null) return null;
        var assemblyname = new AssemblyName(args.Name).Name;
        var assemblyFileName = Path.Combine(lookupPath, assemblyname + ".dll");
        var assembly = Assembly.LoadFrom(assemblyFileName);
        return assembly;
    };
var proxy = _domain.CreateInstanceAndUnwrap(otherType.Assembly.FullName, otherType.FullName) as BootstrapProxy;

最后一行抛出异常,AssemblyResolve事件从不触发(通过在var lookupPath行上放置断点来确定)

我也尝试过使用与上面相同的处理程序的AppDomain.CurrentDomain.AssemblyResolve事件,但没有成功。我还尝试在BootstrapProxy类中创建相同的处理程序。

我认为我做得很好,但要注意第一段,所以如果我完全偏离了基础,我并不反对用不同的方式做事。

更新:

我已经更改了代码,将程序集强制加载到新的appdomain中,但仍然存在问题。

var otherType = typeof(BootstrapProxy);
var domaininfo = new AppDomainSetup
    {
        ConfigurationFile = executingAssembly + ".config",
        ApplicationBase = _root
    };
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
_domain = AppDomain.CreateDomain(_type.ToString(), adevidence, domaininfo);
var deps = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var dep in deps)
{
    var lookupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (lookupPath == null) continue;
    var assemblyname = new AssemblyName(dep.Name).Name;
    var assemblyFileName = Path.Combine(lookupPath, assemblyname + ".dll");
    if (File.Exists(assemblyFileName))
        _domain.Load(File.ReadAllBytes(assemblyFileName));
}
_domain.Load(File.ReadAllBytes(Assembly.GetExecutingAssembly().Location));
var sl = _domain.GetAssemblies().ToArray();
var proxy = _domain.CreateInstanceAndUnwrap(otherType.Assembly.FullName, otherType.FullName) as BootstrapProxy;

sl显示所有dll,包括FileNotFoundException中引用的dll,都加载在新的appdomain中。

public class BootstrapProxy : MarshalByRefObject
{
    public void Main()
    {
        Console.WriteLine("Magic happened.");
    }
}

更新2:

我把它改成了这个:

var deps = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var dep in deps)
{
    var lookupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (lookupPath == null) continue;
    var assemblyname = new AssemblyName(dep.Name).Name;
    var assemblyFileName = Path.Combine(lookupPath, assemblyname + ".dll");
    if (File.Exists(assemblyFileName))
        File.Copy(assemblyFileName, Path.Combine(_root, assemblyname + ".dll"));
}
File.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(_root, Path.GetFileName(Assembly.GetExecutingAssembly().Location)));
var otherType = typeof(BootstrapProxy);
var domaininfo = new AppDomainSetup
    {
        ConfigurationFile = executingAssembly + ".config",
        ApplicationBase = _root
    };
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
_domain = AppDomain.CreateDomain(_type.ToString(), adevidence, domaininfo);
var proxy = _domain.CreateInstanceAndUnwrap(otherType.Assembly.FullName, otherType.FullName) as BootstrapProxy;
if (proxy != null)
{
    proxy.Main();
}

这种将程序集及其引用复制到新AppDomain的ApplicationBase的方法并不理想,因为有一些常见的引用,我可能会遇到版本冲突和其他问题。

AppDomain执行程序集

只是猜测,但问题就在这里:

var otherType = typeof(BootstrapProxy);

通过这样做,您将把该程序集加载到调用appdomain中。由于初始化,它尝试加载调用域的查找路径中不存在的程序集。卡博姆!

要解决此问题:

通过其完全限定名称引用otherType,并将程序集名称作为字符串传入。(我想你可能只需要使用这种类型的FQN就可以了)

此外。您不应该真正为appdomain之外的程序集处理AssemblyResolve