项目场景:
当我们在进行插件开发的时候经常会遇到一个问题:当前程序运行路径和程序集加载路径不一样,最简单的方法是,将当前程序需要的dll放到我们使用的软件的程序的根目录下。
但是我们能不能从代码上解决这个问题,当它加载失败的时候使它从另一个地方重新加载dll呢。
问题描述
加载失败的时候从另一个地方重新加载dll
,废话不多说,直接上代码(可以直接用):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace ZONZCENAddin
{
/// <summary>
/// 用于确定解决方案文件(在文件系统上)的路径并加载程序集
/// </summary>
public class AssemblyLoader : IDisposable
{
/// <summary>
/// 返回fileInfo中的文件列表
/// </summary>
public static IEnumerable<string> GetFiles(DirectoryInfo fileInfo)
{
return from file in fileInfo.EnumerateFiles()
where (file.Name.EndsWith(".dll") || file.Name.EndsWith(".exe") || file.Name.EndsWith(".xaml") || file.Name.EndsWith(".cs"))
select file.FullName;
}
private static string _executingPath;
public AssemblyName _assemblyName;
private DirectoryInfo _fileInfo;
private IEnumerable<string> _assemblies;
readonly AppDomain currentDomain = AppDomain.CurrentDomain;
private IEnumerable<Assembly> _domainAssemblies;
public AssemblyLoader()
{
// 存储加载的程序集
_executingPath = Assembly.GetExecutingAssembly().Location;
_fileInfo = new FileInfo(_executingPath).Directory;
// 返回执行目录中所有DLL的列表
_assemblies = GetFiles(_fileInfo);
_domainAssemblies = currentDomain.GetAssemblies().Where(a => !a.IsDynamic);
AppDomain.CurrentDomain.AssemblyResolve += LoadApplicationAssemblies;
}
/// <summary>
/// 从指定路径加载
/// </summary>
public AssemblyLoader(string pPath)
{
// 指定路径
_executingPath = pPath;
_fileInfo = new FileInfo(_executingPath).Directory;
// 返回执行目录中所有DLL的列表
_assemblies = GetFiles(_fileInfo);
_domainAssemblies = currentDomain.GetAssemblies().Where(a => !a.IsDynamic);
AppDomain.CurrentDomain.AssemblyResolve += LoadApplicationAssemblies;
}
/// <summary>
/// 返回程序集的事件处理程序
/// </summary>
/// <returns>程序集的名称</returns>
public Assembly LoadApplicationAssemblies(object sender, ResolveEventArgs args)
{
if (string.IsNullOrEmpty(_executingPath))
return null;
try
{
// 忽略缺少的资源
if (args.Name.Contains(".resources"))
return null;
// 检查是否已加载程序集
Assembly loadedAssembly = _domainAssemblies.FirstOrDefault(x => x.FullName == args.Name);
if (loadedAssembly != null)
return loadedAssembly;
var requestedAssembly = args.Name.Split(',')[0];
var assemblyToLoad = _assemblies.Where(x => x.Contains(requestedAssembly)).FirstOrDefault();
return Assembly.LoadFrom(assemblyToLoad);
}
catch (Exception e)
{
return null;
}
}
public void Dispose()
{
AppDomain.CurrentDomain.AssemblyResolve -= LoadApplicationAssemblies;
}
}
}
解决方案:
在加载程序集前注册事件AppDomain.CurrentDomain.AssemblyResolve,加载失败的的时候触发。获取指定路径的文件列表,判断是否已经加载了,未加载的从指定路径加载。加载完成后别忘了Dispose掉。
这是在用wpf做插件的时候发现的问题,衍生的问题还有wpf制作插件,然后通过这个获取共享盘上的资源文件。还有在做大型项目的时候将所有dll,放在一个文件夹中。