在本文中,您将了解到如何在 Visual Basic .NET (VB.NET) 和 Visual C# .NET (C#) 中使用数据库事务。具体来讲,您将系统学习数据库事务、在 .NET 程序中使用 OracleTransaction 对象以及如何设置事务保存点。本文中引用的所有脚本和文件都在这里提供。本文假定您大体上熟悉 C# 和 VB.NET 编程。
所需软件
如果您要跟随我们逐步完成本文中给出的示例,那么您需要安装以下软件:
Windows NT 4.0、Windows 2000、Windows XP Professional 或 Windows Server 2003
能够访问一个已安装的 Oracle 数据库(Oracle8i 版本 3 8.1.7 或更高版本)
Oracle 客户机(版本 10.1.0.2.0 或更高版本)
Oracle Net(版本 10.1.0.2.0 或更高版本)
Oracle Data Providers for .NET(版本 10.1.0.2.0 或更高版本)
Microsoft .NET Framework(版本 1.0 或更高版本)
Microsoft .NET 框架 SDK(版本 1.0 或更高版本)
如果您打算使用企业服务事务或分布式事务来开发和运行应用程序,那么您还需要安装 Oracle Services for Microsoft Transaction Server(10.1.0.2.0 或更高版本)。
您需要分别下载和安装 .NET 框架以及 SDK(先安装框架)。您还需要下载和安装 Oracle 数据库 10g,它包括 Oracle Data Provider for .NET (ODP.NET)。您可以选择在不同计算机或同一计算机上安装 ODP.NET 和数据库服务器。
注意:ODP.NET 驱动程序针对 Oracle 数据库访问进行了优化,因此可以获得最佳性能,并且它们还支持 Oracle 数据库的丰富特性,如 BFILE、BLOB、CLOB、XMLType 等。如果您正在开发基于 Oracle 数据库的 .NET 应用程序,那么就特性和性能来讲,ODP.NET 无疑是最佳的选择。
数据库模式设置
首先,您需要设置数据库模式,在此我们使用一个简化的 Web 商店示例。您必须首先创建一个名为 store 的用户并按以下方式将所需的权限授予该用户(您必须首先以拥有 CREATE USER 权限的用户身份登录数据库才能创建用户):
CREATE USER store IDENTIFIED BY store;
GRANT connect, resource TO store;
注意:您会在源代码文件 db1.sql 中找到前两个语句和该部分中出现的设置 store 模式的其他语句。
接下的语句以 store 用户身份进行连接:
CONNECT store/store;
以下语句创建了所需的两个数据库表,名称分别为 product_types 和 products:
CREATE TABLE product_types (
product_type_id INTEGER
CONSTRAINT product_types_pk PRIMARY KEY,
name VARCHAR2(10) NOT NULL
);
CREATE TABLE products (
product_id INTEGER
CONSTRAINT products_pk PRIMARY KEY,
product_type_id INTEGER
CONSTRAINT products_fk_product_types
REFERENCES product_types(product_type_id),
name VARCHAR2(30) NOT NULL,
description VARCHAR2(50),
price NUMBER(5, 2)
);
注意:如果您在一个不同的模式中为 store 用户创建了这些数据库表,那么您将需要修改示例配置文件(您稍后将看到)中的模式名称。
表 product_types 用于存储示例在线商店可能库存的产品类型的名称,表 products 包含了所销售产品的详细信息。
下面的 INSERT 语句为表 product_types 和 products 添加行:
INSERT INTO product_types (
product_type_id, name
) VALUES (
1, 'Book'
);
INSERT INTO product_types (
product_type_id, name
) VALUES (
2, 'DVD'
);
INSERT INTO products (
product_id, product_type_id, name, description, price
) VALUES (
1, 1, 'Modern Science', 'A description of modern science', 19.95
);
INSERT INTO products (
product_id, product_type_id, name, description, price
) VALUES (
2, 1, 'Chemistry', 'Introduction to Chemistry', 30.00
);
INSERT INTO products (
product_id, product_type_id, name, description, price
) VALUES (
3, 2, 'Supernova', 'A star explodes', 25.99
);
INSERT INTO products (
product_id, product_type_id, name, description, price
) VALUES (
4, 2, 'Tank War', 'Action movie about a future war', 13.95
);
COMMIT;
接下来,您将了解有关数据库事务的内容。
数据库事务简介
数据库事务是由一组 SQL 语句组成的一个逻辑工作单元。您可以把事务看作是一组不可分的 SQL 语句,这些语句作为一个整体永久记录在数据库中或一并撤销。比如在银行帐户之间转移资金:一条 UPDATE 语句将从一个帐户的资金总数中减去一部分,另一条 UPDATE 语句将把资金加到另一个帐户中。减操作和加操作必须永久记录在数据库中,或者必须一并撤销 ― 否则将损失资金。这个简单的示例仅使用了两条 UPDATE 语句,但一个更实际的事务可能包含许多 INSERT、UPDATE 和 DELETE 语句。
要永久记录一个事务中的 SQL 语句的结果,您可以通过 COMMIT 语句来执行提交。要撤销 SQL 语句的结果,您可以使用 ROLLBACK 语句来执行回滚,这会把所有的行重设为它们原来的状态。只要您事先没有与数据库断开,则您在执行回滚之前所做的任何修改都将被撤销。您还可以设置一个保存点,以便将事务回滚至该特定的点,同时保持事务中的其他语句原封不动。
在 C# 和 VB.NET 中使用数据库事务
您可以使用 OracleTransaction 类的一个对象来表示一个事务。OracleTransaction 类包含多个属性,其中的两个为 Connection(指定与事务关联的数据库连接)和 IsolationLevel(指定事务隔离级别);本文稍后将向您介绍更多有关事务隔离级别的内容。
OracleTransaction 类包含许多操控事务的方法。您可以使用 Commit() 方法永久提交 SQL 语句,并可以使用 Rollback() 撤销这些语句。您还可以使用 Save() 在事务中设置一个保存点。
我现在将带着您逐步完成两个示例程序 ― 一个用 C# 编写 (TransExample1.cs),另一个用 VB.NET 编写 (TransExample1.vb)。这些程序演示了如何执行一个包含了两条 INSERT 语句的事务。第一条 INSERT 语句将在表 product_types 中添加一行,第二条将在表 products 中添加一行。
导入命名空间
以下 C# 程序语句指定在程序中使用 System 和 Oracle.DataAcess.Client 命名空间:
using System;
using Oracle.DataAccess.Client;
下面是等价的 VB.NET 语句:
Imports System
Imports Oracle.DataAccess.Client
Oracle.DataAccess.Client 命名空间是 ODP.NET 的一部分,它包含许多类,其中有 OracleConnection、OracleCommand 和 OracleTransaction。示例程序用到了这些类。
第 1 步
创建一个 OracleConnection 对象连接到 Oracle 数据库,然后打开该连接。
在 C# 中:
OracleConnection myOracleConnection =
new OracleConnection(
"User Id=store;Password=store;Data Source=ORCL"
);
myOracleConnection.Open();
在 VB.NET 中:
Dim myOracleConnection As New OracleConnection( _
"User Id=store;Password=store;Data Source=ORCL")
myOracleConnection.Open()
User Id 和 Password 属性指定了您所要连接到的模式的数据库用户和口令。Data Source 属性指定了数据库的 Oracle Net 服务名称;初始数据库的默认服务名称为 ORCL。如果您使用的不是初始数据库,或者您的服务名称不同,那么您需要在程序中修改 Data Source 属性的设置。
第 2 步
创建一个 OracleTransaction 对象,然后调用 OracleConnection 对象的 BeginTransaction() 方法启动事务。
在 C# 中:
OracleTransaction myOracleTransaction =
myOracleConnection.BeginTransaction();
In VB.NET:
Dim myOracleTransaction As OracleTransaction = _
myOracleConnection.BeginTransaction()
第 3 步
创建一个 OracleCommand 对象,用于存储 SQL 语句。
在 C# 中:
OracleCommand myOracleCommand = myOracleConnection.CreateCommand();
在 VB.NET 中:
Dim myOracleCommand As OracleCommand =
myOracleConnection.CreateCommand
因为 OracleCommand 对象使用 OracleConnection 对象的 CreateCommand() 方法创建的,所以它自动使用在第 2 步中为 OracleConnection 对象设置的事务。
第 4 步
将 OracleCommand 对象的 CommandText 属性设为向表 product_types 中添加一行的第一条 INSERT 语句。
在 C# 中:
myOracleCommand.CommandText =
"INSERT INTO product_types ("
" product_type_id, name"
") VALUES ("
" 3, 'Magazine'"
")";
在 VB.NET 中:
myOracleCommand.CommandText = _
"INSERT INTO product_types (" & _
" product_type_id, name" & _
") VALUES (" & _
" 3, 'Magazine'" & _
")"
第 5 步
使用 OracleCommand 对象的 ExecuteNonQuery() 方法运行 INSERT 语句。
在 C# 中:
myOracleCommand.ExecuteNonQuery();
在 VB.NET 中:
myOracleCommand.ExecuteNonQuery()
第 6 和第 7 步
将 OracleCommand 对象的 CommandText 属性设为向表 Products 中添加一行的第二条 INSERT 语句,并运行它。
在 C# 中:
myOracleCommand.CommandText =
"INSERT INTO products ("
" product_id, product_type_id, name, description, price"
") VALUES ("
" 5, 3, 'Oracle Magazine', 'Magazine about Oracle', 4.99"
")";
myOracleCommand.ExecuteNonQuery();
在 VB.NET 中:
myOracleCommand.CommandText = _
"INSERT INTO products (" & _
" product_id, product_type_id, name, description, price" & _
") VALUES (" & _
" 5, 3, 'Oracle Magazine', 'Magazine about Oracle', 4.99" & _
")"
myOracleCommand.ExecuteNonQuery()
第 8 步
使用 OracleTransaction 对象的 Commit() 方法提交数据库中的事务。
在 C# 中:
myOracleTransaction.Commit();
在 VB.NET 中:
myOracleTransaction.Commit()
在完成 Commit() 方法之后,由 INSERT 语句添加的两行将在数据库中永久记录。
第 9 步
使用 Close() 方法关闭 OracleConnection 对象。
在 C# 中:
myOracleConnection.Close();
在 VB.NET 中:
myOracleConnection.Close()
编译并运行示例程序
要编译 C# 示例程序,您可以使用 csc 命令运行 C# 编译器。因为程序使用 Oracle Data Access DLL,所以您应使用 /r 选项指定该 DLL 的完整路径,例如:
csc TransExample1.cs /r:C:\oracle\product\10.1.0\
Client_1\bin\Oracle.DataAccess.dll
注意:您需要用您计算机上的相应路径来替换该 DLL 的路径。此外,如果您的计算机找不到 csc 编译器,那么您可能需要运行 Microsoft sdkvars.bat 脚本来首先设置 .NET SDK 的环境变量;您可以在安装 .NET SDK 的 bin 目录中找到该脚本。
如果您遇到以下错误:
Example1.cs(10,7):error CS0246:The type or namespace name 'Oracle'
could not be found (are you missing a using directive or an assembly reference?)
这说明您没有在编译命令中正确指定 Oracle Data Access DLL。(有关设置的信息,请参阅 John Paul Cook 的技术文章“在 Oracle 数据库上构建 .NET 应用程序”。)
下面是用于编译 VB.NET 程序的等价命令:
vbc TransExample1.vb /r:C:\oracle\product\10.1.0\
Client_1\bin\Oracle.DataAccess.dll /r:system.dll /r:system.data.dll
接下来,输入以下命令,运行示例:
TransExample1
您将看到程序的输出。不过,如果您遇到类似以下的异常:
An exception was thrown
Message = ORA-12514:TNS:listener does not currently know
of service requested in connect descriptor
这说明 OracleConnection 对象的连接字符串中的 Data Source 的设置不正确。您应当咨询您的 DBA 或查阅 Oracle Net 文档以获得更多详细信息。
如果您使用的是 VS .NET,那么您可以遵循以下指示来编译和运行 C# 程序 TransExample1.cs:
创建一个新的 C# 控制台应用程序。File>New Project,然后选择 Visual C# Projects,Console Application。
将项目命名为 TransExample1。
用 TransExample1.cs 中的代码替换 VS .NET 生成的所有代码。
选择 Project>Add Reference 添加对 Oracle.DataAccess.dll 的引用,然后浏览至您安装 ODP.NET 的目录(在我的计算机上,它是 C:\oracle\product\10.1.0\Client_1\bin\Oracle.DataAccess.dll),然后双击 Oracle.DataAccess.dll。
选择 Debug>Start without Debugging 运行该程序。
要编译和运行 TransExample1.vb,您可以执行类似的一系列步骤,但第 1 步应选择一个 Visual Basic 控制台应用程序,并在第 3 步用 TransExample1.vb 中的代码替换生成的代码。
查看程序的运行结果
当您运行完 C# 或 VB .NET 程序时,您可以在 SQL*Plus 中使用以下 SELECT 语句查看事务的结果:
SELECT p.product_id, p.product_type_id, pt. name, p.name, p.description, p.price
FROM products p, product_types pt
WHERE p.product_type_id = pt.product_type_id
AND p.product_id = 5;
您将看到以下结果:
PRODUCT_ID PRODUCT_TYPE_ID NAME NAME
---------- --------------- ---------- -----------------------
DESCRIPTION PRICE
-------------------------------------------------- ----------
5 3 Magazine Oracle Magazine
Magazine about Oracle 4.99
接下来,您将了解如何设置事务保存点。
在 .NET 程序中设置事务保存点
正如本文前面所提到的那样,您可以设置一个保存点,以便将事务回滚至该特定的点,同时保持事务中的其他语句原封不动。您可以使用 OracleTransaction 类的 Save() 方法在事务中设置保存点。
如果您有一个非常长的事务并且希望能够仅回滚到某个特定的时间点,那么您可能要使用保存点。例如,您可能想对 10 个产品做一些更改,然后设置一个保存点,然后再对另 10 个产品做更改;如果您在进行第二批更改时出现了错误,那么您可以回滚至保存点,使您的第一批更改原封不动。
我将带您逐步完成演示如何使用保存点的 C# (TransExample2.cs) 示例程序和 VB.NET (TransExample2.vb) 示例程序中的相关新步骤。这些程序向表 products 中添加一行,设置一个保存点,向表 products 中添加另一行,回滚至保存点,然后从表 products 中读取这些行。在回滚至保存点后,只有添加到表 products 中的第一行保留了下来:第二行将已被删除。
第 1 到第 3 步与“在 C# 和 VB.NET 中使用数据库事务”部分中所示的步骤相同,因此在这里将其省略。
第 4 步
向表 products 中添加一行,该行的产品 ID 为 6。
在 C# 中:
myOracleCommand.CommandText =
"INSERT INTO products ("
" product_id, product_type_id, name, description, price"
") VALUES ("
" 6, 2, 'Man from Another World', 'Man from Venus lands on Earth', 24.99"
")";
myOracleCommand.ExecuteNonQuery();
在 VB.NET 中:
myOracleCommand.CommandText = _
"INSERT INTO products (" & _
" product_id, product_type_id, name, description, price" & _
") VALUES (" & _
" 6, 2, 'Man from Another World', 'Man from Venus lands on Earth', 24.99" & _
")"
myOracleCommand.ExecuteNonQuery()
第 5 步
使用 OracleTransaction 的 Save() 方法设置一个名为 SaveProduct 的保存点。
在 C# 中:
myOracleTransaction.Save("SaveProduct");
在 VB.NET 中:
myOracleTransaction.Save("SaveProduct")
第 6 步
向表 products 中添加另一行,该行的产品 ID 为 7。
在 C# 中:
myOracleCommand.CommandText =
"INSERT INTO products ("
" product_id, product_type_id, name, description, price"
") VALUES ("
" 7, 2, 'Z-Files', 'Mysterious stories', 14.99"
")";
myOracleCommand.ExecuteNonQuery();
在 VB.NET 中:
myOracleCommand.CommandText = _
"INSERT INTO products (" & _
" product_id, product_type_id, name, description, price" & _
") VALUES (" & _
" 7, 2, 'Z-Files', 'Mysterious stories', 14.99" & _
")"
myOracleCommand.ExecuteNonQuery()
第 7 步
回滚到先前在第 5 步中设置的 SaveProduct 保存点。
在 C# 中:
myOracleTransaction.Rollback("SaveProduct");
在 VB.NET 中:
myOracleTransaction.Rollback("SaveProduct")
完成回滚后,在第 6 步中添加的第二行已被删除,而在第 4 步中添加的第一行保留了下来。
TransExample2.cs 和 TransExample2.vb 中剩下的步骤显示表 products 的内容,回滚整个事务并从数据库断开。
用于 Microsoft Transaction Server 的 Oracle 事务服务的快速说明
Microsoft Transaction Server 是一个运行在互联网或网络服务器上的专有事务处理系统。Microsoft Transaction Server 为客户端计算机部署和管理应用程序和数据库事务请求。
Microsoft Transaction Server 是以服务器为中心的三层体系结构模型的一个组件。这种方法实现了将应用程序的表示、业务逻辑和数据元素清晰地分布到在一个网络中连接的不同计算机上。无需专门集成,您就可以在与 Oracle 数据库服务器 8.0.6 版或更高版本连接的 Microsoft Transaction Server 中部署一个组件,但首先您必须安装 Oracle Services for Microsoft Transaction Server。
结论
在本文中,您系统学习了在 .NET 程序中使用数据库事务。您了解了如何创建 OracleTransaction 对象并用它们将事务提交给数据库,如何使用保存点部分回滚一个事务,以及 Oracle 数据库如何分离并发事务。
SQL Server提供了一个特别的数据类型:image,它是一个包含binary数据的类型。下边这个例子就向你展示了如何将文本或照片放入到数据库中的办法。在这篇文章中我们要看到如何在SQL Server中存储和读取图片。
1、建立一个表:
在SQL SERVER中建立这样结构的一个表:
列名 类型 目的
ID Integer 主键ID
IMGTITLE Varchar(50) 图片的标题
IMGTYPE Varchar(50) 图片类型. ASP.net要以辨认的类型
IMGDATA Image 用于存储二进制数据
2、存储图片到SQL SERVER数据库中
为了能存储到表中,你首先要上传它们到你的Web 服务器上,你可以开发一个web form,它用来将客户端中TextBox web control中的图片入到你的WEB服务器上来。将你的 encType 属性设置为:myltipart/formdata.
Stream imgdatastream = File1.PostedFile.InputStream;
int imgdatalen = File1.PostedFile.ContentLength;
string imgtype = File1.PostedFile.ContentType;
string imgtitle = TextBox1.Text;
byte[] imgdata = new byte[imgdatalen];
int n = imgdatastream.Read(imgdata,0,imgdatalen);
string connstr=((NameValueCollection)Context.GetConfig("appSettings"))["connstr"];
SqlConnection connection = new SqlConnection(connstr);
SqlCommand command = new SqlCommand
("INSERT INTO ImageStore(imgtitle,imgtype,imgdata)
VALUES ( @imgtitle, @imgtype,@imgdata )", connection );
SqlParameter paramTitle = new SqlParameter
("@imgtitle", SqlDbType.VarChar,50 );
paramTitle.Value = imgtitle;
command.Parameters.Add( paramTitle);
SqlParameter paramData = new SqlParameter( "@imgdata", SqlDbType.Image );
paramData.Value = imgdata;
command.Parameters.Add( paramData );
SqlParameter paramType = new SqlParameter( "@imgtype", SqlDbType.VarChar,50 );
paramType.Value = imgtype;
command.Parameters.Add( paramType );
connection.Open();
int numRowsAffected = command.ExecuteNonQuery();
connection.Close();
3、从数据库中恢复读取
现在让我们来从SQL Server中读取我们放入的数据吧!我们将要输出图片到你的浏览器上,你也可以将它存放到你要的位置。
private void Page_Load(object sender, System.EventArgs e)
{
string imgid =Request.QueryString["imgid"];
string connstr=((NameValueCollection)
Context.GetConfig("appSettings"))["connstr"];
string sql="SELECT imgdata, imgtype FROM ImageStore WHERE id = " imgid;
SqlConnection connection = new SqlConnection(connstr);
SqlCommand command = new SqlCommand(sql, connection);
connection.Open();
SqlDataReader dr = command.ExecuteReader();
if(dr.Read())
{
Response.ContentType = dr["imgtype"].ToString();
Response.BinaryWrite( (byte[]) dr["imgdata"] );
}
connection.Close();
}
要注意的是Response.BinaryWrite 而不是Response.Write.
下面给大家一个用于C# Winform的存入、读取程序。其中不同请大家自己比较!(为了方便起见,我将数据库字段简化为二个:imgtitle和imgdata。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.SqlClient;
namespace WindowSAPplication21
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
private string ConnectionString = "Integrated Security=SSPI;Initial Catalog=;Data Source=localhost;";
private SqlConnection conn = null;
private SqlCommand cmd = null;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.PictureBox pic1;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private string sql = null;
private System.Windows.Forms.Label label2;
private string nowId=null;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
conn = new SqlConnection(ConnectionString);
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if (conn.State == ConnectionState.Open)
conn.Close();
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.pic1 = new System.Windows.Forms.PictureBox();
this.button2 = new System.Windows.Forms.Button();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.label2 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(0, 40);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(264, 48);
this.button1.TabIndex = 0;
this.button1.Text = "加入新的图片";
this.button1.Click = new System.EventHandler(this.button1_Click);
//
// pic1
//
this.pic1.Location = new System.Drawing.Point(280, 8);
this.pic1.Name = "pic1";
this.pic1.Size = new System.Drawing.Size(344, 264);
this.pic1.TabIndex = 3;
this.pic1.TabStop = false;
//
// button2
//
this.button2.Location = new System.Drawing.Point(0, 104);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(264, 40);
this.button2.TabIndex = 4;
this.button2.Text = "从数据库中恢复图像";
this.button2.Click = new System.EventHandler(this.button2_Click);
//
// openFileDialog1
//
this.openFileDialog1.Filter = "\"图像文件(*.jpg,*.bmp,*.gif)|*.jpg|*.bmp|*.gif\"";
//
// label2
//
this.label2.Location = new System.Drawing.Point(0, 152);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(264, 48);
this.label2.TabIndex = 5;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(632, 273);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.label2,
this.button2,
this.pic1,
this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.Load = new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
openFileDialog1.ShowDialog ();
if (openFileDialog1.FileName.Trim()!="")
{
FileInfo fi = new FileInfo(openFileDialog1.FileName);
string imgtitle=openFileDialog1.FileName;
int imgdatalen=(int)fi.Length;
byte[] imgdata = new byte[imgdatalen];
Stream imgdatastream=fi.OpenRead();
int n=imgdatastream.Read(imgdata,0,imgdatalen);
if( conn.State == ConnectionState.Open)
conn.Close();
ConnectionString ="Integrated Security=SSPI;" "Initial Catalog=mydb;" "Data Source=localhost;";
conn.ConnectionString = ConnectionString;
try
{
string mySelectQuery = "INSERT INTO ImageStore(imgtitle,imgdata) VALUES (@imgtitle, @imgdata )";
//string mySelectQuery="UPDATE ImageStore set imgtitle=@imgtitle,imgdata=@imgdata" ;
SqlCommand myCommand = new SqlCommand(mySelectQuery, conn);
SqlParameter paramTitle = new SqlParameter("@imgtitle", SqlDbType.VarChar,50 );
paramTitle.Value = imgtitle;
myCommand.Parameters.Add( paramTitle);
SqlParameter paramData = new SqlParameter( "@imgdata", SqlDbType.Image );
paramData.Value = imgdata;
myCommand.Parameters.Add( paramData );
conn.Open();
int numRowsAffected = myCommand.ExecuteNonQuery();
conn.Close();
}
catch(Exception err)
{
MessageBox.Show("您输入名称可能在数据库中已存在或输入为空,请检查!" err.ToString() );
}
finally
{}
}
}
private void Form1_Load(object sender, System.EventArgs e)
{
}
private void button2_Click(object sender, System.EventArgs e)
{
//打开数据库连接
if( conn.State == ConnectionState.Open)
conn.Close();
ConnectionString ="Integrated Security=SSPI;" "Initial Catalog=mydb;" "Data Source=localhost;";
conn.ConnectionString = ConnectionString;
// 创建数据适配器
string sql="SELECT * FROM ImageStore" ;
SqlCommand command = new SqlCommand(sql, conn);
try
{conn.Open();}
catch(Exception newerr)
{
MessageBox.Show(" 不能打开数据联接!") ;
}
finally
{}
SqlDataReader dr = command.ExecuteReader();
if(dr.Read())
{
FileInfo fi = new FileInfo("temp");
FileStream myStream=fi.Open(FileMode.Create);
byte[] mydata=((byte[])dr["imgdata"]);
//label2.Text="您现在看到的是:" dr["imgtitle"].ToString();
foreach(byte a in mydata)
{
myStream.WriteByte(a);
}
myStream.Close();
Image myImage=Image.FromFile("temp") ;
pic1.Image=myImage;
pic1.Refresh();
dr.Close ();
}
else
{
MessageBox.Show("没有成功读入数据!") ;
}
conn.Close();
}
}
}
棒图有时又称为"Bar"图。在我的上一篇文章《在ASP.net实现数据图表》中已经介绍了在浏览器看到的图表,一般都是图片文件。那么在ASP.NET中是否也可以生成这些图表?答案是肯定的,因为在ASP.NET中拥有了一个新功能--绘图功能,通过此功能就能够按照要实现的图表的模样来绘制,最后在客户端的浏览器中形成一个图片,从而显示出图表来。
本文就在上一篇文章的基础上,进一步介绍在ASP.NET页面中实现Bar图的具体方法。希望本篇文章不仅能够让您领会到ASP.NET中强大的绘图功能,更希望能够弥补上一篇文章的一个缺憾,就是上一篇实现的图表的数据来自固定数值,而我们知道图表只有在和数据库关联以后,才能够显示出更强大的优势。下面就来介绍在ASP.NET页面中从数据库中提起数据,并以此数据形成Bar图的具体实现方法。
一.本文程序设计和运行的软件环境:
(1).微软公司视窗2000服务器版。
(2).Visual Studio .Net正式版,.Net Framework SDK版本号3705。
(3).MDAC 2.6(Microsoft Data Acess Component)以上版本。
二.建立数据源
为了方便起见,本文选择的数据库类型为本地数据库--Access 2000,如果你使用的是其他数据库类型,只需对下面介绍的程序中的关于数据库连接的代码进行相应的修改就可以了。Access数据库名称为"db.mdb",在此数据库中只定义了一张数据表"Table01",此表的结构如表01所示:
字段名称 类型 说明
ID 自动编号 主键 ,递增
YF 数字 销售月份
SL 数字 销量
表01:Table01数据表的结构
在定义完"db.mdb"数据库中的"Table01"数据表后,在Table01数据表中按照表02所示添加记录:
ID YF SL
1 1 12
2 2 5
3 3 7
4 4 20
5 5 16
6 6 10
7 7 19
8 8 8
9 9 7
10 10 13
11 11 11
12 12 15
表02:Table01数据表中的记录情况
在Table01数据表中添加完这12条记录后,保存"db.mdb"数据库到C盘的根目录中。
三.ASP.net页面中实现数据Bar图的关键步骤及其实现方法:
在ASP.NET页面中实现数据Bar图首先必须解决二大问题:
(1).首先要解决在ASP.NET页面中实现数据库连接和从数据库中读取数据的方法。
程序要实现从数据库中一条条的读取数据,则要使用OleDbDataReader类,OleDbDataReader类提供了从数据库中逐条读取数据的方法。下面代码是连接C盘根目录下的"db.mdb"数据库,逐条读取Table01数据表中的记录,并把数据存放到定义的二个数组中:
string sRouter = "c:\\db.mdb" ;
//获得当前Access数据库在服务器端的绝对路径
string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " sRouter ;
//创建一个数据库连接
OleDbConnection myConn = new OleDbConnection ( strCon ) ;
string strCom = " SELECT YF ,SL FROM Table01 ORDER BY YF" ;
myConn.Open ( ) ;
OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
//创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
int [ ] iXiaoSH = new int [ 12 ] ;
//定义一个数组,用以存放从数据库中读取的销售数据
string [ ] sMoth = new string [ 12 ] ;
//定义一个数组,用以存放从数据库中读取的销售月份
int iIndex = 0 ;
while ( myOleDbDataReader.Read ( ) )
{
iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString ( ) "月" ;
iIndex ;
}
//读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
myConn . Close ( ) ;
myOleDbDataReader . Close ( ) ;
//关闭各种资源
(2).根据得到数据,绘制图片,并显示出来:
通过第一步,已经把从数据库中的读取的数据存放到"iXiaoSH"和"sMoth"数组中。下面就要解决依据这些数据绘制出Bar图?首先先了解一下在ASP.NET页面中将要实现的数据Bar图的模样。具体可如图01所示:
图01:在ASP.NET中实现的数据Bar图
程序中把图01所示各个元素,按照区域分成了五个部分,这五个部分将在后面介绍的程序中分别实现:
1. 构建整个图片
首先要创建一Bitmap实例,并以此来构建一个Graphics实例,Graphics实例提供了各种绘制方法,这样才能按照数据的要求在Bitmap实例上绘制各种图形。下面代码是在ASP.NET中创建Bitmap实例,并以此实例来构建 Graphics实例的具体方法:
Bitmap bm = new Bitmap ( 600 , 250 ) ;
//创建一个长度为600,宽带为250的Bitmap实例
Graphics g ;
g = Graphics.FromImage ( bm ) ;
//由此Bitmap实例创建Graphic实例
g . Clear ( Color . Snow ) ;
//用Snow色彩为背景色填充此绘画图面
2. 图01中的标题部分文字:
这是通过Graphics实例中提供的DrawString方法以指定的字体、颜色、在指定的位置绘制指定的字符串。下面代码的作用是绘制图01中标题:
g . DrawString ( " ××公司××器件2002年度销售情况一览表" , new Font ( "宋体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
//在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
3. 图01中的提示区域,即图01中的右上角显示的内容:
要绘制这部分内容首先要定位,可以把这部分要绘制的内容分成三个小部分:
其一,是图01中的"单位:万套"文字,这部分处理起来比较简单,当选定要在图片中输出的文字坐标后,调用Graphics实例中提供的DrawString方法就可以了;
其二,是绘制图01中的小方块,首先要调用Graphics实例中的DrawRectangle方法在指定位置,以指定的颜色,绘制指定大小的方块,然后再条约Graphics实例中的FillRectangle填充这个小方块就完成了;
其三,是绘制小方块右边的文字。同样要使用Graphics实例中提供的DrawString方法,只不过位置坐标和字体要进行相应改变罢了。下面代码功能是绘制图01右上角显示的内容:
Point myRec = new Point ( 535 , 30 ) ;
Point myDec = new Point ( 560 , 26 ) ;
//以上是在图01中为下面绘制定位
g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 525 , 12 ) ) ;
for ( int i = 0 ; i < sMoth.Length ; i )
{
g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
//绘制小方块
g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec . X , myRec . Y , 20 , 10 ) ;
//填充小方块
g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , myDec ) ;
//绘制小方块右边的文字
myRec . Y = 15 ;
myDec . Y = 15 ;
}
4. 根据从数据库中读取的数据,绘制数据Bar图:
此部分与第三部分比较类似,最主要的区别在于,绘制的位置不相同,下面代码是在图01中绘制数据Bar图,并提示Bar图所代表的数量:
int iBarWidth = 40 ;
int scale = 10 ;
for ( int i = 0 ; i < iXiaoSH . Length ; i )
{
g . DrawRectangle ( Pens.Black , ( i * iBarWidth ) 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) 5 ) ;
//绘制Bar图
g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , ( i * iBarWidth ) 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) 5 ) ;
//以指定的色彩填充Bar图
g . DrawString ( iXiaoSH [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , ( i * iBarWidth ) 20 , 235 - ( iXiaoSH [ i ] * scale ) ) ;
//显示Bar图代表的数据
}
5. 绘制图片边框,并形成Jpeg文件格式在客户端显示:
绘制图片边框,使用的Graphics实例中的DrawRectangle方法。至于采用Jpeg格式文件在客户端显示,是因为Jpeg文件占用的空间较小,利于网络传送。下面代码是绘制图01中的边框,并形成Jpeg文件:
Pen p = new Pen ( Color.Black , 2 ) ;
g . DrawRectangle ( p , 1 , 1 , 598 , 248 ) ;
bm.Save ( Response . OutputStream , ImageFormat . Jpeg ) ;
四.ASP.NET页面中实现数据Bar图实现步骤:
掌握了上面的关键步骤及其解决方法后,在ASP.NET实现数据Bar相对就容易许多了,下面是ASP.NET页面中实现数据Bar图的具体实现步骤,在开发工具上选用的是Visual Stuido .Net企业构建版,采用的开发语言是C#。
1. 启动Visual Studio .Net
2. 选择菜单【文件】|【新建】|【项目】后,弹出【新建项目】对话框
3. 将【项目类型】设置为【Visual C#项目】
4. 将【模板】设置为【ASP.NET Web 应用程序】
5. 在【位置】的文本框中输入"http://localhost/Bar"。然后单击【确定】按钮,这样在Visual Studio .Net就会在当前项目文件所在目录中建立一个名称为"Bar"文件夹,里面存放是此项目的项目文件,项目中的其他文件存放的位置是计算机Internet信息服务的默认的Web站点所在的目录中新建的一个名称为"Bar"的文件夹中。具体如图02所示:
图02:新建一个ASP.NET项目对话框
6. 把Visual Studio .Net的当前窗口切换到WebForm的代码编辑窗口,即:WebForm1.aspx.cs文件的编辑窗口。
7. 在WebForm1.aspx.cs文件首部,用下列代码替换WebForm1.aspx.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 . Drawing . Imaging ;
//下面程序中使用的ImageFormat类所在的命名空间
using System . Data . OleDb ;
//下面程序中使用到关于数据库方面的类所在的命名空间
8. WebForm1.ASPx.cs文件中的Page_Load事件处理代码中添加下列代码,下列代码的作用是打开数据库,读取数据,并以此数据形成数据Bar图:
string sRouter = "c:\\db.mdb" ;
//获得当前Access数据库在服务器端的绝对路径
string strCon = " Provider = Microsoft.Jet.OLEDB.4.0; Data Source = " sRouter ;
//创建一个数据库连接
OleDbConnection myConn = new OleDbConnection ( strCon ) ;
string strCom = " SELECT YF ,SL FROM Table01 ORDER BY YF" ;
myConn.Open ( ) ;
OleDbCommand myCommand = new OleDbCommand ( strCom , myConn ) ;
OleDbDataReader myOleDbDataReader = myCommand.ExecuteReader ( ) ;
//创建OleDbDataReader实例,并以此实例来获取数据库中各条记录数据
int [ ] iXiaoSH = new int [ 12 ] ;
//定义一个数组,用以存放从数据库中读取的销售数据
string [ ] sMoth = new string [ 12 ] ;
//定义一个数组,用以存放从数据库中读取的销售月份
int iIndex = 0 ;
while ( myOleDbDataReader.Read ( ) )
{
iXiaoSH [ iIndex ] = myOleDbDataReader.GetInt32 ( 1 ) ;
sMoth [ iIndex ] = myOleDbDataReader.GetInt32 ( 0 ) . ToString ( ) "月" ;
iIndex ;
}
//读取Table01数据表中的各条数据,并存放在先前定义的二个数组中
myConn . Close ( ) ;
myOleDbDataReader . Close ( ) ;
//关闭各种资源
Bitmap bm = new Bitmap ( 600 , 250 ) ;
//创建一个长度为600,宽带为250的Bitmap实例
Graphics g ;
g = Graphics.FromImage ( bm ) ;
//由此Bitmap实例创建Graphic实例
g . Clear ( Color . Snow ) ;
//用Snow色彩为背景色填充此绘画图面
g . DrawString ( " ××公司××器件2002年度销售情况一览表" , new Font ( "宋体" , 16 ) , Brushes . Black , new Point ( 5 , 5 ) ) ;
//在绘画图面的指定位置,以指定的字体、指定的颜色绘制指定的字符串。即为图表标题
//以下代码是是实现图01中的右上部
Point myRec = new Point ( 535 , 30 ) ;
Point myDec = new Point ( 560 , 26 ) ;
//以上是在图01中为下面绘制定位
g . DrawString ( "单位:万套" , new Font ( "宋体" , 9 ) , Brushes . Black , new Point ( 525 , 12 ) ) ;
for ( int i = 0 ; i < sMoth.Length ; i )
{
g . DrawRectangle ( Pens.Black , myRec . X , myRec . Y , 20 , 10 ) ;
//绘制小方块
g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , myRec . X , myRec . Y , 20 , 10 ) ;
//填充小方块
g . DrawString ( sMoth [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , myDec ) ;
//绘制小方块右边的文字
myRec . Y = 15 ;
myDec . Y = 15 ;
}
//以下代码是绘制图01中的Bar图,及其销售数量
int iBarWidth = 40 ;
int scale = 10 ;
for ( int i = 0 ; i < iXiaoSH . Length ; i )
{
g . DrawRectangle ( Pens.Black , ( i * iBarWidth ) 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) 5 ) ;
//绘制Bar图
g . FillRectangle ( new SolidBrush ( GetColor ( i ) ) , ( i * iBarWidth ) 15 , 250 - ( iXiaoSH [ i ] * scale ) , 20 , ( iXiaoSH [ i ] * scale ) 5 ) ;
//以指定的色彩填充Bar图
g . DrawString ( iXiaoSH [ i ] . ToString ( ) , new Font ( "宋体" , 9 ) , Brushes . Black , ( i * iBarWidth ) 20 , 235 - ( iXiaoSH [ i ] * scale ) ) ;
//显示Bar图代表的数据
}
//以下代码是绘制图01中的边框,并形成Jpeg文件,供浏览器显示出来
Pen p = new Pen ( Color.Black , 2 ) ;
g . DrawRectangle ( p , 1 , 1 , 598 , 248 ) ;
bm.Save ( Response . OutputStream , ImageFormat . Jpeg ) ;
9. WebForm1.aspx.cs文件中的InitializeComponent过程之后,添加下列代码,下列代码的作用是定义一个名称为GetColor函数,此函数的功能根据索引号得到相应的系统颜色:
private Color GetColor ( int itemIndex )
{
Color MyColor ;
int i = itemIndex ;
switch ( i )
{
case 0 :
MyColor = Color . Cornsilk ;
return MyColor ;
case 1 :
MyColor = Color . Red ;
return MyColor ;
case 2 :
MyColor = Color . Yellow ;
return MyColor ;
case 3 :
MyColor = Color . Peru ;
return MyColor ;
case 4 :
MyColor = Color . Orange ;
return MyColor ;
case 5 :
MyColor = Color . Coral ;
return MyColor ;
case 6:
MyColor = Color . Gray ;
return MyColor ;
case 7:
MyColor = Color . Maroon ;
return MyColor ;
case 8:
MyColor = Color . Azure ;
return MyColor ;
case 9:
MyColor = Color.AliceBlue ;
return MyColor ;
case 10:
MyColor = Color . Bisque ;
return MyColor ;
case 11:
MyColor = Color . BurlyWood ;
return MyColor ;
case 12:
MyColor = Color . Chartreuse ;
return MyColor ;
default:
MyColor = Color . Green ;
return MyColor ;
}
}
10. 至此,在上述步骤都正确执行后,在ASP.NET页面中实现数据Bar图的全部工作就完成了。在确定上面建立的Access数据库"db.mdb"位于C盘的根目录中之后,单击快捷键F5,就可以得到如图01所示的数据Bar图了。
五.总结:
在ASP.net页面中实现各种图表,其所使用的就是ASP.NET的绘图功能,而这一功能是ASP.NET的前一个版本所不具备的。上面的这些介绍,不仅介绍了在ASP.NET绘制各种图片的方法,还介绍了数据库连接和从数据库中逐条读取记录的方法。这些方法对您了解和掌握在ASP.NET中操作数据库是非常有用的。在下一篇文章中,将介绍浏览器中经常看到的另外一种图表--饼图,在ASP.NET页面中的实现方法。如果您感兴趣,那就让我们下一讲再见吧!
事务是一组组合成逻辑工作单元的数据库操作,虽然系统中可能会出错,但事务将控制和维护每个数据库的一致性和完整性。如果在事务过程中没有遇到错误,事务中的所有修改都将永久成为数据库的一部分。如果遇到错误,则不会对数据库作出任何修改。
例如,在一个银行应用程序中,如果资金从一个帐户转到另一个帐户,则会将一定的金额记入一个帐户的贷方,同时将相同的金额记入另一个帐户的借方。由于计算机可能会因为停电、网络中断等原因而出现故障,所以有可能更新了一个表中的行,但没有更新相关表中的行。如果数据库支持事务,则可以将数据库操作组成一个事务,以防止因这些事件而使数据库出现不一致。
在 ADO.NET 中,可以使用 Connection 和 Transaction 对象来控制事务。若要执行事务,请执行下列操作:
调用 Connection 对象的 BeginTransaction 方法来标记事务的开始。BeginTransaction 返回对 Transaction 的引用。请保留此引用,以便将其分配给在事务中登记的 Command。
将 Transaction 对象分配给要执行的 Command 的 Transaction 属性。如果通过活动的 Transaction 对象对 Connection 执行 Command,但该 Transaction 对象尚未分配给 Command 的 Transaction 属性,则将引发异常。
执行所需的命令。
调用 Transaction 对象的 Commit 方法来完成事务,或调用 Rollback 方法来取消事务。
以下代码示例使用 Microsoft? SQL Server? 上的 ADO.net 来演示事务逻辑。
SqlConnection myConnection = new SqlConnection("Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI;");
myConnection.Open();
// 启动一个事务
SqlTransaction myTrans = myConnection.BeginTransaction();
// 为事务创建一个命令
SqlCommand myCommand = new SqlCommand();
myCommand.Connection=myConnection;
myCommand.Transaction = myTrans;
try
{
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, "Description")";
myCommand.ExecuteNonQuery();
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, "Description")";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Both records are written to database.");
}
catch(Exception e)
{
myTrans.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Neither record was written to database.");
}
finally
{
myConnection.Close();
}
使用Excel文件做为DataGrid的数据源是非常简单的,一旦数据被装载进来,就可以把数据再保存进SQL Server或XML中。我们只需要简单地使用OLE DB Provider 来访问Excel文件,然后返回DataSet即可。
下面是要显示的Excel数据contact.xls:
姓名 性别 地址
net_lover Male amxh@21cn.com
amxh Male amxh@21cn.com
孟子 E 章 Male amxh@21cn.com
只需要指定Excel路径,并用[]选择一个工作表即可。
完整代码如下:
<%@ Page Language="C#" Debug="true" %>
<%@ Import Namespace="System.Data"%>
<%@ Import Namespace="System.Data.OleDb"%>
<script runat="server">
private DataSet CreateDataSource(){
string strConn;
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
"Data Source=C:\\Inetpub\\wwwroot\\contacts.xls;"
"Extended Properties=Excel 8.0;";
OleDbConnection conn = new OleDbConnection(strConn);
OleDbDataAdapter myCommand = new OleDbDataAdapter("SELECT * FROM [ContactList$]", strConn);
DataSet myDataSet = new DataSet();
myCommand.Fill(myDataSet);
return myDataSet;
}
public void Page_Load(Object sender, EventArgs e){
if (!IsPostBack) {
mygrid.DataSource = CreateDataSource();
mygrid.DataBind();
}
}
</script>
<center>
<form runat="server">
<ASP:datagrid runat="server" AutoGenerateColumns="false"
width="500" id="mygrid">
<HeaderStyle BorderColor="White" BackColor="black"
ForeColor="White"
Font-Bold="True"
Font-Name="Arial"
Font-Size="9" HorizontalAlign="Center"/>
<ItemStyle BorderColor=""
BackColor="#FFFFF0"
ForeColor="Black"
Font-Name="Arial"
Font-Size="8"
Font-Bold="False" HorizontalAlign="Center"/>
<Columns>
<asp:BoundColumn HeaderText="姓名" ReadOnly="true" DataField="姓名"/>
<asp:BoundColumn HeaderText="性别" ReadOnly="true" DataField="性别"/>
<asp:BoundColumn HeaderText="Email" ReadOnly="true" DataField="地址"/>
</Columns>
</asp:datagrid>
</form>
System名称空间有一个Random类,用来产生随机数。本文就介绍利用这个Random类来随机显示数据库记录。
Random类有一个重载方法叫Next,它可以产生随机数,它允许输入两个参数,以产生这两个数之间的随机数。例如:
Random R = new Random();
Random.Next(1,100);
将会在产生1-100之间的随机数。
要随机显示数据库记录,需要知道数据库最大记录数和最小记录数。
int RecNo=0,MaxRecNo,MinRecNo;
Random R = new Random();
SqlDataReader DR;
SqlConnection CN = newSqlConnection("Server=Mengxianhui;Database=Northwind;uid=sa");
CN.Open();
SqlCommand Cmd = new SqlCommand("select Max(ProductId) as MaxProdid ,Min(ProductId) as MinProdId from Products",CN);
DR= Cmd.ExecuteReader();
DR.Read();
MaxRecNo = (int)DR["MaxProdid"] ;
MinRecNo = (int)DR["MinProdid"] ;
RecNo = R.Next(MinRecNo,MaxRecNo);
然后得到随机得到记录。
Cmd = new SqlCommand("select * from Products Where ProductID = " RecNo,CN);
DR = Cmd.ExecuteReader();
DR.Read();
Response.Write("今日的产品名称: " DR["ProductID"] " - " DR["ProductName"] "");
CN.Close();
完整代码如下:
<%@ Page Language="C#" Debug="true" %>
<%@Import NameSpace="System.Data.SqlClient"%>
<%@Import NameSpace="System.Data"%>
<html>
<head>
<title>随机显示数据库记录</title>
</head>
<body>
<script runat="server">
void Page_Load(object Sender,EventArgs E)
{
int RecNo=0,MaxRecNo,MinRecNo;
Random R = new Random();
SqlDataReader DR;
//**** 连接到数据库
SqlConnection CN = new SqlConnection("Server=Mengxianhui;Database=Northwind;uid=sa");
CN.Open();
//**** 找到最大的和最小的ID号
SqlCommand Cmd = new SqlCommand("select Max(ProductId) as MaxProdid ,Min(ProductId) as MinProdId from Products",CN);
DR= Cmd.ExecuteReader();
DR.Read();
MaxRecNo = (int)DR["MaxProdid"];
MinRecNo = (int)DR["MinProdid"];
DR.Close();
//**** 创建一个随机数
RecNo = R.Next(MinRecNo,MaxRecNo);
//**** 显示随机记录信息。
Cmd = new SqlCommand("select * from Products Where ProductID = " RecNo,CN);
DR = Cmd.ExecuteReader();
DR.Read();
Response.Write("今日的产品名称: <b>" DR["ProductID"] " - " DR["ProductName"] "</b>");
DR.Close();
CN.Close();
}
</script>
</body>
</html>
由于DataList不支持内建的分页机制,因此,我们必须使用 SqlDataAdapter对象的Fill方法来实现分页,Fill方法主要用来增加或刷新DataSet的记录行。Fill方法已经被重载,我们这里选用四个参数的那个重载方法:DataSet, startRecord, maxRecords 和 TableName。
<%@ Import NameSpace="System.Data.OleDb" %>
<%@ Import NameSpace="System.Data" %>
<HTML>
<HEAD>
<script language="<a href="http://dev.21tx.com/language/vb/" target="_blank">VB</a>" runat="server">
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
If Not Page.IsPostBack() Then
intPageSize.Text = "2"
intCurrIndex.Text = "0"
DataBind()
End If
End Sub
Private Sub DataBind()
Dim CnString As String
CnString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
CnString = CnString Server.MapPath("dataDB.mdb"))
Dim objConn As New OleDbConnection(CnString)
Dim objDA As New OleDbDataAdapter("SELECT * FROM Document ORDER BY CreateDate DESC", objConn)
Dim objDS As New DataSet()
If Not Page.IsPostBack() Then
objDA.Fill(objDS)
intRecordCount.Text = CStr(objDS.Tables(0).Rows.Count)
objDS = Nothing
objDS = New DataSet()
End If
objDA.Fill (objDS, CInt(intCurrIndex.Text), CInt(intPageSize.Text), "Document")
dList.DataSource = objDS.Tables(0).DefaultView
dList.DataBind()
objConn.Close()
PrintStatus()
End Sub
Public Sub ShowFirst(ByVal s As Object, ByVal e As EventArgs)
intCurrIndex.Text = "0"
DataBind()
End Sub
Public Sub ShowPrevious(ByVal s As Object, ByVal e As EventArgs)
intCurrIndex.Text = Cstr(Cint(intCurrIndex.Text) - CInt(intPageSize.Text))
If CInt(intCurrIndex.Text) < 0 Then
intCurrIndex.Text = "0"
End If
DataBind()
End Sub
Public Sub ShowNext(ByVal s As Object, ByVal e As EventArgs)
If CInt(intCurrIndex.Text) 1 < CInt(intRecordCount.Text) Then
intCurrIndex.Text = CStr(CInt(intCurrIndex.Text) CInt(intPageSize.Text))
End If
DataBind()
End Sub
Public Sub ShowLast(ByVal s As Object, ByVal e As EventArgs)
Dim tmpInt as Integer
tmpInt = CInt(intRecordCount.Text) Mod CInt(intPageSize.Text)
If tmpInt > 0 Then
intCurrIndex.Text = Cstr(CInt(intRecordCount.Text) - tmpInt)
Else
intCurrIndex.Text = Cstr(CInt(intRecordCount.Text) - CInt(intPageSize.Text))
End If
DataBind()
End Sub
Private Sub PrintStatus()
lblStatus.Text = "总记录数:<b>" & intRecordCount.Text
lblStatus.Text = "</b> 当前:<b> "
lblStatus.Text = CStr(CInt(CInt(intCurrIndex.Text) / CInt(intPageSize.Text) 1))
lblStatus.Text = "</b>/<b>"
If (CInt(intRecordCount.Text) Mod CInt(intPageSize.Text)) > 0 Then
lblStatus.Text = CStr(CInt(CInt(intRecordCount.Text) / CInt(intPageSize.Text) 1))
Else
lblStatus.Text = CStr(CInt(intRecordCount.Text) / CInt(intPageSize.Text))
End If
lblStatus.Text = "</b>"
End Sub
</script>
</HEAD>
<body MS_POSITIONING="GridLayout">
<TABLE height="528" cellSpacing="0" cellPadding="0" width="244" border="0"
ms_2d_layout="TRUE">
<TBODY>
<TR vAlign="top">
<TD width="244" height="528">
<form id="Form1" method="post" runat="server">
<TABLE height="227" cellSpacing="0" cellPadding="0" width="516" border="0"
ms_2d_layout="TRUE">
<TR vAlign="top">
<TD width="10" height="15"></TD>
<TD width="506"></TD>
</TR>
<TR vAlign="top">
<TD height="48"></TD>
<TD>
<h2 align="center"><font face="verdana">Paging in DataList</font></h2>
</TD>
</TR>
<TR vAlign="top">
<TD height="106"></TD>
<TD>
<a name="this"></a>
</TD>
</TR>
<TR vAlign="top">
<TD height="19"></TD>
<TD rowSpan="2">
<table width="505" align="right" height="25">
<tr>
<td width="76%" align="left">
<asp:label ID="lblStatus" Runat="server" Font-Name="verdana" Font-Size="10pt" />
</td>
<td width="6%">
<a href="datalistpaging.aspx#this" ID="hrefFirst" onserverclick="ShowFirst" runat="server">
<b><<</b></a>
</td>
<td width="6%">
<a href="datalistpaging.aspx#this" ID="hrefPrevious"
onserverclick="ShowPrevious" runat="server">
<b><</b></a>
</td>
<td width="6%">
<a href="datalistpaging.aspx#this" ID="hrefNext" onserverclick="ShowNext" runat="server">
<b>></b></a>
</td>
<td width="6%">
<a href="datalistpaging.aspx#this" ID="hrefLast" onserverclick="ShowLast" runat="server">
<b>>></b></a>
</td>
</tr>
</table>
</TD>
</TR>
<TR vAlign="top">
<TD height="19"></TD>
<TD>
<asp:label ID="intPageSize" Visible="False" Runat="server" /></TD>
</TR>
<TR vAlign="top">
<TD height="20"></TD>
<TD>
<asp:label ID="intRecordCount" Visible="False" Runat="server" /></TD>
</TR>
<asp:DataList ID="dList" Runat="server" Width="100%"
ItemStyle-BackColor="Beige" ItemStyle-Font-Name="宋体"
BorderWidth="1" HeaderStyle-Font-Name="Verdana" EnableViewState="False">
<HeaderTemplate>
<table width="100%" style="font: 10pt verdana" cellpadding="0" cellspacing="0">
<tr style="background-color:FF0000">
<th align="left">
<font color="#FFFFFF">Store ID</font></th>
<th align="left">
<font color="#FFFFFF">Order Number</font></th>
<th align="left">
<font color="#FFFFFF">Order Date</font></th>
<th align="left">
<font color="#FFFFFF">Qty</font></th>
<th align="left">
<font color="#FFFFFF">Title ID</font></th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr style="background-color:#f5f5dc">
<td><%# DataBinder.Eval(Container.DataItem, "id") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "Title") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "Author") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "Source") %></td>
<td><%# DataBinder.Eval(Container.DataItem, "CreateDate") %></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</TABLE>
</FooterTemplate>
</asp:DataList>
<asp:label ID="intCurrIndex" Visible="False" Runat="server" />
</TABLE>
</FORM>
</TD></TR>
</TBODY>
</TABLE>
</body>
</HTML>
为了避免大量记录造成的网络阻塞,可以用存储过程。
首先:创建为Page_Load事件编写数据绑定的代码:
<%@ Page Language="<a href="http://dev.21tx.com/language/vb/" target="_blank">VB</a>" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<p>
<script runat="server">
Sub Page_Load(Sender As Object, E As EventArgs)
Dim myConnectionString As String = "Data Source=.;Initial Catalog=NorthWind;User Id=sa;Password=;"
Dim myConnection As SqlConnection = new SqlConnection(myConnectionString)
Dim myCommand As SqlCommand = New SqlCommand("select * from Categories", myConnection)
Dim myDataReader As SqlDataReader
Try
myConnection.Open()
myDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection)
my<a href="http://dev.21tx.com/dotnet/aspnet/datagrid/" target="_blank">DataGrid</a>.DataSource = myDataReader
myDataGrid.DataBind()
Catch myException As Exception
Response.Write("数据错误:" & myException.ToString())
Finally
If Not myDataReader Is Nothing Then
myDataReader.Close()
End If
End Try
End Sub
其次:创建OnItemDataBound事件,在OnItemDataBound事件中,我们可以对DataGrid中每行进行数据绑定时进行检测。这里我们只添加Footer部分的内容,因此,我们只检测DataGrid中的Footer部分。下面是 DataGrid中几种ItemTypes类型。
Item Type Description
Header DataGrid控件的Heading部分
Footer DataGrid控件的Footer部分
Item DataGrid控件中每个条目
AlternatingItem DataGrid控件的alternating条目
SelectedItem DataGrid控件的selected条目
EditItem DataGrid控件的可编辑条目
Separator DataGrid控件每个条目之间的分割部分
Pager DataGrid控件的page selection部分
最后:一旦我们检测到当前是Footer部分,就可以添加我们的动态内容。这里我在第二列添加一个链接。
Public Sub myDataGrid_ItemDataBound(sender As Object, e As DataGridItemEventArgs)
'只有类型为footer的时候进行执行
If(e.Item.ItemType = ListItemType.Footer )
Dim myHy<a href="http://dev.21tx.com/web/perl/" target="_blank">Perl</a>ink As HyperLink = new HyperLink()
If Not Request.QueryString("id") = Nothing Then
myHyperLink.Text = "添加内容"
myHyperLink.NavigateURL = "adddetail.<a href="http://dev.21tx.com/web/asp/" target="_blank">ASP</a>x?id=" & Request.QueryString("id")
Else
myHyperLink.Text = "没有添加内容"
End If
'Cells从0开始
e.Item.Cells(1).Controls.Add(myHyperLink)
End If
End Sub
</script>
下面是aspx页面部分:
<html>
<head>
</head>
<body>
<form runat="server">
<asp:datagrid id="myDataGrid"
runat="server"
showfooter="true"
onitemdatabound="myDataGrid_ItemDataBound"
enableviewstate="false">
</asp:datagrid>
</form>
</body>
</html>
在应用程序开发中,我们会经常遇到把从数据源动态取回的数据用统计图表现出来,在Microsoft .net Framework出现之前,我们采取的方法主要是编写组件来完成这一任务。现在,利用Microsoft .NET Framework提供的丰富的GDI 类和对象可以很轻松地实现这一功能。在本文中,我们就来看看在ASP.NET中如何动态创建常用的柱状图和饼图。数据源有许多种,在本文里我们就以数组来进行示例,但本例的方法很容易转换成数据库类型的数据源来进行。
查看例子
第一步:创建一个新的ASP.NET项目。
打开Microsoft Visual Studio .NET,点击“文件(File)”-“新建(New)”-“项目(Project)”,打开“新建项目(New Project)”对话框,在“项目类型(Project Types)”里选择“Visual Basic 项目(Projects)”,在“模板(Templates)”里选择“ASP.NET应用程序(Web Application)”,在应用程序地址里输入:http://localhost/aspCharts,点击“确定(OK)”按钮,Microsoft Visual Studio .NET将会自动在wwwroot目录下创建一个名为aspCharts的Web工程。
第二步:为默认起始页编写代码(Aspxhttp://image.21tx.com/image/20030502/10107.jpg)。
我们要在这个页面里显示动态创建的图形,打开Aspxhttp://image.21tx.com/image/20030502/10107.jpg的标签页的“HTML”视图,插入下面的代码:
<html>
<body>
<form id="Form1" method="post" runat="server">
<table width="517" border="0" height="255">
<tr>
<td align="middle"><img src="http://image.21tx.com/image/20030502/10107.jpg"></td>
</tr>
<tr>
<td height="20" align="middle">ASP.NET 中动态创建图形范例</td>
</tr>
</table>
</form>
</body>
</html>
第三步:添加名为http://image.21tx.com/image/20030502/10107.jpg的Web窗体页。
打开“解决方案资源管理器(Solution Explorer)”,在“aspCharts项目”上点击右键,选择“添加(Add)”-“添加新项(Add New Item)”,弹出“添加新项(Add New Item)”对话框,在右边的“模板”里选择“Web 窗体”,在底下的名字输入框了输入“http://image.21tx.com/image/20030502/10107.jpg”,点击“打开”按钮。
第四步:为“http://image.21tx.com/image/20030502/10107.jpg”Web 窗体页添加代码。
在“http://image.21tx.com/image/20030502/10107.jpg”窗体上点击右键,选择“查看代码(View Code)”,在代码的第一行添加下面二行:
Imports System.Drawing
Imports System.Drawing.Imaging
Public Class Chart
Inherits System.Web.UI.Page
#Region " Web 窗体设计器生成的代码 "
'该调用是 Web 窗体设计器所必需的。
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
End Sub
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
'CODEGEN: 此方法调用是 Web 窗体设计器所必需的
'不要使用代码编辑器修改它。
InitializeComponent()
End Sub
#End Region
'创建页面事件
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'声明整型变量i,
Dim i As Integer
'创建一个位图对象,用来放置柱形图,我们可以把它看作是一块画布。
'这里宽、高分别是400和200,当然,你也可以根据需要把它们做为参数来进行传递。
Dim objBitMap As New Bitmap(400, 200)
'声明一个图形对象,在上面创建的位图上画图。
Dim objGraphics As Graphics
'从指定的objBitMap对象创建新图形对象objGraphics。
objGraphics = Graphics.FromImage(objBitMap)
'清除整个绘图面并以指定白色为背景色进行填充。
objGraphics.Clear(Color.White)
'创建一个数据源,这里我们为了方便其间,采用数组做为柱形图和饼图的数据源。
Dim arrValues(5) As Integer
arrValues(0) = 100
arrValues(1) = 135
arrValues(2) = 115
arrValues(3) = 125
arrValues(4) = 75
arrValues(5) = 120
'定义数组对象,用来描述图例。
Dim arrValueNames(5) As String
arrValueNames(0) = "一月"
arrValueNames(1) = "二月"
arrValueNames(2) = "三月"
arrValueNames(3) = "四月"
arrValueNames(4) = "五月"
arrValueNames(5) = "六月"
'在画布(objBitMap对象)的坐标5,5处,用指定的Brush(画笔)对象和Font(字体)对象绘制统计图标题。
objGraphics.DrawString(" X 公司上半年销售情况", _
New Font("宋体", 16), Brushes.Black, New PointF(5, 5))
'创建图例文字。
Dim symbolLeg As PointF = New PointF(335, 20)
Dim descLeg As PointF = New PointF(360, 16)
'画出图例。利用objGraphics图形对象的三个方法画出图例:
'FillRectangle()方法画出填充矩形,DrawRectangle()方法画出矩形的边框,
'DrawString()方法画出说明文字。这三个图形对象的方法在 .NET 框架类库类库中均已重载,
'可以很方便根据不同的参数来画出图形。
For i = 0 To arrValueNames.Length - 1
'画出填充矩形。
objGraphics.FillRectangle(New SolidBrush(GetColor(i)), symbolLeg.X, symbolLeg.Y, 20, 10)
'画出矩形边框。
objGraphics.DrawRectangle(Pens.Black, symbolLeg.X, symbolLeg.Y, 20, 10)
'画出图例说明文字。
objGraphics.DrawString(arrValueNames(i).ToString, New Font("宋体", 10), Brushes.Black, descLeg)
'移动坐标位置,只移动Y方向的值即可。
symbolLeg.Y = 15
descLeg.Y = 15
Next i
'遍历数据源的每一项数据,并根据数据的大小画出矩形图(即柱形图的柱)。
For i = 0 To arrValues.Length - 1
'画出填充矩形。
objGraphics.FillRectangle(New SolidBrush(GetColor(i)), _
(i * 35) 15, 200 - arrValues(i), 20, arrValues(i) 5)
'画出矩形边框线。
objGraphics.DrawRectangle(Pens.Black, (i * 35) 15, 200 - arrValues(i), 20, arrValues(i) 5)
Next
'下面画饼图。先定义两个变量,代表当前角度和总角度,以便于画图时将角度进行按比例换算。
Dim sglCurrentAngle As Single = 0
Dim sglTotalAngle As Single = 0
'定义一个变量,代表总的销售额。
Dim sglTotalValues As Single = 0
'计算总销售额。
For i = 0 To arrValues.Length - 1
sglTotalValues = arrValues(i)
Next
i = 0
'遍历数据源的每一项数据,并根据数据的大小画出饼图。
'图形对象的FillPie()方法和DrawPie()在.NET 框架类库中已重载。
For i = 0 To arrValues.Length - 1
'计算当前角度值:当月销售额 / 总销售额 * 360,得到饼图中当月所占的角度大小。
sglCurrentAngle = arrValues(i) / sglTotalValues * 360
'画出填充圆弧。
objGraphics.FillPie(New SolidBrush(GetColor(i)), _
220, 95, 100, 100, sglTotalAngle, sglCurrentAngle)
'画出圆弧线。
objGraphics.DrawPie(Pens.Black, 220, 95, 100, 100, sglTotalAngle, sglCurrentAngle)
'把当前圆弧角度加到总角度上。
sglTotalAngle = sglCurrentAngle
Next i
'将objGraphics对象以指定的图形格式(这里是Gif)保存到指定的Stream对象,并输出到客户端。
objBitMap.Save(Response.OutputStream, ImageFormat.Gif)
End Sub
'下面这段函数用来根据不同的月份返回不同的颜色值。
Private Function GetColor(ByVal itemIndex As Integer) As Color
Dim objColor As Color
Select Case itemIndex
Case 0
objColor = Color.Blue
Case 1
objColor = Color.Red
Case 2
objColor = Color.Yellow
Case 3
objColor = Color.Purple
Case 4
objColor = Color.Orange
Case 5
objColor = Color.Brown
Case 6
objColor = Color.Gray
Case 7
objColor = Color.Maroon
Case 8
objColor = Color.Maroon
Case Else
objColor = Color.Blue
End Select
Return objColor
End Function
End Class
好了,我们的代码已经写完,点击“全部保存”按钮,然后按“F5”执行,看看最好的结果。如果没有错误的话,您将会看到如下的结果:

本文所有代码在简体中文Windows 2000 .NET FrameWork 1.0(英文正式版) .NET FrameWork SP1和Windows XP .NET FrameWork 1.0(中文版)下调试通过。
C#代码
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.<a href="http://dev.21tx.com/dotnet/aspnet/webcontrols/" target="_blank">WebControls</a>;
using System.Web.UI.HtmlControls;
using System.Drawing.Imaging;
namespace eMeng.Exam
{
/// <summary>
/// Chart 的摘要说明。
/// </summary>
public class Chart : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
Bitmap objBitMap = new Bitmap(400, 200);
Graphics objGraphics;
objGraphics = Graphics.FromImage(objBitMap);
objGraphics.Clear(Color.White);
int[] arrValues = {100,135,115,125,75,120};
string[] arrValueNames = new string[]{"一月","二月","三月","四月","五月","六月"};
objGraphics.DrawString(" X 公司上半年销售情况",
new Font("宋体", 16), Brushes.Black, new PointF(5, 5));
PointF symbolLeg = new PointF(335, 20);
PointF descLeg = new PointF(360, 16);
for (int i = 0; i < arrValueNames.Length; i )
{
objGraphics.FillRectangle(new SolidBrush(GetColor(i)), symbolLeg.X, symbolLeg.Y, 20, 10);
objGraphics.DrawRectangle(Pens.Black, symbolLeg.X, symbolLeg.Y, 20, 10);
objGraphics.DrawString(arrValueNames[i].ToString(), new Font("宋体", 10), Brushes.Black, descLeg);
symbolLeg.Y = 15;
descLeg.Y = 15;
}
for (int i = 0; i < arrValues.Length; i )
{
objGraphics.FillRectangle(new SolidBrush(GetColor(i)), (i * 35) 15, 200 - arrValues[i], 20,
arrValues[i] 5);
objGraphics.DrawRectangle(Pens.Black, (i * 35) 15, 200 - arrValues[i], 20, arrValues[i] 5);
}
float sglCurrentAngle = 0;
float sglTotalAngle = 0;
float sglTotalValues = 0;
for (int i = 0; i <= arrValues.Length - 1; i )
{
sglTotalValues = arrValues[i];
}
for (int i = 0; i < arrValues.Length; i )
{
sglCurrentAngle = arrValues[i] / sglTotalValues * 360;
objGraphics.FillPie(new SolidBrush(GetColor(i)), 220, 95, 100, 100, sglTotalAngle, sglCurrentAngle);
objGraphics.DrawPie(Pens.Black, 220, 95, 100, 100, sglTotalAngle, sglCurrentAngle);
sglTotalAngle = sglCurrentAngle;
}
objBitMap.Save(Response.OutputStream, ImageFormat.Gif);
}
private Color GetColor(int itemIndex)
{
Color objColor;
if (itemIndex == 0)
{
objColor = Color.Blue;
}
else if (itemIndex == 1)
{
objColor = Color.Red;
}
else if (itemIndex == 2)
{
objColor = Color.Yellow;
}
else if (itemIndex == 3)
{
objColor = Color.Purple;
}
else if (itemIndex == 4)
{
objColor = Color.Orange;
}
else if (itemIndex == 5)
{
objColor = Color.Brown;
}
else if (itemIndex == 6)
{
objColor = Color.Gray;
}
else if (itemIndex == 7)
{
objColor = Color.Maroon;
}
else if (itemIndex == 8)
{
objColor = Color.Maroon;
}
else
{
objColor = Color.Blue;
}
return objColor;
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load = new System.EventHandler(this.Page_Load);
}
#endregion
}
}
Web.config文件是一个XML文件,它用来储存 ASP.NET Web 应用程序的配置信息(如最常用的设置ASP.NET Web 应用程序的身份验证方式),它可以出现在应用程序的每一个目录中。当你通过Visual Studio.NET新建一个Web应用程序后,默认情况下会在根目录自动创建一个默认的Web.config文件,包括默认的配置设置,所有的子目录都继承它的配置设置。如果你想修改子目录的配置设置,你可以在该子目录下新建一个Web.config文件。它可以提供除从父目录继承的配置信息以外的配置信息,也可以重写或修改父目录中定义的设置。
在Web应用程序运行时,对Web.config文件的修改不需要重启服务就可以生效(注:<processModel> 节例外)。当然Web.config文件是可以扩展的。你可以自定义新配置参数并编写配置节处理程序以对它们进行处理。
web.config配置文件
web.config是个XML文件,所有配置信息都是以相应的节点来记录的。配置文件以下所有的代码都应该位下面的根节点中:
<configuration>
<system.web>
……
……
</system.web>
</configuration>
便于学习和节约篇幅,本书就省略了其他节点代码,读者可以从每个Web应用程序的目录下找到它,用文本编辑器就可以打开来看。下面我们就几个重要的节点来介绍。
(1) <authentication> 节点
作用:配置 ASP.NET 身份验证支持(为Windows、Forms、PassPort、None四种)。该元素只能在计算机、站点或应用程序级别声明。<authentication> 元素必需与<authorization> 节配合使用。
(2) <authorization> 节点
作用:控制对 URL 资源的客户端访问(如允许匿名用户访问)。此元素可以在任何级别(计算机、站点、应用程序、子目录或页)上声明。必需与<authentication> 节配合使用。
(3) <compilation>节
作用:配置 ASP.NET 使用的所有编译设置。默认的debug属性为"True".在程序编译完成交付使用之后应将其设为True(Web.config文件中有详细说明,此处省略示例)
(4) <customErrors>节点
作用:为 ASP.NET 应用程序提供有关自定义错误信息的信息。它不适用于 XML Web services 中发生的错误。
例如:当发生错误时,将网页跳转到自定义的错误页面。
<customErrors defaultRedirect="ErrorPage.aspx" mode="RemoteOnly">
</customErrors>
其中元素defaultRedirect表示自定义的错误网页的名称。mode元素表示:对不在本地 Web 服务器上运行的用户显示自定义(友好的)信息。
(5)<httpRuntime>节点
作用:配置 ASP.NET HTTP 运行库设置。该节可以在计算机、站点、应用程序和子目录级别声明。
例如:控制用户上传文件最大为4M,最长时间为60秒,最多请求数为100。
<httpRuntime maxRequestLength="4096" executionTimeout="60" appRequestQueueLimit="100"/>
(6) <pages>节点
作用:标识特定于页的配置设置(如是否启用会话状态、视图状态,是否检测用户的输入等)。<pages>可以在计算机、站点、应用程序和子目录级别声明。
例如:不检测用户在浏览器输入的内容中是否存在潜在的危险数据(注:该项默认是检测,如果你使用了不检测,一要对用户的输入进行编码或验证),在从客户端回发页时将检查加密的视图状态,以验证视图状态是否已在客户端被篡改。(注:该项默认是不验证)。
<pages buffer="true" enableViewStateMac="true" validateRequest="false"/>
(7)<sessionState>节点
作用:为当前应用程序配置会话状态设置(如设置是否启用会话状态,会话状态保存位置)。
例如:
<sessionState mode="InProc" cookieless="true" timeout="20"/>
</sessionState>
需要说明的是:
mode="InProc"表示:在本地储存会话状态(你也可以选择储存在远程服务器或SAL服务器中或不启用会话状态);
cookieless="true"表示:如果用户浏览器不支持Cookie时启用会话状态(默认为False);
timeout="20"表示:会话可以处于空闲状态的分钟数;
(8)<trace>节点
作用:配置 ASP.NET 跟踪服务,主要用来程序测试判断哪里出错。
例如:以下为Web.config中的默认配置:
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
需要说明的是:
enabled="false"表示不启用跟踪;requestLimit="10"表示指定在服务器上存储的跟踪请求的数目 ;
pageOutput="false"表示只能通过跟踪实用工具访问跟踪输出;
traceMode="SortByTime"表示以处理跟踪的顺序来显示跟踪信息;
localOnly="true" 表示跟踪查看器 (trace.axd) 只用于宿主 Web 服务器。
自定义Web.config文件配置节
自定义Web.config文件配置节过程分为两步:
(一) 在配置文件顶部 <configSections> 和 </configSections>标记之间声明配置节的名称和处理该节中配置数据的 .NET Framework 类的名称。
(二) 在 <configSections> 区域之后为声明的节做实际的配置设置。
例如:创建一个节存储数据库连接字符串
<configuration>
<configSections>
<section name="appSettings" type="System.Configuration.NameValueFileSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</configSections>
<appSettings>
<add key="SQLCon" value="server=ASPNET;database=northwind;uid=sa;pwd=1234567abc"/>
</appSettings>
<system.web>
......
</system.web>
</configuration>
访问Web.config文件的节点信息
可以通过使用ConfigurationSettings.AppSettings 静态字符串集合来访问 Web.config 文件示例:获取上面例子中建立的连接字符串。
Dim SQLCon As String = ConfigurationSettings.AppSettings("SQLCon ")
Dim sqlcon = New SqlConnection(SQLCon)
随着Web服务从原始模型到产品的发展,XML的安全问题和加速问题已经提高到主要位置上来了。尽管重量级公司IBM和Cisco系统公司都通过涉入XML设备领域的方式来利用目前的这种需要——IBM最近挖出了DataPower技术公司——但是,Forum系统公司打赌说:这一周他们将把Forum Vantage XML加速器投放市场,并且随着这一举动他们将赢得更多机会。 “比起传统的二进制通信协议,XML甚至可以消耗高达50倍的带宽。它有可能导致交互应用性能的下降。仅仅只处理XML有可能是令人失望的。” Forum系统公司市场副总裁Walid Negm说,该公司坐落在盐湖城。
到目前为止,Forum公司已经将其研究计划集中到XML的安全问题上。
“安全基本设施在变化着,网络设备在变化着,中间件基础设施也在变化着,” Negm 说,“我们把这一切看作是Forum公司在其他领域扩张的一个绝佳机会,因此推出了XML加速器。”
然而,Negm强调说加速器已经自始自终成为Forum Sentry SOA网关和 Forum XWall Web 服务防火墙的一部分。“在当我们受到攻击时,XML加速器一直是产品值得信任的基础,因此我们一直把为用户加速事务处理当作基本的功能。以前,我们只是希望能够把我们的精力集中于安全方面,但是现在是我们大展身手的时候了。”
根据Forrester研究公司高级分析师Michael Gavin研究表明,“这个市场随时准备着放弃那些迄今为止已经累积了很重的负担”。该公司位于麻省剑桥。
由于组织是去年才把Web服务发展到产品生产,“XML占用如此多的宽待是存在着安全问题和加速问题的,” Gavin说,“人们知道他们需要XML设备。在加速和安全方面,中间件解决方案无法提供与这些产品相媲美的好处。”
XML设备是“服务中间体的集合” ZapThink LLC 公司高级分析师Jason Bloomberg说,该公司位于麻省华生市。“所有的这些设备,与那些诸如Blue Titan经销商所提供的设备一样,都是中间件方式的替代物,这种中间件方式是ESB的经销商来提供SOA基础设施。但是,大量的中间件经销商企图采用新的方式来卖出陈旧的中间件。显然,这并不是构建灵活的SOA基础设施的正确方法。”
相比之下,他说:“一种智能的中间体方式将会更加的灵活。它依靠现有的网络,并且你可以尽可能多地拥有中间体。你可以不需要ESB的同时构建企业级的SOA基础设施。”
Forum公司的Vantage XML加速器利用一个64位平台架构和Forum公司的Hermes语法分析器来加速XML/SOAP的解析、XML模式的确认、XPath的处理以及XSLT的功能转换。根据这个公司自己所说,他们的XML加速器能够达到每秒处理1万多条XML消息。
与这个领域的一些竞争者不同的是,Forum公司的产品在多种因素中都是有效的:软件、可编程通信接口卡(PCI card)以及设备。同时提供硬件和软件版本“是该公司赢得了潜在的用户和商业伙伴”,Bloomberg说。并且,他补充道,“他们的设备具备危险防护角,这是其它的设备所没有强调的,当然这也就是Forum公司的核心实力。”
Negm 说Forum公司在10月份到达了他的第一个


