Building,Packaging,Deploying,and Administering Applications and Types

在我们进入章节之前,我们讨论一下生成、打包和部署你的应用程序和应用程序类型必须的步骤。在这章里,我将关注如何为你的应用程序的用途生成程序集。在第三章,“共享程序集合和强命名程序集”,我将会涉及你需要了解的高级概念,包括如何生成和使用包含类型的程序集,这些程序集将被多个应用程序共享。在这两章中,我也会讨论管理员可以影响执行应用程序和它的类型的方式。

如今,应用程序由几个类型组成,通常由你和微软创建。此外,有很多组件供应商创建和出售类型,其它公司可以用来减少软件项目开发时间。假如这些类型是用任何以CLR为目标的语言开发的,它们可以全部一起无缝的工作;一种语言写的一个类型可以使用另一个类型做为它基类并且不关心基础类型是用什么语言开发的。

在这一章中,我将解释这些类型为了部署怎么生成和打包到文件。在这个过程中,我将带你回顾一些.NET Framework解决的问题。

.NET Framework Depoyment Goals(.NET Framework部署目标)

多年以来,Windows得到了一个不稳定和繁复的名声。这个名声是否名副其实要看很多不同的因素。首先,所有的应用程序使用微软或其他供应商的动态链接库(DLLs)。因为一个应用程序从各种各样的供应商执行代码,开发者的任何一段代码都不能100%的确定别人是怎么使用它的。即使这种类型的交互存在各种各样潜在的麻烦,事实上,这些问题一般不会出现因为应用程序在部署前都会进行测试和调试。

无论如何,当一家公司决定更新它的代码和装载新的文件时用户运行经常会遇到问题。这些新文件被假设能向后兼容之前的文件,但是谁可以确定?事实上,当一家供运商更新它的代码时,它一般发现它不可能重新测试和调试所有已装载的应用程序以确保有不希望的影响。

我相信每个读这本书的人都经历过这个问题的变异:当安装一个新的应用程序,你发现它以某种方式破坏了一个已经安装好的应用程序。这种困境是众所周知的“DLL地狱”。这种类型的不稳定在一般的电脑使用者心里和大脑中都留下了恐惧的烙印。结果是用户不得不小心考虑是否在他们的机器上安装一个新的软件。就我自己来说,我决定不尝试安装应用程序走出恐惧,它可能会对我依赖的应用程序产生不利的影响。

第二个原因,给前面提及的Windows名声做出贡献的是安装的复杂性。如今,当安装了大多数应用程序,它们影响系统所有的部分。例如,安装一个应用程序引起文件被拷贝到不同目录,更新注册表,在你的桌面和开始菜单/桌面安装快捷方式。这带来的问题是应用程序没有分离为一个单独的实体。你不能容易的备份应用程序因为你必须拷贝应用程序的文件和注册的相关部分。此外,你不能容易的从一个机器移动应用程序到另一个机器。你必须在运行一次安装程序,所有文件和注册表才能设置正确。最终,你不能容易的卸载或者移除应用程序而没有这种讨厌的感觉,应用程序的一些部分还潜伏在你的机器上。

第三个原因和安全有关。当应用程序安装好了,伴随着它们的是各种各样的文件,其中很多是通过不同的公司写的。此外,网页应用程序经常有代码(就像ActiveX控件)这样下载,用户甚至没有察觉代码已经安装在他们的机器上了。如今,这份代码可以执行任何操作,包括删除文件或发邮件。用户害怕安装新的应用程序是正确的,因为它们会引起潜在的损害。为使用户舒服,系统中必须建立安全,用户可以明确地允许或者不允许不同的公司开发的代码访问他们的系统资源。

.NET Framework把DLL地狱问题放在重要位置,就像你将在这章和第三章里看到的。.NET Framework在修复一个应用程序的状态散布在用户硬盘的各个角落问题走了很远。例如,不像COM,类型不需要在在注册表中设置。不幸的是,应用程序依然需要快捷方式链接。至于安全,.NET Framework包含一个叫做代码访问安全(code access security)的安全模型。鉴于Windows安全是以用户身份为基础的,代码访问安全允许机主设置权限,从而控制下载的组件可以做什么。一个主机应用程序像Microsoft SQL Server只给代码少量授权,然而一个本地安装(自我寄宿)的应用程序运行时拥有所有权限。正如你将看到的,.NET Framework使用户可以控制安装什么和运行什么,总之,对于控制他们的机器,Windows从未这么做过。

Building Types into a Module(类型生成一个模块)

在这个场景,我将给你看怎么把你源文件(包含不同的类型)转换成一个可以部署的文件。让我们从仔细查看下面的简单应用程序开始。

public sealed class Program
    {
        public static void Main(string[] args)
        {
            System.Console.WriteLine("Hi");
        }
    }

这个应用程序定义了一个类型,叫做Program。这个类型有一个单独的公共的、静态的叫做Main的方法。在Main中应用了一个由微软实现的叫做System.Console.System.Console的类型,并且在MSCorLib.dll文件中实现了这个类型的方法的中间语言(IL)代码。所以我们的应用程序定义了一个类型同时也使用了另一个公司的类型。

生成这个简单的应用程序,把之前的代码放到一个源代码文件中,叫做,Program.cs,然后执行以下命令行:

csc.exe /out: Program.exe /t:exe /r:MSCorLib.dll Program.cs

这个命令行告诉C#编译器发布一个叫做Program.exe(/out: Program.exe)的可执行文件。这个类型文件产生一个Win32控制台应用程序(/t[arget]:exe)。

当C#编译器处理源文件,它看到代码引用System.Console类型的WriteLine方法。这时候,编译器要确定这个类型在哪里存在,它有一个WriteLine方法,并且参数被传递给这个方法,且匹配方法期望的参数。因为这个类型不是在C#中定义的,为了使C#编译器开心,你必须给它一个程序集使它能够解决外部类型引用。在之前提到的命令行,我已经包括了/r[eference]:MSCoreLib.dll开关,它告诉编译器通过MSCorLib.dll文件定义的程序集查找外部类型。

MSCorLib.dll是一个特殊的文件,它包含所有的核心类型:Byte,Char,String,Int32和其他。事实上,这些类型是如此频繁的被使用C#编译器自动引用MSCorLib.dll程序集。换句话说,下面的命令行(省略/r 开关)和上面的命令行结果是一样。

csc.exe /out: Program.exe /t:exe Program.cs

此外,因为/out: Program.exe和/t:exe命令行开关也匹配C#编译器的默认选择,下面的命令行也会给出相同的结果。

csc.exe Program.cs

假如,为了一些原因,你真的不想要C#编译器引用MSCorLib.dll程序集,你可以使用/nostdlib开关。当建立MSCorLib.dll程序集时微软使用这个开关。例如,当CSC.exe尝试编译Program.cs文件时以下的命令行将会产生一个错误因为System.Console类型定义在MSCorLib.dll中。

csc.exe /out: Program.exe /t:exe /nostdlib Program.cs

现在,让我们近一点看C#编译器生成的Program.exe文件。这个文件实际上是什么?好吧,首先,它是一个标准的可移植执行体(portable executable,PE)文件。这意味着一个运行32位或者64位版本Windows的机器可以加载这个文件并用它做点什么。Windows支持三种类型的应用程序。建立一个控制台用户界面(console user interface,CUI)应用程序,指定/t:exe开关;建立一个图形用户界面(graphical user interface,GUI)应用程序,指定/t:winexe开关;建立一个Windows商店App,指定/t:appcontainerexe开关。

Response Files(响应文档)

在搁置关于编译的开关的讨论前,我要花一点时间谈谈响应文档。一个响应文件是一个包含一个编译器命令行开关集合的文本文件。当你执行CSC.exe,编译器打开响应文档并使用详细定义的开关就像命令行传递给CSC.exe的一样。你命令编译器通过在命令行前加@符号指定响应文件的名字使用指定的响应文件。例如,你有一个叫做MyProject.rsp的响应文件包含以下文本。

/out:MyProject.exe

/target:winexe

为了CSC.exe使用这些设置,你可以使用以下内容调用。

csc.exe @MyProjext.rsp CodeFile1.cs  CodeFile2.cs

这告诉C#编译器输出文件时什么名字和要创建什么目标类型。就你看见的,响应文档很方便因为你不需要每次编译你的项目时手动给命令行参数表达你的意愿。

C#编译器支持多个响应文档。除了文档外你显式指定在命令行的,编译器自动在CSC.rsp文档中查找。当你运行CSC.exe,它查找包含CSC.exe文件的目录以得到全面的CSC.rsp文件。你需要应用到你的项目的设置应该都放在这个文件中了。编译器集合和使用在这些响应文档中的设置。假如你在本地和全面响应文档中有冲突设置,本地的设置重载在全面响应文件中的设置。同样的,任何在命令行显式传递的设置从本地响应文件重载设置。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。