c# - AppDomain 执行程序集

标签 c# reflection appdomain fusion

我正在尝试将程序集 (dll) 加载到 AppDomain 中并调用入口点。 (本质上是将包引导到 Azure 环境中)我一直在关注这篇 SO 文章 ( How do I create an application domain and run my application in it? ),我认为我做对了,但我遇到了一些问题。

我已经使用了这里的几篇文章来了解我目前的情况,但我一直遇到 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 类中创建相同的处理程序。

我认为我这样做是正确的,但请记下第一段,所以如果我完全偏离基地,我不反对以不同的方式做事。

更新:

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

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 中引用的那个,都已加载到新的应用程序域中。

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 的方法并不理想,因为有一些公共(public)引用,我最终可能会遇到版本冲突和其他问题。

最佳答案

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

var otherType = typeof(BootstrapProxy);

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

解决这个问题:

通过其完全限定名称引用 otherType 并将程序集名称也作为字符串传递。 (我认为您可能只使用该类型的 FQN 就可以逃脱)

还有。您不应该为应用程序域之外的程序集真正处理 AssemblyResolve

关于c# - AppDomain 执行程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17583648/

相关文章:

c# - DllImport 中的编码(marshal)处理、StringBuilder 和字符指针

c# - Entity Framework 代码优先和 ironpython

c# - 如何只查找同时具有 getter 和 setter 的属性?

Java:如何调用名称存储在字符串变量中的函数

c# - ProcessExit 与 DomainUnload

c# - 在不从父域引用程序集的情况下从子 AppDomain 检索数据

c# - SqlBulkCopy 不工作,没有错误

c# - 通过两个代理的 HttpWebRequest

c# - 使用反射创建命名空间中所有类的列表并转换为其真实类型

C# AppDomains 和线程