开通VIP,畅享免费电子书等14项超值服
首页
好书
留言交流
下载APP
联系客服
2012.05.02
程序集
应用程序集和应用程序域
-----------------------|----------------------------进程一进程二____________|____________应用程序域A应用程序域B|......____________|____________-----------------------------------------------------进程之间有边界,应用程序域存在于某个进程中,之间也有边界,处在不同应用程序域中的应用程序不能互相访问应用程序域可以互相包含
////FLAG////AppDomain.secondDomain=AppDomain.CreateDomain("NewAppDomain");//创建一个新的应用程序域NewAppDomain
secondDomain.ExecuteAssembly("AssemblyA.exe");//把程序集AssemblyA加载到新域中,通过调用ExecuteAssembly来调用Main()方法}}}
在启动DomainTest.exe前,必须把程序集AssemblyA.exe复制到DomainTest.exe所在的目录下,这样程序才能找到这个程序集,不能添加AssemblyA.exe程序集的引用,因为在VS.NET中,只能给以DLL格式存储的程序集添加引用,不支持EXE格式,但是EXE格式的程序集可以在命令行上执行,如果找不到这个程序集就会抛出System.IO.FileNotFoundExection异常结果:MainindomainNewAppDomaincalled
在上面第二个程序表明的FLAG处可以改为:再创建一个实例,用于替代Main()方法/////////////////////////////////////////////////////////////////////////////////////////AppDomainsecondDomain=AppDomain.CreateDomain("NewAppDomain");
secondDomain.CreateInstance("AssemblyA","Wrox.ProCShap.Assemblies.AppDomains.Class1",true,System.Reflection.BindingFlags.CreateInstance,null,newobject[]{7,3}null,null,null);///////////////////////////////////////////////////////////////////////////////////////////1-程序集名;2-应实例化的类;3-true表示不区分大小写;4-邦定标志枚举值,指定应调用的构造函数;得到的输出为:Constructorwiththevalues7,3indomainNewAppDomaincalled
在运行期间主应用程序域会自动创建,ASP.NET为每个运行在WEB服务器上的Web应用程序创建一个应用程序域,InternetExplorer创建运行托管控件的应用程序域,卸载应用程序域只能通过中断应用程序域来进行
----------------------------------------------------------------------2程序集的结构----------------------------------------------------------------------程序集由=描述它的元数据(程序集元数据)+描述导出类型和方法的类型元数据+MSIL代码+资源存在于一个文件中或分布在多个文件中例如:1程序集由一个文件组成:Component.dll2Component.dll=描述它的元数据+描述导出类型和方法的类型元数据+MSIL代码,资源不在其中这个程序集使用了一个图:Pictrue.jpeg,该图没有嵌入在dll中,而是在程序集的元数据中引用程序集的原数据还引用了一个模块:Util.netmodule,该模块只包含一个类的类型元数据和MSIL代码不包含程序集的元数据,所以这个模块没有版本信息,也不能单独安装这3个文件构成了程序集,这个程序集是一个安装单元,还可以在另外一个文件中放置程序集清单Component.dllUtil.netmodule____________________________________Picture.jpeg<-------程序集元数据-------〉类型元数据__________-------〉IL代码资源类型元数据IL代码
程序集的清单元数据的一部分,描述了程序集和引用它所需的所有信息,并列出,了所有的依赖关系清单=标识(名称,版本,文化,公钥)+属于该程序集的一个文件列表+引用程序集的列表+一组许可请求--运行的许可证+导出的类型(当它们在一个模块中定义,该模块在程序集中引用,否则不属于清单)
---------------------------------------------======================命名空间,程序集和组件1命名空间完全独立于程序集2一个程序集中可以有不同的命名空间3一个命名空间也可以分布在多个程序集中4命名空间只是类名的一种扩展,它属于类名的范畴======================---------------------------------------------
======================私有程序集和共享程序集在使用共享程序集时,程序集必须是唯一的,名称唯一(强名),该名称的一部分是一个强制的版本号,如第三方控件============================================查看程序集命令行工具:ILDASM或FILE-->OPEN-->打开程序集============================================构建程序集1-可以创建模块:csc/target:modulehello.cs模块是一个没有程序集特性的DLL,可以添加到程序集中创建了hello.netmodule2-生成一个程序集B.DLL,它包含模块A.netmodule:csc/target:library/addmodule:A.netmodule/out:B.dll3-模块的作用1是可以更快的启动程序集,因为并不是所有类都在一个文件中模块只在需要时加载2是是否需要使用多种编程语言来创建一个程序集:一个模块用VB.net,一个模块用C#,这两个模块都包含在一个程序集中4-使用VS创建程序集VS2003不支持直接创建模块创建一个项目时,系统自动生成源文件AssemblyInfo.cs,在该文件中可以使用一般的源代码编辑器配置程序集的属性[assembly]和[module]是程序集的全局属性
System.Runtime.CompilerServices命名空间中的类:AssemblyCulture--程序集的文化背景,如en-USAssemblyDelaySign/AssemblyKeyFile/AssemblyKeyName--用于创建共享程序集的强名AssemblyVersion--指定程序集的版本号,版本问题在共享程序集中具有非常重要的地位======================
======================跨语言支持.NET使用通用类型系统CommonTypeSystem-CTS-定义了如何在.net中定义值类型和引用类型,以及这些类型的内存布局但CTS没有确保在任何语言中定义的类型都可以用于其它语言。这应是公共语言规范CommonLanguageSpecification-CLS的任务。CLS定义了.net语言必须支持的最低要求======================
CTS=commontypesystem=通用类型系统CLS=commonlanguagespecification=公共语言规范======================例如:**********************************************************************************VisualC++编写的基类HelloMCPP/继承于HelloMCPP的类HelloVB/继承于HelloVB的类HelloCSharpHelloMCPPHelloVBHelloCSharp+Hello()+Hello()+Hello()+Hello2()+Add()+Add()+Add()+Main()**********************************************************************************--使用VS2003创建一个VC的类-classlibrary(.net)1>HelloMCPP//HelloMCPP.h#pragmaonce#include
intAdd(intval1,intval2){returnval1+val2;}};}}}}**********************************************************************************--使用VS2003创建一个VB.net的类-classlibrary--打开项目属性,在RootNamespace中将项目的根命名空间改为Wrox.ProCSharp.Assemblies.CrossLanguage,这样就改变了类的命名空间--添加对HellpMCPP的引用:Project-->AddReference给项目添加引用就是将引用的程序集复制到VB.net项目的输出目录上(/bin),然后对原引用程序集的改变就是独立的2>HelloVBpublicclassHelloVBInheritsHelloMCPP
publicOverridesSubHello()MyBase.Hello()'MyBase关键字代表基类,此处调用基类的方法Console.WriteLine("Hello,VB.NET")EndSub
publicShadowsFunctionAdd(ByValval1asinteger,_ByValval2asinteger)asinteger'Shadows关键字用来隐藏基类的方法Add(),因为在基类中Add()不是虚拟(virtual)的'不能被重写returnval1+val2EndFunctionEndclass**********************************************************************************--创建一个C#控制台应用程序,添加对HelloVB和HelloMCPP的引用3>HelloCSharpusingSystem;namespaceWrox.ProCSharp.Assemblies.CrossLanguage{publicclassHelloCSharp:HelloVB{publicHelloCSharp(){}
publicoverridevoidHello(){base.Hello();Console.WriteLine("Hello,C#");}
publicnewintAdd(intval1,intval2){returnval1+val2;}
[STAThread]
**********************************************************************************全局程序集缓存查看器全局程序缓存可以使用shfusion.dll来显示,它是一个Windows外壳扩展程序,可以查看和处理缓存的内容Windows外壳扩展程序是一个与Windows资源管理器集成的COMDLL用户启动资源管理器,进入
**********************************************************************************公钥的加密对称加密:使用同一个密钥进行加密和解密公钥/私钥加密:使用一个公钥加密,使用对应的私钥解密/使用一个私钥加密,使用对应的公钥解密成对创建公钥和私钥,公钥可以任何人使用,甚至可以放在web站点上,但私钥必须安全的加锁Sarah-->oneemail-->Julian,除了Julian外的人都不能看使用Julian的公钥加密,Julian打开该email,并使用他秘密存储的私钥解密但还有一个问题,Julian不能确保email是Sarah发来的,任何人都可以使用Julian的公钥加密发送email给他解决办法是党Sarah发送email给Julian时,使用Julian的公钥加密邮件之前他添加了自己的签名,再使用自己的私钥加密该签名,然后使用Julian的公钥加密email,这个签名可以使用Sarah的公钥来解密,而Julian可以访问Sarah的公钥,在解密了签名后,Julian就可以确定是Sarah发送了email
**********************************************************************************将公钥/私钥应用于程序集创建共享组件,必须使用公钥/私钥对编译器把公钥写入程序集清单,创建属于该程序集的所有文件的散列表--用私钥标记这个散列表私钥不存储在程序集中,确保没有人可以修改这个程序集,签名可以使用公钥来验证在开发过程中,客户程序集必须引用共享程序集。编译器把引用程序集的公钥写入客户程序集的清单中要减少存储量,就不应把公钥写入客户程序集的清单,而应写入公钥标记,公钥标记是公钥散列表中的最后8位字节,且是唯一的在运行期间加载共享程序集时(如果客户程序集是使用本机图像生成器安装的,则应在安装期间加载),共享程序集的散列表可以使用存储在客户程序集中的公钥来验证,除了私钥的主人外其他人都不能修改共享程序集例如:销售商A创建了一个组件Math,在客户机上引用该组件,黑客的组件就无法替代它,只有私钥的主人才能用新版本来替换原来的共享组件,保证了其完整性
**************************b>安装共享程序集**************************使用全局程序集缓存工具gacutil及其/I选项把它安装到全局程序集缓存中:gacutil/iSharedDemo.dll可以使用全局程序集缓存查看器检查共享程序集的版本,看看它是否安装成功
程序集(assembly)是包含编译好的、面向.NETFramework的代码的逻辑单元。程序集是完全自我描述性的,也是一个逻辑单元而不是物理单元,它可以存储在多个文件中(动态程序集的确存储在内存中,而不是存储在文件中)。如果一个程序集存储在多个文件中,其中就会有一个包含入口点的主文件,该文件描述了程序集中的其他文件。
注意可执行代码和库代码使用相同的程序集结构。惟一的区别是可执行的程序集包含一个主程序入口点,而库程序集则不包含。
程序集的一个重要特性是它们包含的元数据描述了对应代码中定义的类型和方法。程序集也包含描述程序集本身的元数据,这种程序集元数据包含在一个称为程序集清单的区域中,可以检查程序集的版本及其完整性。
注意:
ildasm是一个基于Windows的实用程序,可以用于检查程序集的内容,包括程序集清单和元数据。第15章将介绍ildasm。
程序集包含程序的元数据,表示调用给定程序集中的代码的应用程序或其他程序集不需要指定注册表或其他数据源,以便确定如何使用该程序集。这与以前的COM有很大的不同,以前,组件的GUID和接口必须从注册表中获取,在某些情况下,方法和属性的详细信息也需要从类型库中读取。
把数据分散在3个以上的不同位置上,可能会出现信息不同步的情况,从而妨碍其他软件成功地使用该组件。有了程序集后,就不会发生这种情况,因为所有的元数据都与程序的可执行指令存储在一起。注意,即使程序集存储在几个文件中,数据也不会出现不同步的问题。这是因为包含程序集入口的文件也存储了其他文件的细节、散列和内容,如果一个文件被替换,或者被塞满,系统肯定会检测出来,并拒绝加载程序集。
程序集有两种类型:共享程序集和私有程序集。
私有程序集是最简单的一种程序集类型。私有程序集一般附带在某些软件上,且只能用于该软件中。附带私有程序集的常见情况是,以可执行文件或许多库的方式提供应用程序,这些库包含的代码只能用于该应用程序。
系统可以保证私有程序集不被其他软件使用,因为应用程序只能加载位于主执行文件所在文件夹或其子文件夹中的程序集。
用户一般会希望把商用软件安装在它自己的目录下,这样软件包没有覆盖、修改或加载另一个软件包的私有程序集的风险。私有程序集只能用于自己的软件包,这样,用户对什么软件使用它们就有了更多的控制。因此,不需要采取安全措施,因为这没有其他商用软件用某个新版本的程序集覆盖原来的私有程序集的风险(但软件是专门执行怀有恶意的损害性操作的情况除外)。名称也不会有冲突。如果私有程序集中的类正巧与另一个人的私有程序集中的类同名,是不会有问题的,因为给定的应用程序只能使用私有程序集的名称。
因为私有程序集完全是自含式的,所以安装它的过程就很简单。只需把相应的文件放在文件系统的对应文件夹中即可(不需要注册表项),这个过程称为“0影响(xcopy)安装”。
共享程序集是其他应用程序可以使用的公共库。因为其他软件可以访问共享程序集,所以需要采取一定的保护措施来防止以下风险:
●名称冲突,另一个公司的共享程序集执行的类型与自己的共享程序集中的类型同名。因为客户机代码理论上可以同时访问这些程序集,所以这是一个严重的问题。
●程序集被同一个程序集的不同版本覆盖——新版本与某些已有的客户机代码不兼容。
这些问题的解决方法是把共享程序集放在文件系统的一个特定的子目录树中,称为全局程序集高速缓存(GAC)。与私有程序集不同,不能简单地把共享程序集复制到对应的文件夹中,而需要专门安装到高速缓存中,这个过程可以用许多.NET工具来完成,其中包含对程序集的检查、在程序集高速缓存中设置一个小的文件夹层次结构,以确保程序集的完整性。
为了避免名称冲突,共享程序集应根据私有密钥加密法指定一个名称(私有程序集只需要指定与其主文件名相同的名称即可)。该名称称为强名(strongname),并保证其惟一性,它必须由要引用共享程序集的应用程序来引用。
因为程序集存储了元数据,包括在程序集中定义的所有类型和这些类型的成员的细节,所以可以编程访问这些元数据。这个技术称为反射,第11章详细介绍了它们。该技术很有趣,因为它表示托管代码实际上可以检查其他托管代码,甚至检查它自己,以确定该代码的信息。它们常常用于获取特性的详细信息,也可以把反射用于其他目的,例如作为实例化类或调用方法的一种间接方式,如果把方法上的类名指定为字符串,就可以选择类来实例化方法,以便在运行时调用,而不是在编译时调用,例如根据用户的输入来调用(动态绑定)。