使用已加载的所有引用加载程序集

时间:2017-10-24 17:19:56

标签: c# appdomain system.reflection

我想从不是我当前的应用程序域基本文件夹的文件夹加载程序集。我想加载的一些程序集已经加载到默认应用程序域中的旧版本中。为了运行它,我找到了以下代码。新加载的程序集位于文件夹c:\ testa \

How to Load an Assembly to AppDomain with all references recursively?

class Program
{
    static void Main(string[] args)
    {
        AppDomainSetup domaininfo = new AppDomainSetup();
        domaininfo.ApplicationBase = @"c:\testa\";
        Evidence adevidence = AppDomain.CurrentDomain.Evidence;
        AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);

        Type type = typeof(Proxy);
        var value = (Proxy)domain.CreateInstanceAndUnwrap(
            type.Assembly.FullName,
            type.FullName);

        var assembly = value.GetAssembly(args[0]);
        // AppDomain.Unload(domain);
    }
}

public class Proxy : MarshalByRefObject
{
    public Assembly GetAssembly(string assemblyPath)
    {
        try
        {
            return Assembly.LoadFile(assemblyPath);
        }
        catch (Exception)
        {
            return null;
            // throw new InvalidOperationException(ex);
        }
    }
}

作为提到的代码的作者,我得到了一个未找到的文件或依赖项。那么我该如何处理这个问题呢。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

.NET Framework允许在加载到Application Domain期间通过程序集解析代码进行完全控制。它是通过使用附加到AppDomain.AssemblyResolve事件的事件处理程序实现的。事件处理程序的作用是加载程序集并返回Assembly实例。只要加载的程序集准备好执行,它的完成方式取决于实现者。例如,可以动态生成新的程序集,然后加载它,返回对它的引用。似乎使用thet方法可以解决问题,因为此事件将触发主模块,卫星组件,资源程序集和所有依赖项。

static void Main(string[] args)
{
    AppDomainSetup domaininfo = new AppDomainSetup();
    domaininfo.ApplicationBase = @"c:\testa\";
    Evidence adevidence = AppDomain.CurrentDomain.Evidence;
    AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);
    AssemblyResolver resolver = new AssemblyResolver();
    domain.Assembly += resolver.Resolve;

    Type type = typeof(Proxy);
    var value = (Proxy)domain.CreateInstanceAndUnwrap(
        type.Assembly.FullName,
        type.FullName);

    var assembly = value.GetAssembly(args[0]);
    // AppDomain.Unload(domain);
}

使用硬编码汇编数据实现更复杂的AssemblyResolver类的Resolve实例方法,在生产中从主应用程序组件配置文件中检索这些数据:

public Assembly Resolve(object sender, ResolveEventArgs e)
{

    System.Diagnostics.Debug.WriteLine("AssemblyResolve event for: {0}\t\tRequestingAssembly {1}", e.Name, e.RequestingAssembly);

    switch(e.Name)
    {
        case "EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=aed0ab2de30e5e00":
            return LoadAssembly(e);
        case "System.Data.SQLite.EF6, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139":
            return LoadAssembly(e);
        case "BlueTechZone.Sqlite.EF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7741556173e269b9":
            string codeBase = CodeBase + _SubDirectory + "System.Data.SQLite.EF6.dll";
            var ef6SQLite = Assembly.LoadFrom(codeBase);
            return LoadAssembly(e, new String[] { "SQLite.Interop.dll" });
        case "System.Data.SQLite, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139":
            return LoadAssembly(e, new String[] { "SQLite.Interop.dll" });
        default:
            return null;
    }
}

下面是用于将解析程序附加到运行它的同一域的代码,然后将剩余的应用程序部分加载到域中。 APP_CONFIG_FILE用于设置应用程序域使用的配置文件的路径。

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"E:\src\**\<assembly name>.dll.config");

AssemblyResolver = new AssemblyResolver();
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolver.Resolve;

答案 1 :(得分:0)

我修复了问题因为我改变了程序的流程。

首先,我将dll从当前目录复制到目录c:\ testa。现有文件不会被覆盖。

然后我启动程序:

class Program
{
    static void Main(string[] args)
    {
        /* Copy files from current folder to c:\testa\ */

        AppDomainSetup domaininfo = new AppDomainSetup();
        domaininfo.ApplicationBase = @"c:\testa\";
        domaininfo.PrivateBinPath = @"c:\testa\";
        Evidence adevidence = AppDomain.CurrentDomain.Evidence;
        AppDomain domain = AppDomain.CreateDomain("MyDomain", adevidence, domaininfo);

        Type type = typeof(Proxy);
        var value = (Proxy)domain.CreateInstanceAndUnwrap(
            type.Assembly.FullName,
            type.FullName);

        var assembly = value.Run(() => { /* My Program */});

    }
}

public class Proxy : MarshalByRefObject
{
    public void GetAssembly(Action a)
    {
        a();
    }
}

所以我在新的appdomain中运行程序,所有程序集都正确加载。