1、引言
在一个项目开发中一般都是把引用的dll放在根目录下,随着项目的日益增大,根目录下的dll文件就会越来越多,合理规划这些dll的存放地址,可以使整个项目更加的规范与美观。这篇文章就为大家介绍关于C#如何在指定文件夹寻找文件dll的相关内容,文中通过基于RDIFramework框架WinForm版为基础进行介绍,Web的相关dll规划类似,希望对大家具有一定的参考学习价值。
我们框架原执行目录下的dll存放如下,可以看到整个目录下的文件非常多。
下面我们通过最常用的方式对dll文件进行规划处理,使整个运行目录更加的干净,规范,最终效果如下图所示。
可以看到,上图的整个运行目录结构非常的清爽与整洁了。如何实现的呢?下面我们就具体讲解。
2、实现方法
2.1、系统搜索dll的目录以及顺序
CLR解析一个程序集会在一个根目录内进行搜索,整个探索过程又称Probing,这个根目录很显然就是当前包含当前程序集的目录。
AppDomainSetup这个类存储着探索目录的信息,其成员包括:ApplicationBase、PrivateBinPath。
程序搜索dll的顺序如下(区分强名称签名的和没有强名称签名的程序集):
没有做强名称签名的程序集:
- 程序的根目录
- 根目录下面,与被引用程序集同名的子目录
- 根目录下面被明确定义为私有目录的子目录
- 在目录中查找的时候,如果dll查找不到,则会尝试查找同名的exe
- 如果程序集带有区域性,而不是语言中立的,则还会尝试查找以语言区域命名的子目录
具有强名称签名的程序集:
全局程序集缓存
如果有定义codebase,则以codebase定义为准,如果codebase指定的路径找不到,则直接报告错误
程序的根目录
根目录下面,与被引用程序集同名的子目录
根目录下面被明确定义为私有目录的子目录
在目录中查找的时候,如果dll查找不到,则会尝试查找同名的exe
如果程序集带有区域性,而不是语言中立的,则还会尝试查找以语言区域命名的子目录。如下图所示:
2.2、如何让程序识别不同目录下的dll?
我们看到,上面的顺序无论是否有强名称签名,都会用到私有目录,要实现程序识别不同目录下的dll文件,一般有三种方式。
1、配置App.config文件的privatePath——【推荐】。
2、订阅程序集解析事件AssemblyResolve在代码中解析。
3、在加载使用到dll的代码之前重置当前环境的目录。
2.2.1、配置App.config文件的privatePath——【推荐】
这是最简单最常用的方法,也是我们采用的方式。这儿要说明的是此方法有一定的局限性,就是没法对dll做控制,另外无法解决第三方DllImprt
中引入的程序集不在根目录下的问题。配置如下,多个目录用;分隔。
<configuration>
<runtime>
<!--xmlns是必需的特性。指定程序集绑定所需的 XML 命名空间。 使用字符串“urn: 架构-microsoft-com:asm.v1”作为值。-->
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<publisherPolicy apply="yes"/> <!--指定运行时是否使用发布者策略-->
<!--指定加载程序集时公共语言运行时搜索的子目录, 其中privatePath是相对于*.exe.config文件的相对路径,多个文件夹以分号分隔。-->
<probing privatePath="devLibs;3rdLibs;frameworkLibs"/>
</assemblyBinding>
</runtime>
</configuration>
其中privatePath是相对于*.exe.config文件的相对路径,多个文件夹以分号分隔。当编译后会在生成目录下生成一个后缀为.exe.config的文件,就是相对这个文件的。
添加程序集DLL引用之后,将DLL的属性“复制本地”设置为False。程序编译过程中,会自动检索Common和Security文件夹下的DLL及其依赖项。
我们框架就是使用这种方式来实现,最终的运行目录结构效果如下。
2.2.2、订阅程序集解析事件AssemblyResolve在代码中解析。
应用程序集域中支持在程序集解析时的处理:
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
通过这个事件,我们可以在程序集解析时,根据不同的程序集做不用的处理,比如加载x86的程序集还是64位的程序集,当然也就可以指定程序集目录了。这也正是Assembly.Load
和Assembly.LoadFrom
等方法的用武之地。
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AssemblyName assemblyName = new AssemblyName(args.Name);
return Assembly.LoadFrom(Path.Combine(baseDirectory, "3rdLibs"));
}
2.2.3、在加载使用到dll的代码之前重置当前环境的目录。
这个方法是通过Environment.CurrentDirectory=customPath
,这样在调用dll方法时,因为目录已经切换到了我们指定的目录下,就可以实现相应的dll正确的加载。这是一个取巧的方法不是很实用,需要来回切换程序集目录,但是在某些情况下非常好用。
2.3、如何处理[dllImport]中的程序集的加载
针对dllImport也分为几种情况。
自己写
dllImport
引用的C#的插件又使用了
dllImport
2.3.1、自己写的dllImport
如果是自己写的就非常好控制了,可以直接指定相对的目录DllImport(3rdLibs\NLog.dll)
。不过这种方法不一定可靠,在某些系统加载不了,如果使用了dllImport还是,推荐下面的介绍的方法(引用的C#的插件又使用了dllImport
)。
2.3.2、引用的C#的插件又使用了dllImport
因为无法更改路径,那么只能够使用上述特殊的方法,更改当前程序的路径
当然,还有更省事一点的做法,就是在系统环境中,增加一条记录,指向要加载的dll的所在目录。因为C++的代码中,Windows目录和Windows\System32目录以及环境变量设定的目录都是搜索路径之一。
这里提供怎么从C#中修改系统环境变量的代码:
static void AddEnvironmentPaths(IEnumerable<string> paths)
{
var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty };
string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths));
Environment.SetEnvironmentVariable("PATH", newPath);
}
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值。
3、运行效果
4、参考文章
4.1、文章相关
4.2、框架相关
最好用的.NET敏捷开发框架-RDIFramework.NET V3.6版全新发布 100%源码授权
RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系列目录
RDIFramework.NET敏捷开发框架 ━ 工作流程组件介绍
RDIFramework.NET框架SOA解决方案(集Windows服务、WinForm形式与IIS形式发布)-分布式应用
RDIFramework.NET敏捷开发框架 ━ 工作流程组件Web业务平台
RDIFramework.NET敏捷开发框架通过SignalR技术整合即时通讯(IM)
RDIFramework.NET框架基于Quartz.Net实现任务调度详解及效果展示
一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,大家可以通过下面的地址了解详情。
RDIFramework.NET官方网站:http://www.rdiframework.net/
RDIFramework.NET官方博客:http://blog.rdiframework.net/
同时需要说明的,以后的所有技术文章以官方网站为准,欢迎大家收藏!
RDIFramework.NET框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用!
欢迎关注RDIFramework.net框架官方公众微信(微信号:guosisoft),及时了解最新动态。
扫描二维码立即关注
相关推荐
### ASP.NET - Module 4: Separating Code from Content #### 概述 在ASP.NET开发过程中,将代码与内容分离是一种常见的做法,它能够提高...这不仅可以使代码更加整洁、易于维护,还可以显著提升开发效率和程序性能。
总的来说,MySQL.Data.dll是.NET开发者与MySQL数据库进行交互的关键组件,尤其在MVC架构下,它能帮助你高效地实现数据库操作,同时保持代码的整洁和模块化。正确地引入和使用这个库,可以极大地提升开发效率和项目的...
**NHibernateMappingGenerator.vshost.exe** 和 **NHibernateMappingGenerator.vshost.exe.manifest** 分别是Visual Studio的调试主机程序和应用程序清单文件,它们在开发过程中提供了一些额外的调试支持和服务信息...
Prism.Maui 是一个强大的框架,它将 Prism 框架与 .NET MAUI(Multi-platform App UI)相结合,用于构建高效、可维护且模块化的跨平台移动和桌面应用程序。Prism 是一个针对 Windows Presentation Foundation (WPF)...
- **Data Access Objects (DAO)**:DAO层封装了对数据的访问,提供了一种统一的接口来操作数据,隐藏了持久层的具体实现,使得应用程序更易于切换不同的数据存储机制。 3. **准备工作** - **下载软件包**:访问...
.NET开发者可以利用SSDT生成的dll(数据库项目的编译结果)与应用程序交互,通过ADO.NET或ORM实现数据访问层。 5. **持续集成/持续部署(CI/CD)**: SSDT项目可轻松集成到CI/CD流程,例如Azure DevOps或Jenkins,...
8. **更友好的许可证模式**:PostSharp 2.0提供了更为灵活的许可证选项,适应不同规模的项目和团队需求。 **使用PostSharp 2.0** 在实际开发中,PostSharp可以通过以下步骤使用: 1. **安装**:下载并安装...
在描述中提到,这个版本的 IBatis.net DLL 文件适合 C# 项目集成,意味着它可以方便地与基于 C# 的应用程序配合使用,简化数据库访问的实现。 IBatis 在.NET 环境中的核心功能包括: 1. **映射器接口**: IBatis ...
5. **代码分离与MVP模式**:dotnetmagic可能支持Model-View-Presenter(MVP)设计模式,将界面显示、用户交互和业务逻辑分开,使代码更易维护和测试。 6. **API文档和示例**:类库通常会提供详细的API文档,解释每...
Ibatis.Net 是其针对 .NET 平台的移植版本,它简化了数据访问层(DAL)的编写,将 SQL 语句和业务逻辑分离,提高了代码的可维护性和可扩展性。 **一、Ibatis 的核心组成** Ibatis 主要由两个关键组件构成: 1. **...
5. **Binaries**: 存放编译后的二进制文件,如DLL和EXE。 6. **EasySL.Core.SL**: 核心库项目,可能包含EASYSL的公共类和功能。 7. **.svn**: 版本控制系统Subversion的文件,表明项目在版本控制下。 8. **EasySL...
在本文中,我们将深入探讨如何使用C#编程语言来实现一个手机号码归属地查询系统,这个系统基于描述中的"经典改编",集成了多种网络上的优秀代码,可以在WinForm界面中提供本地和在线两种查询方式。我们将分析这个...
NKalore Compiler是一个...通过NKalore.dll和mcs.exe这两个文件,我们可以推测项目是如何实现编译过程并集成到现有的开发流程中的。对于想要探索AOP在C#中应用的开发者,NKalore Compiler是一个值得研究和尝试的工具。