1、引言

在一个项目开发中一般都是把引用的dll放在根目录下,随着项目的日益增大,根目录下的dll文件就会越来越多,合理规划这些dll的存放地址,可以使整个项目更加的规范与美观。这篇文章就为大家介绍关于C#如何在指定文件夹寻找文件dll的相关内容,文中通过基于RDIFramework框架WinForm版为基础进行介绍,Web的相关dll规划类似,希望对大家具有一定的参考学习价值。

我们框架原执行目录下的dll存放如下,可以看到整个目录下的文件非常多。

下面我们通过最常用的方式对dll文件进行规划处理,使整个运行目录更加的干净,规范,最终效果如下图所示。

可以看到,上图的整个运行目录结构非常的清爽与整洁了。如何实现的呢?下面我们就具体讲解。

2、实现方法

2.1、系统搜索dll的目录以及顺序

CLR解析一个程序集会在一个根目录内进行搜索,整个探索过程又称Probing,这个根目录很显然就是当前包含当前程序集的目录。

AppDomainSetup这个类存储着探索目录的信息,其成员包括:ApplicationBase、PrivateBinPath。

程序搜索dll的顺序如下(区分强名称签名的和没有强名称签名的程序集):

没有做强名称签名的程序集:

  1. 程序的根目录
  2. 根目录下面,与被引用程序集同名的子目录
  3. 根目录下面被明确定义为私有目录的子目录
  4. 在目录中查找的时候,如果dll查找不到,则会尝试查找同名的exe
  5. 如果程序集带有区域性,而不是语言中立的,则还会尝试查找以语言区域命名的子目录

具有强名称签名的程序集:

  1. 全局程序集缓存

  2. 如果有定义codebase,则以codebase定义为准,如果codebase指定的路径找不到,则直接报告错误

  3. 程序的根目录

  4. 根目录下面,与被引用程序集同名的子目录

  5. 根目录下面被明确定义为私有目录的子目录

  6. 在目录中查找的时候,如果dll查找不到,则会尝试查找同名的exe

  7. 如果程序集带有区域性,而不是语言中立的,则还会尝试查找以语言区域命名的子目录。如下图所示:

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.LoadAssembly.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形式发布)-分布式应用

微信公众号开发系列-玩转微信开发-目录汇总

史上最全面的SignalR系列教程-目录汇总

RDIFramework.NET敏捷开发框架 ━ 工作流程组件Web业务平台

RDIFramework.NET敏捷开发框架通过SignalR技术整合即时通讯(IM)

RDIFramework.NET框架基于Quartz.Net实现任务调度详解及效果展示

RDIFramework框架整合微信开发应用效果展示


一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,大家可以通过下面的地址了解详情。

RDIFramework.NET官方网站:http://www.rdiframework.net/

RDIFramework.NET官方博客:http://blog.rdiframework.net/

同时需要说明的,以后的所有技术文章以官方网站为准,欢迎大家收藏!

RDIFramework.NET框架由海南国思软件科技有限公司专业团队长期打造、一直在更新、一直在升级,请放心使用!

欢迎关注RDIFramework.net框架官方公众微信(微信号:guosisoft),及时了解最新动态。

扫描二维码立即关注

.NET分离exe和dll在不同的目录让你的程序更整洁的更多相关文章

  1. C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁

    系列文章 C#开发奇技淫巧一:调试windows系统服务 C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件 C#开发奇技淫巧三:把dll放在不同的目录让你的程序更整洁 程序目录的整理 ...

  2. 【重构】C# VS 配置引用程序集的路径(分离exe和dll从指定路径调用)

    原文:[重构]C# VS 配置引用程序集的路径(分离exe和dll从指定路径调用) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/CocoWu892 ...

  3. 设置程序PrivatePath,配置引用程序集的路径(分离exe和dll)

    原文:设置程序PrivatePath,配置引用程序集的路径(分离exe和dll) 有时候我们想让程序的exe文件和dll文件分开在不同目录,这时候可以有3种方法 1.在app.config中配置 &l ...

  4. .NET配置引用程序集的路径(分离exe和dll)

    按照引用程序集路径的不同,程序集DLL分为两类: 1)全局DLL(在GAC中注册,GAC——全局程序集缓存),有关GAC的详细资料可以参考一下链接: http://dddspace.com/2011/ ...

  5. 有关windows系统的EXE和DLL文件说法错误

    正确答案: B C   你的答案: C (错误) EXE和DLL文件都是PE文件 EXE不能有导出函数,DLL可以有导出函数 EXE有x86和x64之分,则DLL没有 EXE可以单独运行,DLL则不行 ...

  6. 如何判断exe或dll的目标平台及是否是.NET?

    1. COFF文件头中偏移0处的Machine指示目标机器类型(IMAGE_FILE_MACHINE_AMD64等),偏移18处的Characteristics位指示文件属性(IMAGE_FILE_3 ...

  7. [under the hood]Reduce EXE and DLL Size with LIBCTINY.LIB

    Matt Pietrek Download the code for this article: Hood0101.exe (45KB) W ay back in my October 1996 co ...

  8. 如何用VS调试不属于解决方案的EXE和DLL程序

    如果你手里有一个现成的EXE, 以及EXE相关联PDB文件, 还有相关联的CPP文件和H文件. 你如何用VS调试? (当然你可以选择WinDbg.不过这里就讨论VS) 你或许想问我干嘛不从一开始就用V ...

  9. PE头的应用---插入代码到EXE或DLL文件中

    三.代码实现(DELPHI版本),采用第三种方式实现代码插入. 1. 定义两个类,一个用来实现在内存中建立输入表:一个用来实现对PE头的代码插入. DelphiCode: const MAX_SECT ...

随机推荐

  1. J - Recommendations CodeForces - 1315D

    https://blog.csdn.net/w_udixixi/article/details/104479288 大意:n个数,每个数只能向上加,a[i]+1需要的时间是t[i],求使这n个数无重复 ...

  2. 4. git log的常见用法

    git log ======见https://blog.csdn.net/daguanjia11/article/details/73823617 +++++++++++++++++++++++ 使用 ...

  3. NCTF2019 小部分题解

    前言 礼拜五领航杯打的比较累,做不出WEB,D3CTF没用,做了NJCTF的一些题目(懒,睡觉到12点起) Misc 第一次比赛先去做misc,以前一直做WEB,以后要WEB+MISC做.礼拜六下午做 ...

  4. vue路由中 Navigating to current location ("/router") is not allowed

    报错原因:多次点击同一路由,导致路由被多次添加 解决方法: router/index中添加以下代码: //router/index.js Vue.use(VueRouter) //导入vue路由 co ...

  5. MySQL之唯一索引、外键的变种、SQL语句数据行操作补充

    0.唯一索引 unique对num进行唯一限制,表示num是独一无二的,uql是唯一索引名称 上面为联合索引:num和xx不能完全一样  1.外键的变种 a. 用户表和部门表 用户: 1 alex 1 ...

  6. Java锁之自旋锁

    Java锁之自旋锁 自旋锁:spinlock,是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU 原来提到的比较并交换,底层 ...

  7. ES6中对数值的扩展

    上一节和大家学习了字符串的扩展,这一节轮到了数值,我们一起来学习数值的扩展. 剧透一下,这一节并不会很烧脑,都是介绍类的知识讲解,理解性的东西不多,初学者们也可以愉快地看完. 传统的写法 在介绍数值的 ...

  8. Centos史上新版最详细步骤-Linux无脑命令式oracle11g静默安装

    1. 关闭selinux 1.1 sed -i "s/SELINUX=enforcing/SELINUX=disabled/" /etc/selinux/config 1.2 或者 ...

  9. 20199326《Linux内核原理与分析》第十二周作业

    Collabtive系统跨站请求伪造攻击实验 实验背景 CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/sessi ...

  10. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...