<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Doctor's WebLog]]></title> 
<link>http://www.gaobo.info/index.php</link> 
<description><![CDATA[博乐的自留地]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Doctor's WebLog]]></copyright>
<item>
<link>http://www.gaobo.info/read.php/736.htm</link>
<title><![CDATA[解决WIN2008 R2 x64未注册Microsoft.Jet.OLEDB.4.0程序错误]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 03 Sep 2010 07:19:36 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/736.htm</guid> 
<description>
<![CDATA[ 
	这两天学校搬迁，我们办公室也从老校区转战到新校区了，呵呵<br /><br />搬过来后部分服务器进行了调整，一些站点无法访问，出现了老的站点在新的系统下工作不正常的情况。下边列举一例。<br />提示如下错误:<br />未在本地计算机上注册&ldquo;Microsoft.Jet.OLEDB.4.0&rdquo;提供程序。<br />说明: 执行当前 Web 请求期间，出现未处理的异常。请检查堆栈跟踪信息，以了解有关该错误以及代码中导致错误的出处的详细信息。 <br />异常详细信息: System.InvalidOperationException: 未在本地计算机上注册&ldquo;Microsoft.Jet.OLEDB.4.0&rdquo;提供程序。<br /><br />解决方法如下：<br />用于Access和Excel数据库的Microsoft OLE DB Provider for Jet在64位版本中不可用。 <p>必须在IIS中启用32位应该程序才可以正常使用</p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/windows/" rel="tag">windows</a> , <a href="http://www.gaobo.info/go.php/tags/2008/" rel="tag">2008</a> , <a href="http://www.gaobo.info/go.php/tags/r2/" rel="tag">r2</a> , <a href="http://www.gaobo.info/go.php/tags/x86/" rel="tag">x86</a> , <a href="http://www.gaobo.info/go.php/tags/x64/" rel="tag">x64</a> , <a href="http://www.gaobo.info/go.php/tags/microsoft/" rel="tag">microsoft</a> , <a href="http://www.gaobo.info/go.php/tags/jet/" rel="tag">jet</a> , <a href="http://www.gaobo.info/go.php/tags/oledb/" rel="tag">oledb</a> , <a href="http://www.gaobo.info/go.php/tags/access/" rel="tag">access</a> , <a href="http://www.gaobo.info/go.php/tags/excel/" rel="tag">excel</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/735.htm</link>
<title><![CDATA[应用Visual Studio 2010辅助敏捷测试]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Wed, 01 Sep 2010 12:31:13 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/735.htm</guid> 
<description>
<![CDATA[ 
	<p>敏捷软件开发是近些年来比较热门的话题，《敏捷宣言》四条主要精神和十二条基本准则概括了敏捷开发的基本思想。围绕着这些基本概念和思想，产生了一系列的轻量级方法，如：极限编程、测试驱动开发、Scrum、特性驱动开发等。虽然具体名称、过程和侧重点不尽相同，但是相对于非敏捷的开发方法而言，它们都更强调面对面的沟通、团队不同角色之间的紧密协作、频繁交付新的可用的软件版本、紧凑而自我组织型的团队等。敏捷开发只是提供了一个思想和方法论,而要在实际的工程中正确运用它，并真正显现出它的优点和产生实际的效果，这对于每个团队而言一开始都是一个挑战，尤其是对那些那些习惯了传统瀑布模式的团队。<br />敏捷是整个团队的敏捷，不只是团队中某个角色或者某个阶段的敏捷，开发、测试和项目经理等所有角色都要敏捷起来。敏捷方法的采用对团队每个成员都提出了新的挑战，尤其是测试人员。之所以这样说，是因为相对于传统的瀑布模型，敏捷开发所要求的频繁交付，给测试所留出的时间更为紧迫，要求测试人员更早的介入和更及时地完成测试任务。如何在这么短的时间内完成测试的计划和实施呢？如何有效地避免回归问题的出现？手工测试人员如何能更好的融入到敏捷团队？等等问题接踵而至，这都需要需要测试人员不断的思考和尝试。</p><p>无论是哪种开发模式，软件的开发过程都可以归结为：人、工具和过程这三个因素，三者的有机结合才能更高效的完成任务。有人会说：《敏捷宣言》四条主旨精神的第一条就是&ldquo;个体和交互重于过程和工具&rdquo;，工具还有那么重要吗？回答是肯定的，工具很重要，这条主旨所提到的是&ldquo;重于&rdquo;而不是不要。为了支持敏捷开发，Visual Studio 2010（以下简称为VS 2010）应用程序生命周期管理中引入了MSF for Agile Software Development v5.0过程模板，用于辅助敏捷团队在实际工程中进行敏捷实践，它支持Scrum敏捷开发过程框架。本文将从工具角度出发， 介绍Visual Studio 2010如何帮助测试人员更胜任敏捷项目中的测试工作。对于工具与人的关系而言，好的工具应该是将人从重复和机械的劳动中解脱出来，让人有更多的精力和时间花在有创造性地劳动上，而由工具去完成将繁琐和冗余的事务性操作；而对于工具和过程的关系，工具是过程能够得到确实落实和准确执行的基石，很多时候我们总是依赖于人去执行某个过程或者流程要求，但人的执行往往带有一定不稳定性和主观性，而工具则可以帮助我们准确客观的执行。</p><h2>团队有效协作的基石&mdash;&mdash;Team Foundation Server</h2><p>敏捷开发强调人与人之间的有效沟通和紧密的团队协作。对于测试团队和测试人员而言，首先应该需要考虑的是：如何让测试工作更有效的集成整个敏捷开发的活动中去？而不是将测试工作仅作为一个&ldquo;附件&rdquo;或者可有可无的副产品。当然，这会受到团队组织形式和开发过程的限制，例如：采用功能小组模型的团队，所有角色成员（PM、开发人员、测试人员）隶属于同一个功能团队，客观上其沟通就更为方便；而对于采用纵向按职能划分团队的公司而言，测试和开发在隶属关系上是分开的，相对在沟通上障碍就会更多些。无论是哪种组织形式，好的工具能帮助促进和统一各个角色间的信息互通和共享，而不是要让他们彼此之间更为孤立、工作在各自的一亩三分地（Silo）中。Team Foundation Server 2010（以下简称为TFS 2010）就是这样的工具，作为整个团队协作的核心，它统一了团队不同角色信息、实现了信息之间的有效互联互通、彼此之间的共享和关联，例如：TFS 2010定义6种默认的工作项类型，如下图所示。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest1.JPG" border="0" width="586" height="482" /></p><p><strong>图1：</strong>TFS 2010定义6种默认的工作项类型</p><p>其中，Test Case和 Shared Steps是2010专门为测试新加入的。不要小看这些工作项，它们之间有着丰富的关联关系，这种关系背后所代表是角色之间的关系。对于测试而言，它将测试和团队紧密的结合在一起。例如：Test Case工作项用来详细定义和管理测试用例，它还可以和User Story相关联，也就是将测试和用户需求进行了关联，用户可以从需求追溯到覆盖的它的测试用例，这背后体现的是测试人员和需求人员/PM的协作；Test Case还可以与Bug关联，通过这种关联可以挖掘出哪些 Bug被测试用例覆盖，哪些还没有，这种关联体现了测试人员与开发人员的写作，如果是自动化测试用例，则体现了手工测试人员和自动化工程师的协作；Bug还可以可以和签入集（Change-set）关联，可以找到为了修复Bug，开发人员修改过哪些产品代码，这体现了测试人员和开发的关联。</p><p>敏捷开发频繁的迭代和较短的迭代周期，对项目管理的精确性、透明性和可见性都提出了更高的要求， 尤其对于那些项目复杂和人员较多的团队。Task是另一个重要的工作项类型，它用于管理开发过过程中的所有任务项，包括：开发、测试以及需求等任务，统一管理开发中的所有任务，统一计算项目的开销和剩余工作量等。例如，项目的燃尽图就是由它产生出来的。现在，人们虽然在理论和概念上已经非常认同软件测试的在工程中的重要地位，但在具体实际操作中，测试却仍然被看作是低于开发和需求分析等的&ldquo;二等公民&rdquo;。当然这是由于多方面的综合因素造成的，从管理技术角度讲，这是由于测试工作本身缺乏可度量性和可见性，从导致了测试工作的透明性的缺失，团队往往看不到测试工作的进度和所带来的成果，从而意识不到测试的真正作用。对于测试人员自身而言，缺乏可度量性也让自己无法对工作进度准确把握，进而失去了对自己工作的目标感和认同感。将测试工作同其他工作一样的用Task工作项管理起来，增加了它的可度量性和可见性。将测试工作和其它任务一起统筹，时刻确保测试被作为整体中的一部分进行考虑，所有的测试任务都被作为Task工作项记录下来，例如：编写测试计划、设计测试用例、自动化测试用例等等，每项任务都有三个默认时间估计数据需要填写，它们是：Original Estimate、Remaining和Completed，分别代表了任务的预估时间、剩余工作量和完成工作量。</p><p>为了增强敏捷过程的透明性和可见性，TFS 2010定义了很多的报表和仪表板（Dashboard），它们会自动生成各种报表，以可见的方式描述敏捷项目的健康状况，这其中就有很多反映测试工作的报表，如下面所示。Stories Overview展示了用户故事的进展情况，包括了每个用户故事的测试用例覆盖数量和执行结果，以及相应的Bug数量；Test Dashboard显示了测试用例的状态，包括正在设计的用例以及设计完毕可以执行的用例数量，现实当前Bug的状况，包括未被修复和以修复Bug的数量。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest2.JPG" border="0" width="678" height="465" /></p><p><strong>图2：</strong>Stories Overview展示了用户故事的进展情况</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest3.JPG" border="0" width="686" height="509" /></p><p><strong>图3：</strong>Test Dashboard显示了测试用例的状态</p><h2>集成测试环境&mdash;&mdash;Microsoft Test Manager</h2><p>在过去的十几年中，为了适应了软件项目的复杂度和规模的不断膨胀，软件开发工具和框架得到了长足的发展，而测试工具则始终是块短板 ，特别是对于那些需要手工完成的测试任务而言，进展就更为缓慢，例如：现在很多团队仍然使用Word或者Excel这样&ldquo;原始&rdquo;工具来管理测试用例。通过对业界的调查和分析，我们发现70%的软件测试工作仍然是通过手工或者简单的脚本来完成的，在测试团队中不具备编程能力和仅有基本脚本编写能力的测试人员仍然是测试的主力。</p><p>要让你的项目敏捷起来，对于那些仍以手工测试为主的团队而言是一个非常大的挑战，如何提高手工测试工作的效率将是实现敏捷的成败关键。在VS 2010中，微软首次为测试人员设计了一款专用的集成测试环境，称为微软测试管理器2010（Microsoft Test Manager 2010，以下简称为MTM）。之所以称之为集成测试环境，是因为MTM的功能涵盖了测试计划、测试用例、手动测试用例的执行和录制回放、自动测试用例执行、创建信息丰富的Bug、验证Bug、以及与测试实验室管理相关的对策是自动化相关的功能等。下图展示的是MTM测试计划的操作界面，它以树形的层次结构来组织测试用例。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest4.JPG" border="0" width="672" height="409" /></p><p><strong>图4：</strong>MTM测试计划的操作界面</p><p>《敏捷序言》强调：&ldquo;可工作的软件重于完备的文档&rdquo;，那么是不是意味着敏捷测试也不需要测试计划呢？当然不是。敏捷的本质是要去除软件过程所有造成时间浪费地方，不需要的是那些动辄就几十或上百页的文档。敏捷对文档要求是要简明扼要，一两页列出测试要点计划还是必须的，较短迭代周期（1-4周）也不可能要求文档面面俱到。敏捷需要更快的对功能进行验证，是不是不需要编写测试用例直接根据用户故事或者功能需求进行探索性测试就可以了？当然也不是。功能需求和用户故事勾画出的是一棵大树躯干和主要枝杈，而那测试用例则不但要准确描述出躯干和主枝，还要描述出细小的枝杈和绿叶的正确位置。从某种意义上讲，测试用例在敏捷中的作用和地位应该更为加强，它扮演着详细功能文档的角色。功能需求和设计文档可以简单，但测试用例可不是这样，相反我认为敏捷对测试用例的设计和管理要求更高。</p><p>每个迭代周期，团队都会专注于实现不同的产品功能，用户故事虽然描述了功能的内容，但并不足以覆盖所有相关的内容。很多由用户故事展开和关联的功能一般在文档中会体现出来，需要测试人员在早期围绕着用户故事测试展开需求文档测试（需求评审），已明确那些未严格定义出来的内容，以测试用例的形式明确和记录下来。由1个简单用户故事就有可能扩展为1+N用户可能执行的执行片段，也就我们测试用例。当你有M个用故事，需要Ｍ个迭代周期来完成产品，那么就会有 ( M + N<sub>1 </sub>+ N<sub>2 </sub><sub>&hellip; </sub>+ N<sub>M</sub>) 个测试用例，不把它们落实到笔头上，很容易就会丢失一些重要的测试细节。此外，在敏捷方法中需求变化比较快，随着多个迭代的深入，文档的变化往往赶不上产品功能的变化，这时唯一能够赶上这个变化的只有测试用例，应为只有它准确地反映了产品的变化，否则测试用例就是无法通过的。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest5.JPG" border="0" width="683" height="535" /></p><p><strong>图5：</strong>测试用例</p><p>在MTM 中，测试用例被分类至各个测试用例集，结构十分清晰。测试用例只是逻辑上从属于某个测试用例集，并没有物理从属关系，即一个测试用例可以同时被分在多个测试用例集内，比如某个测试用例性质上是一个性能测试，但是由于该用户故事的诉求就是性能改进，我们也就很自然得可以将其作为该用户故事的验收测试，此时我们就可以将此测试用例添加到验收测试和性能测试两个测试用例集中；另一个例子是给每个用户故事都定义了不少测试，这些测试用例都应该能在用户故事测试用例集下找到，但是这些测试既可能是手动测试也可能是自动化测试用例，所以它们又会被本别归类至这两个测试用例集。在这种逻辑分类的支持下，我们可以很容易的根据需要指定运行测试集中一部分测试用例。比如，我们可以定义一个签入测试的测试用例集，挑选最基本的若干个测试置入其中，这样在每次签入前通过运行这个测试用例集就能帮助我们确保签入的代码不至于破坏最基本的功能，即保证了版本随时可运行可测试，这无疑为测试带来了更多的方便。具体如何创建测试用例集的结构，团队可以根据自己项目的特点，灵活运用此功能，制定分类规则以提高工作的效率。</p><p>很多测试团队仍然在使用Word或者是Excel管理测试用例，有些是使用专门的测试用例管理工具，使用独立的数据库来存储测试用例信息。MTM相对于这些工具的优点在于，它的所有数据都是存储在TFS上，测试用例使用的是Test Case工作项。由于同存储在TFS 上，所以可以轻松的实现与其它数据项的关联，例如：在上一部分我们介绍的不同类型工作项之间关联，此外还可以把Test Case与代码关联，即将测试用例与自动化测试代码关联。这样在MTM中，也可以直接管理和运行自动化测试用例，使MTM兼具了管理手工测试用例和自动化测试用例的能力。</p><p>探索性测试（Exploratory Testing）是测试人员在对被测试系统的功能进行不断了解和学习的过程中进行测试，包括：设计测试用例、执行测试、以及汇报测试结果。与传统的测试相比，它不需要事先定义好的齐备的测试文档，更强调测试人员在对系统不断地学习中，边了解边测试，它在很大程度上给测试人员更多地自由和想象空间，充分发挥他们的创造力，在不断地学习中找到测试的灵感和快乐。这种测试的灵感和快乐对于组建和培养一支热爱测试的团队是非常非常重要，它会让测试人员觉得自己不是执行重复测试劳动机器，而是一个有着创造力和灵光的团队成员。MTM也支持探索测试功能，用户可以使用MTM创建一个仅有一个测试步骤的测试用例，然后执行它，Test Runner工具会辅助执行手动测试。它会记录下所有用户的操作，一旦发现有Bug时候，可以直接选择&lsquo;Create exploratory bug&rsquo;直接创建一个Bug。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest6.JPG" border="0" width="507" height="411" /></p><p><strong>图6：</strong>创建一个Bug</p><p>Bug是测试工作最重要的产出之一，也是测试和开发人员之间重要接触点。每个提交的Bug都应该详细记录下如何重现（reproduce）的步骤，这是衡量Bug质量的重要因素之一。因为不可重现的Bug是没有意义的，只会耽误开发人员和项目经理的时间。偶尔出现不可重现的Bug还是可以理解的，但如果经常出现，那就会引来开发人员的抱怨和不满，久而久之会造成开发和测试之间的不信任。 好的Bug应该是有清晰和详细的重现步骤，期望的结果和实际得到结果，并提供尽可能多的信息，例如：出现问题的产品版本编号、语言、操作系统的版本以及日志信息等。大多数情况下，用文字进行描述的内容就可以了，但如果能配上一张问题现场截图，或者对于更为复杂的Bug，配上一段小的录像，这样的Bug会给开发人员快速诊断和修复产品问题带来很大帮助，大大提升测试和开发人员之间的协作效率，避免了不可重现Bug在开发和测试之间推来推去的&ldquo;Bug乒乓&rdquo;现象。然而要收工创建这样一个信息丰富的Bug，是需要很多时间的。MTM提供了这样的功能为帮助测试人员创建这样高质量Bug，它实现了多种诊断数据适配器（Diagnostic Data Adapters），在测试确认Bug的过程中，这些适配器会在后台运行收集大量的数据，包括：执行操作、系统配置、IntelliTrace已经操作过程的录像等，当测试人员要创建一个Bug时，这些信息会被自动添加的Bug中，如下图所示，测试仅需填写很少的内容就可以创建好一个信息丰富的Bug。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-1/zh/resources/agiletest7.JPG" border="0" width="590" height="505" /></p><p><strong>图7：</strong>信息丰富的Bug<br /></p><h2>实现自动化测试用例&mdash;&mdash;自动化测试用例框架</h2><p>随着需求的不断变化和迭代的深入，代码库不可避免的会有频繁的签入和签出，此时测试人员一项很重要的任务就是要预防回归问题发生。执行手工测试用例可以帮助我们预防及和发现回归问题，但是它的执行效率太低，无法胜任频繁执行的要求。这时就我们需要考虑采用自动化测试用例完成这项工作。决定是否采用自动化测试是有很多因素决定，其中很重要的一条就是自动测试的收益，下面的公式从概念上解释了如何来计算这个收益，当收益值大于1的时候，实施自动化测试就是合算的；否则，就是不合算的。</p><p><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest00.JPG" border="0" width="350" height="74" /></p><p><strong>图1：</strong>计算收益公式</p><p>这其中，开发和维护自动测试的成本是影响这个收益的重要因素，为此VS 2010提供了一整套的解决方案，帮助测试团队减少这部分成本，这包括前面我们所提到的测试计划和用力管理工具，以及后面将会要介绍的生成和实验室管理。此外，Visual Studio 提供了多种测试工程模板，帮助测试人员开发自动化的测试用例，如下图所示。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest8.JPG" border="0" width="569" height="492" /></p><p><strong>图2：</strong>Visual Studio提供的多种测试模板</p><p>这些测试工程模板可以帮助测试自动化工程师，在Visual Studio 集成开发环境中创建和管理单元测试、功能测试、Web性能测试、负载测试等等一系列的自动化测试用例。这其中，编码的UI测试（Coded UI Test，以下简称为CUIT）是首次出现，是VS 2010测试部分一大亮点。测试人员可以通过它使用C#或者 VB.NET语言编写自动化测试用例，从用户界面层驱动Web、Winform或者是WPF的应用。CUIT为测试用例的自动化提供了一个框架、API和可扩展的接口，测试人员可以很轻松地开发出所要的自动化测试用例。其实CUIT背后的测试自动化实现技术对大家并不陌生，下面列出针对Web、WinForm和WPF应用的测试技术基础。对每种技术的支持采用的是插件的形式实现的，VS 2010包括了如下的三种插件：</p><ul><li>Document Object Model（DOM）插件 : IE 7/8 HTML/AJAX </li><li>User Interface Automation（UIA）插件 : WPF </li><li>Microsoft Active Accessibility（MSAA）插件 : Winform，Win32和MFC 。MSAA插件是默认选项，用来支持出其它两者之外的任何应用。 </li></ul><p>CUIT 现在支持主要的微软平台，详细的内容可以参见<a href="http://msdn.microsoft.com/en-us/library/dd380742.aspx"><span style="color: #0b59b2">MSDN : Supported Configuration and Platforms for Coded UI Tests and Action Recordings</span></a>。对于那些尚不支持的平台或者UI控件，CUIT提供了很好的扩展机制，允许大家针对自己的特殊应用进行扩充，下图就是CUIT框架的体系结构图 。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest9.JPG" border="0" width="567" height="384" /></p><p><strong>图3：</strong>CUIT框架的体系结构</p><p>开发自动化测试用例对于有效预防回归问题的出现时非常必要，在实际应用中应该特别注意它的合理比例关系和灵活的策略，包括：自动化用例和手工用例的比例、UI和非UI测试用例的比例关系。自动化测试用例、执行、分析和维护它们都是需要一定投入的，对于敏捷项目而言时间资源的紧缺尤为突出，所以在任何时候团队都要根据自身的资源，有选择性进行测试用例的自动化，通常情况下应该优先自动化那些高优先级的测试用例。</p><p>对于UI和非UI的自动化测试用例而言，应该是以非UI 的单元测试和功能测试为主，UI测试未必要的补充。基于UI自动化测试用例有它独特优点，例如：它从真实用户角度出发进行测试，即涵盖了界面层、逻辑层和数据层，自动化人员不需要了解被测试应用的代码实现细节等；但是相对于非UI测试它也有着先天的不足，包括：执行速度相对比较慢、易受干扰不稳定等。所以在自动化过程中，能用非UI测试覆盖的功能尽可能采用非UI的测试覆盖，如：API单元测试等，UI测试用例只用来实现最基本用户故事的验收测试（Acceptance Test）。</p><h2>早测试和经常测试&mdash;&mdash;封闭签入和滚动生成</h2><p>敏捷开发中最可怕的事情莫过于在迭代最后一两天进行测试，结果发现了严重功能缺陷或者回归缺陷，导致不能按计划发布给用户试用。要想彻底解决这样的问题，一方面要在迭代开发阶段测试人员就要参与进来，从客户的角度出发对功能需求和设计文档进行文档测试，即文档评审。测试人员和开发还有项目经理一起从源头上保障将要实现的功能是用户想要的。另一方面就是要在迭代的早期就开始就开始测试，特别前几个迭代已经实现好的自动化测试用例，尽早的执行它们可以有效地避免回归问题的出现。在TFS 2010上专门提供封闭签入（Gated Check-in）、滚动生成（Rolling Builds）和持续集成（Continuous Integration）等功能，帮助敏捷团队实现早测试和经常测试。这其中封闭签入和滚动生成是对敏捷团队比较实用的功能。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest10.JPG" border="0" width="840" height="410" /></p><p><strong>图4：</strong>选择签入方式</p><p>封闭签入是TFS 2010提供的一种新的代码签入方式，在配置这项功能后，当用户要签入任何代码时，系统会先将用户本地要签入的代码打包成一个搁置集（shelve-set），然后提交到服务器端，TFS生成（Build）服务先从TFS源代码控制器中同步项目的最新代码，再将提交的代码与之进行自动合并，然后进行编译，如果编译成功，则执行配置的自动化测试用例，如果测试用例全部通过则代码会被自动签入到代码库中，否则返回错误信息给用户，代码是不会进入到代码库。表面上看是与产品测试没有直接关系，但实际上它和测试以及最终产品质量的密不可分。因为代码签入是整个开发过程中发生最为频繁的操作，每次签入代码的质量直接影响着日常的开发活动。对于绝大多数的开发团队来说，check in代码前不仅要保证编译通过，同时还要最大限度的保证新代码不会破坏已有的功能，也就是要执行测试用例去验证。Gated Check-in中提到的&ldquo;Build成功&rdquo;，实际上包含两部分内容：编译成功和测试用例执行成功，有了它作为保护代码库的第一道屏障，就可以保证它在任何适合都是可编译，并且达到一定质量标准的。</p><p>滚动生成是在VS 2008种就有的功能，当TFS检测到在它所监控的范围内有任何新的代码变化被签入后，它就启动对最新的代码库进行生成验证，该验证包括编译和运行指定的自动化测试用例。之所以称之为&ldquo;滚动&rdquo;，因为它是在一个生成验证操作完成后再去探测有没有新的签入发生，对这期间发生的所有新签入进行新的生成验证。这里需要再强调一下滚动生成的重要意义：它看似只是一个自动生成代码的功能，但实际上起着协调整个开发团队、时刻监控代码库质量、以及尽早暴露产品问题的作用。因为滚动生成时刻都在不停的运转着，对于任何代码签入它都保持着警觉，会去自动验证编译是否成功，自动化测试用例是否都能通过。它就像一个不知疲倦的&ldquo;代码守护者&rdquo;一样监控着代码库，第一时间发现其中的任何问题，将问题通知给整个团队，从而避免了问题的积累和拖延。这非常符合敏捷开发中&ldquo;今日问题今日解决，不要拖到以后&rdquo;的原则，它帮你最早的发现问题、报告问题，开发团队则应该建立制度要及时响应滚动生成所报告的问题，把它作为Priority 为0或1的高优先级问题去对待和解决。</p><p>封闭签入和滚动生成都是来保护代码库的正确性和产品质量，它们是否在功能上重复反而让我们不敏捷了呢？其实两者并不重复，只是各有侧重，将它们搭配使用才会发挥其最大效能。封闭签入是在代码进入代码库之前进行验证，签入提交者一般希望竟快知道结果，以便决定下一步的工作，所以封闭签入的时间（编译和运行测试用例）不要太长（10-20分钟）。这也就决定了我们加入的测试用例不能太多，只添加那些高优先级的测试用例，保证主要的用户故事不被破坏。滚动生成是在代码签入后在后台执行的，由于不存在着与用户的交互等待，所以它执行时间可以更长（几个小时），可以为它加入更多的测试用例，从而全面验证代码库的质量，一旦有任何问题它可以及时通知团队进行修复，这种验证是在几个小时或者每天都在发生的，保证了敏捷对频繁测试的。</p><h2>完整的自动化测试解决方案&mdash;&mdash;实验室管理</h2><p>在谈到软件自动化测试的时候，很多人会误以为实现了自动化测试用例就是自动化测试，其实不然，自动化测试仅是测试自动化的一个重要步骤，绝对不等同于自动化测试。一个完整的自动化测试应该包括：构建、部署、执行测试用例、分析测试结果并作出结论。在前面的自动测试的收益公式中，我们可以看到减少自动测试的维护成本，是提高自动测试收益的重要因素之一。VS 2010的实验室管理（Lab Management）与测试用例管理、生成管理、源代码控制、工作项管理等功能相结合，为自动化测试提供了这样一个完整的解决方案，目标就是要降低了自动测试的运营和非维护成本，下面这张图展示了实验室环境的系统构架图。</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest11.JPG" border="0" width="747" height="453" /></p><p><strong>图5：</strong>实验室环境的系统构架图</p><p>实验室管理功能充分利用了微软的虚拟化技术，包括：Hyper-V和 System Center Virtual Machine Manager （SCVMM），快速创建干净的虚拟测试环境并进行产品生成和部署，然后执行指定的测试用例集，将结果以报表的形式呈现出来，方便对此产品质量进行分析，如下图所示：</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest12.JPG" border="0" width="479" height="366" /></p><p><strong>图6：</strong>虚拟测试环境</p><p class="image-wide"><img src="http://www.infoq.com/resource/articles/visual-studio-2010-help-agile-test-2/zh/resources/agiletest13.JPG" border="0" width="476" height="364" /></p><p><strong>图7：</strong>测试结果</p><p>同时，利用虚拟技术的环境快照功能，对于那些难于复现或者环境相关的Bug，利用虚拟环境的快照技术，可以为开发人员准确的复现Bug出现的环境，从而能够快速的进行诊断和及时修复。</p><h2>总结</h2><p>Visual Studio 2010作为Visual Studio系列中一个非常重要的版本，为测试人员和团队提供了一整套解决方案，包括：测试计划和用例管理、创建自动化测试用例、测试用例的自动执行、以及实验室管理等。这些功能强调了测试作为整个软件过程的重要角色的作用，促进了测试人员与其它角色的有效沟通与协作，非常适合于敏捷团队使用来完成测试工作。</p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/visual/" rel="tag">visual</a> , <a href="http://www.gaobo.info/go.php/tags/studio/" rel="tag">studio</a> , <a href="http://www.gaobo.info/go.php/tags/team/" rel="tag">team</a> , <a href="http://www.gaobo.info/go.php/tags/foundation/" rel="tag">foundation</a> , <a href="http://www.gaobo.info/go.php/tags/server/" rel="tag">server</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%2595%258F%25E6%258D%25B7/" rel="tag">敏捷</a> , <a href="http://www.gaobo.info/go.php/tags/agile/" rel="tag">agile</a> , <a href="http://www.gaobo.info/go.php/tags/test/" rel="tag">test</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25BE%25AE%25E8%25BD%25AF/" rel="tag">微软</a> , <a href="http://www.gaobo.info/go.php/tags/microsoft/" rel="tag">microsoft</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/727.htm</link>
<title><![CDATA[手把手教程：使用代码优先的方式创建NerdDinner（by Scottgu）]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Thu, 12 Aug 2010 02:41:34 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/727.htm</guid> 
<description>
<![CDATA[ 
	以下是Scottgu先生使用.Net Framework 4里最新的Entity Framework 4更新的一篇创建一个叫做&ldquo;NerdDinner&rdquo;的简单程序的过程，这个程序方便人们在线组织、主办和参加餐会。其中使用&ldquo;代码优先&rdquo;方式的过程真的很&hellip;&hellip;Amazing！<br /><br />（以下第一人称为Scottgu先生）<br /><br /><p>去年我写了一篇ASP.NET MVC 1.0的教程，发表在<a href="http://blog.joycode.com/scottgu/archive/2009/04/29/115557.joy" target="_blank">博客</a>和一本书里。这篇教程捋了一遍创建一个叫做&ldquo;NerdDinner&rdquo;的简单程序的过程，这个程序方便人们在线组织、主办和参加餐会。可以在<a href="http://blog.joycode.com/scottgu/archive/2009/04/29/115557.joy" target="_blank">这里</a>参阅我原先的ASP.NET V1 NerdDinner教程。新书<a href="http://www.amazon.com/gp/product/0470643188?ie=UTF8&amp;tag=scoblo04-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0470643188" target="_blank">ASP.NET MVC 2高级编程</a>也包含了更新过的教程。</p><p>这篇NerdDinner教程原先使用的是&ldquo;数据库优先&rdquo;的方式，也就是预先定义好数据库结构，然后使用Visual Stduio设计器创建LINQ to SQL或LINQ to Entities等模型对象来做映射。</p><p>下面我将演示如何用EF 4的&ldquo;代码优先&rdquo;的方式来创建NerdDinner的模型层和数据库结构，然后使用ASP.NET MVC创建一个增删改查程序。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_2.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb.png" border="0" alt="image" title="image" width="781" height="464" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_49970184.png" target="_blank"></a></p><p>我们将一步一步地创建这个程序，本文的最后有完整示例代码的下载链接。</p><h3>第一步：新建一个空的ASP.NET MVC 2程序</h3><p>我们从在Visual Studio 2010新建一个ASP.NET MVC 2项目开始，选择文件 -&gt; 新项目并使用&ldquo;ASP .NET MVC 2空 Web 应用程序&rdquo;项目模板就行了。</p><p>这样就会新建一个空的ASP.NET MVC 2工程，里面没有什么控制器、模型和视图。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_4.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_1.png" border="0" alt="image" title="image" width="215" height="288" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_5A4F480C.png" target="_blank"></a></p><p>下一步我们将定义NerdDinner&ldquo;模型&rdquo;&mdash;&mdash;表示程序中数据的对象，以及包含验证机制和业务规则等的逻辑。模型是基于MVC程序的&ldquo;心脏&rdquo;，实际上掌控了程序的行为。我们将使用EF 4新的&ldquo;代码优先&rdquo;方式来创建这个模型层。</p><h3>第二步：创建模型</h3><p>现在假设我们尚未创建数据库，从头开始创建NerdDinner程序。</p><p><u>我们不需要从数据库开始</u></p><p>当使用代码优先的开发流程时，我们不需要从先创建数据库或者定义数据库结构来开始程序开发。而可以从定义最适合我们程序的模型对象的标准.NET类开始&mdash;&mdash;免除在里面混杂数据持久化逻辑的烦恼。</p><p><u>创建模型类型</u></p><p>NerdDinner是一个小程序，所需要的数据存储非常简单。我们希望能定义和存储代表人们可参加的事件&mdash;&mdash;&ldquo;Dinners（餐会）&rdquo;。我们还希望能够定义和存储参加餐会的人员&mdash;&mdash;&ldquo;RSVP&rdquo;，用来跟踪有兴趣参加特定餐会的人。</p><p>让我们来创建两个类（Dinner和RSVP）来表现这个概念。在我们的ASP.NET MVC项目中添加两个类&mdash;&mdash;&ldquo;Dinner&rdquo;和&ldquo;RSVP&rdquo;就可以了：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_6.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_2.png" border="0" alt="image" title="image" width="523" height="396" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_25CE75C4.png" target="_blank"></a></p><p>上面的&ldquo;Dinner&rdquo;和&ldquo;RSVP&rdquo;模型类就是&ldquo;简单CLR对象&rdquo;（即POCO）。它们不需要继承什么基类或者实现什么接口，而且里面定义的属性都是标准的.NET数据类型。里面没有添加数据持久化属性和操作数据的代码。</p><p>不需要在定义模型类时将他们绑定到特定的数据库、数据库API和数据库结构的功能的确很好，很强大&mdash;&mdash;而且也让我们有了更弹性的数据访问方式。这样我们就能专注于程序和业务需求上，而不用过多考虑持久化的实现方式。另外，它还为我们提供了更换数据库结构或者存储实现方式的弹性空间&mdash;不需要重写模型对象或者与它们交互的代码。</p><p><u>创建Context</u><u>类来处理数据持久化</u></p><p>我们已经定义了两个POCO模型类，现在让我们创建一个类来处理在数据库获取或保存Dinner和RSVP实例的工作。</p><p>我们将这个类命名为&ldquo;NerdDinners&rdquo;。它继承于DbContext基类，并且定义了两个公开属性&mdash;&mdash;一个用来公开Dinner对象集合，另外一个公开RSVP对象集合：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_8.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_3.png" border="0" alt="image" title="image" width="433" height="128" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_241DA9F0.png" target="_blank"></a></p><p>上面用到的DbContext和DbSet类是EF 4代码优先函数库自带的。你需要添加对System.Data.Entity.CTP程序集的引用，它位于目录&#92;Program Files&#92;Microsoft ADO.NET Entity Framework Feature CTP4&#92;Binaries中。另外在&ldquo;NerdDinners&rdquo;类型定义文件中，你需要添加&ldquo;using System.Data.Entity&rdquo;命名空间的引用。</p><p><u>这就是所有我们需要编写的代码了</u></p><p>上面三个类就是为我们NerdDinner程序实现一个基本的模型和数据持久层所需要的所有代码了。我们不需要配置额外的数据库结构影射信息，不需要运行任何工具，不需要编写什么XML文件，不需要用什么设计器来使用我们的类在数据库中获取、更新和存储数据。</p><h3>基于惯例的持久化影射</h3><p>不需要写什么额外代码，不需要创建什么XML文件，不需要运行什么工具来在数据库中映射我们的模型类。你可能会问，这可能吗？</p><p>默认情况下，EF代码优先库支持一个&ldquo;惯例高于配置&rdquo;的方式，它使用常见的映射习惯，从而避免显式地做任何配置。如果你想使用自定义的数据库映射规则的话，可以复写这些惯例。但如果你使用惯例的话，你会发现你自己需要写的代码真的很少，在不需要添加额外的代码和配置的前提下，90%的常见情况都可以正常工作。</p><p>在上面我们的例子当中，NerdDinner Context类默认会将&ldquo;Dinners&rdquo;和&ldquo;RSVPs&rdquo;属性映射为数据库的&ldquo;Dinners&rdquo;和&ldquo;RSVPs&rdquo;数据表。&ldquo;Dinners&rdquo;表里每一行都被映射成&ldquo;Dinner&rdquo;类型的一个实例。当然啦，&ldquo;RSVPs&rdquo;表里每一行都被映射成&ldquo;RSVP&rdquo;类型的一个实例。&ldquo;Dinner&rdquo;和&ldquo;RSVP&rdquo;类型里的属性也就随之被映射成&ldquo;Dinners&rdquo;和&ldquo;RSVPs&rdquo;表里的列。</p><p>EF支持的其它的惯例包括通过常见命名模式自动识别主键和外键（例如：根据Dinner类里的ID或者DinnerID属性推断出主键）。EF还灵巧地支持在两个模型间绑定相联关系的惯例。<a href="http://blogs.msdn.com/b/efdesign/archive/2010/06/01/conventions-for-code-first.aspx" target="_blank">这里</a>有一篇EF团队的博客讲解了所支持的默认惯例的工作方式。</p><h3>使用我们模型的代码示例</h3><p>前面我们创建的三个类包含了所有实现NerdDinner模型和数据持久化的<u>所有代码</u>。现在我们来看一些代码示例，看看如何使用这些类来执行常见的数据库操作：</p><p><u>使用LINQ</u><u>表达式执行查询</u></p><p>用下面的LINQ查询表达式从数据库中获取数据。下图使用了LINQ表达式来获取所有将要举行的餐会：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_10.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_4.png" border="0" alt="image" title="image" width="428" height="169" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_1506CB16.png" target="_blank"></a></p><p>我们在写LINQ表达式的时候也可以利用Dinners和RSVPs存在的关系。留意下图&ldquo;where&rdquo;子句过滤出参加人数大于0的餐会的方式：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_12.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_5.png" border="0" alt="image" title="image" width="451" height="175" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_41AF84EF.png" target="_blank"></a></p><p>要注意的是上面的查询的&ldquo;where&rdquo;子句（即只获取至少有一人参加的餐会）是在服务器端执行的&mdash;&mdash;使执行查询和加载的数据量更为高效。</p><p><u>获取一个实例</u></p><p>我们可以使用LINQ的Single()函数，加上Lamda查询来获取Dinner的一个实例，如下面的代码所示：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_14.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_6.png" border="0" alt="image" title="image" width="556" height="136" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_6085F8CD.png" target="_blank"></a></p><p>或者，我们也可以利用EF&ldquo;代码优先&rdquo;函数库提供的Find()函数，根据ID来加载一个实例：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_16.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_7.png" border="0" alt="image" title="image" width="430" height="132" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_144DEF1F.png" target="_blank"></a></p><p><u>举办新餐会</u></p><p>下面的代码演示了如何创建一个新的Dinner实例并把它添加到数据库中。所有我们需要做的工作就是&ldquo;new&rdquo;一个Dinner对象，设置它的属性，最后把它加到NerdDinner Context对象的Dinners属性中。NerdDinner Context类支持 &ldquo;工作单元&rdquo;的模式，即你可以在Context中添加多个模型，然后调用&ldquo;SaveChanges()&rdquo;以事务的方式保存所有的数据库变动。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_18.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_8.png" border="0" alt="image" title="image" width="442" height="303" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_05371045.png" target="_blank"></a></p><p><u>更新餐会信息</u></p><p>下面的代码演示了获取一个Dinner实例，更新其中一个属性，然后将改动保存到数据库的过程：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_20.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_9.png" border="0" alt="image" title="image" width="412" height="191" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_2AC08DA6.png" target="_blank"></a></p><h3>第三步：创建使用我们的模型的ASP.NET MVC控制器</h3><p>现在来看看使用模型的更完整的场景，使用一个控制器类型来公布即将到来的餐会列表，并允许用户添加新的餐会：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_22.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_10.png" border="0" alt="image" title="image" width="781" height="464" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_49970184.png" target="_blank"></a></p><p>右键单击&ldquo;Controllers&rdquo;文件夹，然后选择&ldquo;添加-&gt;控制器&rdquo;菜单项，我们把新的控制器命名为&ldquo;HomeController&rdquo;。</p><p>接着添加三个&ldquo;动作函数&rdquo;用来处理前面使用EF&ldquo;代码优先&rdquo;函数库创建的NerdDinners模型：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_24.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_11.png" border="0" alt="image" title="image" width="504" height="815" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_52375A10.png" target="_blank"></a>.</p><p>&ldquo;Index&rdquo;动作函数加载并显示即将到来的餐会列表。</p><p>而&ldquo;Create&rdquo;动作函数允许用户发布新的餐会。第一个&ldquo;Create&rdquo;函数用来处理用户访问/HOME/Create页面时，处理&ldquo;HTTP GET&rdquo; 的场景，以及发一个&ldquo;New Dinner&rdquo;表单让用户填写。而第二个&ldquo;Create&rdquo;函数用来处理跟那个表单关联起来的&ldquo;HTTP POST&rdquo;场景&mdash;将新餐会信息保存到数据库中。如果有任何验证错误，它会重新显示表单并加上相应的错误消息。</p><p><u>给我们的控制器加上视图</u></p><p>下一步将是给项目里加两个&ldquo;视图模板&rdquo;&mdash;&mdash;一个给&ldquo;Index&rdquo;，另外一个给&ldquo;Create&rdquo;。</p><p>把鼠标放在控制器里的Index函数里，就可以在项目中为它添加一个视图了，然后单击右键在菜单中选择&ldquo;添加视图&rdquo;，弹出&ldquo;添加视图&rdquo;对话框。我们将创建一个强类型视图，然后给它传入一个包含&ldquo;Dinner&rdquo;模型对象的IEnumerable列表：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_26.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_12.png" border="0" alt="image" title="image" width="384" height="387" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_306B817F.png" target="_blank"></a></p><p>单击&ldquo;添加&rdquo;后，Visual Studio会创建一个<em>/Views/Home/Index.aspx</em>文件。再添加以下这些代码&mdash;&mdash;为餐会信息生成一个&lt;ul&gt;列表，然后显示创建餐会的链接：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_28.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_13.png" border="0" alt="image" title="image" width="527" height="325" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_0A955B1C.png" target="_blank"></a></p><p>把光标放在控制器的Create函数来在项目中添加&ldquo;Create&rdquo;视图，单击右键菜单里的&ldquo;添加视图&rdquo;命令。在&ldquo;添加视图&rdquo;对话框中，我们还是指定创建一个强类型视图，然后传给它一个Dinner对象。另外还说明了我们希望使用&ldquo;Create&rdquo;模板搭个框架：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_30.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_14.png" border="0" alt="image" title="image" width="390" height="391" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_023185C5.png" target="_blank"></a></p><p>单击&ldquo;添加&rdquo;后，Visual Studio会创建一个<em>/Views/Home/Create.aspx</em>文件，里面有一个包含了为&ldquo;Dinner&rdquo;对象生成的HTML &lt;form&gt;表单的草案。我们做一点点的调整，并删掉了为DinnerID属性生成的input元素。最终的视图模板如下所示：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_32.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_15.png" border="0" alt="image" title="image" width="644" height="887" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_6B8F377D.png" target="_blank"></a></p><p>迄今为止，我们已经写好了网站里实现列出餐会清单和创建餐会信息的控制器和视图的所有代码。</p><h3>第四步: 数据库</h3><p>代码已经写好了。现在让我们来运行程序。</p><p><u>但数据库呢？</u></p><p>我们现在还没有数据库呢&mdash;&mdash;其实到目前为止也没有必要，因为我们&ldquo;代码优先&rdquo;的开发流程并不要求数据库来定义和使用我们的模型类。</p><p>但当我们实际运行我们的应用程序时，我们要存储Dinner和 RSVP对象的。我们可以用下面的两种方式之一去创建数据库：</p><p>1. 使用数据库工具（如SQL Management Studio或 Visual Studio）去手动创建和定义数据库结构；</p><p>2. 使用EF代码优先类库根据我们定义好的模型自动创建和生成数据库结构。</p><p>第二种方式非常酷，而且我们要把它用在我们的NerdDinner程序中。</p><p><u>配置数据库连接字符串</u></p><p>在开始前，我们要设置好指向将要创建的数据库的连接字符串。我们把数据库连接字符串&ldquo;NerdDinners&rdquo;添加到应用程序的web.config文件中，如下所示：</p><pre><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_34.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_16.png" border="0" alt="image" title="image" width="603" height="162" /></a> </pre><p>在默认情况下，当你用EF的代码优先类库创建一个DbContext类的时候，它会自动查找和Context类名匹配的连接字符串。因为我们将Context类命名为&ldquo;NerdDinners&rdquo;，所以，当ASP.NET应用程序初始化它的时候，默认会找到前面添加好的&ldquo;NerdDinners&rdquo;数据库连接字符串。</p><p><u>使用</u><u> SQL CE 4</u></p><p>EF 代码优先类库可以支持多个不同的数据库&mdash;&mdash;包括 SQL Server、 SQL Express和 MySQL。</p><p>两个星期前，我写了一篇在ASP.NET中使用<a href="http://weblogs.asp.net/scottgu/archive/2010/06/30/new-embedded-database-support-with-asp-net.aspx" target="_blank">嵌入式SQL CE 4 数据库引擎</a>的<a href="http://weblogs.asp.net/scottgu/archive/2010/06/30/new-embedded-database-support-with-asp-net.aspx" target="_blank">博客</a>。SQL CE 4 是一个轻量级的基于文件的数据库，安装简便，且可以嵌入在ASP.NET应用程序中。它支持低成本的宿主环境，又能够轻松地迁移到SQL Server 数据库当中。</p><p>在定义（和重新定义） 你的数据模型层的前期阶段，SQL CE可以是一个很不错的选择&mdash;&mdash;另外，只要你想，还可以快速地创建和重新创建数据库。在开发NerdDinner应用程序时，我们将以SQL CE 4 作为数据库。后面，我们可以选择更改连接字符串去将产品部署到SQL Express或者SQL Server上&mdash;&mdash;无需修改任何一行代码。</p><p>我前面设置的数据库连接字符串，指定了NerdDinners.sdf 数据库文件，并使用SQL CE 4 数据库驱动程序。要使它正常工作，你还需要安装SQL CE 4&mdash;&mdash;安装它可以通过<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0d2357ea-324f-46fd-88fc-7364c80e4fdb&amp;displaylang=en" target="_blank">标准的SQL CE安装程序</a>或<a href="http://blog.joycode.com/scottgu/archive/2010/07/21/116031.joy" target="_blank">WebMatrix</a>（已内置SQL CE）。SQL CE 4 很小，只要几秒钟就可以安装好。</p><p><strong><em>重要事项</em></strong>：<em>上面的连接字符串中，我们指定将</em><em>NerdDinners.sdf </em><em>文件创建在</em><em>&#92;DataDirectory&#92; </em><em>文件夹下</em><em>&mdash;&mdash;</em><em>在</em><em> ASP.NET</em><em>应用程序中对应的就是其根目录下的</em><em>&#92;App_Data&#92;</em><em>文件夹。默认情况下，新建</em><em>&quot;</em><em>空</em><em> ASP.NET MVC Web </em><em>应用程序</em><em>&quot;</em><em>项目模板不会创建此目录。所以你需要显式在项目中创建此文件夹（右键单击该项目并选择</em><em>&quot;</em><em>添加</em><em> ASP.NET </em><em>文件夹</em><em>-&gt; Add_Data-&gt;&quot;</em><em>菜单项）。</em></p><p><u>自动创建数据库结构（</u><u>Schema</u><u>）</u></p><p>EF 代码优先类库支持自动地从数据模型类生成数据库结构和数据库的能力&mdash;&mdash;免除用户必须手动去执行这些步骤。</p><p>如果您的连接字符串指定的SQL CE 或 SQL Express 数据库文件在<u>磁盘中不存在</u>，<u>默认</u>就会发生。你根本不需要执行任何手动步骤。</p><p>要看到效果，我们可以按 F5 键运行我们的NerdDinner应用程序。它会启动浏览器，并访问我们应用程序的根目录&quot;/&quot;。你应该可以看到下面所示的画面：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_36.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_17.png" border="0" alt="image" title="image" width="579" height="377" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_6EE0A958.png" target="_blank"></a></p><p>访问应用程序的根目录会调用到HomeController.Index()这个函数&mdash;&mdash;它会实例化并查询我们的NerdDinners context类，来从数据库获取即将举办的餐会列表。因为我们在连接字符串中指定的NerdDinners.sdf数据库文件并不存在，所以EF 代码优先类库将自动地为我们创建该数据库。它会根据NerdDinners context类，推断出数据库结构，最后生成数据库。</p><p>你可以通过在Visual Studio解决方案管理器上点击&ldquo;显示所有文件&rdquo;图标，然后点击&ldquo;刷新&rdquo;按钮，展开App_Data文件夹查看那个自动生成的SQL CE数据库文件。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_38.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_18.png" border="0" alt="image" title="image" width="203" height="348" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_33ACCD8D.png" target="_blank"></a></p><p>将来我们会发布一个VS 2010的升级包，你将能在&ldquo;服务器资源管理器&rdquo;上打开、编辑SQL CE 4数据库（就跟你现在编辑SQL 数据库一样）。这样，你就可以很容易地看到（或许做点调整）数据库结构和数据内容了。到了那时，你也可以在WebMatrix中使用数据库工具去查看SQL CE 4数据库文件的内容。</p><p>我们还没有给NerdDinners数据类指定任何自定义的数据持久化映射规则&mdash;&mdash;所以EF 代码优先类库将会根据默认的命名规范作为映射规则自动生成数据库。但是如果我们指定了任何自定义的映射规的话，EF 代码优先类库将会遵守这些规则，生成与它们匹配的数据库。</p><p>让我们回顾一下，这里是我们先前定义的两个POCO数据模型类和NerdDinners Context类：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_40.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_19.png" border="0" alt="image" title="image" width="513" height="517" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_38AF0B3C.png" target="_blank"></a></p><p>下面是我们运行应用程序后，根据上述模型类自动创建的数据库中的两个表。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_42.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_20.png" border="0" alt="image" title="image" width="174" height="116" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_2FDF02F0.png" target="_blank"></a></p><p>&ldquo;Dinners&rdquo;表的定义如下图所示。其中，列名和它的数据类型和Dinner类中定义的属性是完全对应的。DinnerID列被自动的设置成了该表的主键和唯一标识列。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_44.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_21.png" border="0" alt="image" title="image" width="340" height="318" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_3CD8E301.png" target="_blank"></a></p><p>&ldquo;RSVPs&rdquo;表的定义如下图所示。该表的列名和它的数据类型和我们在RSVP类中定义的属性也是一致的。其中，RsvpID列被设置成了该表的主键和唯一标识列。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_46.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_22.png" border="0" alt="image" title="image" width="338" height="307" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_5B4323EA.png" target="_blank"></a></p><p>在Dinners表和RSVPs表之间，一个一对多的主键/外键关系也同时被创建起来了。EF 代码优先类库自动建立了这种关联，因为Dinner类中有一个类型为ICollection&lt;RSVP&gt;的RSVPs属性，同时，RSVP类中也有一个Dinner的属性。</p><p><u>为数据库填充</u><u>餐会信息</u></p><p>现在，让我们来新建一些餐会信息并将它们写入数据库。我们可以通过点击我们首页中的&ldquo;Create New Dinner&rdquo;链接来跳转到&ldquo;新建&rdquo;页面。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_48.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_23.png" border="0" alt="image" title="image" width="573" height="492" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_6BDB1ED8.png" target="_blank"></a></p><p>当我们点击&ldquo;Create&rdquo;按钮时，新餐会将被保存到数据库。我们可以重复数次来新建多个不同的餐会。每条我们新建的餐会都将会保存在数据库中，并会被显示在首页的&ldquo;Upcoming Dinners&rdquo;（即将举办的餐会）列表中。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_50.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_24.png" border="0" alt="image" title="image" width="582" height="360" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_02B9F055.png" target="_blank"></a></p><h3>第五步：更改数据模型</h3><p>随着我们应用程序开发的推进，我们将继续改进和重构我们的模型。EF 代码优先类库包括一些很好的开发功能，这使我们在开发数据库时更容易协调某些改进。</p><p><u>给</u><u>Dinner</u><u>（餐会）模型添加一个新的属性</u></p><p>让我们对我们的Dinner类做一个简单的修改，更具体的说，我们将给Dinner类添加一个新的&ldquo;Country&rdquo;属性。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_52.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_25.png" border="0" alt="image" title="image" width="509" height="241" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_55C48D79.png" target="_blank"></a></p><p>做完改动，让我们在Virtual Studio中按下F5按钮，重新编译并运行应用程序。将会看到下面的这些错误信息：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_54.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_26.png" border="0" alt="image" title="image" width="667" height="410" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_665C8867.png" target="_blank"></a></p><p>这些错误信息之所以出现，是因为我们修改了Dinner类的结构定义，我们的模型对象现在已经不再和数据库中自动创建的Dinners表一致了。</p><p>当EF自动地为你创建数据库时，默认地会增加一个&ldquo;EdmMetadata&rdquo;表，这个表用来记录自动创建数据库时使用的模型对象的形状。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_56.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_27.png" border="0" alt="image" title="image" width="184" height="112" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_6AF29321.png" target="_blank"></a></p><p>当EF发现你修改过模型对象，并且和之前自动创建的数据库不再同步时，就会出现上面的错误消息。</p><p><u>重新同步数据模型类到数据库</u></p><p>我们有很多同步模型对像和数据库的方式：</p><ul><li>我们可以手动地更新数据库中的结构（Schema）让它们保持一致。</li><li>我们也可以先删除数据库文件，然后重新运行应用程序，让EF自动重新创建数据库。</li><li>我们也可以开启EF 代码优先功能，当数据模型发生任何改变时能够自动更新数据库 。</li></ul><p>下面，让我们在NerdDinner应用程序中看看如何使用最后一种的自动更新的方式。</p><p><u>当模型对象发生变化时重新创建数据库（</u><u>RecreateDatabaseIfModelChanges</u><u>）功能</u></p><p>在EF 代码优先类库的CTP 4版本中包括了一个非常有用的<u>开发时</u>（<em>development-time</em>）功能，它允许你在任意时刻修改数据模型类，自动重建数据库。当你开启这项功能的时候，EF能够识别用来创建数据库的类模型在何时被改动，何时可以重建你的数据库以匹配新的模型类&mdash;&mdash;你不需要做任何手工操作。</p><p>这项功能在你刚开发一个应用程序时特别实用，因为它为你快速地重构你的模型代码带来了很大的自由度和灵活性&mdash;&mdash;你根本不用去手动地保持数据库结构的同步。它特别适合SQL CE，因为SQL CE是一个基于文件的数据库而且可以随时在运行时删除和创建。这使得开发流程变得不可思议的流畅。</p><p>启用这项功能最简单的方法就是在Global.asax类中的Application_Start()事件处理函数中加上Database.SetInitializer()方法的调用。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_58.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_28.png" border="0" alt="image" title="image" width="798" height="148" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_0315FD7D.png" target="_blank"></a></p><p>这个调用告诉EF当数据模型发生任何变化时，重建NerdDinners.sdf数据库以匹配NerdDinners类。现在当我们重新运行应用程序的时候，再也不会出现提示说类模型和数据库不匹配的错误信息了。反而，EF会自动重建数据库以匹配新的数据模型类，我们的应用程序会正常运行：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_60.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_29.png" border="0" alt="image" title="image" width="551" height="299" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_6F889DDB.png" target="_blank"></a></p><p><u>为自动创建的数据库产生初始化的数据</u></p><p>在上面的截图上，你可能已经注意到我们之前添加的餐会数据在重建数据库之后就丢失了。这是因为根据模型变化自动重建数据库的功能并不适用于实际场合，此时你想将已经存在的数据从一个数据库移植到另外一个数据库中。相反，它是被设计用来适用于开发场合，我们需要数据库结构能快速地自动更新&mdash;&mdash;而不是通过手动地或指定移植规则来实现。</p><p><em>注意：我们另外正在做的工作，用来提供更好的数据移植服务，支持这种适用于产品数据和数据库结构的版本管理。但我们想这和前面讲的前期开发时（</em><em>development-time</em><em>）功能是不同的场景。这种数据移植的功能现在还不会在这个星期的</em><em>CTP</em><em>上发布。</em></p><p>其实，EF已经为我们提供了可选的 &ldquo;种子&rdquo; 功能，用以在创建或者重建数据库时产生默认或测试数据。我觉得这个功能真的很实用，因为这样一来，在我重构一个数据模型后，马上就可运行应用程序去测试&mdash;不用重新手动地输入一堆的测试数据。</p><p>我们可以通过实现一个如下所示的&ldquo;NerdDinnersIntializer&rdquo;类，将这些&ldquo;种子&rdquo;数据到加入到数据库当中。我这里用它创建两个&ldquo;示例餐会&rdquo;并把它们加入到数据库中。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_62.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_30.png" border="0" alt="image" title="image" width="696" height="485" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_18B0361A.png" target="_blank"></a></p><p>然后，我们可以在Global.asax加入Database.Initializer()方法以在启动时使用这个&ldquo;NerdDinnersInitializer&rdquo;类。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_64.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_31.png" border="0" alt="image" title="image" width="627" height="148" /></a> </p><p>现在任何时候我们更新NerdDinner模型类，数据库文件都会被删除和重建以匹配我们的模型类，同时，两条默认餐会数据也会被添加到数据库中用以测试。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_66.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_32.png" border="0" alt="image" title="image" width="590" height="332" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_3C88E7A7.png" target="_blank"></a></p><p><u>方便重构</u></p><p>上述的功能使我们非常容易地在开发时改进和重构代码&mdash;&mdash;不需要用到任何工具和脚本去手动地保持数据库结构和代码的同步。</p><p>由于我们的模型类、LINQ表达式和&ldquo;种子&rdquo;测试数据都是强类型，所以我们也可以很快速地用Visual Studio的重构工具自动在代码文件中应用所有更改。</p><h3>第六步: 加入验证规则</h3><p>我们已经创建了一个简单但很好的数据服务应用程序。</p><p>但是，这里还是有一个问题，那就是我们还没有任何地方做数据验证以确保我们填入的数据库中的数据都是正确的。让我们来搞定它。</p><p><u>用</u><u>DataAnnotations</u><u>实现数据验证</u></p><p>在基于ASP.NET MVC的应用程序中，通常加入验证规则的地方最好是数据模型。这样，可以只在一个地方进行维护，同时也使强制任何与它交互的Controller和View的遵循它。在ASP.NET MVC中，你可以通过很多种机制去实现数据验证，它可以很灵活地支持你想要使用的任何验证机制。</p><p>ASP.NET MVC 2内置支持使用.NET类库中<strong><em>S</em></strong><em>ystem.ComponentModel.DataAnnotations</em><em>的验证规则库&mdash;你可以显式地在模型类中通过验证特性（</em><em>Attribute</em><em>）来使用验证规则。你可以在</em>我之前发表的<a href="http://blog.joycode.com/scottgu/archive/2010/02/08/115873.joy" target="_blank">博客</a><em>中了解这项功能的更多信息。我们将把这种方式的优势应用到我们的</em><em>NerdDinner</em><em>应用程序中的输入数据验证上面来。</em></p><p>让我们回过头，将一些数据验证的特性加入到我们之前定义好的Dinner类的属性当中去。（注意：我们同时要加入&ldquo;using System.ComponentModel.DataAnnotations&rdquo;命名空间。）</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_68.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_33.png" border="0" alt="image" title="image" width="789" height="436" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_1ABD0F16.png" target="_blank"></a></p><p>[Required] 验证指明这个属性的数据是必须指定的（非空的）。[StringLength] 指定了该属性允许输入的最大字符串长度。[RegularExpression] 验证指定了用以验证输入匹配的正则表达式（这里我们用以验证邮件地址）。</p><p>每一个验证特性都支持&ldquo;ErrorMessage&rdquo;属性，这使得我们可以指定验证失败时显示的错误消息。你既可以通过硬编码的方式（像上面一样）指定，也可以通过让它从一个资源文件里取得&mdash;可以很容易地实现本地化。</p><p><u>引入一些</u><u>CSS</u><u>和</u><u>JavaScript</u><u>文件</u></p><p>最后一步，我们将回到Create.aspx视图模板中，加入&lt;link&gt;引用Site.css文件到项目中，同时也加入两个&lt;script&gt;元素引用两个JavaScript文件。我们还在&lt;form&gt;元素呈现之前加入一行代码来调用Html.EnableClientValidation()方法。</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_70.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_34.png" border="0" alt="image" title="image" width="713" height="211" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_71D1FA0C.png" target="_blank"></a></p><p>这些改动将会确保那些验证错误信息以正确的样式显示出来（让它们更惹眼），而且这些数据模型的验证规则会同时应用在客户端和服务器端。</p><p><u>运行应用程序</u></p><p>让我们重新运行应用程序并尝试注册一个新的餐会。让我们先按一下还没有填写数据时的&quot;创建&quot;按钮。现在我们会发现模型中的验证错误消息在浏览器中已经显示出来：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_72.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_35.png" border="0" alt="image" title="image" width="589" height="499" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_76D437BB.png" target="_blank"></a></p><p>由于我们在ASP.NET MVC中启用了客户端验证（即我们上面所写的代码中的一行)，我们的错误消息将会实时更新：</p><p><a href="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_74.png" target="_blank"><img style="display: inline; border: 0px" src="http://blog.joycode.com/images/metaapis/158/WindowsLiveWriter/EntityFramework4_E2B3/image_thumb_36.png" border="0" alt="image" title="image" width="589" height="499" /></a> </p><p><a href="http://weblogs.asp.net/blogs/scottgu/image_549C2C35.png" target="_blank"></a></p><p>注意上面，当我们给&rdquo;Title&rdquo;输入的字符串长度大于20的时候，验证错误信息改变的方式。这是因为我们为Dinner.Title设置的验证[StringLength]特性指明了最大允许的长度是20。而当我们开始在&ldquo;HostedBy&rdquo;文本框中输入字符串时，错误信息从&ldquo;[Requred]&rdquo;（要求你输入电子邮件地址）变成了&ldquo;[RegularExpression]&rdquo;（它告诉我们没有输入一个有效的电子邮件地址）。</p><p>这些验证规则在浏览器中（通过 JavaScript）和服务器上（即使有人试图绕过JavaScript 验证，也能保护数据的输入有效性）都有效&mdash;&mdash;不用我们对Controller类作任何更改。这种将规则在我们的模型类内指定一次就可以被应用到处任何地方的能力是极其强大的&mdash;&mdash;将使我们能够以一种非常清楚的方式继续改进我们的程序。</p><p>你可以通过<a href="http://blog.joycode.com/scottgu/archive/2010/02/08/115873.joy" target="_blank">这里</a>了解更详细的有关这些 ASP.NET MVC 2 模型验证功能和它们的工作方式。</p><h3><strong><u>下载</u></strong><strong></strong></h3><p><a href="http://www.scottgu.com/blogposts/nerddinnerreloaded.zip" target="_blank">点击这里</a>下载和运行我们在这篇博客里实现的NerdDinnerReloaded示例。你需要安装了VS 2010 (或者免费的Visual Web Developer 2010 Express) 。</p><p><strong>重要提示</strong>：你必须在你的机子上<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0d2357ea-324f-46fd-88fc-7364c80e4fdb&amp;displaylang=en" target="_blank">下载和安装SQL CE 4</a>后才能运行上面的示例程序。你可以从<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=4e094902-aeff-4ee2-a12d-5881d4b0dd3e&amp;displaylang=en" target="_blank">这里</a>下载EF 代码优先类库。这两个下载都不会对你的机器有太大的影响。</p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/scottgu/" rel="tag">scottgu</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/nerd/" rel="tag">nerd</a> , <a href="http://www.gaobo.info/go.php/tags/dinner/" rel="tag">dinner</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/705.htm</link>
<title><![CDATA[.NET Framework 4.0 Client Profile]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Wed, 21 Apr 2010 04:26:37 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/705.htm</guid> 
<description>
<![CDATA[ 
	<p>Visual Studio 2010如期发布了，我怀着迫不及待的心情马上下载了最新的ISO来安装和感受一下。</p><p>.NET Framework 自从 2002 年发展至今，已经历了好几个版本，1.0, 1.1, 2.0, 3.0, 3.5 等不同的版本更替，.NET Framework 的Redistributable Package也愈来愈大，到了 .NET Framework 3.5 SP1 时已经膨胀到 231MB，除非软件本身就很大，不然对于 .NET 软件的Redistribute是相当不利的，除非客户端本身就有安装 .NET Framework，否则几乎都要夹带一个 .NET Framework 的Redistributable Package，如果只是一个小小的应用程序文件 (几十或几百KB) 还要夹一个那 大的 .NET Framework Redistributable Package，大概很多开发人员都会觉得麻烦，就算开发人员接受，但在企业网络的 IT 管理人员就不一定会接受了 &hellip; 所以 .NET Framework 的减肥一直都是 .NET 开发人员的愿望与期待，而 .NET Framework Client Profile 就是微软针对这个需要的主要响应。既然 .NET 应用程序不一定会用到所有的 .NET Class Library，那微软就将 .NET Framework 部份不常用的功能由主函数库中抽离出来，让Redistributable Package可以缩小，有利于重新发布应用程序。</p><p>.NET Framework Client Profile 在 .NET 3.5 时首次和开发人员见面，但是碍于它只能利用 ClickOnce 部署方式安装，因此使用它的开发人员不多，且也有许多人反应希望将 .NET Framework Client Profile 能够利用光盘或其他储存媒体转散布，微软从善如流，将 .NET Framework 4.0 的 Client Profile 改成Redistributable Package。</p><p>The .NET Framework 4 Client Profile 包含下列功能：</p><ul><li>Common Language Runtime (CLR) </li><li>ClickOnce </li><li>Windows Forms </li><li>Windows Presentation Foundation (WPF) </li><li>Windows Communication Foundation (WCF) </li><li>Entity Framework </li><li>Windows Workflow Foundation </li><li>语音 </li><li>XSLT 支援 </li><li>LINQ to SQL </li><li>Entity Framework 与 WCF Data Services 执行期设计函式库 </li><li>Managed Extensibility Framework (MEF) </li><li>动态型别 </li><li>并列程序设计功能，例如 Task Parallel Library (TPL), Parallel LINQ (PLINQ), and Coordination Data Structures (CDS) </li><li>除错客户端应用程序 </li></ul><p>下列功能不包含，要另外安装 .NET Framework 4.0 的完整版本：</p><ul><li>ASP.NET </li><li>进阶 Windows Communication Foundation (WCF) 功能 </li><li>.NET Framework Data Provider for Oracle </li><li>编译用 MSBuild </li><li>Visual Studio 2010 的项目中，下列应用程序会默认使用 .NET Framework 4.0 Client Profile，若要使用完整的 .NET Framework 功能，则要自行到项目属性中设定 target framework 至 .NET Framework 4.0： </li><li>Windows Projects (C# and Visual Basic) </li><li>Windows Presentation Foundation </li><li>WPF Application </li><li>WPF Browser Application </li><li>WPF Custom Control Library </li><li>WPF User Control Library </li><li>Windows Forms </li><li>Windows Forms Application </li><li>Windows Forms Control Library </li><li>Console Application </li><li>Empty Project </li><li>Window Service </li><li>Visual F# </li><li>F# Application </li><li>F# Tutorial </li><li>Workflow (C# and Visual Basic) </li><li>Activity Designer Library </li><li>Activity Library </li><li>Workflow Console Application </li><li>Windows Communication Foundation </li><li>WCF Service Library </li><li>Office 2007 and Office 2010 </li><li>All projects target the .NET Framework 4 Client Profile </li></ul><p><a rel="lightbox" href="file:///C:/Users/Administrator/AppData/Local/Temp/WindowsLiveWriter-429641856/supfiles5CAF64E/image[2].png"></a><img class="insertimage" src="attachment.php?fid=92" border="0" /> </p><p>而 .NET Framework 4.0 Client Profile 与原有的 .NET Framework 3.5 Client Profile 不同的地方有：</p><ul><li>3.5 版本的 Client Profile 只能使用在 Web (ClickOnce)，4.0 版本则因为具有Redistributable Package，所以可同时适用于本机或 Web 安装。 </li><li>3.5 版本只支持 x86 的 Windows XP SP2/SP3，4.0 版本则支持除了 IA64 以外，.NET Framework 4 支持的所有平台。 </li><li>3.5 版本的 Client Profile 与 .NET Framework 3.5 是分开的版本，4.0 版则为 .NET Framework 4.0 完整功能的子集。 </li><li>3.5 版本会受 Windows Update 的影响自动升级到 .NET Framework 3.5，4.0 版则可以在不需要完整 .NET Framework 4.0 下自行运作，也可以分开提供服务。 </li></ul><p>不过也因为如此，当在 Visual Studio 2010 建立新项目时，如果发现 [添加引用] 中没有列出原本应该列出的组件时，可以先检查是否是项目的 target framework 设成了 .NET 4.0 Client Profile (例如 System.Web.dll 就不在 .NET 4.0 Client Profile 套件中)。</p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/client/" rel="tag">client</a> , <a href="http://www.gaobo.info/go.php/tags/profile/" rel="tag">profile</a> , <a href="http://www.gaobo.info/go.php/tags/visual/" rel="tag">visual</a> , <a href="http://www.gaobo.info/go.php/tags/studio/" rel="tag">studio</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/702.htm</link>
<title><![CDATA[WPF+C#实现获取和改变屏幕分辨率]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Tue, 23 Mar 2010 05:36:01 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/702.htm</guid> 
<description>
<![CDATA[ 
	最近做的一个WPF的东西要求程序启动的时候改变屏幕分辨率到1024*768，在程序退出的时候还原回之前的分辨率，看似简单的功能，我研究了下，发现也不是很简单的。<br/>开始用了网上搜到的最常见的代码，是一个名为SettingDisplay的类，调用SettingDisplay.SettingDisplay.ChangeRes()即可设置分辨率，结果设置到1024*768没问题，改回来就死活不行，不知道为什么，很奇怪。后来找到下边这个代码，用其中的Resolution类解决了：先new一个Resolution类的对象，然后调用setResolution()方法即可。<br/><a href="attachment.php?fid=91">点击这里下载文件</a><br/>在WPF下，设置App.xaml的Application的属性：<br/><div class="code">Startup=&quot;Application_Startup&quot; Exit=&quot;Application_Exit&quot; ShutdownMode=&quot;OnLastWindowClose&quot;</div><br/>设置分辨率的代码写在“Application_Startup”和“Application_Exit”方法里。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/wpf/" rel="tag">wpf</a> , <a href="http://www.gaobo.info/go.php/tags/resolution/" rel="tag">resolution</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%2588%2586%25E8%25BE%25A8%25E7%258E%2587/" rel="tag">分辨率</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25B1%258F%25E5%25B9%2595/" rel="tag">屏幕</a> , <a href="http://www.gaobo.info/go.php/tags/display/" rel="tag">display</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/687.htm</link>
<title><![CDATA[敏捷项目延迟的原因（转帖）]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Tue, 29 Dec 2009 02:13:26 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/687.htm</guid> 
<description>
<![CDATA[ 
	<p>通常意义上的<a id="fcvh" href="http://en.wikipedia.org/wiki/Delay" target="_blank" title="延迟">延迟</a>，是指某件事完成得比预期晚，因此造成压力和不便。 在敏捷的术语中，延迟同样也被看做是浪费。延迟会造成工作不能延续，因此带来其他浪费，比如重新学习、任务切换等等。</p><p><a id="vc36" href="http://blog.agilebuddy.com/about.html" target="_blank" title="Jack Milunsky">Jack Milunsky</a>将<a id="vxdj" href="http://blog.agilebuddy.com/2009/09/the-7-software-development-wastes-lean-series-part-6-delays.html" target="_blank" title="常见的延迟归为以下几类">常见的延迟归为以下几类</a>：</p><ul><li><strong>项目批准过程</strong>&mdash;&mdash;开发人员坐等项目得到批准，由此造成时间和金钱的浪费。 </li><li><strong>等待需求的正确优先级</strong>&mdash;&mdash;这样工作才能开始推进。 </li><li><strong>等待可用的资源</strong>&mdash;&mdash;这常常标志着组织需要反省自己是不是承接了太多工作。 </li><li><strong>变更批准流程</strong>&mdash;&mdash;该流程本身就是浪费。如果发生次数太多，就该考虑缩短sprint长度了。 </li><li><strong>在制品增加</strong>&mdash;&mdash;在制品越多，开发人员要想将代码发布到生产环境，要等待的时间也就越长。 </li><li><strong>客户签收验收测试时的延迟</strong>&mdash;&mdash;不仅在这方面，还包括让客户解决需求问题、提供演示反馈等方面。 </li></ul><p>Jack提到：在sprint之间也有很多延迟。团队应该认真投入精力，识别并根除这些延迟。他建议：</p><blockquote>必须保证backlog得到正确的&ldquo;看护&rdquo;。要有一个高效的产品负责人，他能理解市场和客户。你还需要写得很好的用户故事。要尽早从开发人员那里得到估算，这样产品负责人才能在规划会议之前做出决策。这都是为了&ldquo;防&lsquo;延迟&rsquo;于未然&rdquo;，保证在所有的转换点上，工作都能得到顺利交接。把这个端到端的过程勾画出来，识别出各个转换点上的延迟，这样做很有价值。 </blockquote><p><a id="p5bx" href="http://www.pmhut.com/?s=%22Wouter+Baars%22" target="_blank" title="Wouter Baars">Wouter Baars</a>也提出了<a id="oowo" href="http://www.pmhut.com/top-11-causes-of-delays-in-it-projects" target="_blank" title="IT项目延迟最主要的几个原因">IT项目延迟最主要的几个原因</a>，其中包括：</p><ul><li><strong>画蛇添足</strong>&mdash;&mdash;团队花费太多时间去增强客户没有要求的功能。 </li><li><strong>忽略质量控制</strong>&mdash;&mdash;时间压力有时会让程序员或项目团队有意跳过测试过程。相对其减少的延迟，这常常会导致更多延迟。 </li><li><strong>同时开发多个项目</strong>&mdash;&mdash;任务切换会<a id="z6lo" href="http://www.infoq.com/news/2009/09/study-multitasking-performance" target="_blank" title="招致更多问题，而不是解决问题">招致更多问题，而不是解决问题</a>。 </li><li><strong>&ldquo;一劳永逸&rdquo;症状</strong>&mdash;&mdash;试图将一种现有的解决方案用在任何新问题上。 </li><li><strong>平庸的人员素质</strong>&mdash;&mdash;人员在技术或流程方面的能力不足会导致多个层面的延迟。 </li><li><strong>客户无法实现承诺</strong>&mdash;&mdash;当客户无法在他们必须参与的工作中及时响应时，项目会陷于停滞。 </li><li><strong>客户和开发人员之间的关系紧张</strong>&mdash;&mdash;如果项目进展不顺利，&ldquo;不和谐&rdquo;会导致更多延迟。这会破坏彼此之间的信任感，影响工作气氛。 </li></ul><p>Robert Neri提出另一个造成延迟的有趣原因，他指出：<a id="urcv" href="http://blog.outsystems.com/mt/mt-search.cgi?blog_id=2&amp;tag=agile%20project%20management&amp;limit=20" title="企业中敏捷实施的差异">企业中敏捷实施的差异</a>可能导致延迟。他提到：</p><blockquote>我们常常遇到这种情况：支持部门无法做到项目sprint那么快的速度，因此会造成敏捷项目延迟。类似地，非敏捷项目难以和敏捷项目整合。 </blockquote><p>因此，如果你的敏捷项目延迟了，看看是不是由于上面这些常见的原因。一旦你识别出了根源，赶紧想办法解决才是明智之道。这会去除项目中最大的一个浪费。<br /><br />（From InfoQ）</p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/xp/" rel="tag">xp</a> , <a href="http://www.gaobo.info/go.php/tags/agile/" rel="tag">agile</a> , <a href="http://www.gaobo.info/go.php/tags/delay/" rel="tag">delay</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%2595%258F%25E6%258D%25B7/" rel="tag">敏捷</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25BB%25B6%25E8%25BF%259F/" rel="tag">延迟</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/684.htm</link>
<title><![CDATA[在Windows Vista以后版本系统中自动保存TFS的账号密码]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Wed, 09 Dec 2009 07:31:51 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/684.htm</guid> 
<description>
<![CDATA[ 
	其实很简单：<br />打开&ldquo;控制面板&rdquo;&mdash;&ldquo;用户账户&rdquo;&mdash;&ldquo;凭据管理器&rdquo;，添加一个Windows凭据：<br />地址：（这里一定要写TFS的机器名称，就是在hosts文件中做静态对应的那个机器名称，写IP地址是无法成功滴<img src="images/emot/grin.gif" border="0" width="24" height="24" />）<br />用户名：甲乙丙丁<br />密码：ABCD<br />打完收工&hellip;&hellip;<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/windows/" rel="tag">windows</a> , <a href="http://www.gaobo.info/go.php/tags/vista/" rel="tag">vista</a> , <a href="http://www.gaobo.info/go.php/tags/seven/" rel="tag">seven</a> , <a href="http://www.gaobo.info/go.php/tags/tfs/" rel="tag">tfs</a> , <a href="http://www.gaobo.info/go.php/tags/team/" rel="tag">team</a> , <a href="http://www.gaobo.info/go.php/tags/foundation/" rel="tag">foundation</a> , <a href="http://www.gaobo.info/go.php/tags/server/" rel="tag">server</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%2587%25AD%25E6%258D%25AE/" rel="tag">凭据</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%2587%25AD%25E6%258D%25AE%25E7%25AE%25A1%25E7%2590%2586%25E5%2599%25A8/" rel="tag">凭据管理器</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/683.htm</link>
<title><![CDATA[自动化测试工具汇总]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Sun, 06 Dec 2009 08:41:50 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/683.htm</guid> 
<description>
<![CDATA[ 
	<span>自动化测试工具可以减少测试工作量，提高测试工作效率，但首先是能够选择一个合适的且满足企业信息系统工程环境的自动化测试工具，因为不同的测试工具，其面向的测试对象是不一样的。按照测试工具的主要用途和应用领域，可以将自动化测试工具分为以下几类</span><span>:<br /></span><span><br /></span><strong><span>负载压力测试</span></strong><strong><span><br /></span></strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>LoadRunner </span><span>特点</span><span>a</span><span>，支持的协议多且个别协议支持的版本比较高；特点</span><span>b</span><span>，负载压力测试方案设置灵活；特点</span><span>c</span><span>，丰富的资源监控；特点</span><span>d</span><span>，报告可以导出到</span><span>Word</span><span>、</span><span>Excel</span><span>以及</span><span>HTML</span><span>格式。</span><span> <span><br /></span></span><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>QALoad (1).</span><span>测试接口多；</span><span>(2)</span><span>可预测系统性能；</span><span>(3)</span><span>通过重复测试寻找瓶颈问题；</span><span>(4)</span><span>从控制中心管理全局负载测试；</span><span>(5)</span><span>可验证应用的扩展性；</span><span>(6)</span><span>快速创建仿真的负载测试；</span><span>(7)</span><span>性能价格比较高。此外，</span><span>QALoad</span><span>不单单测试</span><span>Web</span><span>应用，还可以测试一些后台的东西，比如</span><span>SQL Server</span><span>等。只要它支持的协议，都可以测试。</span><span> <span><br /></span></span><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Benchmark Factory </span><span>首先它可以测试服务器群集的性能；其次，可以实施基准测试；最后，可以生成高级脚本。</span><span> <span><br /></span></span><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>SilkPerformance</span><span>：</span><span> <span><br /></span></span><span><span>5.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>E-Test Suite </span><span>由</span><span>Empirix</span><span>公司开发的测试软件，能够和被测试应用软件无缝结合的</span><span>Web</span><span>应用测试工具。工具包含</span><span>e-Tester</span><span>、</span><span>e-Load</span><span>和</span><span>e-Monitor</span><span>，这三种工具分别对应功能测试、压力测试以及应用监控，每一部分功能相互独立，测试过程又可彼此协同。</span><span> <span><br /></span></span><span><span>6.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>JMeter </span><span>是一个专门为运行和服务器负载测试而设计、</span><span>100%</span><span>的纯</span><span>Java</span><span>桌面运行程序。原先它是为</span><span>Web/HTTP</span><span>测试而设计的，但是它已经扩展以支持各种各样的测试模块。它和</span><span>HTTP</span><span>和</span><span>SQL(</span><span>使用</span><span>JDBC)</span><span>的模块一起运行。它可以用来测试静止或活动资料库中的服务器运行情况，可以用来模拟服务器或网络系统在重负载下的运行情况。它也提供了一个可替换的界面用来定制数据显示，测试同步及测试的创建和执行。</span><span> <span><br /></span></span><span><span>7.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>WAS </span><span>是</span><span>Micro$oft</span><span>提供的免费的</span><span>Web</span><span>负载压力测试工具，应用广泛。</span><span>WAS</span><span>可以通过一台或者多台客户机模拟大量用户的活动。</span><span>WAS</span><span>支持身份验证、加密和</span><span>Cookies</span><span>，也能够模拟各种浏览器和</span><span>Modem</span><span>速度，它的功能和性能可以与数万美元的产品媲美。</span><span> <span><br /></span></span><span><span>8.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>ACT </span><span>或称</span><span>MSACT</span><span>，它是微软的</span><span>Visual Studio</span><span>和</span><span>Visual Studio.net</span><span>带的一套进行程序压力测试的工具。</span><span>ACT</span><span>不但可以记录程序运行的详细数据参数，用图表显示程序运行情况，而且安装和使用都比较简单，结果阅读叶很方便，是一套较理想的测试工具。</span><span> <span><br /></span></span><span><span>9.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>OpenSTA </span><span>它的全称是</span><span>Open System Testing Architecture</span><span>。</span><span>OpenST</span><span>的特点是可以模拟很多用户来访问需要测试的网站，它是一个功能强大、自定义设置功能完备的软件。但是，这些设置大部分需要通过</span><span>Script</span><span>来完成，因此在真正使用这个软件之前，必须学习好它的</span><span>Script</span><span>编写。如果需要完成很复杂的功能，</span><span>Script</span><span>的要求还比较高。当然这也是它的优点，一些程序员不会在意编写</span><span>Script</span><span>的。</span><span> <span><br /></span></span><span><span>10.<span>&nbsp;&nbsp; </span></span></span><span>PureLoad </span><span>一个完全基于</span><span>Java</span><span>的测试工具，它的</span><span>Script</span><span>代码完全使用</span><span>XML</span><span>。所以，编写</span><span>Script</span><span>很简单。它的测试包含文字和图形并可以输出为</span><span>HTML</span><span>文件。由于是基于</span><span>Java</span><span>的软件，因此</span><span>PureLoad</span><span>可以通过</span><span>Java Beans API</span><span>来增强软件功能。</span><span> <span><br /></span></span><strong><span>功能测试</span></strong><strong><span><br /></span></strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>WinRunner </span><span>企业级的功能测试工具，用于检测应用程序是否能够达到预期的功能及正常运行，自动执行重复任务并优化测试工作，从而缩短测试时间。通过自动录制、检测和回防用户的应用操作，从而提高测试效率。</span><span> <span><br /></span></span><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>QARun </span><span>一款自动回归测试工具，与</span><span>Winrunner</span><span>比较学习成本要低很多。不过要安装</span><span>QARun</span><span>必须安装</span><span>.net</span><span>环境，另外它还提供与</span><span>TestTrack Pro</span><span>的集成。</span><span> <span><br /></span></span><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Rational Robot </span><span>我经常使用的测试工具，属于</span><span>Rational TestSuite</span><span>中的一员，对于</span><span>Visual studio 6</span><span>编写的程序支持的非常好，同时还支持</span><span>Java Applet</span><span>、</span><span>HTML</span><span>、</span><span>Oracle Forms</span><span>、</span><span>People Tools</span><span>应用程序的支持。要支持</span><span>Delphi</span><span>程序的测试还必须下载插件。</span><span>Rational Robot</span><span>的语法使用</span><span>Basic</span><span>语法，它的语言使用</span><span>SQABasic</span><span>。</span><span> <span><br /></span></span><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Functional Tester </span><span>它是</span><span>Robot</span><span>的</span><span>Java</span><span>实现版本，在</span><span>Rational</span><span>被</span><span>IBM</span><span>收购后发布的。在</span><span>Java</span><span>的浪潮下，</span><span>Robot</span><span>被移植到了</span><span>Eclipse</span><span>平台，并完全支持</span><span> Java</span><span>和</span><span>.net</span><span>。可以使用</span><span>VB.net</span><span>和</span><span>Java</span><span>进行脚本的编写，当然了录下脚本让后做做修改是最爽的事情了。由于支持</span><span>Java</span><span>，那么对测试脚本进行测试也变成了可能。更多的信息请到</span><span>IBM developerworks</span><span>上查看，另外还提供试用版本下载。</span><span> <span><br /></span></span><strong><span>白盒测试</span></strong><strong><span><br /></span></strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Logiscope <br /></span><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>PRQA <br /></span><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Junit <br /></span><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>DevPartner <br /></span><span><span>5.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Rational Purify <br /></span><strong><span>测试管理</span></strong><strong><span><br /></span></strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>TestDirector MI</span><span>的测试管理工具，可以与</span><span>winrunner</span><span>、</span><span>Loadrunner</span><span>、</span><span>QuickTestPro</span><span>进行集成。除了可以跟踪</span><span>Bug</span><span>外，还可以编写测试用例、管理测试进度等等，是测试管理的首选软件。</span><span> <span><br /></span></span><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>TestManager Rational Testsuite</span><span>中的一员，可以用来编写测试用例、生成</span><span>Datapool</span><span>、生成报表、管理缺陷以及日志等等。是一个企业级的强大测试管理工具。缺点是必须和其它组件一起使用，测试成本比较高。</span><span> <span><br /></span></span><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>TrackRecord </span><span>一款擅长于</span><span>Bug</span><span>管理的工具，与</span><span>TestDirecotr</span><span>和</span><span>Testmanager</span><span>比较起来是很</span><span>light</span><span>的。不过至今还没有配成功过。</span><span>:( <br /></span><span><span>4.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Bugzilla </span><span>一个产品缺陷的记录及跟踪工具，它能够为你建立一个完善的</span><span>Bug</span><span>跟踪体系，包括报告、查询并产生报表、处理解决等几个部分。它的主要特点为：基于</span><span>Web</span><span>方式，安装简单；有利于缺陷的清楚传达；系统灵活，可配置性很强；自动发送</span><span>Email</span><span>。</span><span> <span><br /></span></span><span><span>5.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Jira </span><span>是一个</span><span>Bug</span><span>管理工具，自带一个</span><span>Tomcat 4</span><span>；同时有简单的工作流编辑，可用来定制流程；数据存储在</span><span>HSQL</span><span>数据引擎中，因此只要安装了</span><span>JDK</span><span>这个工具就可以使用。相比较</span><span>Bugzilla</span><span>来说有不少自身的特点，不过可惜它并不是开源工具，有</span><span>Lisence</span><span>限制。</span><span> <span><br /></span></span><strong><span>测试辅助</span></strong><strong><span><br /></span></strong><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>SmartDraw </span><span>用于绘制</span><span>UCML</span><span>，进行负载压力测试需求分析。对压力测试测试前的工作很有帮助。</span><span> <span><br /></span></span><p class="MsoListParagraph"><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>SDemo </span><span>我个人比较喜欢用这个工具，可以将操作录成</span><span>EXE</span><span>文件，并回放出来。这样就避免了那些偶尔才出现的</span><span>Bug</span></p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/%25E8%2587%25AA%25E5%258A%25A8%25E5%258C%2596/" rel="tag">自动化</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%25B5%258B%25E8%25AF%2595/" rel="tag">测试</a> , <a href="http://www.gaobo.info/go.php/tags/automation/" rel="tag">automation</a> , <a href="http://www.gaobo.info/go.php/tags/test/" rel="tag">test</a> , <a href="http://www.gaobo.info/go.php/tags/tools/" rel="tag">tools</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25B7%25A5%25E5%2585%25B7/" rel="tag">工具</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/682.htm</link>
<title><![CDATA[用一个小例子来说明手工测试，自动化测试，系统命令，编程语言，API的关系]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Sun, 06 Dec 2009 08:21:06 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/682.htm</guid> 
<description>
<![CDATA[ 
	有两个计算机帐号，A和B。我们需要用B帐号进行系统的设置，也就是测试的准备工作，然后用A帐号来进行测试。下边来说一下不同水平的人是如何进行自动化的。 <p>1. 手工测试人员</p><ul><li>Log on B </li><li>Configure </li><li>Log out </li><li>Log on A </li><li>Test </li></ul><p>2. 初级自动化人员（直接把手工case转成自动化）</p><ul><li>Set autologon B </li><li>Set autorun </li><li>Record test status: 0 </li><li>Logout </li><li>Check status </li></ul><blockquote><p>if(status==0) <br />&#123; <br />Configure <br />Set autologon A <br />Record test status:1 <br />Logout <br />&#125;</p></blockquote><blockquote><p>if(status==1) <br />&#123; <br />Test <br />&#125;</p><p>这个级别的人，需要懂得脚本编程，需要懂得系统设置，autologon and autorun。</p></blockquote><p>3. 有一定经验的自动化人员（改变手工测试case以利于自动化的更简单，可靠的实现）</p><ul><li><p>不需要log out and log on</p></li><li><p>利用Windows命令Runas</p></li><li><p>用高级语言调用Runas</p></li><li><p>利用重定向来输入Password</p></li></ul><blockquote><p>这个级别的人，需要懂得高级语言，重定向，Windows系统命令Runas</p></blockquote><p>4. 中级自动化人员（具有更丰富的开发经验，可以用程序代替UI和系统命令）</p><ul><li>不需要Runas命令 </li><li>利用.NET的Process对象 </li><li>用B的身份生成一个Process来进行配置工作 </li></ul><blockquote><p>这个级别的人，要比较熟悉高级语言，比较熟悉高级语言的类库，懂得操作系统的内核基本概念</p></blockquote><p>5. 高级自动化人员（精通高级语言，精通操作系统内核）</p><ul><li>不需要多生成一个进程 </li><li>用本线程impersonate用户B </li><li>利用.NET WindowsIdentity 对象 </li><li>必须要调用Windows API，LogonUser </li></ul><blockquote><p>这个级别的人，要精通C/C++和Java，C#等高级语言，精通Windows内核的知识和Windows API</p></blockquote><p>从以上的例子可以看到，针对同一个test case，不同的测试人员，从手工到高级自动化，由于自己知识面的原因，会设计出非常不同的case出来。越高级的自动化越灵活，稳定，可靠，也更需要掌握更多的开发和内核的知识。因此，我们看到很多人在强烈的否定自动化，你先看看他到底在哪个层次中。越下边层次的自动化人员，由于技术的原因，碰到的问题会越多，能解决的问题却越少，因此对自动化的抱怨也就越大了。这些都是可以理解的，不过以此来否定自动化，我觉得还是不太应该，毕竟自己技术还不过关。</p><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/%25E8%2587%25AA%25E5%258A%25A8%25E5%258C%2596/" rel="tag">自动化</a> , <a href="http://www.gaobo.info/go.php/tags/automation/" rel="tag">automation</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%25B5%258B%25E8%25AF%2595/" rel="tag">测试</a> , <a href="http://www.gaobo.info/go.php/tags/test/" rel="tag">test</a> , <a href="http://www.gaobo.info/go.php/tags/case/" rel="tag">case</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/675.htm</link>
<title><![CDATA[C#/.NET Winform获取本机的公网IP地址的简单方法]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Thu, 05 Nov 2009 12:31:33 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/675.htm</guid> 
<description>
<![CDATA[ 
	获取本机（网关）的外网IP，在C#里面实现的方法，通常是遍历获取到的本机的IP地址，然后判断，不过这种方式只能取得独立拨号或具有独立公网IP的地址，对于局域网的方式，是取不到的，这种方式的代码大致如下：<br/><div class="code">System.Net.IPHostEntry ips = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());<br/>foreach (System.Net.IPAddress ip in ips.AddressList)<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(ip.ToString());<br/>&#125;</div><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/winform/" rel="tag">winform</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%259C%25AC%25E6%259C%25BA/" rel="tag">本机</a> , <a href="http://www.gaobo.info/go.php/tags/localhost/" rel="tag">localhost</a> , <a href="http://www.gaobo.info/go.php/tags/ip/" rel="tag">ip</a> , <a href="http://www.gaobo.info/go.php/tags/address/" rel="tag">address</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/664.htm</link>
<title><![CDATA[Entity Framework中出现已有打开的与此命令相关联的 DataReader，必须首先将它关闭。的解决方案]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Tue, 13 Oct 2009 07:02:49 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/664.htm</guid> 
<description>
<![CDATA[ 
	解决方案有两种：<br />1、数据库为SQL Server 2005版本时，可以在web.config数据库链接串中加入<span>MultipleActiveResultSets=true。<br /></span><span>2、进行重复操作之前，将数据查询结果放入内存中，再进行使用。<br /><br />参考：<br /><a href="http://www.cnblogs.com/china0zzl/archive/2009/08/06/1540025.html"><a href="http://www.cnblogs.com/china0zzl/archive/2009/08/06/1540025.html" target="_blank">http://www.cnblogs.com/china0zzl/archive/2009/08/06/1540025.html</a></a><br /><a href="http://www.netknowledgenow.com/blogs/onmaterialize/archive/2006/09/20/Fixing-the-_2200_There-is-already-an-open-DataReader-associated-with-this-Command-which-must-be-closed-first_2E002200_-exception-in-Entity-Framework.aspx"><a href="http://www.netknowledgenow.com/blogs/onmaterialize/archive/2006/09/20/Fixing-the-_2200_There-is-already-an-open-DataReader-associated-with-this-Command-which-must-be-closed-first_2E002200_-exception-in-Entity-Framework.aspx" target="_blank">http://www.netknowledgenow.com/blogs/onmaterialize/archive/2006/09/20/Fixing-the-_2200_There-is-already-an-open-DataReader-associated-with-this-Command-which-must-be-closed-first_2E002200_-exception-in-Entity-Framework.aspx</a></a></span><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/asp/" rel="tag">asp</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/mvc/" rel="tag">mvc</a> , <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/datareader/" rel="tag">datareader</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/660.htm</link>
<title><![CDATA[C#(ASP.Net)获取当前路径的方法集合]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Tue, 06 Oct 2009 10:59:35 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/660.htm</guid> 
<description>
<![CDATA[ 
	//获取当前进程的完整路径，包含文件名(进程名)。<br/>string str = this.GetType().Assembly.Location;<br/>result: X:&#92;xxx&#92;xxx&#92;xxx.exe (.exe文件所在的目录+.exe文件名)<br/><br/>//获取新的 Process 组件并将其与当前活动的进程关联的主模块的完整路径，包含文件名(进程名)。<br/>string str = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;<br/>result: X:&#92;xxx&#92;xxx&#92;xxx.exe (.exe文件所在的目录+.exe文件名)<br/><br/>//获取和设置当前目录（即该进程从中启动的目录）的完全限定路径。<br/>string str = System.Environment.CurrentDirectory;<br/>result: X:&#92;xxx&#92;xxx (.exe文件所在的目录)<br/><br/>//获取当前 Thread 的当前应用程序域的基目录，它由程序集冲突解决程序用来探测程序集。<br/>string str = System.AppDomain.CurrentDomain.BaseDirectory;<br/>result: X:&#92;xxx&#92;xxx&#92; (.exe文件所在的目录+"&#92;")<br/><br/>//获取和设置包含该应用程序的目录的名称。<br/>string str = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;<br/>result: X:&#92;xxx&#92;xxx&#92; (.exe文件所在的目录+"&#92;")<br/><br/>//获取启动了应用程序的可执行文件的路径，不包括可执行文件的名称。<br/>string str = System.Windows.Forms.Application.StartupPath;<br/>result: X:&#92;xxx&#92;xxx (.exe文件所在的目录)<br/><br/>//获取启动了应用程序的可执行文件的路径，包括可执行文件的名称。<br/>string str = System.Windows.Forms.Application.ExecutablePath;<br/>result: X:&#92;xxx&#92;xxx&#92;xxx.exe (.exe文件所在的目录+.exe文件名)<br/><br/>//获取应用程序的当前工作目录(不可靠)。<br/>string str = System.IO.Directory.GetCurrentDirectory();<br/>result: X:&#92;xxx&#92;xxx (.exe文件所在的目录)<br/>========================================================<br/>.NET中三种获取当前路径的代码<br/><br/>//Web编程 <br/>HttpContext.Current.Server.MapPath("FileName") <br/>System.Web.HttpContext.Current.Request.Path <br/><br/>//Windows编程 <br/>System.Environment.CurrentDirectory <br/><br/>//Mobile编程 <br/>Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);<br/><br/>A.指定 客户端元素 资源的路径 <br/>B.指定 服务器控件 资源的路径 <br/>C.确定当前网站的物理文件路径 <br/><br/>============================ <br/><br/>使用网站中的资源时，通常必须指定资源的路径。 <br/>例如，您可以使用 URL 路径引用页面中的图像文件或网站中其他位置处的页面的 URL。 <br/>同样，Web 应用程序中的代码可以使用基于服务器的文件的物理文件路径对文件进行读写操作。 <br/>ASP.NET 提供用于引用资源并确定应用程序中的页面或其他资源的路径的方法。 <br/><br/><br/>A.指定 客户端元素 资源的路径 <br/>------------------------------ <br/><br/>许多情况下，页面中的元素或控件必须引用外部资源，如文件。 <br/>ASP.NET 允许您通过各种方法引用外部资源。 <br/>所选方法取决于使用客户端元素还是服务器控件。 <br/><br/>元素（不是页面中的服务器控件，而是客户端元素）以原样传递给浏览器。 <br/>因此，从客户端元素中引用资源时，应根据 HTML 中 URL 的标准规则构造路径。 <br/>可以使用完全限定（绝对）URL 路径，也可以使用各种类型的相对路径。 <br/>例如，如果页面包含一个 img 标记，则可以使用以下路径之一设置其 src 属性： <br/><br/>绝对 URL 路径： <br/>阅读代码编辑代码运行效果复制HTML代码保存代码<img src="http://www.xxx.com/MyApplication/Images/SampleImage.jpg" /><img src="http://www.xxx.com/MyApplication/Images/SampleImage.jpg" /><br/>如果引用其他位置（如外部网站）中的资源，则绝对 URL 路径非常有用。 <br/><br/><br/>站点根目录相对路径， <br/>根据站点（不是应用程序）根目录进行解析。 <br/>此示例路径假定 Images 文件夹存在于网站根目录下： <br/>阅读代码编辑代码运行效果复制HTML代码保存代码<img src="/Images/SampleImage.jpg" /><img src="/Images/SampleImage.jpg" /><br/>如果您的网站为 <a href="http://www.xxx.com" target="_blank">http://www.xxx.com</a>，则路径将解析为以下形式： <br/><a href="http://www.xxx.com/Images/SampleImage.jpg" target="_blank">http://www.xxx.com/Images/SampleImage.jpg</a> <br/>如果将跨应用程序的资源（如图像或客户端脚本文件） <br/>保留在网站根目录下的文件夹中，则站点根目录相对路径非常有用。 <br/><br/><br/>根据当前页面路径解析的相对路径： <br/>阅读代码编辑代码运行效果复制HTML代码保存代码<img src="Images/SampleImage.jpg" /><img src="Images/SampleImage.jpg" /><br/><br/>解析为当前页面路径对等的相对路径。 <br/>阅读代码编辑代码运行效果复制HTML代码保存代码<img src="../Images/SampleImage.jpg" /><img src="../Images/SampleImage.jpg" /><br/><br/>注意 <br/>默认情况下，浏览器使用当前页面的 URL 作为基准解析相对路径。 <br/>但是，您可以在页面中包含 HTML base 元素，以指定替代基路径。 <br/><br/><br/>B.指定 服务器控件 资源的路径 <br/>----------------------------- <br/><br/>在引用资源的 ASP.NET 服务器控件中， <br/>可以使用绝对路径或相对路径，这一点与客户端元素一样。 <br/>如果使用相对路径，则相对于页面、用户控件或包含该控件的主题的路径进行解析。 <br/>例如，假设 Controls 文件夹中包含一个用户控件。 <br/>该用户控件包含一个 Image Web 服务器控件， <br/>该服务器控件的 ImageUrl 属性设置为以下路径： <br/>Images/SampleImage.jpg <br/>该用户控件运行时，路径将解析为以下形式： <br/>/Controls/Images/SampleImage.jpg <br/>无论承载用户控件的页面位置如何，都是如此。 <br/><br/><br/>服务器控件中的绝对和相对路径引用具有以下缺点： <br/><br/>绝对路径在应用程序之间是不可移植的。 <br/>如果移动绝对路径指向的应用程序，则链接将会中断。 <br/>如果将资源或页面移动到不同的文件夹， <br/>可能很难维护采用客户端元素样式的相对路径。 <br/><br/><br/>为克服这些缺点， <br/>ASP.NET 启用了 Web 应用程序根目录运算符 (~)， <br/>在服务器控件中指定路径时，可以使用该运算符。 <br/>ASP.NET 会将 ~ 运算符解析为当前应用程序的根目录。 <br/>可以结合使用 ~ 运算符和文件夹来指定基于当前根目录的路径。 <br/><br/>下面的示例 <br/>演示使用 Image 服务器控件时用于指定图像的根目录相对路径的 ~ 运算符： <br/>复制ASPX代码保存代码<asp:image runat="server" id="Image1"<br/>ImageUrl="~/Images/SampleImage.jpg" /><asp:image runat="server" id="Image1"<br/>ImageUrl="~/Images/SampleImage.jpg" /><br/>在该示例中， <br/>图像文件将从 Web 应用程序根目录下的 Images 文件夹中直接读取， <br/>无论该页面位于网站的什么位置。 <br/><br/>注意 <br/>~ 运算符只能为服务器控件识别，并且位于服务器代码中。 <br/>不能将 ~ 运算符用于客户端元素。 <br/><br/>可以在服务器控件中的任何与路径有关的属性中使用 ~ 运算符。 <br/><br/>注意 <br/>在主控页中，资源的路径基于内容页的路径进行解析。 <br/><br/><br/>C.确定当前网站的物理文件路径 <br/>---------------------------- <br/>在应用程序中，您可能需要确定服务器上的文件或其他资源的路径。 <br/>例如，如果应用程序以编程方式对文本文件进行读写操作， <br/>则必须为用于读取和写入的方法提供该文件的完整物理路径。 <br/><br/>将物理文件路径（如 C:&#92;Website&#92;MyApplication） <br/>硬编码到应用程序中并不是很好的做法， <br/>因为如果移动或部署应用程序，则路径会发生更改。 <br/>但是， <br/>ASP.NET 为您提供了以编程方式获取应用程序中的任何物理文件路径的方法。 <br/>然后，您可以使用基文件路径创建所需资源的完整路径。 <br/>用于确定文件路径的两种最常用的 ASP.NET 功能是 <br/>返回路径信息的 HttpRequest 对象的属性，以及 MapPath 方法。 <br/><br/>注意 <br/>不应将物理文件路径发送到客户端， <br/>因为它们可能会被恶意用户用来获取有关您的应用程序的信息。 <br/><br/>根据请求属性确定路径 <br/>下表列出了 HttpRequest 对象的属性， <br/>这些属性帮助您确定应用程序中的资源的路径。 <br/>下面的示例假定使用以下 URL 来发出浏览器请求： <br/><a href="http://www.xxx.com/MyApplication/MyPages/Default.aspx" target="_blank">http://www.xxx.com/MyApplication/MyPages/Default.aspx</a> <br/>对于这些示例， <br/>术语“虚拟路径”是指跟在服务器标识符后面的请求 URL 的一部分， <br/>此时虚拟路径如下所示： <br/>/MyApplication/MyPages/Default.aspx <br/>此外，这些示例假定网站根目录的物理路径为以下形式： <br/>C:&#92;inetpub&#92;wwwroot&#92;MyApplication&#92; <br/>最后，这些示例假定物理路径包含一个名为 MyPages 的文件夹。 <br/><br/>则相关属性及其返回值如下： <br/>ApplicationPath <br/>获取当前应用程序的根目录路径， <br/>无论在该应用程序中的什么位置请求该路径。 <br/>对于此示例，该属性将返回以下内容： <br/>/ <br/><br/>CurrentExecutionFilePath <br/>获取当前请求的虚拟路径。 <br/>不同于 FilePath， <br/>差别在于如果请求已在服务器代码中被重定向， <br/>则 CurrentExecutionFilePath 就是正确的。 <br/>对于此示例，该属性将返回以下内容： <br/>/MyApplication/MyPages/Default.aspx <br/>如果作为对 Transfer 或 Execute 进行调用的结果， <br/>您获取正在运行的代码中的属性，则路径将反映该代码的位置。 <br/><br/>FilePath <br/>获取当前请求的虚拟路径。 <br/>对于此示例，该属性将返回以下内容： <br/>/MyApplication/MyPages/Default.aspx <br/>不同于 CurrentExecutionFilePath，FilePath 不反映服务器端转换。 <br/><br/>Path <br/>获取当前请求的虚拟路径。对于此示例，该属性将返回以下内容： <br/>/MyApplication/MyPages/default.aspx <br/><br/>PhysicalApplicationPath <br/>获取当前正在执行的应用程序的根目录的物理文件系统路径。 <br/>对于此示例，该属性将返回以下内容： <br/>C:&#92;inetpub&#92;wwwroot&#92; <br/><br/>PhysicalPath <br/>获取与请求的 URL 对应的物理文件系统路径。 <br/>对于此示例，该属性将返回以下内容： <br/>C:&#92;inetpub&#92;wwwroot&#92;MyApplication&#92;MyPages&#92;default.aspx <br/><br/>使用 MapPath 方法 <br/>MapPath 方法返回传递给该方法的虚拟路径的完整物理路径。 <br/>例如，以下代码返回网站根目录的文件路径： <br/>Visual Basic : <br/>复制VB.NET代码保存代码Dim rootPath As String = Server.MapPath("~")<br/>C# : <br/>复制C#代码保存代码String rootPath = Server.MapPath("~");<br/><br/>注意 <br/>传递给 MapPath 方法的路径必须为应用程序相对路径，而不是绝对路径。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/asp.net/" rel="tag">asp.net</a> , <a href="http://www.gaobo.info/go.php/tags/%25E8%25B7%25AF%25E5%25BE%2584/" rel="tag">路径</a> , <a href="http://www.gaobo.info/go.php/tags/path/" rel="tag">path</a> , <a href="http://www.gaobo.info/go.php/tags/map/" rel="tag">map</a> , <a href="http://www.gaobo.info/go.php/tags/http/" rel="tag">http</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/657.htm</link>
<title><![CDATA[在Linq to Entities中实现模糊查询]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 25 Sep 2009 14:31:17 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/657.htm</guid> 
<description>
<![CDATA[ 
	在实际项目中遇到了RT的需求，查了下资料，可用的不多（除去使用StartsWith和EndsWith两个方法以外），主要方法有以下两个：<br/>1、使用SqlMethods.Like方法<br/><div class="code">using System.Data.Linq.SqlClient;<br/><br/>var query = from c in ctx.Customers<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where SqlMethods.Like(c.City, &quot;L_n%&quot;)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;select c;</div><br/>这个方法据说可以，但是我没有用成功。<br/>2、使用String.IndexOf("C")>-1方式<br/><div class="code">where c.CustomerID.IndexOf(&quot;C&quot;)&gt;-1</div><br/>这个我试过了，可以。<br/><br/>PS：模糊查询的结果一般都是转化为LIKE语法，这一点和Contains语法不同（Linq to Entities不支持Contains方法），Contains是转化为IN语法。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/linq/" rel="tag">linq</a> , <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/entities/" rel="tag">entities</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%25A8%25A1%25E7%25B3%258A/" rel="tag">模糊</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%259F%25A5%25E8%25AF%25A2/" rel="tag">查询</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/656.htm</link>
<title><![CDATA[Oracle 10g for Windows XP/Vista/Server 2008的下载页面]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Sun, 20 Sep 2009 01:46:18 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/656.htm</guid> 
<description>
<![CDATA[ 
	找了很久才找到，Oracle官方站点的下载做的真不咋地，故意让人找不到下载？？<br /><br /><span class="topstoryhead">Oracle Database 10<em>g</em> Release 2 (10.2.0.1.0) </span><br /><span class="parahead2">Enterprise/Standard Edition for Microsoft Windows (32-bit)<br /><a href="http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10201winsoft.html"><a href="http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10201winsoft.html" target="_blank">http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10201winsoft.html</a></a><br /><br /><span class="topstoryhead">Oracle Database 10<em>g</em> Release 2 (10.2.0.3/10.2.0.4) </span><br /><span class="parahead2">Enterprise/Standard Edition for Microsoft Windows Vista and Windows 2008<br /><a href="http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10203vista.html"><a href="http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10203vista.html" target="_blank">http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10203vista.html</a></a></span></span><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/oracle/" rel="tag">oracle</a> , <a href="http://www.gaobo.info/go.php/tags/client/" rel="tag">client</a> , <a href="http://www.gaobo.info/go.php/tags/db/" rel="tag">db</a> , <a href="http://www.gaobo.info/go.php/tags/database/" rel="tag">database</a> , <a href="http://www.gaobo.info/go.php/tags/windows/" rel="tag">windows</a> , <a href="http://www.gaobo.info/go.php/tags/xp/" rel="tag">xp</a> , <a href="http://www.gaobo.info/go.php/tags/vista/" rel="tag">vista</a> , <a href="http://www.gaobo.info/go.php/tags/server/" rel="tag">server</a> , <a href="http://www.gaobo.info/go.php/tags/%25E4%25B8%258B%25E8%25BD%25BD/" rel="tag">下载</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/652.htm</link>
<title><![CDATA[Entity Framework的默认值BUG解决方法]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 04 Sep 2009 07:04:44 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/652.htm</guid> 
<description>
<![CDATA[ 
	在使用.Net 3.5里的Entity Framework开发网站的时候，遇到了一个问题：添加记录时，对于DateTime型的数据，无法使用数据库的默认值。<br/>查找了资料之后，知道这是Entities FrameWork的一个Bug，需要将edmx文件里，使用DateTime类型的字段加上<br/><div class="code">StoreGeneratedPattern=&quot;Identity&quot;</div><br/>属性才行。<br/>找到edmx文件，然后用文本工具打开，找到对应的字段属性，添加<br/><div class="code">StoreGeneratedPattern=&quot;Identity&quot;</div><br/>属性，然后保存退出，重新执行上述的语句，就会用默认值插入到数据库了。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/entities/" rel="tag">entities</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/datetime/" rel="tag">datetime</a> , <a href="http://www.gaobo.info/go.php/tags/edmx/" rel="tag">edmx</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/651.htm</link>
<title><![CDATA[Linq to Entities中连续保存多条数据的做法]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Thu, 03 Sep 2009 14:25:02 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/651.htm</guid> 
<description>
<![CDATA[ 
	程序需要用到连续保存多条数据，代码示意如下：<br/><div class="code">string&#91;&#93; auditors = ……;<br/>foreach (string each in auditors)<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;……<br/>&nbsp;&nbsp;&nbsp;&nbsp;……<br/>&nbsp;&nbsp;&nbsp;&nbsp;_db.AddToAuditResult(ar);<br/>&#125;<br/>_db.SaveChanges();</div><br/><br/>按照以上的方法，在循环第二次执行到SaveChanges()方法的时候，会出现异常：<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">无法创建类型为“结束类型”的常量值。此上下文仅支持基元类型(“例如 Int32、String 和 Guid”)。</div></div><br/>解决方法：<br/><div class="code">foreach (string each in auditors)<br/>&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;……<br/>&nbsp;&nbsp;&nbsp;&nbsp;……<br/>&nbsp;&nbsp;&nbsp;&nbsp;_db.AddToAuditResult(ar);<br/>&nbsp;&nbsp;&nbsp;&nbsp;_db.SaveChanges(false);<br/>&#125;<br/>_db.AcceptAllChanges();</div><br/>每次执行完AddTo……方法后调用SaveChanges()方法，但传入“false”参数，最后在循环体外部调用AcceptAllChanges()方法即可。<br/>这个方式其实常常被用来完成代码中的Transaction（事务）提交，在每次操作后SaveChanges()方法，但传入“false”参数，Entity Framework会保存当前对象的状态信息，但不会提交到数据库，直到显式的调用AcceptAllChanges()方法。只调用SaveChanges()方法，不传入任何参数，则默认会隐式的调用AcceptAllChanges()方法。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/asp.net/" rel="tag">asp.net</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/entities/" rel="tag">entities</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/linq/" rel="tag">linq</a> , <a href="http://www.gaobo.info/go.php/tags/savechanges/" rel="tag">savechanges</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/650.htm</link>
<title><![CDATA[“无法更新EntitySet“*****”，因为它有一个DefiningQuery，而ModificationFunctionMapping元素中没有支持当前操作的InsertFunction元素”问题的解决方法]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Mon, 31 Aug 2009 01:36:45 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/650.htm</guid> 
<description>
<![CDATA[ 
	遇到RT的问题的原因很尴尬，其实很可能就是没有定义这个表的主键，至于为什么没有定义主键，这个&hellip;&hellip;<img src="images/emot/cry.gif" border="0" /><br /><br />打开表定义设置好主键，然后更新Entity Model；如果不行，删除已有的Entity Model，删除Web.Config中的Entity定义，重建一个，应该可以了<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/primary/" rel="tag">primary</a> , <a href="http://www.gaobo.info/go.php/tags/key/" rel="tag">key</a> , <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a> , <a href="http://www.gaobo.info/go.php/tags/model/" rel="tag">model</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25AE%259E%25E4%25BD%2593/" rel="tag">实体</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25AF%25B9%25E8%25B1%25A1/" rel="tag">对象</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%2598%25A0%25E5%25B0%2584/" rel="tag">映射</a> , <a href="http://www.gaobo.info/go.php/tags/%25E4%25B8%25BB%25E9%2594%25AE/" rel="tag">主键</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/649.htm</link>
<title><![CDATA[LINQ to Entities不支持语法及替代方案]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 28 Aug 2009 08:15:52 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/649.htm</guid> 
<description>
<![CDATA[ 
	　　LINQ to Entities是Ado.net Entity Framework的查询语言之一,它为了更好的兼容更多种的数据库所以在使用方法上有所精简，比之linq2SQL却少了一些好用的方法,下面就说一下这些日子来使用它时遇到的问题及解决方法<br/><br/>　　以下只列出了完全Not supported的内容，部分supported的方法都可以通过简单的增简参数解决<br/><br/>　　<strong>1.Contains</strong><br/>　　这一函数在linq2sql中将生成in方法<br/><div class="code">var s=db.Account.Select(c =&gt; c.ID);<br/>var ret =(from t in db.Profile<br/>　　where s.Contains(t.ID)<br/>　　select t).ToList();</div><br/>　　将生成类似 <br/><div class="code">select * from profile p where p.id in (1, 2, 3, 4)</div><br/>　　的SQL语句,但是这在LINQ to Entities中是行不通的, 可以使用 <br/><div class="code">var ids=db.Account.Select(c =&gt; c.ID);<br/>　　var ret = (from t in db.Profile<br/>　　　　　　　　　　　　　　　　　where ids.Any(c=&gt;c==t.UserID)<br/>　　　　　　　　　　　　　　　　　select t).ToList();</div><br/>　　来完成。<br/><br/>　　<strong>2.DefaultIFEmpty</strong><br/>　　这个在VS里进行了自动提示，可以使用First或FirstOrDefault来解决。<br/><br/>　　<strong>3.Reverse</strong><br/>　　原来的<br/><div class="code">var x = (from c in context.Customers　　　　<br/>　　　　　　　　select c).Reverse();</div><br/>　　要用orderby descending来重写<br/><div class="code">var x = from c in context.Customers<br/>　　　　　　　　orderby c.Address.Region descending<br/>　　　　　　　　select c;</div><br/>　　来代替<br/><br/>　　<strong>4.ElementAt</strong><br/>　　原来的用法<br/><div class="code">ElementAt(index)</div><br/>　　可以用Take，Skip或索引的方式选取，它的使用方法是灵活多样的<br/>　　至于ElementAtOrDefault，可以通过以上方法选取后，使用FirstOrDefault来获得，当然，这样取还有不少问题，希望大家在实践中可以解决<br/><br/>　　<strong>5.Last/LastOrDefault</strong><br/>　　可以通过orderby descending之后取First/FirstOrDefault来完成<br/><br/>　　<strong>6.Single/SingleOrDefault</strong><br/>　　可以用First/FirstOrDefault来替换<br/><br/>　　<strong>7.SkipWhile/TakeWhileAccounts.SkipWhile((x, index) => x.UserID >=1000)</strong><br/>　　这个就较为复杂要用繁杂一些的语句来实现<br/><div class="code">from a1 in Accounts<br/>where a1.UserID&gt;=(from a in Accounts where a.UserID&gt;1000 select a).FirstOrDefault().UserID<br/>select a1</div><br/>　　当然，这只是其中一种实现方法,TakeWhile与SkipWhile 几本相同。<br/><br/>　　Linq to Entities语法支持表：<a href="http://msdn.microsoft.com/en-us/library/bb738550.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/bb738550.aspx</a><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/linq/" rel="tag">linq</a> , <a href="http://www.gaobo.info/go.php/tags/entities/" rel="tag">entities</a> , <a href="http://www.gaobo.info/go.php/tags/contains/" rel="tag">contains</a> , <a href="http://www.gaobo.info/go.php/tags/%25E8%25AF%25AD%25E6%25B3%2595/" rel="tag">语法</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%259B%25BF%25E4%25BB%25A3/" rel="tag">替代</a> , <a href="http://www.gaobo.info/go.php/tags/ado.net/" rel="tag">ado.net</a> , <a href="http://www.gaobo.info/go.php/tags/entity/" rel="tag">entity</a> , <a href="http://www.gaobo.info/go.php/tags/framework/" rel="tag">framework</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/646.htm</link>
<title><![CDATA[在Windows 7下成功安装ORACLE客户端]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Thu, 27 Aug 2009 02:13:28 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/646.htm</guid> 
<description>
<![CDATA[ 
	把先前安装的Windows 7 RC格式化掉安装Retail版以后，工作需要安装Oracle Client，但是到先决性检查的地方过不去，貌似是客户端不支持Windows 7这么先进的操作系统&hellip;&hellip;orz<br /><br />网上搜索了很多资料也不行，自己琢磨了半天终于搞懂了，方法如下：<br /><br />当前任何版本的ORACLE客户端在任何版本的WINDOWS7上都无法正常完成安装.<br />主要是因为ORACLE安装的先决条件里操作系统版本不符合,但是这个问题可以修改refhost.xml解决, 具体是在refhost.xml中添加<br />&nbsp; &lt;!--Microsoft Windows 7--&gt;<br />&nbsp; &lt;OPERATING_SYSTEM&gt;<br />&nbsp;&nbsp;&nbsp; &lt;VERSION VALUE=&quot;6.1&quot;/&gt;<br />&nbsp; &lt;/OPERATING_SYSTEM&gt;<br />即可,不需要添加X32或者X64,注意ORACLE10G或者11有可能有多个refhost.xml文件,都需要修改(好像部分版本需要修改oraparam.ini文件 自己搜索一下吧)。这样可以在检查操作系统的时候绕过检查。无论是oracle client for Windows , vista ,2k8 server 的X32或者X64版本都可以通过这个方法正常安装。<br /><br />PLSQL DEVELOPER和CMD&nbsp;SQLPLUS都依此安装，但是打开PLSQL DEVELOPER 7.1.5.1399 会出问题,提示OCI的错误<br />然后不登录ORACLE进PLSQLDEV 依次选择tools--preferences,配置下面的东西 路径自己改<br />oraclehome : E:&#92;oracle&#92;product&#92;10.2.0&#92;client_1&#92;BIN<br />oci library : E:&#92;oracle&#92;product&#92;10.2.0&#92;client_1&#92;BIN&#92;oci.dll<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/oracle/" rel="tag">oracle</a> , <a href="http://www.gaobo.info/go.php/tags/windows/" rel="tag">windows</a> , <a href="http://www.gaobo.info/go.php/tags/client/" rel="tag">client</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25AE%25A2%25E6%2588%25B7%25E7%25AB%25AF/" rel="tag">客户端</a> , <a href="http://www.gaobo.info/go.php/tags/plsql/" rel="tag">plsql</a> , <a href="http://www.gaobo.info/go.php/tags/sqlplus/" rel="tag">sqlplus</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/632.htm</link>
<title><![CDATA[三表查询时发现LINQ to Entities不支持DefaultIfEmpty()……]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 31 Jul 2009 09:57:02 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/632.htm</guid> 
<description>
<![CDATA[ 
	如题。郁闷。<br/><br/>问题如下：<br/>表Users<br/>表Roles<br/>表Workflows<br/>连接条件：Users.rid == Roles.rid && Roles.level == Workflows.level<br/>Roles <=> Users&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Workflows <=> Roles<br/>1<=>∞&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<=>∞<br/><br/>希望SELECT出Users表中的所有用户，但是有些用户对应的Roles数据在Workflows表中没有数据（例如“管理员”是角色，也有对应的用户，但是这类用户不在工作流的流程中），使用LinqPad测试出可行的Linq：<br/><div class="code">from u in Users<br/>join temp in<br/>(<br/>&nbsp;&nbsp;from r in Roles<br/>&nbsp;&nbsp;join wf in Workflows on r.Level equals wf.Level<br/>&nbsp;&nbsp;into TEMP1<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;from temp1 in TEMP1.DefaultIfEmpty()<br/>&nbsp;&nbsp;select new &#123;r.Rid, r.Title, r.Level, r.Isadmin, temp1.Subject&#125;<br/>)<br/>on u.Rid equals temp.Rid<br/>into TEMP<br/><br/>from temp in TEMP.DefaultIfEmpty()<br/>select new<br/>&#123;<br/>&nbsp;&nbsp;userno = u.Userno,<br/>&nbsp;&nbsp;username = u.Username,<br/>&nbsp;&nbsp;rid = temp.Rid,<br/>&nbsp;&nbsp;title = temp.Title,<br/>&nbsp;&nbsp;isadmin = temp.Isadmin,<br/>&nbsp;&nbsp;level_title = temp.Subject<br/>&#125;</div><br/><br/>但是移植到VS2008中执行，提示“LINQ to Entities不识别方法DefaultIfEmpty()，因此该方法无法转换为存储表达式”……囧死……<br/>只有换个思路，先把Users和Roles连接取出数据，然后在Views中foreach输出的时候判断某个列的值，在这一列中再次foreach遍历Workflow的数据，再输出。好吧，我承认这是个笨方法，貌似老外有更好的做法，例如FirstOrDefault()或逆导航属性之类的，但是……我没有用成功。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/linq/" rel="tag">linq</a> , <a href="http://www.gaobo.info/go.php/tags/entities/" rel="tag">entities</a> , <a href="http://www.gaobo.info/go.php/tags/defaultifempty/" rel="tag">defaultifempty</a> , <a href="http://www.gaobo.info/go.php/tags/firstordefault/" rel="tag">firstordefault</a> , <a href="http://www.gaobo.info/go.php/tags/visual/" rel="tag">visual</a> , <a href="http://www.gaobo.info/go.php/tags/studio/" rel="tag">studio</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/631.htm</link>
<title><![CDATA[使用Linq时必备的小工具——LinqPad]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 31 Jul 2009 07:09:49 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/631.htm</guid> 
<description>
<![CDATA[ 
	用Linq开发东西虽然很好很强大，但是如果操作的数据比较复杂，转换出来的SQL语句有问题的话，可能半天都不知道该怎么解决，幸亏有了LinqPad这个小工具，可以先测试下Linq的结果，更可以查看到其生成的SQL语句，以便对症下药。<br />官方站点：<a href="http://www.linqpad.net" target="_blank">www.linqpad.net</a><br />不注册的话，没有自动完成功能，这里有个XX版的介绍和下载：<br /><a href="http://blog.csdn.net/danny_su/archive/2009/05/07/4159280.aspx"><a href="http://blog.csdn.net/danny_su/archive/2009/05/07/4159280.aspx" target="_blank">http://blog.csdn.net/danny_su/archive/2009/05/07/4159280.aspx</a></a><br />也可以直接下载下边的文件<br /><a href="attachment.php?fid=85">点击这里下载文件</a><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/linq/" rel="tag">linq</a> , <a href="http://www.gaobo.info/go.php/tags/linqpad/" rel="tag">linqpad</a> , <a href="http://www.gaobo.info/go.php/tags/visual/" rel="tag">visual</a> , <a href="http://www.gaobo.info/go.php/tags/studio/" rel="tag">studio</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%25B3%25A8%25E5%2586%258C/" rel="tag">注册</a> , <a href="http://www.gaobo.info/go.php/tags/%25E7%25A0%25B4%25E8%25A7%25A3/" rel="tag">破解</a> , <a href="http://www.gaobo.info/go.php/tags/reg/" rel="tag">reg</a> , <a href="http://www.gaobo.info/go.php/tags/crack/" rel="tag">crack</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/621.htm</link>
<title><![CDATA[ASP.Net MVC值得阅读的一些内容(陆续增加中...)]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Mon, 13 Jul 2009 03:53:07 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/621.htm</guid> 
<description>
<![CDATA[ 
	最近在猛研ASP.Net MVC，其实用起来和PHP、Java中都没有太大差别，主要是对.Net架构的适应过程。在此过程中，搜索了一些感觉还不错的内容，列举如下，希望能对和我差不多的朋友有所帮助<img src="images/emot/shy.gif" border="0" width="24" height="24" /><br /><p><br />ASP.NET MVC 指南 &mdash;&mdash; 概述（一）创建一个电影数据库应用程序<br /><a href="http://www.cnblogs.com/ilovesilence/articles/1399795.html"><a href="http://www.cnblogs.com/ilovesilence/articles/1399795.html" target="_blank">http://www.cnblogs.com/ilovesilence/articles/1399795.html</a></a><br /><br />The Will Will Web - ASP.NET MVC<br /><a href="http://blog.miniasp.com/category/ASPNET-MVC.aspx"><a href="http://blog.miniasp.com/category/ASPNET-MVC.aspx" target="_blank">http://blog.miniasp.com/category/ASPNET-MVC.aspx</a></a><br /><br />Scott的ASP.net MVC框架系列文章之二: URL映射<br /><a href="http://blog.csdn.net/drummery/archive/2008/01/03/2022775.aspx"><a href="http://blog.csdn.net/drummery/archive/2008/01/03/2022775.aspx" target="_blank">http://blog.csdn.net/drummery/archive/2008/01/03/2022775.aspx</a></a><br /><br />[翻译-ASP.NET MVC]Contact Manager开发之旅系列<br /><a href="http://www.pin5i.com/showtopic-23294.html"><a href="http://www.pin5i.com/showtopic-23294.html" target="_blank">http://www.pin5i.com/showtopic-23294.html</a></a><br /><br />ASP.NET MVC 入门8、ModelState与数据验证<br /><a href="http://blog.csdn.net/philiplb/archive/2009/03/24/4020489.aspx"><a href="http://blog.csdn.net/philiplb/archive/2009/03/24/4020489.aspx" target="_blank">http://blog.csdn.net/philiplb/archive/2009/03/24/4020489.aspx</a></a><br /><br />Asp.net MVC中表单验证(Fluent Validation for .NET)<br /><a href="http://space.itpub.net/12639172/viewspace-553431"><a href="http://space.itpub.net/12639172/viewspace-553431" target="_blank">http://space.itpub.net/12639172/viewspace-553431</a></a><br /><br />在ASP.NET MVC Framework 中执行简单验证<br /><a href="http://www.cnblogs.com/darkdawn/archive/2009/03/05/1404201.html"><a href="http://www.cnblogs.com/darkdawn/archive/2009/03/05/1404201.html" target="_blank">http://www.cnblogs.com/darkdawn/archive/2009/03/05/1404201.html</a></a><br /><br /><a id="ctl04_TitleUrl"><span style="color: #a91718">[翻译:ASP.NET MVC 教程]ASP.NET MVC学习之旅&mdash;&mdash;总索引</span></a><br /><a href="http://www.cnblogs.com/Kinglee/archive/2009/07/13/1522676.html"><a href="http://www.cnblogs.com/Kinglee/archive/2009/07/13/1522676.html" target="_blank">http://www.cnblogs.com/Kinglee/archive/2009/07/13/1522676.html</a></a><br /><br />Entity Framework系列初、中、高级教程<br /><a href="http://www.cnblogs.com/xray2005/category/189491.html"><a href="http://www.cnblogs.com/xray2005/category/189491.html" target="_blank">http://www.cnblogs.com/xray2005/category/189491.html</a></a><br /><br /><strong>Cheat Sheets</strong><br /><br /></p><p><strong>C# / .NET / LINQ 相關</strong></p><ul><li><a rel="nofollow" href="http://john-sheehan.com/blog/wp-content/uploads/msnet-formatting-strings.pdf" target="_blank">.NET Format String Quick Reference</a> [PDF]</li><li><a href="http://download.microsoft.com/download/4/a/3/4a3c7c55-84ab-4588-84a4-f96424a7d82d/NET35_Namespaces_Poster_LORES.pdf">Microsoft .NET Framework 3.5 Commonly Uses Types and Namespaces</a> [PDF]</li><li><a rel="nofollow" href="http://weblogs.asp.net/bradvincent/archive/2008/11/01/linq-cheat-sheet.aspx" target="_blank">LINQ Cheat Sheet</a></li><li><a rel="nofollow" href="http://www.aspnetresources.com/blog/linq_sqo__cheat_sheet.aspx" target="_blank">LINQ Standard Query Operators Cheat Sheet</a></li><li>LINQ to SQL语句详解：<a href="http://kb.cnblogs.com/page/42465/"><a href="http://kb.cnblogs.com/page/42465/" target="_blank">http://kb.cnblogs.com/page/42465/</a></a></li><li>Linq to sql 中如何进行 left join：<a href="http://www.cnblogs.com/RChen/archive/2008/07/24/1250736.html"><a href="http://www.cnblogs.com/RChen/archive/2008/07/24/1250736.html" target="_blank">http://www.cnblogs.com/RChen/archive/2008/07/24/1250736.html</a></a></li><li>LINQ to Entities 不识别方法,因此该方法无法转换为存储表达式：LINQ to Entities 中,使用lambada或linq时,变量一定要提前转换好,不能到lambada里或linq里再转换。<a href="http://bbs.51541.com.cn/showtopic-76.html"><a href="http://bbs.51541.com.cn/showtopic-76.html" target="_blank">http://bbs.51541.com.cn/showtopic-76.html</a></a></li><li>Linq中导航属性为Null的问题和解决方法：取出对象后调用MsgsReference.Load()即可，<a href="http://space.cnblogs.com/question/7421/"><a href="http://space.cnblogs.com/question/7421/" target="_blank">http://space.cnblogs.com/question/7421/</a></a></li></ul><p><strong>Visual Studio 相關</strong></p><ul><li><a rel="nofollow" href="http://john-sheehan.com/blog/wp-content/uploads/vs2005-code-snippets.pdf" target="_blank">Visual Studio 2005 Built-in Code Snippets (C#)</a> [PDF]</li><li><a rel="nofollow" href="http://download.microsoft.com/download/e/7/9/e79cce22-b196-4b9f-9ea7-b1a21f5342e9/VCSharp_2005_color.pdf" target="_blank">Visual Studio 2005 Default Keybindings (C#)</a> [PDF] </li><li><a rel="nofollow" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e5f902a8-5bb5-4cc6-907e-472809749973&amp;DisplayLang=en" target="_blank">Visual C# 2008 Keybinding Reference Poster</a></li></ul><p><strong>ASP.NET 相關</strong></p><ul><li><a rel="nofollow" href="http://john-sheehan.com/blog/wp-content/uploads/aspnet-life-cycles-events.pdf" target="_blank">ASP.NET 2.0 Page Life Cycle &amp; Common Events</a> [PDF]</li><li><a rel="nofollow" href="http://blog.krisvandermast.com/content/binary/ASP.NET-2.0-life-cycle.png" target="_blank">ASP.NET Page Life Cycle Diagram</a> [PNG]</li><li><a rel="nofollow" href="http://duartes.org/gustavo/articles/Asp.net-Runtime-Cheat-Sheet-HttpRequest-HttpRuntime.aspx" target="_blank">ASP.NET Runtime Cheat Sheet: HttpRequest, HttpRuntime, AppDomain and friends</a></li><li><a href="http://aspnetresources.com/blog/ms_ajax_cheat_sheets_batch2.aspx">Microsoft ASP.NET AJAX Library</a> </li><li><a href="http://aspnetresources.com/downloads/MS%20Ajax%20Client%20Life-Cycle%20Events.pdf">Microsoft ASP.NET AJAX Client Life Cycle &amp; Events</a> [PDF]</li></ul><p><strong>SQL Server 相關</strong></p><ul><li><a rel="nofollow" href="http://www.addedbytes.com/cheat-sheets/sql-server-cheat-sheet/" target="_blank">SQL Server Cheat Sheekt</a></li></ul><p><strong>Subversion 相關</strong></p><ul><li><a rel="nofollow" href="http://www.addedbytes.com/cheat-sheets/subversion-cheat-sheet/" target="_blank">Subversion Cheat Sheet</a></li></ul><p><strong>Reqular Expression 相關</strong></p><ul><li><a rel="nofollow" href="http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/" target="_blank">Regular Expressions Cheat Sheet (V2)</a></li></ul><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/asp.net/" rel="tag">asp.net</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/mvc/" rel="tag">mvc</a> , <a href="http://www.gaobo.info/go.php/tags/php/" rel="tag">php</a> , <a href="http://www.gaobo.info/go.php/tags/java/" rel="tag">java</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/620.htm</link>
<title><![CDATA[ASP.net中的validaterequest]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Fri, 10 Jul 2009 01:01:33 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/620.htm</guid> 
<description>
<![CDATA[ 
	　　这个属性是用来验证客户端用户的输入的,用来验证用户的输入中是否有危险字符的,这个属性的默认值为true,微软之所以这么做是为了提高asp.net程序的安全性,所以很多程序员即使不知道怎么来防御黑客的攻击,asp.net的一些默认属性等内容已经对安全进行了控制,这也是为什么asp.net的程序相对来说比较安全的原因!<br/>　　既然这个属性的默认值为true,而且asp.net页面的回发又很频繁,那么如果没有用户的交互的地方,这样asp.net 岂不是每次都要去严整呢,这样也是有可能会来回的损耗系统的执行时间的,至于:如果没有客户端的交互的话,到底asp.net会不会去验证这是微软的工程师的问题了,对于我们来说,如果没有客户端交互的地方,我感觉是应该将此属性设置为 false的,这样的话无论 微软的工程师怎样设计,对我们程序的本身是没有任何影响的!<br/>　　直接关闭这个属性的方法是：<br/>　　1、在aspx页面的属性里写“validaterequest="false"”<br/>　　2、在web.config里设置<br/><div class="code">&lt;configuration&gt;<br/>&nbsp;&nbsp; &lt;system.web&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;pages validateRequest=&quot;false&quot;/&gt; <br/><br/>&nbsp;&nbsp; &lt;/system.web&gt; <br/>&lt;/configuration&gt;<br/></div><br/>　　但是当需要跟用户交互的地方,我们就要用它的默认值了,可是事情可能并没有我们想象的那么简单,也没有那么完美,当用户在使用一些html编辑器的时候,自己本身提交的字符里就有<xxxxxxx>等这样的字符,这样就要求程序员必须要关闭validaterequest 属性,这个时候我们又该怎样的来控制asp.net页面的安全性能呢?<br/>　　当然了,这个地方我们可以来对一切危险字符进行过滤,这样可能提高一些安全性,但是我们防止用户的输入可能考虑的会有遗漏,这样就导致了安全还会是有问题的,我们可以反过来考虑我们到底需要提交多少特殊字符,然后对我们提交的特殊字符进行转义或替换,这样我们就又可以将validaterequest的属性设置为true了,这样既解决了程序的安全问题又满足了我们的需求!<br/>　　有时候在与用户进行交互的时候,用户难免的会有输入特殊字符的时候,因为我们设置的validaterequest 的值 为true所以页面会不给任何提示的前提下, 直接输出一大页的错误信息, 这样可能就导致了用户的误解,他们可能认为是我们网站出了问题,用户不可能会想到他输入了非法的字符! 对于这种情况我们又该怎么办呢?<br/>　　答案是可以使用Page_Error的处理事件：<br/><div class="code">protected void Page_Error(object sender, EventArgs e) <br/>　　　 &#123;<br/>　　　　　　 Exception ex = Server.GetLastError();<br/>　　　　　　 if (ex is HttpRequestValidationException)<br/>　　　　　　 &#123;<br/>　　　　　　　 Response.Write(&quot;您输入的字符中有非法字符!&quot;);<br/>　　　　　　　 Server.ClearError(); <br/>　　　　　　　 &#125;<br/>　　　　 &#125;<br/></div><br/>1.它所在的命名空间:System.Web.Configuration<br/>2.程序集:System.Web(在 system.web.dll 中)<br/>3.所在的类:pagesSection<br/><br/>至于在最新的MVC模式中如何关闭这个属性，方法如下（超简单）：<br/><div class="code">&#91;ValidateInput(false)&#93; <br/>public ActionResult Index()&nbsp;&nbsp;<br/>&#123; <br/>&nbsp;&nbsp;&nbsp;&nbsp;return View(); <br/>&#125;</div><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/asp.net/" rel="tag">asp.net</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/validate/" rel="tag">validate</a> , <a href="http://www.gaobo.info/go.php/tags/request/" rel="tag">request</a> , <a href="http://www.gaobo.info/go.php/tags/%25E9%25A1%25B5%25E9%259D%25A2/" rel="tag">页面</a> , <a href="http://www.gaobo.info/go.php/tags/%25E8%25A1%25A8%25E5%258D%2595/" rel="tag">表单</a> , <a href="http://www.gaobo.info/go.php/tags/%25E9%25AA%258C%25E8%25AF%2581/" rel="tag">验证</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/619.htm</link>
<title><![CDATA[SQLServer日期比较、日期查询常用语句]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Thu, 09 Jul 2009 08:03:54 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/619.htm</guid> 
<description>
<![CDATA[ 
	在SQL SERVER中，你可能需要获得当前日期和计算一些其他的日期，例如，你的程序可能需要判断一个月的第一天或者最后一天。你们大部分人大概都知道怎样把日期进行分割（年、月、日等），然后仅仅用分割出来的年、月、日等放在几个函数中计算出自己所需要的日期！在这篇文章里，我将告诉你如何使用DATEADD和DATEDIFF函数来计算出在你的程序中可能你要用到的一些不同日期。<br />&nbsp; <br />在使用本文中的例子之前，你必须注意以下的问题。大部分可能不是所有例子在不同的机器上执行的结果可能不一样，这完全由哪一天是一个星期的第一天这个设置决定。第一天（DATEFIRST）设定决定了你的系统使用哪一天作为一周的第一天。所有以下的例子都是以星期天作为一周的第一天来建立，也就是第一天设置为7。假如你的第一天设置不一样，你可能需要调整这些例子，使它和不同的第一天设置相符合。你可以通过@@DATEFIRST函数来检查第一天设置。&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了理解这些例子，我们先复习一下DATEDIFF和DATEADD函数。DATEDIFF函数计算两个日期之间的小时、天、周、月、年等时间间隔总数。DATEADD函数计算一个日期通过给时间间隔加减来获得一个新的日期。要了解更多的DATEDIFF和DATEADD函数以及时间间隔可以阅读微软联机帮助。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用DATEDIFF和DATEADD函数来计算日期，和本来从当前日期转换到你需要的日期的考虑方法有点不同。你必须从时间间隔这个方面来考虑。比如，从当前日期到你要得到的日期之间有多少时间间隔，或者，从今天到某一天（比如1900-1-1）之间有多少时间间隔，等等。理解怎样着眼于时间间隔有助于你轻松的理解我的不同的日期计算例子。&nbsp; <br />&nbsp;<br />一个月的第一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一个例子，我将告诉你如何从当前日期去这个月的最后一天。请注意：这个例子以及这篇文章中的其他例子都将只使用DATEDIFF和DATEADD函数来计算我们想要的日期。每一个例子都将通过计算但前的时间间隔，然后进行加减来得到想要计算的日期。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是计算一个月第一天的SQL&nbsp; 脚本：&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; DATEADD(mm,&nbsp; DATEDIFF(mm,0,getdate()),&nbsp; 0)&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们把这个语句分开来看看它是如何工作的。最核心的函数是getdate()，大部分人都知道这个是返回当前的日期和时间的函数。下一个执行的函数DATEDIFF(mm,0,getdate())是计算当前日期和&quot;1900-01-01&nbsp; 00:00:00.000&quot;这个日期之间的月数。记住：时期和时间变量和毫秒一样是从&quot;1900-01-01&nbsp; 00:00:00.000&quot;开始计算的。这就是为什么你可以在DATEDIFF函数中指定第一个时间表达式为&quot;0&quot;。下一个函数是DATEADD，增加当前日期到&quot;1900-01-01&quot;的月数。通过增加预定义的日期&quot;1900-01-01&quot;和当前日期的月数，我们可以获得这个月的第一天。另外，计算出来的日期的时间部分将会是&quot;00:00:00.000&quot;。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个计算的技巧是先计算当前日期到&quot;1900-01-01&quot;的时间间隔数，然后把它加到&quot;1900-01-01&quot;上来获得特殊的日期，这个技巧可以用来计算很多不同的日期。下一个例子也是用这个技巧从当前日期来产生不同的日期。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp; <br />本周的星期一&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里我是用周(wk)的时间间隔来计算哪一天是本周的星期一。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; DATEADD(wk,&nbsp; DATEDIFF(wk,0,getdate()),&nbsp; 0)&nbsp; <br />&nbsp;<br />一年的第一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在用年(yy)的时间间隔来显示这一年的第一天。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; DATEADD(yy,&nbsp; DATEDIFF(yy,0,getdate()),&nbsp; 0)&nbsp; <br />&nbsp;<br />季度的第一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 假如你要计算这个季度的第一天，这个例子告诉你该如何做。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; DATEADD(qq,&nbsp; DATEDIFF(qq,0,getdate()),&nbsp; 0)&nbsp; <br />&nbsp;<br />当天的半夜&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 曾经需要通过getdate()函数为了返回时间值截掉时间部分，就会考虑到当前日期是不是在半夜。假如这样，这个例子使用DATEDIFF和DATEADD函数来获得半夜的时间点。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; DATEADD(dd,&nbsp; DATEDIFF(dd,0,getdate()),&nbsp; 0)&nbsp; <br />&nbsp;<br />深入DATEDIFF和DATEADD函数计算&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你可以明白，通过使用简单的DATEDIFF和DATEADD函数计算，你可以发现很多不同的可能有意义的日期。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目前为止的所有例子只是仅仅计算当前的时间和&quot;1900-01-01&quot;之间的时间间隔数量，然后把它加到&quot;1900-01-01&quot;的时间间隔上来计算出日期。假定你修改时间间隔的数量，或者使用不同的时间间隔来调用DATEADD函数，或者减去时间间隔而不是增加，那么通过这些小的调整你可以发现和多不同的日期。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里有四个例子使用另外一个DATEADD函数来计算最后一天来分别替换DATEADD函数前后两个时间间隔。&nbsp; <br />&nbsp;<br />上个月的最后一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是一个计算上个月最后一天的例子。它通过从一个月的最后一天这个例子上减去3毫秒来获得。有一点要记住，在Sql&nbsp; Server中时间是精确到3毫秒。这就是为什么我需要减去3毫秒来获得我要的日期和时间。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; dateadd(ms,-3,DATEADD(mm,&nbsp; DATEDIFF(mm,0,getdate()),&nbsp; 0))&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 计算出来的日期的时间部分包含了一个Sql&nbsp; Server可以记录的一天的最后时刻(&quot;23:59:59:997&quot;)的时间。&nbsp; <br />&nbsp;<br />去年的最后一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 连接上面的例子，为了要得到去年的最后一天，你需要在今年的第一天上减去3毫秒。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; dateadd(ms,-3,DATEADD(yy,&nbsp; DATEDIFF(yy,0,getdate()),&nbsp; 0))&nbsp; <br />&nbsp;<br />本月的最后一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在，为了获得本月的最后一天，我需要稍微修改一下获得上个月的最后一天的语句。修改需要给用DATEDIFF比较当前日期和&quot;1900-01-01&quot;返回的时间间隔上加1。通过加1个月，我计算出下个月的第一天，然后减去3毫秒，这样就计算出了这个月的最后一天。这是计算本月最后一天的SQL脚本。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; dateadd(ms,-3,DATEADD(mm,&nbsp; DATEDIFF(m,0,getdate())+1,&nbsp; 0))&nbsp; <br />&nbsp;<br />本年的最后一天&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 你现在应该掌握这个的做法，这是计算本年最后一天脚本&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp; dateadd(ms,-3,DATEADD(yy,&nbsp; DATEDIFF(yy,0,getdate())+1,&nbsp; 0))。&nbsp; <br />&nbsp;<br />本月的第一个星期一&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 好了，现在是最后一个例子。这里我要计算这个月的第一个星期一。这是计算的脚本。&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select&nbsp; DATEADD(wk,&nbsp; DATEDIFF(wk,0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dateadd(dd,6-datepart(day,getdate()),getdate())&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ),&nbsp; 0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个例子里，我使用了&quot;本周的星期一&quot;的脚本，并作了一点点修改。修改的部分是把原来脚本中&quot;getdate()&quot;部分替换成计算本月的第6天，在计算中用本月的第6天来替换当前日期使得计算可以获得这个月的第一个星期一。&nbsp; <br />&nbsp;<br />总结&nbsp; <br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我希望这些例子可以在你用DATEADD和DATEDIFF函数计算日期时给你一点启发。通过使用这个计算日期的时间间隔的数学方法，我发现为了显示两个日期之间间隔的有用历法是有价值的。注意，这只是计算出这些日期的一种方法。要牢记，还有很多方法可以得到相同的计算结果。假如你有其他的方法，那很不错，要是你没有，我希望这些例子可以给你一些启发，当你要用DATEADD和DATEDIFF函数计算你程序可能要用到的日期时。&nbsp; <br />&nbsp;<br />---------------------------------------------------------------&nbsp; <br />附录，其他日期处理方法&nbsp; <br />&nbsp;<br />1)去掉时分秒&nbsp; <br />declare&nbsp; @&nbsp; datetime&nbsp; <br />set&nbsp; @&nbsp; =&nbsp; getdate()&nbsp; --'2003-7-1&nbsp; 10:00:00'&nbsp; <br />SELECT&nbsp; @,DATEADD(day,&nbsp; DATEDIFF(day,0,@),&nbsp; 0)&nbsp; <br />&nbsp;<br />2）显示星期几&nbsp; <br />select&nbsp; datename(weekday,getdate())&nbsp;&nbsp;&nbsp; <br />&nbsp;<br />3）如何取得某个月的天数&nbsp; <br />declare&nbsp; @m&nbsp; int&nbsp; <br />set&nbsp; @m=2&nbsp; --月份&nbsp; <br />select&nbsp;&nbsp;&nbsp; datediff(day,'2003-'+cast(@m&nbsp; as&nbsp; varchar)+'-15'&nbsp; ,'2003-'+cast(@m+1&nbsp;&nbsp;&nbsp; as&nbsp; varchar)+'-15')&nbsp; <br />另外，取得本月天数&nbsp; <br />select&nbsp;&nbsp;&nbsp; datediff(day,cast(month(GetDate())&nbsp; as&nbsp; varchar)+'-'+cast(month(GetDate())&nbsp; as&nbsp; varchar)+'-15'&nbsp; ,cast(month(GetDate())&nbsp; as&nbsp; varchar)+'-'+cast(month(GetDate())+1&nbsp;&nbsp;&nbsp; as&nbsp; varchar)+'-15')&nbsp; <br />或者使用计算本月的最后一天的脚本，然后用DAY函数区最后一天&nbsp; <br />SELECT&nbsp; Day(dateadd(ms,-3,DATEADD(mm,&nbsp; DATEDIFF(m,0,getdate())+1,&nbsp; 0)))&nbsp; <br />&nbsp;<br />4）判断是否闰年：&nbsp; <br />SELECT&nbsp; case&nbsp; day(dateadd(mm,&nbsp; 2,&nbsp; dateadd(ms,-3,DATEADD(yy,&nbsp; DATEDIFF(yy,0,getdate()),&nbsp; 0))))&nbsp; when&nbsp; 28&nbsp; then&nbsp; '平年'&nbsp; else&nbsp; '闰年'&nbsp; end&nbsp; <br />或者&nbsp; <br />select&nbsp; case&nbsp; datediff(day,datename(year,getdate())+'-02-01',dateadd(mm,1,datename(year,getdate())+'-02-01'))&nbsp; <br />when&nbsp; 28&nbsp; then&nbsp; '平年'&nbsp; else&nbsp; '闰年'&nbsp; end&nbsp; <br />&nbsp;<br />5）一个季度多少天&nbsp; <br />declare&nbsp; @m&nbsp; tinyint,@time&nbsp; smalldatetime&nbsp; <br />select&nbsp; @m=month(getdate())&nbsp; <br />select&nbsp; @m=case&nbsp; when&nbsp; @m&nbsp; between&nbsp; 1&nbsp; and&nbsp; 3&nbsp; then&nbsp; 1&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; when&nbsp; @m&nbsp; between&nbsp; 4&nbsp; and&nbsp; 6&nbsp; then&nbsp; 4&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; when&nbsp; @m&nbsp; between&nbsp; 7&nbsp; and&nbsp; 9&nbsp; then&nbsp; 7&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else&nbsp; 10&nbsp; end&nbsp; <br />select&nbsp; @time=datename(year,getdate())+'-'+convert(varchar(10),@m)+'-01'&nbsp; <br />select&nbsp; datediff(day,@time,dateadd(mm,3,@time))<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/sql/" rel="tag">sql</a> , <a href="http://www.gaobo.info/go.php/tags/server/" rel="tag">server</a> , <a href="http://www.gaobo.info/go.php/tags/sqlserver/" rel="tag">sqlserver</a> , <a href="http://www.gaobo.info/go.php/tags/date/" rel="tag">date</a> , <a href="http://www.gaobo.info/go.php/tags/time/" rel="tag">time</a> , <a href="http://www.gaobo.info/go.php/tags/query/" rel="tag">query</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%2597%25A5%25E6%259C%259F/" rel="tag">日期</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%25AF%2594%25E8%25BE%2583/" rel="tag">比较</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%259F%25A5%25E8%25AF%25A2/" rel="tag">查询</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/618.htm</link>
<title><![CDATA[C#日期格式化]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Thu, 09 Jul 2009 08:01:35 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/618.htm</guid> 
<description>
<![CDATA[ 
	<span style="font-size: x-small"><strong>日期转化一</strong><br /><br />为了达到不同的显示效果有时，我们需要对时间进行转化，默认格式为：2007-01-03 14:33:34 ，要转化为其他格式，要用到DateTime.ToString的方法(String, IFormatProvider)，如下所示：<br /><br />using System;<br />using System.Globalization;<br />String format=&quot;D&quot;;<br />DateTime date=DataTime,Now;<br />Response.Write(date.ToString(format, DateTimeFormatInfo.InvariantInfo));<br /><br />结果输出<br />Thursday, June 16, 2005<br /><br />参数format格式详细用法：<br /><br />格式字符 关联属性/说明 <br />d ShortDatePattern <br />D LongDatePattern <br />f 完整日期和时间（长日期和短时间） <br />F FullDateTimePattern（长日期和长时间） <br />g 常规（短日期和短时间） <br />G 常规（短日期和长时间） <br />m、M MonthDayPattern <br />r、R RFC1123Pattern <br />s 使用当地时间的 SortableDateTimePattern（基于 ISO 8601） <br />t ShortTimePattern <br />T LongTimePattern <br />u UniversalSortableDateTimePattern 用于显示通用时间的格式 <br />U 使用通用时间的完整日期和时间（长日期和长时间） <br />y、Y YearMonthPattern <br /><br />下表列出了可被合并以构造自定义模式的模式。这些模式是区分大小写的；例如，识别&ldquo;MM&rdquo;，但不识别&ldquo;mm&rdquo;。如果自定义模式包含空白字符或用单引号括起来的字符，则输出字符串页也将包含这些字符。未定义为格式模式的一部分或未定义为格式字符的字符按其原义复制。<br /><br />格式模式 说明 <br />d 月中的某一天。一位数的日期没有前导零。 <br />dd 月中的某一天。一位数的日期有一个前导零。 <br />ddd 周中某天的缩写名称，在 AbbreviatedDayNames 中定义。 <br />dddd 周中某天的完整名称，在 DayNames 中定义。 <br />M 月份数字。一位数的月份没有前导零。 <br />MM 月份数字。一位数的月份有一个前导零。 <br />MMM 月份的缩写名称，在 AbbreviatedMonthNames 中定义。 <br />MMMM 月份的完整名称，在 MonthNames 中定义。 <br />y 不包含纪元的年份。如果不包含纪元的年份小于 10，则显示不具有前导零的年份。 <br />yy 不包含纪元的年份。如果不包含纪元的年份小于 10，则显示具有前导零的年份。 <br />yyyy 包括纪元的四位数的年份。 <br />gg 时期或纪元。如果要设置格式的日期不具有关联的时期或纪元字符串，则忽略该模式。 <br />h 12 小时制的小时。一位数的小时数没有前导零。 <br />hh 12 小时制的小时。一位数的小时数有前导零。 <br />H 24 小时制的小时。一位数的小时数没有前导零。 <br />HH 24 小时制的小时。一位数的小时数有前导零。 <br />m 分钟。一位数的分钟数没有前导零。 <br />mm 分钟。一位数的分钟数有一个前导零。 <br />s 秒。一位数的秒数没有前导零。 <br />ss 秒。一位数的秒数有一个前导零。 <br />f 秒的小数精度为一位。其余数字被截断。 <br />ff 秒的小数精度为两位。其余数字被截断。 <br />fff 秒的小数精度为三位。其余数字被截断。 <br />ffff 秒的小数精度为四位。其余数字被截断。 <br />fffff 秒的小数精度为五位。其余数字被截断。 <br />ffffff 秒的小数精度为六位。其余数字被截断。 <br />fffffff 秒的小数精度为七位。其余数字被截断。 <br />t 在 AMDesignator 或 PMDesignator 中定义的 AM/PM 指示项的第一个字符（如果存在）。 <br />tt 在 AMDesignator 或 PMDesignator 中定义的 AM/PM 指示项（如果存在）。 <br />z 时区偏移量（&ldquo;+&rdquo;或&ldquo;-&rdquo;后面仅跟小时）。一位数的小时数没有前导零。例如，太平洋标准时间是&ldquo;-8&rdquo;。 <br />zz 时区偏移量（&ldquo;+&rdquo;或&ldquo;-&rdquo;后面仅跟小时）。一位数的小时数有前导零。例如，太平洋标准时间是&ldquo;-08&rdquo;。 <br />zzz 完整时区偏移量（&ldquo;+&rdquo;或&ldquo;-&rdquo;后面跟有小时和分钟）。一位数的小时数和分钟数有前导零。例如，太平洋标准时间是&ldquo;-08:00&rdquo;。 <br />: 在 TimeSeparator 中定义的默认时间分隔符。 <br />/ 在 DateSeparator 中定义的默认日期分隔符。 <br />% c 其中 c 是格式模式（如果单独使用）。如果格式模式与原义字符或其他格式模式合并，则可以省略&ldquo;%&rdquo;字符。 <br />&#92; c 其中 c 是任意字符。照原义显示字符。若要显示反斜杠字符，请使用&ldquo;&#92;&#92;&rdquo;。 <br /><br />只有上面第二个表中列出的格式模式才能用于创建自定义模式；在第一个表中列出的标准格式字符不能用于创建自定义模式。自定义模式的长度至少为两个字符；例如， <br /><br />DateTime.ToString( &quot;d&quot;) 返回 DateTime 值；&ldquo;d&rdquo;是标准短日期模式。 <br />DateTime.ToString( &quot;%d&quot;) 返回月中的某天；&ldquo;%d&rdquo;是自定义模式。 <br />DateTime.ToString( &quot;d &quot;) 返回后面跟有一个空白字符的月中的某天；&ldquo;d&rdquo;是自定义模式。 <br /><br />比较方便的是,上面的参数可以随意组合,并且不会出错,多试试,肯定会找到你要的时间格式<br />如要得到2005年06月 这样格式的时间<br />可以这样写:<br />date.ToString(&quot;yyyy年MM月&quot;, DateTimeFormatInfo.InvariantInfo)<br /><br /><strong>日期转化二</strong><br /><br />DateTime dt = DateTime.Now;<br />Label1.Text = dt.ToString();//2005-11-5 13:21:25<br />Label2.Text = dt.ToFileTime().ToString();//127756416859912816<br />Label3.Text = dt.ToFileTimeUtc().ToString();//127756704859912816<br />Label4.Text = dt.ToLocalTime().ToString();//2005-11-5 21:21:25<br />Label5.Text = dt.ToLongDateString().ToString();//2005年11月5日<br />Label6.Text = dt.ToLongTimeString().ToString();//13:21:25<br />Label7.Text = dt.ToOADate().ToString();//38661.5565508218<br />Label8.Text = dt.ToShortDateString().ToString();//2005-11-5<br />Label9.Text = dt.ToShortTimeString().ToString();//13:21<br />Label10.Text = dt.ToUniversalTime().ToString();//2005-11-5 5:21:25<br /><br />Label1.Text = dt.Year.ToString();//2005<br />Label2.Text = dt.Date.ToString();//2005-11-5 0:00:00<br />Label3.Text = dt.DayOfWeek.ToString();//Saturday<br />Label4.Text = dt.DayOfYear.ToString();//309<br />Label5.Text = dt.Hour.ToString();//13<br />Label6.Text = dt.Millisecond.ToString();//441<br />Label7.Text = dt.Minute.ToString();//30<br />Label8.Text = dt.Month.ToString();//11<br />Label9.Text = dt.Second.ToString();//28<br />Label10.Text = dt.Ticks.ToString();//632667942284412864<br />Label11.Text = dt.TimeOfDay.ToString();//13:30:28.4412864<br /><br />Label1.Text = dt.ToString();//2005-11-5 13:47:04<br />Label2.Text = dt.AddYears(1).ToString();//2006-11-5 13:47:04<br />Label3.Text = dt.AddDays(1.1).ToString();//2005-11-6 16:11:04<br />Label4.Text = dt.AddHours(1.1).ToString();//2005-11-5 14:53:04<br />Label5.Text = dt.AddMilliseconds(1.1).ToString();//2005-11-5 13:47:04<br />Label6.Text = dt.AddMonths(1).ToString();//2005-12-5 13:47:04<br />Label7.Text = dt.AddSeconds(1.1).ToString();//2005-11-5 13:47:05<br />Label8.Text = dt.AddMinutes(1.1).ToString();//2005-11-5 13:48:10<br />Label9.Text = dt.AddTicks(1000).ToString();//2005-11-5 13:47:04<br />Label10.Text = dt.CompareTo(dt).ToString();//0<br />Label11.Text = dt.Add(?).ToString();//问号为一个时间段<br /><br />Label1.Text = dt.Equals(&quot;2005-11-6 16:11:04&quot;).ToString();//False<br />Label2.Text = dt.Equals(dt).ToString();//True<br />Label3.Text = dt.GetHashCode().ToString();//1474088234<br />Label4.Text = dt.GetType().ToString();//System.DateTime<br />Label5.Text = dt.GetTypeCode().ToString();//DateTime<br /><br />Label1.Text = dt.GetDateTimeFormats('s')[0].ToString();//2005-11-05T14:06:25<br />Label2.Text = dt.GetDateTimeFormats('t')[0].ToString();//14:06<br />Label3.Text = dt.GetDateTimeFormats('y')[0].ToString();//2005年11月<br />Label4.Text = dt.GetDateTimeFormats('D')[0].ToString();//2005年11月5日<br />Label5.Text = dt.GetDateTimeFormats('D')[1].ToString();//2005 11 05<br />Label6.Text = dt.GetDateTimeFormats('D')[2].ToString();//星期六 2005 11 05<br />Label7.Text = dt.GetDateTimeFormats('D')[3].ToString();//星期六 2005年11月5日<br />Label8.Text = dt.GetDateTimeFormats('M')[0].ToString();//11月5日<br />Label9.Text = dt.GetDateTimeFormats('f')[0].ToString();//2005年11月5日 14:06<br />Label10.Text = dt.GetDateTimeFormats('g')[0].ToString();//2005-11-5 14:06<br />Label11.Text = dt.GetDateTimeFormats('r')[0].ToString();//Sat, 05 Nov 2005 14:06:25 GMT<br /><br />Label1.Text = string.Format(&quot;&#123;0:d&#125;&quot;,dt);//2005-11-5<br />Label2.Text = string.Format(&quot;&#123;0:D&#125;&quot;,dt);//2005年11月5日<br />Label3.Text = string.Format(&quot;&#123;0:f&#125;&quot;,dt);//2005年11月5日 14:23<br />Label4.Text = string.Format(&quot;&#123;0:F&#125;&quot;,dt);//2005年11月5日 14:23:23<br />Label5.Text = string.Format(&quot;&#123;0:g&#125;&quot;,dt);//2005-11-5 14:23<br />Label6.Text = string.Format(&quot;&#123;0:G&#125;&quot;,dt);//2005-11-5 14:23:23<br />Label7.Text = string.Format(&quot;&#123;0:M&#125;&quot;,dt);//11月5日<br />Label8.Text = string.Format(&quot;&#123;0:R&#125;&quot;,dt);//Sat, 05 Nov 2005 14:23:23 GMT<br />Label9.Text = string.Format(&quot;&#123;0:s&#125;&quot;,dt);//2005-11-05T14:23:23<br />Label10.Text&nbsp;&nbsp; string.Format(&quot;&#123;0:t&#125;&quot;,dt);//14:23<br />Label11.Text = string.Format(&quot;&#123;0:T&#125;&quot;,dt);//14:23:23<br />Label12.Text = string.Format(&quot;&#123;0:u&#125;&quot;,dt);//2005-11-05 14:23:23Z<br />Label13.Text = string.Format(&quot;&#123;0:U&#125;&quot;,dt);//2005年11月5日 6:23:23<br />Label14.Text = string.Format(&quot;&#123;0:Y&#125;&quot;,dt);//2005年11月<br />Label15.Text = string.Format(&quot;&#123;0&#125;&quot;,dt);//2005-11-5 14:23:23<br />Label16.Text = string.Format(&quot;&#123;0:yyyyMMddHHmmssffff&#125;&quot;,dt);&nbsp;&nbsp;</span><pre><h1><span style="color: #993366; font-size: x-small">C＃比较两时间大小</span></h1></pre><pre><span style="font-size: x-small">1、比较时间大小的实验<br />&nbsp;&nbsp;&nbsp; string st1=&quot;12:13&quot;;<br />&nbsp;&nbsp;&nbsp; string st2=&quot;14:14&quot;;<br />&nbsp;&nbsp;&nbsp; DateTime dt1=Convert.ToDateTime(st1);<br />&nbsp;&nbsp;&nbsp; DateTime dt2=Convert.ToDateTime(st2);<br />&nbsp;&nbsp;&nbsp; DateTime dt3=DateTime.Now;<br />&nbsp;&nbsp;&nbsp; if(DateTime.Compare(dt1,dt2)&gt;0)<br />&nbsp;&nbsp;&nbsp;&nbsp; msg.Text=st1+&quot;&gt;&quot;+st2;<br />&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp; msg.Text=st1+&quot;&lt;&quot;+st2;<br />&nbsp;&nbsp;&nbsp; msg.Text+=&quot;&#92;r&#92;n&quot;+dt1.ToString();<br />&nbsp;&nbsp;&nbsp; if(DateTime.Compare(dt1,dt3)&gt;0)<br />&nbsp;&nbsp;&nbsp;&nbsp; msg.Text+=&quot;&#92;r&#92;n&quot;+st1+&quot;&gt;&quot;+dt3.ToString();<br />&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp; msg.Text+=&quot;&#92;r&#92;n&quot;+st1+&quot;&lt;&quot;+dt3.ToString();</span></pre><pre><span style="font-size: x-small">2、计算两个时间差值的函数，返回时间差的绝对值：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private string DateDiff(DateTime DateTime1,DateTime DateTime2)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#123;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string dateDiff=null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#123;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeSpan ts1=new&nbsp;&nbsp; TimeSpan(DateTime1.Ticks);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeSpan ts2=new&nbsp;&nbsp; TimeSpan(DateTime2.Ticks);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeSpan ts=ts1.Subtract(ts2).Duration();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dateDiff=ts.Days.ToString()+&quot;天&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +ts.Hours.ToString()+&quot;小时&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +ts.Minutes.ToString()+&quot;分钟&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +ts.Seconds.ToString()+&quot;秒&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#123;</span></pre><pre><span style="font-size: x-small">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return dateDiff;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#125;</span></pre><pre><span style="font-size: x-small">3、实现计算DateTime1－36天＝DateTime2的功能</span></pre><pre><span style="font-size: x-small">&nbsp;&nbsp;&nbsp; TimeSpan ts=new TimeSpan(40,0,0,0);<br />&nbsp;&nbsp;&nbsp; DateTime dt2=DateTime.Now.Subtract(ts);<br />&nbsp;&nbsp;&nbsp; msg.Text=DateTime.Now.ToString()+&quot;-&quot;+ts.Days.ToString()+&quot;天&#92;r&#92;n&quot;;<br />&nbsp;&nbsp;&nbsp; msg.Text+=dt2.ToString();</span></pre><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/date/" rel="tag">date</a> , <a href="http://www.gaobo.info/go.php/tags/time/" rel="tag">time</a> , <a href="http://www.gaobo.info/go.php/tags/format/" rel="tag">format</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%2597%25A5%25E6%259C%259F/" rel="tag">日期</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%25A0%25BC%25E5%25BC%258F%25E5%258C%2596/" rel="tag">格式化</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/452.htm</link>
<title><![CDATA[Visual Studio Express与SharpDevelop的对比]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Sun, 28 Oct 2007 11:11:27 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/452.htm</guid> 
<description>
<![CDATA[ 
	同为C#的集成开发工具（IDE），微软出品的工具与另外一套第三方的工具功能对比如下。<br /><table border="0" class="article"><tbody><tr><th>Feature</th><th>SharpDevelop 2.1</th><th>Visual Studio Express Editions</th></tr><tr><td>Code auto-completion</td><td>Yes</td><td>Yes</td></tr><tr><td>Code syntax highlighting</td><td>Yes</td><td>Yes</td></tr><tr><td>Windows Forms Designer</td><td>Yes</td><td>Yes</td></tr><tr><td>Web Forms Designer</td><td>No</td><td>Provided with Visual Web Developer</td></tr><tr><td>Code Coverage</td><td>Yes</td><td>No</td></tr><tr><td>Unit Testing</td><td>Yes</td><td>No</td></tr><tr><td>Languages Supported</td><td>C#, VB.NET, Boo</td><td>C#, C++, VB.NET, J#</td></tr><tr><td>Help documentation</td><td>No</td><td>Yes</td></tr><tr><td>Plug-in support</td><td>Yes</td><td>No explicit support for plug-ins however third party plug-ins can work with the Express edition.</td></tr><tr><td>Insert PInvoke Signatures</td><td>Yes</td><td>No</td></tr><tr><td>Testing Regular Expressions</td><td>Yes</td><td>No</td></tr><tr><td>Class View</td><td>Yes</td><td>Yes</td></tr><tr><td>Solution Explorer</td><td>Yes</td><td>Yes</td></tr><tr><td>Project and Solution File Format</td><td>MSBuild</td><td>MSBuild</td></tr><tr><td>Web references</td><td>Yes</td><td>Yes</td></tr><tr><td>Refactorings</td><td>Rename</td><td>Rename, Extract Method</td></tr><tr><td>Go to definition</td><td>Yes</td><td>Yes</td></tr><tr><td>Find References</td><td>Yes</td><td>Yes</td></tr><tr><td>Code generation</td><td>Yes. Not as powerful as Visual Studio's Code Snippet Manager.</td><td>Yes</td></tr><tr><td>Object Browser</td><td>Yes</td><td>Yes</td></tr><tr><td>Database Explorer</td><td>Yes. Lacking support for many database providers.</td><td>Yes</td></tr><tr><td>Publishing</td><td>No</td><td>Yes</td></tr><tr><td>Data Sources View</td><td>No</td><td>Yes</td></tr><tr><td>Add Data Source Wizard</td><td>No</td><td>Yes</td></tr><tr><td>Document Outline View</td><td>No</td><td>Yes</td></tr><tr><td>Resources</td><td>Local only</td><td>Local and project</td></tr><tr><td>ActiveX Toolbox Items</td><td>Partial - need to generate .NET interop library</td><td>Yes</td></tr><tr><td>Integrated debugger</td><td>Yes</td><td>Yes</td></tr><tr><td>Targeting different .NET frameworks</td><td>Yes</td><td>No</td></tr><tr><td>Code Completion for different .NET frameworks</td><td>Yes</td><td>No</td></tr><tr><td>Reporting</td><td>Yes</td><td>Yes through the report viewer plug-in</td></tr><tr><td>Task List</td><td>Yes</td><td>Yes</td></tr><tr><td>Error List</td><td>Yes</td><td>Yes</td></tr><tr><td>Database Designer Tools</td><td>No</td><td>Yes</td></tr><tr><td>Code conversion</td><td>Yes</td><td>No</td></tr><tr><td>Integrated NAnt support</td><td>Yes</td><td>No</td></tr><tr><td>Integrated WiX support</td><td>Yes</td><td>No</td></tr><tr><td>Integrated FxCop support</td><td>Yes</td><td>No</td></tr><tr><td>Navigation History</td><td>Yes</td><td>Yes</td></tr><tr><td>XPath Queries</td><td>Yes</td><td>No</td></tr><tr><td>Incremental Search</td><td>Yes</td><td>Yes</td></tr><tr><td>XML documentation preview and generation</td><td>Yes</td><td>No</td></tr></tbody></table><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/visual/" rel="tag">visual</a> , <a href="http://www.gaobo.info/go.php/tags/studio/" rel="tag">studio</a> , <a href="http://www.gaobo.info/go.php/tags/express/" rel="tag">express</a> , <a href="http://www.gaobo.info/go.php/tags/sharpdevelop/" rel="tag">sharpdevelop</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25BC%2580%25E5%258F%2591%25E5%25B7%25A5%25E5%2585%25B7/" rel="tag">开发工具</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/450.htm</link>
<title><![CDATA[Silverlight开发工具的安装步骤]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Sun, 28 Oct 2007 10:30:44 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/450.htm</guid> 
<description>
<![CDATA[ 
	如果现在要开发Silverlight应用程序也好、RIA也好、想要在ASP.NET当中整合Silverlight也好，请安装底下这些开发工具，注意，请依序安装。底下说明每一个工具的用途以及为何需要安装...<br/><br/>建议“务必依序”安装底下套件： <br/>◎ Visual Studio 2005 → 这个做什么的不用说吧，请最好不要用Express版本 <br/>◎ Silverlight 1.0 Run-time(Windows版本) → 用来将你的浏览器外挂Silverlight显示功能 <br/>◎ Visual Studio 2005 Services Pack 1 → 要先装这个之后，后面Silvrlight 1.0 SDK才装得起来<br/>◎ Silvrlight 1.0 SDK → 装这个之后，VS2005中就会有 Silverlight 样板Project(位于C#) <br/>◎ ASP.NET AJAX 1.0 → 要先装这个之后，后面的 Futures Release才装得起来，而且，安装之后，Silverlight 才能够透过AJAX技术读取后端资料库 <br/>◎ ASP.NET Futures Release → 让ASP.NET可以轻松整合Silverlight <br/>◎ .NET Framework 3.0(中文版) → 要先装这个之后，后面的 Blend 2 才装得起来 <br/>◎ Expression Blend 2(英文版) → 该死的VS2005没有所视即所得，所以需要用Blend 2帮开发人员用拖曳的方式设计Silverlight的UI，除非你的Xaml指令码滚瓜烂熟。此软件也三五不时有新版，请自己找一下... <br/><br/>完成之后即可开发各式各样的Silverlight应用程序。<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/silverlight/" rel="tag">silverlight</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25BC%2580%25E5%258F%2591%25E5%25B7%25A5%25E5%2585%25B7/" rel="tag">开发工具</a> , <a href="http://www.gaobo.info/go.php/tags/%25E5%25AE%2589%25E8%25A3%2585/" rel="tag">安装</a> , <a href="http://www.gaobo.info/go.php/tags/visual/" rel="tag">visual</a> , <a href="http://www.gaobo.info/go.php/tags/studio/" rel="tag">studio</a> , <a href="http://www.gaobo.info/go.php/tags/asp/" rel="tag">asp</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/c%2523/" rel="tag">c#</a> , <a href="http://www.gaobo.info/go.php/tags/expression/" rel="tag">expression</a> , <a href="http://www.gaobo.info/go.php/tags/blend/" rel="tag">blend</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/337.htm</link>
<title><![CDATA[。Net大文件上传组件SunriseUpload]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Sun, 25 Feb 2007 14:35:57 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/337.htm</guid> 
<description>
<![CDATA[ 
	这个大文件上传组件是Mic在2004年写的，主页丢失后就再也没有升级过，后来把它放到了<a href="http://www.gotdotnet.com" target="_blank">www.gotdotnet.com</a>，还可以在这里找到它：<br/><a href="http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=FE16801F-2D2C-49FD-BE31-D28135365379" target="_blank">http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=FE16801F-2D2C-49FD-BE31-D28135365379</a><br/>组件基本可以使用，但可能还有些bug没有解决<br/>SunriseUpload组件的特点:<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">支持几百M的文件上传 <br/>提供一个上传进度条展现上载进度 <br/>可以上传一到多个文件</div></div><br/><a href="attachment/200702/1172413671_0.zip">点击这里下载文件</a><br/>Tags - <a href="http://www.gaobo.info/go.php/tags/%25E5%25A4%25A7%25E6%2596%2587%25E4%25BB%25B6/" rel="tag">大文件</a> , <a href="http://www.gaobo.info/go.php/tags/%25E4%25B8%258A%25E4%25BC%25A0/" rel="tag">上传</a> , <a href="http://www.gaobo.info/go.php/tags/%25E7%25BB%2584%25E4%25BB%25B6/" rel="tag">组件</a> , <a href="http://www.gaobo.info/go.php/tags/sunrise/" rel="tag">sunrise</a> , <a href="http://www.gaobo.info/go.php/tags/upload/" rel="tag">upload</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/219.htm</link>
<title><![CDATA[Asp.net 1.x全局设置经验]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Tue, 05 Sep 2006 01:09:28 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/219.htm</guid> 
<description>
<![CDATA[ 
	可以通过以下设置控制asp.net对服务器内存的占用。并能设置aspnet进程定时重建（类似IIS6中AppPool里的定时重启），这样可以避免服务器长时间运行aspnet占用大量空闲内存，有利于提高aspnet运行效率。<br/><br/>aspnet配置文件位置为C:&#92;WINDOWS&#92;Microsoft.NET&#92;Framework&#92;v1.1.4322&#92;CONFIG&#92;machine.config<br/>用文本编辑器打开该文件，找到以内容按注释修改<br/><br/><processModel enable="true"<br/> &nbsp; timeout="01:00:00"　　--超时时间，指定多长时间后重建aspnet进程，建议设为数小时，格式"小时:分钟:秒"<br/> &nbsp; idleTimeout="00:20:00"　　--aspnet多长时间无动作时关闭进程，建议数十分钟<br/> &nbsp; ...<br/> &nbsp; memoryLimit="40" 　--aspnet最多占用服务器内存数，默认40%<br/> &nbsp; ...<br/>Tags - <a href="http://www.gaobo.info/go.php/tags/asp/" rel="tag">asp</a> , <a href="http://www.gaobo.info/go.php/tags/.net/" rel="tag">.net</a> , <a href="http://www.gaobo.info/go.php/tags/%25E6%259C%258D%25E5%258A%25A1%25E5%2599%25A8/" rel="tag">服务器</a> , <a href="http://www.gaobo.info/go.php/tags/%25E9%2585%258D%25E7%25BD%25AE/" rel="tag">配置</a>
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/190.htm</link>
<title><![CDATA[.net官方编码方法和命名规则]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Wed, 16 Aug 2006 09:16:25 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/190.htm</guid> 
<description>
<![CDATA[ 
	<strong>编码方法</strong><br/>编码方法合并了软件开发的许多方面。尽管它们通常对应用程序的功能没有影响，但它们对于改善对源代码的理解是有帮助的。这里考虑了所有形式的源代码，包括编程、脚本撰写、标记和查询语言。<br/><br/>不建议将这里定义的编码方法形成一套固定的编码标准。相反，它们旨在作为开发特定软件项目的编码标准的指南。<br/><br/>编码方法分为三部分： <br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content">命名 <br/>注释 <br/>格式</div></div><br/><strong>命名</strong><br/>对于理解应用程序的逻辑流，命名方案是最有影响力的一种帮助。名称应该说明“什么”而不是“如何”。通过避免使用公开基础实现（它们会发生改变）的名称，可以保留简化复杂性的抽象层。例如，可以使用 GetNextStudent()，而不是 GetNextArrayElement()。<br/><br/><strong>命名原则是：选择正确名称时的困难可能表明需要进一步分析或定义项的目的。使名称足够长以便有一定的意义，并且足够短以避免冗长。唯一名称在编程上仅用于将各项区分开。表现力强的名称是为了帮助人们阅读；因此，提供人们可以理解的名称是有意义的。不过，请确保选择的名称符合适用语言的规则和标准。</strong><br/><br/>以下几点是推荐的命名方法。<br/><br/><strong>例程</strong><br/>避免容易被主观解释的难懂的名称，如对于例程的 AnalyzeThis()，或者对于变量的 xxK8。这样的名称会导致多义性，而不仅仅是抽象。 <br/>在面向对象的语言中，在类属性的名称中包含类名是多余的，如 Book.BookTitle。而是应该使用 Book.Title。 <br/>使用动词-名词的方法来命名对给定对象执行特定操作的例程，如 CalculateInvoiceTotal()。 <br/>在允许函数重载的语言中，所有重载都应该执行相似的函数。对于那些不允许函数重载的语言，建立使相似函数发生关系的命名标准。 <br/><strong>变量</strong><br/>只要合适，在变量名的末尾追加计算限定符（Avg、Sum、Min、Max、Index）。 <br/>在变量名中使用互补对，如 min/max、begin/end 和 open/close。 <br/>鉴于大多数名称都是通过连接若干单词构造的，请使用大小写混合的格式以简化它们的阅读。另外，为了帮助区分变量和例程，请对例程名称使用 Pascal 大小写处理 (CalculateInvoiceTotal)，其中每个单词的第一个字母都是大写的。对于变量名，请使用 camel 大小写处理 (documentFormatType)，其中除了第一个单词外每个单词的第一个字母都是大写的。 <br/>布尔变量名应该包含 Is，这意味着 Yes/No 或 True/False 值，如 fileIsFound。 <br/>在命名状态变量时，避免使用诸如 Flag 的术语。状态变量不同于布尔变量的地方是它可以具有两个以上的可能值。不是使用 documentFlag，而是使用更具描述性的名称，如 documentFormatType。 <br/>即使对于可能仅出现在几个代码行中的生存期很短的变量，仍然使用有意义的名称。仅对于短循环索引使用单字母变量名，如 i 或 j。 <br/>不要使用原义数字或原义字符串，如 For i = 1 To 7。而是使用命名常数，如 For i = 1 To NUM_DAYS_IN_WEEK 以便于维护和理解。<br/><br/><strong>表</strong><br/>在命名表时，用单数形式表示名称。例如，使用 Employee，而不是 Employees。 <br/>在命名表的列时，不要重复表的名称；例如，在名为 Employee 的表中避免使用名为 EmployeeLastName 的字段。 <br/>不要在列的名称中包含数据类型。如果后来有必要更改数据类型，这将减少工作量。 <br/>Microsoft SQL Server<br/>不要给存储过程加 sp 前缀，这个前缀是为标识系统存储过程保留的。 <br/>不要给用户定义的函数加 fn_ 前缀，这个前缀是为标识内置函数保留的。 <br/>不要给扩展存储过程加 xp_ 前缀，这个前缀是为标识系统扩展存储过程保留的。 <br/><strong>杂项</strong><br/>尽量减少使用缩写，而是使用以一致方式创建的缩写。缩写应该只有一个意思；同样，每个缩写词也应该只有一个缩写。例如，如果用 min 作为 minimum 的缩写，那么在所有地方都应这样做；不要将 min 又用作 minute 的缩写。 <br/>在命名函数时包括返回值的说明，如 GetCurrentWindowName()。 <br/>与过程名一样，文件和文件夹的名称也应该精确地说明它们的用途。 <br/>避免对不同的元素重用名称，如名为 ProcessSales() 的例程和名为 iProcessSales 的变量。 <br/>在命名元素时避免同音异义词（如 write 和 right），以防在检查代码时发生混淆。 <br/>在命名元素时，避免使用普遍拼错的词。另外，应清楚区域拼写之间存在的差异，如 color/colour 和 check/cheque。 <br/>避免用印刷标记来标识数据类型，如用 $ 代表字符串或用 % 代表整数。<br/><br/><strong>注释</strong><br/>软件文档以两种形式存在：外部的和内部的。外部文档（如规范、帮助文件和设计文档）在源代码的外部维护。内部文档由开发人员在开发时在源代码中编写的注释组成。<br/><br/>不考虑外部文档的可用性，由于硬拷贝文档可能会放错地方，源代码清单应该能够独立存在。外部文档应该由规范、设计文档、更改请求、错误历史记录和使用的编码标准组成。<br/><br/>内部软件文档的一个难题是确保注释的维护与更新与源代码同时进行。尽管正确注释源代码在运行时没有任何用途，但这对于必须维护特别复杂或麻烦的软件片段的开发人员来说却是无价的。<br/><br/>以下几点是推荐的注释方法： <br/><br/>如果用 C# 进行开发，请使用 XML 文档功能。有关更多信息，请参见：XML 文档。 <br/>修改代码时，总是使代码周围的注释保持最新。 <br/>在每个例程的开始，提供标准的注释样本以指示例程的用途、假设和限制很有帮助。注释样本应该是解释它为什么存在和可以做什么的简短介绍。 <br/>避免在代码行的末尾添加注释；行尾注释使代码更难阅读。不过在批注变量声明时，行尾注释是合适的；在这种情况下，将所有行尾注释在公共制表位处对齐。 <br/>避免杂乱的注释，如一整行星号。而是应该使用空白将注释同代码分开。 <br/>避免在块注释的周围加上印刷框。这样看起来可能很漂亮，但是难于维护。 <br/>在部署之前，移除所有临时或无关的注释，以避免在日后的维护工作中产生混乱。 <br/>如果需要用注释来解释复杂的代码节，请检查此代码以确定是否应该重写它。尽一切可能不注释难以理解的代码，而应该重写它。尽管一般不应该为了使代码更简单以便于人们使用而牺牲性能，但必须保持性能和可维护性之间的平衡。 <br/>在编写注释时使用完整的句子。注释应该阐明代码，而不应该增加多义性。 <br/>在编写代码时就注释，因为以后很可能没有时间这样做。另外，如果有机会复查已编写的代码，在今天看来很明显的东西六周以后或许就不明显了。 <br/>避免多余的或不适当的注释，如幽默的不主要的备注。 <br/>使用注释来解释代码的意图。它们不应作为代码的联机翻译。 <br/>注释代码中不十分明显的任何内容。 <br/>为了防止问题反复出现，对错误修复和解决方法代码总是使用注释，尤其是在团队环境中。 <br/>对由循环和逻辑分支组成的代码使用注释。这些是帮助源代码读者的主要方面。 <br/>在整个应用程序中，使用具有一致的标点和结构的统一样式来构造注释。 <br/>用空白将注释同注释分隔符分开。在没有颜色提示的情况下查看注释时，这样做会使注释很明显且容易被找到。<br/><br/><strong>格式</strong><br/>格式化使代码的逻辑结构很明显。花时间确保源代码以一致的逻辑方式进行格式化，这对于您和必须解密源代码的其他开发人员都有帮助。<br/><br/>以下几点是推荐的格式化方法。 <br/><br/>建立标准的缩进大小（如四个空格），并一致地使用此标准。用规定的缩进对齐代码节。 <br/>在发布源代码的硬拷贝版本时使用 monotype 字体。 <br/>在括号对对齐的位置垂直对齐左括号和右括号，如： <br/><div class="code">for (i = 0; i &lt; 100; i++)<br/>&#123;<br/> &nbsp; ...<br/>&#125;</div><br/>还可以使用倾斜样式，即左括号出现在行尾，右括号出现在行首，如： <br/><div class="code">for (i = 0; i &lt; 100; i++)&#123;<br/> &nbsp; ...<br/>&#125;</div><br/>无论选择哪种样式，请在整个源代码中使用那个样式。 <br/><br/>沿逻辑结构行缩进代码。没有缩进，代码将变得难以理解，如： <br/><div class="code">If ... Then<br/>If ... Then<br/>...<br/>Else<br/>End If<br/>Else<br/>...<br/>End If</div><br/><br/>缩进代码会产生出更容易阅读的代码，如： <br/><div class="code">If ... Then<br/> &nbsp; If ... Then<br/> &nbsp; ...<br/> &nbsp; Else<br/> &nbsp; ...<br/> &nbsp; End If<br/>Else<br/>...<br/>End If</div><br/>为注释和代码建立最大的行长度，以避免不得不滚动源代码编辑器，并且可以提供整齐的硬拷贝表示形式。 <br/>在大多数运算符之前和之后使用空格，这样做时不会改变代码的意图。但是，C++ 中使用的指针表示法是一个例外。 <br/>使用空白为源代码提供结构线索。这样做会创建代码“段”，有助于读者理解软件的逻辑分段。 <br/>当一行被分为几行时，通过将串联运算符放在每一行的末尾而不是开头，清楚地表示没有后面的行是不完整的。 <br/>只要合适，每一行上放置的语句避免超过一条。例外是 C、C++、C# 或 JScript 中的循环，如 for (i = 0; i < 100; i++)。 <br/>编写 HTML 时，建立标准的标记和属性格式，如所有标记都大写或所有属性都小写。另一种方法是，坚持 XHTML 规范以确保所有 HTML 文档都有效。尽管在创建 Web 页时需折中考虑文件大小，但应使用带引号的属性值和结束标记以方便维护。 <br/>编写 SQL 语句时，对于关键字使用全部大写，对于数据库元素（如表、列和视图）使用大小写混合。 <br/>在物理文件之间在逻辑上划分源代码。 <br/>将每个主要的 SQL 子句放在不同的行上，这样更容易阅读和编辑语句，例如： <br/><div class="code">SELECT FirstName, LastName<br/>FROM Customers<br/>WHERE State = &#039;WA&#039;</div><br/>将大的复杂代码节分为较小的、易于理解的模块。
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/188.htm</link>
<title><![CDATA[.net中获取机器硬件信息]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Wed, 16 Aug 2006 08:48:12 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/188.htm</guid> 
<description>
<![CDATA[ 
	在.net环境下（用VC#描述）获取机器的硬件信息，要用到一个类库（System.Management.dll）,在解决方案资源管理器中添加System.Management 即可。可以将该程序编译成.dll文件，便于以后调用。<br/>在程序代码中需要进行引用 using System.Management;<br/><br/>具体代码:<br/><br/>1.获取机器名：<br/><div class="code">　public string GetHostName()<br/> &nbsp;&#123;<br/> &nbsp; return System.Net.Dns.GetHostName(); <br/> &nbsp;&#125;</div><br/><br/>２.获取ＣＰＵ编号<br/><div class="code">　public string GetCpuId()<br/><br/> &nbsp; &#123;<br/><br/> &nbsp; &nbsp;ManagementClass mc = new ManagementClass(&quot;Win32_Processor&quot;);<br/> &nbsp; &nbsp;ManagementObjectCollection moc = mc.GetInstances();<br/> &nbsp; &nbsp; &nbsp;<br/> &nbsp; &nbsp;String strCpuID = null ;<br/> &nbsp; &nbsp;foreach( ManagementObject mo in moc ) <br/> &nbsp; &nbsp;&#123;<br/> &nbsp; &nbsp; strCpuID = mo.Properties&#91;&quot;ProcessorId&quot;&#93;.Value.ToString();<br/> &nbsp; &nbsp; break; <br/> &nbsp; &nbsp;&#125;<br/> &nbsp; &nbsp;return strCpuID;<br/><br/> &nbsp; &#125;</div><br/><br/>3.获取主硬盘编号<br/><div class="code"> public string GetMainHardDiskId()<br/><br/>&#123;<br/><br/> &nbsp; ManagementObjectSearcher searcher = new ManagementObjectSearcher(&quot;SELECT * FROM Win32_PhysicalMedia&quot;);<br/> &nbsp; &nbsp;String strHardDiskID = null ;<br/> &nbsp; &nbsp;foreach(ManagementObject mo in searcher.Get()) <br/> &nbsp; &nbsp;&#123; &nbsp; &nbsp;<br/> &nbsp; &nbsp; strHardDiskID = mo&#91;&quot;SerialNumber&quot;&#93;.ToString().Trim();<br/> &nbsp; &nbsp; break; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br/> &nbsp; &nbsp;&#125;<br/> &nbsp; &nbsp;return strHardDiskID ;<br/><br/>&#125;</div><br/><br/>4.获取bios和mac地址，这个有点复杂，需要用到NETAPI32.DLL
]]>
</description>
</item><item>
<link>http://www.gaobo.info/read.php/187.htm</link>
<title><![CDATA[Microsoft .NET 开发框架]]></title> 
<author>Doctor &lt;gregry@cqut.edu.cn&gt;</author>
<category><![CDATA[DotNet.etc]]></category>
<pubDate>Wed, 16 Aug 2006 08:42:52 +0000</pubDate> 
<guid>http://www.gaobo.info/read.php/187.htm</guid> 
<description>
<![CDATA[ 
	Microsoft .NET战略基于一组开放的互联网协议，推出了一系列的产品、技术和服务，吹响了一次互联网技术变革的号角 。毫无疑问，开发人员处于这个变革的中心。使用微软开发技术的开发者们一直习惯了使用ASP进行Web编程，使用VB, VC++进行Win32编程，基于COM/DCOM技术设计自己的应用程序，那么他们在Microsoft .NET战略中需要面对什么样的挑战，如何利用Microsoft .NET的开发技术和工具构建下一代的互联网应用呢？<br/><br/>一．概述<br/>首先为了让我们对Microsoft .NET开发框架有一个整体的认识，请参阅下图：<br/><br/><a href="http://www.gaobo.info/attachment/1155717678_0.gif" target="_blank"><img src="http://www.gaobo.info/attachment/1155717678_0.gif" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a> <br/>Microsoft .NET开发框架<br/><br/>从上图我们可以简要的了解.NET开发框架的几个主要组成部分：首先是整个开发框架的基础，即通用语言运行时以及它所提供的一组基础类库；在开发技术方面，.NET提供了全新的数据库访问技术ADO .NET，以及网络应用开发技术ASP .NET和Windows编程技术Win Forms；在开发语言方面，.NET提供了VB,VC++,C#, Jscript等多种语言支持；而Visual Studio .NET则是全面支持.NET的开发工具。下面就让我们来一步步的来了解它们：<br/><br/>通用语言运行时，即Common Language Runtime 。Microsoft .NET 给开发人员带来了一种全新的开发框架，而通用语言运行时则处于这个框架的最低层，是这个框架的基础。开发人员对于所谓的C运行时、VB运行时、Jave虚拟机这些概念已经非常熟悉了，而通用语言运行时则为多种语言提供了一种统一的运行环境。另外它还提供了更多的功能和特性，比如统一和简化的编程模型，用户不必迷惑于Win32 API和COM；避免了DLL的版本和更新问题（常称为DLL地狱），从而大大简化了应用程序的发布和升级；多种语言之间的交互，例如我们甚至可以在VB中使用C++编写的类；自动的内存和资源管理等等。Microsoft .NET正是基于通用语言运行时，实现了这些开发人员梦寐以求的功能。 <br/><br/>基于通用语言运行时开发的代码称为受控代码，它的运行步骤大体如下：首先使用一种通用语言运行时支持的编程语言编写源代码，然后使用针对通用语言运行时的编译器生成独立于机器的微软中间语言（Microsoft Intermediate Language），同时产生运行所需的元数据，在代码运行时再使用即时编译器（Just In Time Compiler）生成相应的机器代码来执行。 <br/><br/>当然对于开发者而言，他们除了关心通用语言运行时提供那么多新特性外，它究竟给开发者提供了什么样的编程接口，这就是基础类库（Base Class Library）。这组基础类库包括了从输入输出到数据访问等各方面，提供了一个统一的面向对象的、层次化的、可扩展的编程接口。它使用一种点号分隔的方法，使得查找和使用类库非常容易。例如基础类库中的根，它的命名空间是System，提供数据访问的类库的命名空间是System.Data。在使用时，开发者只需在自己的应用中添加所需的基础类库的引用，然后就可以使用这个类库中的所有方法、属性等等。跟传统的Windows编程相比，使用和扩展基础类库都非常容易，这使得开发者能够高效、快速的构建基于下一代互联网的网络应用。 <br/><br/>几乎所有的应用程序都需要访问从简单的文本文件到大型的关系型数据库等各种不同类型的数据 。在Microsoft .NET中访问数据库的技术是ADO .NET。ADO .NET提供了一组用来连接到数据库，运行命令，返回记录集的类库，与从前的ADO(ActiveX Data Object)相比，Connection和Command对象很类似，而ADO .NET的革新主要体现在如下几个方面： <br/><br/>首先，ADO .NET提供了对XML的强大支持，这也是ADO .NET的一个主要设计目标。在ADO .NET中通过XMLReader，XMLWriter， XMLNavigator， XMLDocument等可以方便的创建和使用XML数据，并且支持W3C 的 XSLT、DTD、XDR等标准。ADO .NET对XML的支持也为XML成为Microsoft .NET中数据交换的统一格式提供了基础。 <br/><br/>其次，ADO .NET引入了DataSet的概念，这是一个驻于内存的数据缓冲区，它提供了数据的关系型视图。不管数据来源于一个关系型的数据库，还是来源于一个XML文档，我们都可以用一个统一的编程模型来创建和使用它。它替代了原有的Recordset的对象，提高了程序的交互性和可扩展性，尤其适合于分布式的应用场合。 <br/><br/>另外，ADO .NET中还引入了一些新的对象，例如DataReader可以用来高效率的读取数据，产生一个只读的记录集等等。简而言之，ADO .NET通过一系列新的对象和编程模型，并与XML紧密结合，使得在Microsoft .NET中的数据操作十分方便和高效。 ASP .NET是Microsoft .NET中的网络编程结构，它使得建造、运行和发布网络应用非常方便和高效 。我们可以从以下几个方面来了解ASP .NET： <br/><br/>1. ASP .NET网络表单 <br/><br/>ASP .NET网络表单的设计目的就是使得开发者能够非常容易的创建网络表单，它把VB中的快速开发模型引入到网络开发中来，从而大大简化了网络应用的开发。具体的说：在ASP .NET中可以支持多种语言，不仅仅支持脚本语言，通用语言运行时支持的所有语言在ASP .NET中都可以使用；代码和内容分开，在现在的ASP(Active Server Pages)开发中，内容和脚本交错，维护和升级很困难，将他们分开可以使得开发人员和设计人员能够更好的分工合作，提高开发效率；另外在ASP .NET中通过引入服务器端控件，将类似VB的快速开发应用到了网络开发中来，这样大大提高了构建网络表单效率，并且服务器端控件是可扩展的，开发者可以建造自己需要的的服务器端控件。 <br/><br/>2. ASP .NET网络服务 <br/><br/>网络服务（Web Service）是下一代可编程网络的核心，它实际上就是一个可命名的网络资源，可用来在Internet 范围内方便的表现和使用对象，就像使用今天的 COM对象一样，不同的是使用和表现网络服务是通过SOAP（简单对象访问协议）甚至HTTP来实现的。在ASP .NET中，建造和使用网络服务都非常方便： <br/><br/>在ASP .NET中建造网络服务就是编写一个后缀为.ASMX的文件，在这个文件中加入想要表现出来的方法就可以了，网络服务的建造者不需要了解SOAP，XML的细节，只需要把精力集中在自己的服务本身，这也为独立软件服务开发商提供了很好的机会；使用网络服务最简单的方式就是使用HTTP协议（HTTP GET 或HTTP POST），用户只需要直接访问网络服务（.ASMX文件）的URL即可；当然用户还可以通过SOAP在自己的应用中更灵活的使用网络服务。 <br/><br/>3. ASP .NET应用框架 <br/><br/>ASP .NET应用不再是解释脚本，而是编译运行，再加上灵活的缓冲技术，从根本上提高了性能；由于ASP .NET的应用框架基于通用语言运行时，发布一个网络应用，仅仅是一个拷贝文件的过程，即使是组件的发布也是如此，更新和删除网络应用，可以直接替换/删除文件；开发者可以将应用的配置信息存放XML格式的文件中，管理员和开发者对应用程序的管理可以分开进行；提供了更多样的认证和安全管理方式；在可靠性等多方面都有很大提高。 <br/><br/>传统的基于Windows的应用（Win Forms），它仍然是Microsoft .NET战略中不可或缺的一部分。在Microsoft .NET中开发传统的基于Windows的应用程序时，除了可以利用现有的技术例如ActiveX控件以及丰富的Windows接口外，还可以基于通用语言运行时开发，可以使用ADO .NET、网络服务等，这样也可以实现诸如避免DLL地狱、多语言支持等.NET的新特性。从上面的介绍中我们已经知道Microsoft .NET开发框架支持多种语言，在目前的测试版中已经支持 VB,C++，C#和Jscript四种语言以及它们之间的深层次交互 <br/><br/>。而且微软支持第三方生产针对Microsoft .NET的编译器和开发工具，这也就是说几乎所有市场上的编程语言都有可能应用于Microsoft .NET开发框架。这样开发者可以任意选择自己喜爱的语言，这种开放和交互的特性正是开发者所热爱的。 <br/><br/>需要特别指出的是，微软在Microsoft .NET中推出了全新的C#语言，这种全新的面向对象的语言使得开发者可以快速的构建从底层系统级到高层商业组件的不同应用。C#在保证了强大的功能和灵活性的同时，给C和C++带来了类似于VB的快速开发，并且它还针对.NET作了特别设计，比如C#允许XML数据直接映射为它的数据类型等等，这些特性结合起来使得C#成为优秀的下一代网络编程语言。 <br/><br/>与此同时Microsoft .NET对原有的VB和C++也做了很大的改进，使得它们更加适应Microsoft .NET开发框架的需求。例如在Visual Basic .NET中增加了继承等面向对象的特性，结构化的出错处理等等；可管理的C++扩展，大大提高了利用C++来开发Microsoft .NET应用的效率等。 <br/><br/>Visual Studio .NET作为微软的下一代开发工具，它和.NET 开发框架紧密结合，是构建下一代互联网应用的优秀工具，目前已经有Beta测试版面世。Visual Studio .NET通过提供一个统一的集成开发环境及工具，大大提高了开发者的效率；集成了多种语言支持；简化了服务器端的开发；提供了高效地创建和使用网络服务的方法等等。 .NET框架的一个主要目的是使COM开发变得更加容易 <br/><br/>。COM开发过程中最难的一件事是处理COM基本结构。因此，为了简化COM开发，.NET框架实际上已自动处理了所有在开发人员看来是与“COM”紧密相关的任务，包括引用计算、接口描述以及注册。 必须认识到，这并不意味着.NET框架组件不是COM组件。事实上，使用Visual Studio 6.0的COM开发人员可以调用.NET框架组件，并且在他们看来，后者更像是拥有iUnknown数据的COM组件。相反，使用Visual Studio.NET的.NET框架开发人员则将COM组件视作.NET框架组件。 <br/><br/>为了避免引起误解，这里需对这种关系加以特别说明：COM开发人员必须手动去做大多数.NET框架开发人员可以在运行时自动执行的事情。例如，必须手写COM组件的安全性模块，且无法自动管理模块占用的内存，而在安装COM组件时，注册条目必须放进Windows注册表中。对.NET框架而言，运行时实现了这些功能的自动化。例如，组件本身是自我描述型的，因而无需注册到Windows注册表中便能安装。 <br/><br/>当把COM与Microsoft事务服务器(MTS)和分布式COM(DCOM)结合在一起时，就变成了COM+。COM+提供了一组面向中间层的服务。特别是COM+提供了进程管理功能和数据库与对象连接池处理功能。在将来的版本中，它还将提供一种称为分区的功能——专门为应用程序服务提供商设计的更强大的进程隔离功能。 <br/><br/>COM+服务主要面向中间层应用程序开发，并主要为大型分布式应用程序提供可靠性和可扩展性。这些服务是对.NET框架所提供服务的补充；通过.NET框架类，可以直接访问这些服务。 .NET框架有几个要素值得一提。首先是它的安全系统和配置系统。这两个系统协同工作，有力地遏止了运行不安全代码的可能性，并大幅度减少了号称“DLL Hell”的对应用程序进行配置时所面临的挑战。 <br/><br/>安全系统是一个高度细化、基于事实的系统，它赋予开发人员和管理员多种代码处理权限（而不仅仅是“on”或“off”）。将来，还会根据代码本身的核心要素来决定如何实施上述权限。 <br/><br/>例如，当.NET框架应用程序被下载到某一系统中时，它会申请一组权限（诸如对临时目录的写入权限）。运行时将收集有关应用程序的事实信息（诸如：它是从何处下载的、是否用了有效签名、甚至它访问系统的准确程度），并按管理策略决定是否允许应用程序运行。运行时甚至还可告之应用程序它无法授权申请的所有权限，并允许应用程序自行决定是否继续运行。 <br/><br/>有这种安全系统作保障，许多应用程序配置问题便会迎刃而解。开发人员和管理员（最终是用户）所面临的最大挑战之一是版本的管理问题。如果在您新装了某个应用程序之后，一切都限于瘫痪状态，而在这之前系统一直运行得非常良好，那么最大的可能是新安装的应用程序重写了一些共享库，并极有可能修正了现有应用程序正使用的程序错误。这种情况出现的频率很高，以致人们将它称为：“DLL Hell”。 <br/><br/>.NET框架拥有的几项高级功能可以彻底消除“DLL Hell”现象。首先，它有一个非常强大的内部命名系统，能够有效地防止两个库因互相重名而被错当为对方的情况发生。除此之外，它还提供一项被称作“并行”配置的新功能。如果前例中新安装的应用程序确实重写了共享库，现有应用程序可对该库进行修复。等现有应用程序再次启动时，它会检查所有的共享文件。如果发现文件被更改，同时这些更改又是不兼容的，则它可以请求运行时提取一个它可以使用的版本。得益于强大的安全系统，运行时可以安全地执行该操作，这样应用程序就完成了本身的修复工作。 <br/><br/>总之，Microsoft .NET开发框架在通用语言运行时的基础上，给开发者提供了完善的基础类库、下一代的数据库访问技术ADO .NET、网络开发技术ASP .NET，开发者可以使用多种语言及Visual Studio .NET来快速构建下一代的网络应用。随着相关的互联网标准及技术的普及，可以预言将会有越来越多的开发者采用这种开发结构，开发出丰富多样的下一代互联网应用来。
]]>
</description>
</item>
</channel>
</rss>