C# 有没有办法强制将所有引用的程序集加载到应用程序域中?

C# 有没有办法强制将所有引用的程序集加载到应用程序域中?,c#,assemblies,appdomain,C#,Assemblies,Appdomain,我的项目设置如下: foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { this.LoadReferencedAssembly(assembly); } 项目“定义” 项目“实施” “消费者”项目 项目“使用者”引用“定义”和“实现”,但不静态引用“实现”中的任何类型 当应用程序启动时,项目“Consumer”调用“Definition”中的静态方法,该方法需要在“Implementati

我的项目设置如下:

foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    this.LoadReferencedAssembly(assembly);
}
  • 项目“定义”
  • 项目“实施”
  • “消费者”项目
项目“使用者”引用“定义”和“实现”,但不静态引用“实现”中的任何类型

当应用程序启动时,项目“Consumer”调用“Definition”中的静态方法,该方法需要在“Implementation”中查找类型


是否有一种方法可以强制将任何引用的程序集加载到应用程序域中,而不知道路径或名称,最好不必使用成熟的IOC框架?

您可以使用获取
AssemblyName[]
,然后对每个程序集调用
assembly.Load(AssemblyName)
。当然,您需要递归,但最好是跟踪您已经加载的程序集:)

这似乎起到了作用:

var loadeAssemblies=AppDomain.CurrentDomain.GetAssemblies().ToList();
var loadedPaths=loadedsassemblies.Select(a=>a.Location.ToArray();
var referencedPaths=Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory,“*.dll”);
var-toLoad=referencedPaths.Where(r=>!loadedPaths.Contains(r,StringComparer.InvariantCultureIgnoreCase)).ToList();
toLoad.ForEach(路径=>loadedAssemblies.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(路径)));
正如Jon所指出的,理想的解决方案需要递归到每个已加载程序集的依赖项中,但在我的特定场景中,我不必担心它



更新:包含在.NET 4中的托管可扩展性框架(System.ComponentModel)具有更好的功能来完成类似的任务。

如果使用Fody.Costura或任何其他程序集合并解决方案,则公认的答案将不起作用

以下命令将加载任何当前加载的程序集的引用程序集。递归留给您

var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();

loadedAssemblies
    .SelectMany(x => x.GetReferencedAssemblies())
    .Distinct()
    .Where(y => loadedAssemblies.Any((a) => a.FullName == y.FullName) == false)
    .ToList()
    .ForEach(x => loadedAssemblies.Add(AppDomain.CurrentDomain.Load(x)));

我只是想分享一个递归的例子。我在启动例程中调用LoadReferencedAssembly方法,如下所示:

foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    this.LoadReferencedAssembly(assembly);
}
这是递归方法:

private void LoadReferencedAssembly(Assembly assembly)
{
    foreach (AssemblyName name in assembly.GetReferencedAssemblies())
    {
        if (!AppDomain.CurrentDomain.GetAssemblies().Any(a => a.FullName == name.FullName))
        {
            this.LoadReferencedAssembly(Assembly.Load(name));
        }
    }
}

鉴于我必须从特定路径加载程序集+依赖项,今天我编写了这个类来完成这项工作

public static class AssemblyLoader
{
    private static readonly ConcurrentDictionary<string, bool> AssemblyDirectories = new ConcurrentDictionary<string, bool>();

    static AssemblyLoader()
    {
        AssemblyDirectories[GetExecutingAssemblyDirectory()] = true;
        AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

    }

    public static Assembly LoadWithDependencies(string assemblyPath)
    {
        AssemblyDirectories[Path.GetDirectoryName(assemblyPath)] = true;
        return Assembly.LoadFile(assemblyPath);
    }

    private static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
    {
        string dependentAssemblyName = args.Name.Split(',')[0] + ".dll";
        List<string> directoriesToScan = AssemblyDirectories.Keys.ToList();

        foreach (string directoryToScan in directoriesToScan)
        {
            string dependentAssemblyPath = Path.Combine(directoryToScan, dependentAssemblyName);
            if (File.Exists(dependentAssemblyPath))
                return LoadWithDependencies(dependentAssemblyPath);
        }
        return null;
    }

    private static string GetExecutingAssemblyDirectory()
    {
        string codeBase = Assembly.GetExecutingAssembly().CodeBase;
        var uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        return Path.GetDirectoryName(path);
    }
}
公共静态类AssemblyLoader
{
私有静态只读ConcurrentDictionary AssemblyDirectory=新ConcurrentDictionary();
静态AssemblyLoader()
{
AssemblyDirectory[GetExecutionGassemblyDirectory()]=true;
AppDomain.CurrentDomain.AssemblyResolve+=ResolveAssembly;
}
公共静态程序集LoadWithDependencies(字符串assemblyPath)
{
AssemblyDirectory[Path.GetDirectoryName(assemblyPath)]=true;
返回Assembly.LoadFile(assemblyPath);
}
私有静态程序集ResolveAssembly(对象发送方,ResolveEventArgs args args)
{
字符串dependentAssemblyName=args.Name.Split(',')[0]+.dll;
List directoriesToScan=AssemblyDirectories.Keys.ToList();
foreach(directoriesToScan中的字符串directoryToScan)
{
字符串dependentAssemblyPath=Path.Combine(directoryToScan,dependentAssemblyName);
if(File.Exists(dependentAssemblyPath))
返回loadwithdependentials(dependentAssemblyPath);
}
返回null;
}
私有静态字符串GetExecutionGassemblyDirectory()
{
字符串codeBase=Assembly.getExecutionGassembly().codeBase;
var uri=新的UriBuilder(代码库);
字符串路径=Uri.UnescapeDataString(Uri.path);
返回Path.GetDirectoryName(路径);
}
}
另一个版本(基于答案)可能不需要加载所有程序集,而是加载预定义数量的程序集:

var assembliesToLoad = { "MY_SLN.PROJECT_1", "MY_SLN.PROJECT_2" };

// First trying to get all in above list, however this might not 
// load all of them, because CLR will exclude the ones 
// which are not used in the code
List<Assembly> dataAssembliesNames =
   AppDomain.CurrentDomain.GetAssemblies()
            .Where(assembly => AssembliesToLoad.Any(a => assembly.GetName().Name == a))
            .ToList();

var loadedPaths = dataAssembliesNames.Select(a => a.Location).ToArray();

var compareConfig = StringComparison.InvariantCultureIgnoreCase;
var referencedPaths = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
    .Where(f =>
    {
       // filtering the ones which are in above list
       var lastIndexOf = f.LastIndexOf("\\", compareConfig);
       var dllIndex = f.LastIndexOf(".dll", compareConfig);

       if (-1 == lastIndexOf || -1 == dllIndex)
       {
          return false;
       }

       return AssembliesToLoad.Any(aName => aName == 
          f.Substring(lastIndexOf + 1, dllIndex - lastIndexOf - 1));
     });

var toLoad = referencedPaths.Where(r => !loadedPaths.Contains(r, StringComparer.InvariantCultureIgnoreCase)).ToList();

toLoad.ForEach(path => dataAssembliesNames.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path))));

if (dataAssembliesNames.Count() != AssembliesToLoad.Length)
{
   throw new Exception("Not all assemblies were loaded into the  project!");
}
var assembliesToLoad={“MY_SLN.PROJECT_1”、“MY_SLN.PROJECT_2”};
//首先尝试将所有内容都包含在上面的列表中,但这可能不会
//加载所有这些文件,因为CLR将排除这些文件
//代码中未使用的
列出数据集合名称=
AppDomain.CurrentDomain.GetAssemblys()
.Where(assembly=>AssembliesToLoad.Any(a=>assembly.GetName().Name==a))
.ToList();
var loadedPaths=dataAssembliesNames.Select(a=>a.Location.ToArray();
var compareConfig=StringComparison.invariantCultureInogoreCase;
var referencedPaths=Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory,“*.dll”)
.其中(f=>
{
//筛选上面列表中的内容
var lastIndexOf=f.lastIndexOf(“\\”,compareConfig);
var dllIndex=f.LastIndexOf(“.dll”,compareConfig);
如果(-1==lastIndexOf | |-1==dllIndex)
{
返回false;
}
返回AssembliesToLoad.Any(aName=>aName==
f、 子串(lastIndexOf+1,dllIndex-lastIndexOf-1);
});
var-toLoad=referencedPaths.Where(r=>!loadedPaths.Contains(r,StringComparer.InvariantCultureIgnoreCase)).ToList();
toLoad.ForEach(path=>dataAssembliesNames.Add(AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(path)));
if(dataAssembliesNames.Count()!=AssembliesToLoad.Length)
{
抛出新异常(“并非所有程序集都加载到项目中!”);
}

如果您的程序集在编译时未引用任何代码,则这些程序集将不会作为对其他程序集的引用而包含,即使您已将项目或nuget包添加为引用。这与
Debug
Release
生成设置、代码优化等无关。在这些情况下,必须显式调用
Assembly.LoadFrom(dllFileName)
才能加载程序集。

要按名称获取引用的程序集,可以使用以下方法:

public static Assembly GetAssemblyByName(string name)
{
    var asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == name);
    if (asm == null)
        asm = AppDomain.CurrentDomain.Load(name);
    return asm;
}

在我的winforms应用程序中,我为JavaScript(在WebView2控件中)提供了调用各种.NET事物的可能性,例如程序集Microsoft.VisualBasic.dll中的
Microsoft.VisualBasic.Interaction
(例如
public static IEnumerable<Assembly> GetProjectAssemblies(string prefixName)
{
    var assemblies = new HashSet<Assembly>
    {
        Assembly.GetEntryAssembly()
    };

    for (int i = 0; i < assemblies.Count; i++)
    {
        var assembly = assemblies.ElementAt(i);

        var referencedProjectAssemblies = assembly.GetReferencedAssemblies()
            .Where(assemblyName => assemblyName.FullName.StartsWith(prefixName))
            .Select(assemblyName => Assembly.Load(assemblyName));

        assemblies.UnionWith(referencedProjectAssemblies);
    }

    return assemblies;
}