.Net下的开源持续集成

谈到持续集成,不如先谈谈集成。软件开发中的集成,通俗地讲就是把各个相关部分的东西组合起来,形成一个可用的软件。比如一个软件项目由几个小组来负责完成,每个小组负责其中一部分功能的实现,比较典型的是在现在的网络游戏开发中,通常有负责引擎的小组,负责游戏逻辑的小组,负责美工的小组,这些小组开发出的东西必须结合在一起才能形成一个可用的游戏;而每个小组内部的每个成员,他们每天在写着不同部分的代码,这些开发人员必须将各自的成果组合起来,才能完成他们共同的目标。从这个意义上讲,从每天每个开发者的日常开发,到各个软件模块的组合拼接,软件集成无所不在,一个完整可用的软件,就是通过不断地集成每个开发人员的代码而形成的。

每个开发过软件的人都能体会到,软件开发绝非一帆风顺,每个人开发出来的代码绝对不会魔术般的自己组合在一起,当新的功能加入到原有软件中的时候,往往不小心破坏了原有的功能,引入了一些bug,当老的bug被修复的时候,又往往会导致其他bug的产生,更糟糕的是,这些bug往往在当时并不能及时被发现。当小组成员们完成了自己所负责的模块,等到最后来一起集成的时候,他们可能已经做好了修复集成问题的心理准备。所有的这一切,都是每个开发人员的切肤之痛。那么,问题到底出在哪了?

让我们不妨换一种思维,让我们不要停留在如何地去修复bug和集成过程中产生的问题,我们渴望的理想状况是,每当我们开发出新的代码并将他们加入原系统中的时候,如果我们能够被及时告知我们是否破坏了原有系统的功能,那么我就能够及时的作出反应,修复这些部分。如果这个过程的粒度足够的细、足够地频繁,我们就能期望每次新功能引入的时候所引起的破坏足够小,并且修复起来足够简单,如果每个开发人员都能够享受到如此的方便并且保证新加入的功能不会影响原有的功能,我们的整个软件过程就能够以一个稳步可靠的步伐,持续增量的向前行进,而不是不断地加入新的代码,然后等到后来bug被人发现的时候被动地去修复它。我想稳步可靠、持续增量的软件过程,是我们每个开发者心目中的理想过程。从开发者的角度来看,毕竟谁也不想经历那种当发现自己的修改破坏的原有的功能的时候的恼火的感受。

持续集成通俗地说就是持续地、频繁地进行集成,每当有新的修改加入的时候,修改的作者能够被及时地告知他的修改是否在引入新的功能的同时保证原有功能的完整。如果整个软件开发团队在一开始就采用这种方式,我们的软件就能被稳步可靠的构建起来。

你也许会有疑问:“你说的只是一种理想状况罢了,谁都希望自己在加入新的代码的时候得知自己的代码是否破坏了原有的功能,但是怎么能够做到这一点,谁有能力来及时地告诉我们哪里有问题?持续集成这个想法不错,但怎么样能够做到持续集成?”我想这些问题是非常好也是关键的问题,持续集成究竟是否可行,如果可行,又该如何执行?我们这里不妨来整理一下,看看究竟什么是持续集成的难点。持续集成的难点主要在于,在新的功能加入的时候,如何来判断整个系统功能仍然完整;出错或者成功,谁来告诉我,如何告诉我;当大家一起协作的时候,如何保证每个人都能够准确地被告知而不会发生混乱。让我们来一个个地分析这些问题。

首先,确保真个系统功能完整性的手段就是测试,如果我们对所有的功能都有完整的测试,那么当新的功能引入的时候,如果某些原有的测试失败,就说明新的修改破坏了原有的功能,而失败的测试就能准确地告诉我们新的修改破坏了哪些原有的功能。其次,持续集成工具将告诉我们集成是否成功,持续集成工具通过运行整个系统中的测试,根据测试的结果来通知开发者,哪些测试失败导致的集成失败。每个软件项目通常会使用版本控制工具例如SVN、CVS,每当有开发者将新的修改加入到系统的代码库中时,持续集成工具会check out出代码库中的最新版本,使用自动化的构建工具例如Ant、Rake等,自动地编译项目中的代码、部署整个应用、准备测试所需的环境和数据、运行所有的测试包括单元测试、功能测试、集成测试等,在整个过程结束后将结果报告出来,持续集成工具会指出任何一个过程中出现的错误,并且准确地报告给开发者。在多人协作的情况下,版本控制工具确保了每个开发者的修改被正确有序地保存,当每个开发者想要提交自己的修改的之前,必须首先确保上一个人所提交的修改被成功集成,才能提交自己的代码,当确保自己的代码被正确集成之后,自己的工作才算完成,否则,就必须修复错误,再次提交,如此反复,直到被成功集成。

开源社区已经为我们提供了非常优秀的持续集成工具,CruiseControl、CruiseControl .Net已成为广泛使用而且非常成熟的持续集成工具,而持续集成所需要的自动化构建工具和版本管理工具如Ant、NAnt、SVN也已经是非常成熟。在下面,我尝试在我的使用经验的感受的基础上,挑选一些比较成熟或者很有潜力的工具,结合自己的使用经验,给大家做一些介绍。 Continue reading “.Net下的开源持续集成”

.NET中如何使用嵌入的资源

.Net中嵌入资源(位图、图标或光标等)有两种方式,一是直接把资源文件加入到项目,作为嵌入资源,在代码中通过Assembly的GetManifestResourceStream方法获取资源的Stream。另一种方法是在项目中加入. resx资源文件,在资源文件中添加资源,由ResourceManager类统一管理其中的资源。下面分别详述这两种方法:

使用GetManifestResourceStream读取嵌入资源

  1. 加入资源文件

    直接把要嵌入到程序集的资源文件加入到项目中,可以加在项目的根目录,可以加在项目的任何目录中。

  2. 设置资源文件的“BuildAction”属性

    将嵌入资源文件的“BuildAction”属性设置为“Embedded Resource”

  3. 代码中使用嵌入资源

//获得正在运行类所在的名称空间

Type type = MethodBase.GetCurrentMethod().DeclaringType;

string _namespace = type.Namespace;

//获得当前运行的Assembly

Assembly _assembly = Assembly.GetExecutingAssembly();

//根据名称空间和文件名生成资源名称

string resourceName = _namespace + ".directory.BitmapManifest.bmp";

//根据资源名称从Assembly中获取此资源的Stream

Stream stream = _assembly.GetManifestResourceStream(resourceName);

Image myImage = Image.FromStream(stream);

上述代码中有部分步骤是为了获得resourceName的值,resourceName的值结构形式类似于:”命名空间.目录路径.文件名+后缀”

此外还有一种访问资源的格式:”assembly://SpringSample/Sample.Spring/Resources.BitmapManifest.bmp”,有点像URI格式,不同的是协议为”assembly://”,”SpringSample”为程序集名称,”Sample.Spring”为默认命名空间,”Resources”为目录路径。注意:程序集名称与默认命名空间之间、默认命名空间与目录路径之间用”/”分隔,目录路径与文件名之间用”.”分隔,因为如此我们理解了访问资源的路径方式,就可以直接进行引用了。

使用. resx资源文件嵌入资源

  • 新建资源文件

    在项目中新建一个资源文件,资源文件以.resx为后缀,同时还会新建一个跟资源文件同名的Designer.cs文件。
    其实资源文件最大的用处是用来做多语言版本的软件时保存不同语言的资源,比如不同语言的菜单文本,可以把不同语言的字符串放在同一个资源类型下的不同资源包中,程序运行时根据运行时系统的culture选择不同的包显示不同语言的字符串。
    新建了资源文件后就能往资源文件中添加资源文件:

    资源中可以添加字符串、位图、图标、音频、文件等等的资源。
    添加的资源都会被保存在项目的Resources文件夹中。

  • 设置资源文件的“BuildAction”属性

    Resources文件夹中的所有资源文件的“BuildAction”属性设置为“Embedded Resource”。

  • 资源存在方式

    .resx资源文件管理的资源可以用两种存在形式,一种是以一般的文件形式存在于Resources文件夹中,另一个是经过Base64编码后嵌入到.resx资源文件中。
    打开.resx资源文件,选择资源,在属性中Persistence属性决定资源的存在形式。资源的两种存在形式,在代码中调用都是一样的。

  • 代码中使用嵌入资源
    Icon myIcon = (Icon)Resource1.ResourceManager.GetObject("IconTest");
    Icon myIcon = Resource1.MyIcon
  • 多语言的资源应用

    //得到当前语言环境
    CultureInfo ci = Thread.CurrentThread.CurrentCulture;
    //CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture;
    
    Icon myIcon = (Icon)Resource1.ResourceManager("IconText", ci);

在.Net中检查Sql注入

SQL 注入是一种攻击方式,在这种攻击方式中,恶意代码被插入到字符串中,然后将该字符串传递到 SQL Server 的实例以进行分析和执行。任何构成 SQL 语句的过程都应进行注入漏洞检查,因为 SQL Server 将执行其接收到的所有语法有效的查询。一个有经验的、坚定的攻击者甚至可以操作参数化数据。

SQL 注入的主要形式包括直接将代码插入到与 SQL 命令串联在一起并使其得以执行的用户输入变量。一种间接的攻击会将恶意代码注入要在表中存储或作为元数据存储的字符串。在存储的字符串随后串连到一个动态 SQL 命令中时,将执行该恶意代码。

注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。由于插入的命令可能在执行前追加其他字符串,因此攻击者将用注释标记“–”来终止注入的字符串。执行时,此后的文本将被忽略。

Continue reading “在.Net中检查Sql注入”

.NET之栈、堆、值类型、引用类型、装箱、拆箱

引言

这篇文章是我很早之前看到的,当时解决了我很多疑惑的地方。现在拿出来与大家分享。本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱。文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆;最后介绍值类型和引用类型,并说明一些有关它们的重要原理。

最后通过一个简单的示例代码说明装箱拆箱带来的性能损耗。

声明变量的内部机制

在.NET程序中,当你声明一个变量,将在内存中分配一块内存。这块内存分为三部分:1,变量名;2,变量类型;3,变量值。

下图揭示了声明一个变量时的内部机制,其中分配的内存类型依据你的变量类型。.NET中有两种类型的内存:栈内存和堆内存。在接下来的内容中,我们会了解到这两种类型的详细内容。
Continue reading “.NET之栈、堆、值类型、引用类型、装箱、拆箱”