仪征化纤股份有限公司信息中心 赵卫民
在对大批量的数据进行分析比较时,最常用也是最直观明了的表现方法莫过于绘制趋势图表。一般情况下,我们利用EXCEL制作各种类型的趋势图表,但它们都是基于静态数据的,即数据是事先整理好的而不 是动态生成的。如果在网上发布,只能将绘制好的图表以静态GIF图像发布,这无法从根本上满足不同用户对不同数据的需求。
ASP擅长服务器端的Web编程,操作后台数据库更是它的强项。但是用ASP制作实时数据库图表有点困难,因为ASP本身并不支持图表功能,只能借助第三方控件进行开发,如VB的MSChart控件。微软推出的.NET Framework较好地解决了这个问题。微软在.NET平台上集成了实时数据库图表制作组件—OWC(Microsoft Office Web Components)。通过在ASP.NET页面中调用OWC,我们可以轻松地绘制出各种类型的实时图表。OWC支持近50种图表类型,包括曲线图、折线图、柱状图、面积图、K线图等。与MSChart相比,OWC功能强大,操作简单。此外,由于OWC是基于服务端的,而MSChart只能应用在客户端,因此在服务器端的Web开发中,MSChart要比OWC逊色不少。
下面笔者将结合实例来具体阐述OWC在ASP.NET页面中的应用,这个实例是笔者开发的项目《化纤产品及其原料市场分析系统》中的一个子系统,笔者在该项目中用到OWC,充分享受到了OWC的强大功能给开发工作带来的方便。
三层结构
系统整体架构采用了B/S三层结构模式,将系统分为用户界面层(也称为表现层)、业务逻辑层(也称为功能层)和数据库服务层(也称为数据层),开发平台则采用了.NET Framework,有效地降低了系统对客户机的要求,避免了在客户机上分发应用程序与版本控制的困难。
● 用户界面层: 用户界面采用的是ASP.NET技术。ASP.NET技术的应用增强了系统的通用性,客户端只需安装IE或Netscape等任一款浏览器,无需加载任何组件。
● 业务逻辑层: 采用了.NET Framework调用OWC的技术,能够根据用户的要求快速取得数据库中的数据动态生成图表。系统能够支持复杂的检索条件,检索速度快,响应时间短。
● 数据库服务层:数据库服务层可采用任何一款关系型数据库。在本项目中,笔者使用的是SQL Server,它能与.NET Framework无缝集成。数据库存取技术则采用了ADO.NET。
下文我们将着重介绍业务逻辑层的实现方法。
图表元素简介
一张完整的图表由若干个元素组成,我们必须对它们有所了解,才能随心所欲、充分自如地对图表进行全方位的控制,也才能更好地理解本程序。笔者制作了一张简易的图表,在图中标注了程序涉及到的主要部位和元素的名称,借此帮助读者掌握OWC以及理解本文所引用的代码。
使用OWC组件
在这一节里所涉及的源代码摘自于《化纤产品及其原料市场分析系统》,该系统在Window 2000/XP简体中文专业版、.NET Framewrok 1 .0环境下通过。使用OWC组件的步骤如下:
1. 在当前目录中新建一个存放图表文件的子目录chart,同时把对该目录的“修改”权限赋予ASP.NET账户。具体步骤如下:用鼠标右键单击chart目录名,选择“属性”菜单项,在弹出的“Chart”属性对话框中单击“安全”选项卡,再单击“添加”按钮,找到ASP.NET账户,赋予“修改”权限,单击“确定”按钮结束。这样,ASP.NET就可以在chart目录中写入图表文件了。
2. 定义一个服务器端的Image图像控件,该图像的属性imageURL将在程序末尾被指向动态生成的图表文件,因此在这里无需为它赋值。
< asp:image id=“imgChart” Width=“500” Height=“300” Visible=“False” Runat=“server”>< /asp:image>
3. 添加OWC引用。
在使用OWC之前,首先必须将OWC的引用加入到“解决方案资源管理器”中。具体步骤如下:打开“解决方案资源管理器”面板,鼠标右键单击“引用”,选择“添加引用”菜单,在弹出的“添加引用”对话框中单击“COM”卡片,找到“Microsoft Office Web Components 9.0”,单击“选择”和“确定”按钮,OWC就被添加到了引用中。
4. 定义OWC空间,并在该空间中加入一个OWC图表owcChart。
Dim owcChartSpace As OWC.ChartSpace = New OWC.ChartSpace()
Dim owcChart As OWC.WCChart = owcChartSpace.Charts.Add
5. 用SQL检索条件进行数据库检索,并将检索结果以RecordSet数据集的方式赋给owcChart。
OWC只支持RecordSet数据集,不支持DataSet数据集,因此在检索时不能使用sqlCommand、sqlDataAdapter等对象,只能使用RecordSet对象进行检索。
’打开connection连接
ConnADO.Open(connectionString)
RecordsetADO.ActiveConnection = ConnADO
’设置游标为静态游标
RecordsetADO.CursorType = ADODB.CursorTypeEnum.adOpenStatic
RecordsetADO.CursorLocation = ADODB.CursorLocationEnum.adUseClient
’变量strSQL中存放了标准SQL检索条件
RecordsetADO.Open(strSQL)
然后将RecordSet数据集赋给OWC对象:
owcChartSpace.DataSource = RecordsetADO
在本例中,我们假定用SQL语句检索出的数据共有三个字段:产品、日期和价格。这三个字段的值分别与图表中的曲线、分类(X)轴和数值(Y)轴的数据一一对应。
6. 确定曲线类型,并确定区别不同曲线的字段名。
首先确定曲线类型为平滑曲线。
owcChart.Type = OWC.ChartChartTypeEnum.chChartTypeSmoothLine
OWC支持在同一张图表中显示两条以上的曲线。因此我们必须给出区别不同曲线的依据,这个依据就是“产品”字段的取值。具体地说,“产品”字段中有几个不同的取值,就会生成几条不同的曲线。
owcChart.SetData(OWC.ChartDimensionsEnum.chDimSeriesNames, 0, “产品”)
7. 确定分类(X)轴标签与数值(Y)轴标签所对应的字段。
首先需要定义owcSeries为OWC的曲线集合,然后遍历图表中的每一条曲线,将“日期”字段的值赋给分类(X)轴作为X轴刻度标签,将“价格”字段的值赋给数值(Y)轴作为Y轴刻度标签。如果我们能够确定图表中只有一条曲线,也可以省略遍历的过程,但这样无疑会降低程序的通用性。
Dim owcSeries As OWC.WCSeries
For Each owcSeries In owcChart.SeriesCollection
owcSeries.SetData(OWC.ChartDimensionsEnum.chDimCategories, 0, “日期”)
owcSeries.SetData(OWC.ChartDimensionsEnum.chDimValues, 0, “价格”)
Next
8. 对坐标轴的属性进行设置。
这部分代码通过对坐标轴标题的文字内容、颜色、大小、主要和次要刻度线及其标签、主要和次要网络线等方面的设置美化图表。读者如果对本段代码中的概念有些模糊,可以参考前一部分提供的那张图表。具体设置方法请参见以下代码。
’先定义axis为坐标轴集合
Dim axis As OWC.WCAxis
’遍历坐标轴集合
For Each axis In owcChart.Axes
’显示轴标题
axis.HasTitle = True
’先对分类(X)轴进行设置
If axis.Type=OWC.ChartAxisTypeEnum.
chCategoryAxis Then
axis.HasTickLabels = True
’显示X轴刻度标签
axis.Position = OWC.ChartAxisPositionEnum.chAxisPositionBottom
’标签的显示位置
axis.Title.Font.Color =”blue”
’X轴的标题文字颜色
axis.Title.Font.Size = “9”
’X轴的标题文字大小
axis.Title.Caption = “日期范围”
’X轴的标题文字内容
Else
’对数值(Y)轴进行设置
axis.MajorGridlines.Line.Color = “silver”
’Y轴主要网络线的颜色
axis.MajorTickMarks = OWC.ChartTickMarkEnum.chTickMarkNone
’不显示Y轴主要刻度标记
axis.HasTickLabels = True
’显示Y轴刻度标签
axis.Title.Font.Color = “blue”
’Y轴的标题文字颜色
axis.Title.Font.Size = “9”
’Y轴的标题文字大小
axis.Title.Caption=“价格(千元/吨)”
’Y轴的标题文字内容
End If
Next
9. 以GIF图像格式输出图表,并将图像文件名赋给Image控件。
’用随机数来生成随机文件名
Randomize()
Dim nFileNameSuffix As Integer
Dim sFileNameSuffix As String
nFileNameSuffix = 100000 * Rnd()
sFileNameSuffix = System.Convert.ToString(nFileNameSuffix)
’以GIF格式输出图表,大小为500*300,图表的文件名为:polyesterprice_随机数.gif,存放在chart子目录中
owcChartSpace.ExportPicture(MapPath(“chart/PolyesterPrice_”) sFileNameSuffix “.gif”, “gif”, 500, 300)
’将Image控件的URL指向该图表文件
imgChart.ImageUrl=“chart/PolyesterPrice_” sFileNameSuffix “.gif”
通过以上九个步骤,我们就完成了一个实时数据库图表的生成与显示。在此需要指出的是,以上的九个步骤只是生成一张图表必不可少的基本过程,通过设置OWC的其他属性可以更好、更精确地控制图表的生成与显示方式,如图例、线条的粗细与颜色、坐标轴刻度线及标签的显示频度、网络线等。这部分笔者不再介绍,请参见本文第四部分的源代码。
本文代码生成的图表效果请见下图。
优化
上文中所有实时生成的图表文件都存放在chart文件夹中,由于采用了随机文件名的方式,因此这些文件不会互相覆盖。但是如此日积月累,越来越多的文件不仅占用了硬盘空 间,也妨碍了管理,降低了性能。我们能不能在程序中自动删除以前的图表文件呢?答案是肯定的。我们只要在代码文件的Page_Load()函数中放置如下一段代码,程序运行的时候,就会自动删除当日以前的文件。这样,chart文件夹中存放的就总是当日生成的图表文件,从而有效地避免了文件垃圾。
’先取得chart文件夹中的文件列表
Dim fileEntries() As String = System.IO.Directory.GetFiles(MapPath(“chart”))
Dim sFile As String
’遍历文件列表
For Each sFile In fileEntries
’将文件的生成日期与系统日期相比,如果是当日以前生成的文件,删除它
If DateTime.Compare(System.IO.File.GetCreationTime(sFile).AddDays(1), DateTime.Now) < 0 Then
System.IO.File.Delete(sFile)
End If
Next
虽然用OWC生成的图表功能齐全,界面美观,但它也存在着不少的缺陷。首先,OWC不支持DataSet数据集,这样我们就无法在生成图表的同时使用DataGrid显示数据表,除非我们用循环依次取出Recordset记录集中的全部数据手工生成表格,或用同样的检索条件对数据库进行二次检索,但这无疑要增加服务器的负担。其次,在同一张图表中绘制的曲线只能是同一种类型,或同为平滑曲线图,或同为柱状图,它不能在同一张图表中显示不同类型的曲线。最后,在某些细节方面,如分类(X)轴的设置方面,OWC无法提供更加详细、人性化的设置途径。如果读者要追求更强大的功能和更好的显示效果,笔者向您推荐两个专业的基于.NET的图表控件,这两个控件分别由Dundas和Softwarefx公司出品,都同时支持Web Form和Win Form开发,只是这两个控件都是付费的。读者如果有兴趣,可以到它们的网站去下载DEMO版本,以亲身体验一下专业图表控件带来的强大功能。
FRMMAIN.ASPX
<%@ Page language="c#" Codebehind="FrmMain.aspx.cs" AutoEventWireup="false" Inherits="Web_Test.FrmMain" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>FrmMain</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="FrmMain" method="post" runat="server">
<asp:TextBox id="txtServerName" style="Z-INDEX: 101; LEFT: 116px; POSITION: absolute; TOP: 24px; Design_Time_Lock: True" runat="server" Font-Size="10pt" Design_Time_Lock="True">192.168.0.220</asp:TextBox>
<asp:Label id="Label7" style="Z-INDEX: 112; LEFT: 24px; POSITION: absolute; TOP: 98px; Design_Time_Lock: True" runat="server" Width="79px" Height="20px" Font-Size="10pt" Design_Time_Lock="True">数据库列表</asp:Label>
<asp:Label id="Label6" style="Z-INDEX: 111; LEFT: 27px; POSITION: absolute; TOP: 169px; Design_Time_Lock: True" runat="server" Width="53px" Height="20px" Font-Size="10pt" Design_Time_Lock="True" Visible="False">字段名</asp:Label>
<asp:Label id="Label5" style="Z-INDEX: 109; LEFT: 27px; POSITION: absolute; TOP: 135px; Design_Time_Lock: True" runat="server" Width="53px" Height="20px" Font-Size="10pt" Design_Time_Lock="True">表名</asp:Label>
<asp:Button id="Button1" style="Z-INDEX: 107; LEFT: 496px; POSITION: absolute; TOP: 91px; Design_Time_Lock: True" runat="server" Width="102px" Text="GetTable" Font-Size="10pt" Design_Time_Lock="True"></asp:Button>
<asp:Label id="Label4" style="Z-INDEX: 106; LEFT: 288px; POSITION: absolute; TOP: 63px; Design_Time_Lock: True" runat="server" Width="79px" Height="20px" Font-Size="10pt" Design_Time_Lock="True">密码</asp:Label>
<asp:Label id="Label2" style="Z-INDEX: 105; LEFT: 25px; POSITION: absolute; TOP: 61px; Design_Time_Lock: True" runat="server" Width="79px" Height="20px" Font-Size="10pt" Design_Time_Lock="True">用户名</asp:Label>
<asp:Label id="Label1" style="Z-INDEX: 104; LEFT: 25px; POSITION: absolute; TOP: 28px; Design_Time_Lock: True" runat="server" Width="79px" Height="20px" Font-Size="10pt" Design_Time_Lock="True">服务器名</asp:Label>
<asp:TextBox id="txtPassword" style="Z-INDEX: 103; LEFT: 376px; POSITION: absolute; TOP: 60px; Design_Time_Lock: True" runat="server" Font-Size="10pt" BackColor="Transparent" ForeColor="Black" BorderColor="White" Design_Time_Lock="True"></asp:TextBox>
<asp:TextBox id="txtUserName" style="Z-INDEX: 102; LEFT: 116px; POSITION: absolute; TOP: 62px; Design_Time_Lock: True" runat="server" Font-Size="10pt" Design_Time_Lock="True">sa</asp:TextBox>
<asp:DropDownList id="DropDownList1" style="Z-INDEX: 108; LEFT: 115px; POSITION: absolute; TOP: 135px; Design_Time_Lock: True" runat="server" Width="208px" AutoPostBack="True" Font-Size="10pt" Design_Time_Lock="True"></asp:DropDownList>
<asp:DropDownList id="DropDownList2" style="Z-INDEX: 110; LEFT: 115px; POSITION: absolute; TOP: 171px; Design_Time_Lock: True" runat="server" Width="208px" Height="28px" Font-Size="10pt" Design_Time_Lock="True" Visible="False"></asp:DropDownList>
<asp:Button id="Button2" style="Z-INDEX: 113; LEFT: 355px; POSITION: absolute; TOP: 92px; Design_Time_Lock: True" runat="server" Width="107px" Text="GetDataBase" Design_Time_Lock="True"></asp:Button>
<asp:DropDownList id="DropDownList3" style="Z-INDEX: 114; LEFT: 115px; POSITION: absolute; TOP: 98px; Design_Time_Lock: True" runat="server" Width="207px" Height="25px" Design_Time_Lock="True"></asp:DropDownList>
<asp:Button id="Button3" style="Z-INDEX: 115; LEFT: 354px; POSITION: absolute; TOP: 132px; Design_Time_Lock: True" runat="server" Width="110px" Text="生 成" Design_Time_Lock="True" Visible="False"></asp:Button>
<asp:TextBox id="txtLayOut" style="Z-INDEX: 117; LEFT: 26px; POSITION: absolute; TOP: 206px; Design_Time_Lock: True" runat="server" Width="619px" Height="367px" TextMode="MultiLine" BackColor="Ivory" Design_Time_Lock="True"></asp:TextBox>
<asp:Button id="Button4" style="Z-INDEX: 118; LEFT: 497px; POSITION: absolute; TOP: 130px; Design_Time_Lock: True" runat="server" Height="25px" Width="105px" Text="实体类" Design_Time_Lock="True"></asp:Button>
<asp:Button id="Button5" style="Z-INDEX: 119; LEFT: 355px; POSITION: absolute; TOP: 171px; Design_Time_Lock: True" runat="server" Width="107px" Text="Test" Height="25px" Design_Time_Lock="True" Visible="False"></asp:Button>
<asp:Button id="Button6" style="Z-INDEX: 120; LEFT: 499px; POSITION: absolute; TOP: 171px; Design_Time_Lock: True" runat="server" Height="23px" Width="105px" Text="集合类" Design_Time_Lock="True" Visible="False"></asp:Button>
</form>
</body>
</HTML>
FRMMAIN.ASPX.CS
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace Web_Test
{
/// <summary>
/// 作者:davi
/// 日期:3003-03-18
/// </summary>
public class FrmMain : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.WebControls.Label Label2;
protected System.Web.UI.WebControls.Label Label4;
protected System.Web.UI.WebControls.DropDownList DropDownList1;
protected System.Web.UI.WebControls.Label Label5;
protected System.Web.UI.WebControls.TextBox txtServerName;
protected System.Web.UI.WebControls.TextBox txtUserName;
protected System.Web.UI.WebControls.TextBox txtPassword;
protected System.Web.UI.WebControls.Button Button1;
protected System.Web.UI.WebControls.DropDownList DropDownList2;
protected System.Web.UI.WebControls.Label Label6;
protected System.Web.UI.WebControls.Label Label7;
protected System.Web.UI.WebControls.Button Button2;
protected System.Web.UI.WebControls.DropDownList DropDownList3;
protected System.Web.UI.WebControls.Button Button3;
protected System.Web.UI.WebControls.TextBox txtLayOut;
protected System.Web.UI.WebControls.Button Button4;
protected System.Web.UI.WebControls.Button Button5;
protected System.Web.UI.WebControls.Button Button6;
private SqlConnection m_Scon;
private DataSet m_DS;
private void Page_Load(object sender, System.EventArgs e)
{
m_Scon = new SqlConnection();
m_DS = new DataSet();
}
#region Web Form Designer generated code
//[STAThreadAttribute]
override protected void OnInit(EventArgs e)
{
//
// CODEGEN:该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Button1.Click = new System.EventHandler(this.Button1_Click);
this.DropDownList1.SelectedIndexChanged = new System.EventHandler(this.DropDownList1_SelectedIndexChanged);
this.Button2.Click = new System.EventHandler(this.Button2_Click);
this.Button3.Click = new System.EventHandler(this.Button3_Click);
this.Button4.Click = new System.EventHandler(this.Button4_Click);
this.Button5.Click = new System.EventHandler(this.Button5_Click);
this.Button6.Click = new System.EventHandler(this.Button6_Click);
this.Load = new System.EventHandler(this.Page_Load);
}
#endregion
#region 显示数据库的表 Button1_Click
/// <summary>
/// 显示数据库的表
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button1_Click(object sender, System.EventArgs e)
{
try
{
m_Scon.ConnectionString = "user id=" this.txtUserName.Text
";password=" this.txtPassword.Text
";initial catalog=" this.DropDownList3.SelectedItem.Text
";data source=" this.txtServerName.Text;
SqlCommand m_Scmd = new SqlCommand("sp_tables",m_Scon);
m_Scmd.CommandType = CommandType.StoredProcedure;
SqlParameter myParm = m_Scmd.Parameters.Add("@table_type",SqlDbType.VarChar,100);
myParm.Value = "'TABLE'";
m_Scon.Open();
SqlDataReader m_Sdr = m_Scmd.ExecuteReader();
this.DropDownList1.Items.Clear();
while(m_Sdr.Read())
{
if(m_Sdr["TABLE_NAME"].ToString()!="dtproperties")
{
ListItem m_LI = new ListItem();
m_LI.Text = m_Sdr["TABLE_NAME"].ToString();
m_LI.Value = m_Sdr["TABLE_NAME"].ToString();
this.DropDownList1.Items.Add(m_LI);
}
}
m_Sdr.Close();
m_Scon.Close();
}
catch
{
if(m_Scon.State.ToString().ToUpper()=="OPEN")
{
m_Scon.Close();
}
}
}
#endregion
#region Show Columns in a table DropDownList1_SelectedIndexChanged
/// <summary>
/// 显示表的所有列
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DropDownList1_SelectedIndexChanged(object sender, System.EventArgs e)
{
try
{
if(this.DropDownList1.SelectedIndex!=-1)
{
m_Scon.ConnectionString = "user id=" this.txtUserName.Text
";password=" this.txtPassword.Text
";initial catalog=" this.DropDownList3.SelectedItem.Text
";data source=" this.txtServerName.Text;
SqlCommand m_Scmd = new SqlCommand("sp_columns",m_Scon);
m_Scmd.CommandType = CommandType.StoredProcedure;
SqlParameter myParm = m_Scmd.Parameters.Add("@table_name",SqlDbType.VarChar,100);
myParm.Value = this.DropDownList1.SelectedItem.Value;
m_Scon.Open();
SqlDataReader m_Sdr = m_Scmd.ExecuteReader();
this.DropDownList2.Items.Clear();
while(m_Sdr.Read())
{
ListItem m_LI = new ListItem();
m_LI.Text = m_Sdr["COLUMN_NAME"].ToString();
m_LI.Value = m_Sdr["COLUMN_NAME"].ToString();
this.DropDownList2.Items.Add(m_LI);
}
m_Sdr.Close();
m_Scon.Close();
}
}
catch
{
if(m_Scon.State.ToString().ToUpper()=="OPEN")
{
m_Scon.Close();
}
}
}
#endregion
#region Show All DataBase Button2_Click
/// <summary>
/// 显示所有数据库
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button2_Click(object sender, System.EventArgs e)
{
try
{
m_Scon.ConnectionString = "user id=" this.txtUserName.Text
";password=" this.txtPassword.Text
";data source=" this.txtServerName.Text;
SqlCommand m_Scmd = new SqlCommand("sp_databases",m_Scon);
m_Scmd.CommandType = CommandType.StoredProcedure;
m_Scon.Open();
SqlDataReader m_Sdr = m_Scmd.ExecuteReader();
this.DropDownList1.Items.Clear();
while(m_Sdr.Read())
{
ListItem m_LI = new ListItem();
m_LI.Text = m_Sdr["DATABASE_NAME"].ToString();
m_LI.Value = m_Sdr["DATABASE_NAME"].ToString();
this.DropDownList3.Items.Add(m_LI);
}
m_Sdr.Close();
m_Scon.Close();
}
catch
{
if(m_Scon.State.ToString().ToUpper()=="OPEN")
{
m_Scon.Close();
}
}
}
#endregion
#region Make Form
/// <summary>
/// 生成表单项
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button3_Click(object sender, System.EventArgs e)
{
if(this.DropDownList1.SelectedIndex!=-1)
{
m_Scon.ConnectionString = "user id=" this.txtUserName.Text
";password=" this.txtPassword.Text
";initial catalog=" this.DropDownList3.SelectedItem.Text
";data source=" this.txtServerName.Text;
SqlCommand m_Scmd = new SqlCommand("sp_columns",m_Scon);
m_Scmd.CommandType = CommandType.StoredProcedure;
SqlParameter myParm = m_Scmd.Parameters.Add("@table_name",SqlDbType.VarChar,100);
myParm.Value = this.DropDownList1.SelectedItem.Value;
m_Scon.Open();
SqlDataReader m_Sdr = m_Scmd.ExecuteReader();
string ColName = "";
string ColType = "";
while(m_Sdr.Read())
{
ColName = m_Sdr["COLUMN_NAME"].ToString();
ColType = m_Sdr["TYPE_NAME"].ToString();
}
m_Sdr.Close();
m_Scon.Close();
}
}
#endregion
#region Make object
/// <summary>
/// 生成实体
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button4_Click(object sender, System.EventArgs e)
{
if(this.DropDownList1.SelectedIndex!=-1)
{
m_Scon.ConnectionString = "user id=" this.txtUserName.Text
";password=" this.txtPassword.Text
";initial catalog=" this.DropDownList3.SelectedItem.Text
";data source=" this.txtServerName.Text;
SqlCommand m_Scmd = new SqlCommand("sp_columns",m_Scon);
m_Scmd.CommandType = CommandType.StoredProcedure;
SqlParameter myParm = m_Scmd.Parameters.Add("@table_name",SqlDbType.VarChar,100);
myParm.Value = this.DropDownList1.SelectedItem.Value;
m_Scon.Open();
SqlDataReader m_Sdr = m_Scmd.ExecuteReader();
string TableName = this.DropDownList1.SelectedItem.Value;
string m_LayOut = "";
m_LayOut = m_LayOut "using System;\r\n";
m_LayOut = m_LayOut "using System.Data;\r\n" ;
m_LayOut = m_LayOut "using System.Data.SqlClient;\r\n";
m_LayOut = m_LayOut "\r\n";
m_LayOut = m_LayOut "namespace OceanSoft\r\n";
m_LayOut = m_LayOut "{\r\n";
m_LayOut = m_LayOut BL(4) "///<comment>\r\n";
m_LayOut = m_LayOut BL(4) "///\r\n";
m_LayOut = m_LayOut BL(4) "///</comment>\r\n";
string ColName = ""; //列名
string ColType = ""; //列的数据类型
string ColDefine = ""; //列定义
string ColProperty = ""; //列属性
while(m_Sdr.Read())
{
ColName = m_Sdr["COLUMN_NAME"].ToString();
ColType = GT(m_Sdr["TYPE_NAME"].ToString());
ColDefine = ColDefine BL(8) "private " ColType " m_" ColName ";\r\n";
ColProperty = ColProperty BL(8) "\r\n";
ColProperty = ColProperty BL(8) "public " ColType " " ColName "\r\n";
ColProperty = ColProperty BL(8) "{\r\n";
ColProperty = ColProperty BL(12) "get\r\n";
ColProperty = ColProperty BL(12) "{\r\n";
ColProperty = ColProperty BL(16) "return m_" ColName " ;\r\n";
ColProperty = ColProperty BL(12) "}\r\n";
ColProperty = ColProperty BL(12) "set\r\n";
ColProperty = ColProperty BL(12) "{\r\n";
ColProperty = ColProperty BL(16) "m_" ColName " = value ;\r\n";
ColProperty = ColProperty BL(12) "}\r\n";
ColProperty = ColProperty BL(8) "}\r\n";
}
m_Sdr.Close();
m_Scon.Close();
m_LayOut = m_LayOut BL(4) "public class " TableName "\r\n";
m_LayOut = m_LayOut BL(4) "{\r\n";
m_LayOut = m_LayOut BL(4) "\r\n";
m_LayOut = m_LayOut ColDefine; //定义
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "///构造函数\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "public " TableName "()\r\n"; //构造函数
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "///析构函数\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "~" TableName "()\r\n"; //析构函数
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n";
m_LayOut = m_LayOut ColProperty; //实体属性
m_LayOut = m_LayOut BL(4) "}\r\n";
m_LayOut = m_LayOut "}\r\n";
this.txtLayOut.Text = m_LayOut;
}
}
#endregion
#region Test
private void Button5_Click(object sender, System.EventArgs e)
{
//
}
#endregion
#region Functions
private string BL(int values)
{
switch(values)
{
case 4:
return "\t";
case 8:
return "\t\t";
case 12:
return "\t\t\t";
case 16:
return "\t\t\t\t";
case 20:
return "\t\t\t\t\t";
}
return "";
}
private string GT(string Values)
{
switch(Values.ToUpper())
{
case "INT":
return "int";
case "NVARCHAR":
return "string";
case "TINYINT":
return "int";
case "INT IDENTITY":
return "int";
case "BIT":
return "int";
case "UNIQUEIDENTIFIER":
return "string";
case "DATETIME":
return "string";
case "VARCHAR":
return "string";
default:
return "string";
}
}
#endregion
#region Make Object Collection Class
private void Button6_Click(object sender, System.EventArgs e)
{
if(this.DropDownList1.SelectedIndex!=-1)
{
string TableName = this.DropDownList1.SelectedItem.Value;
string m_LayOut = "";
m_LayOut = m_LayOut "using System;\r\n";
m_LayOut = m_LayOut "using System.Data;\r\n" ;
m_LayOut = m_LayOut "using System.Data.SqlClient;\r\n";
m_LayOut = m_LayOut "using System.Collections;\r\n";
m_LayOut = m_LayOut "\r\n";
m_LayOut = m_LayOut "namespace e3.Pantheon.WorkFlow.Structure\r\n";
m_LayOut = m_LayOut "{\r\n";
m_LayOut = m_LayOut BL(4) "///<comment>\r\n";
m_LayOut = m_LayOut BL(4) "///公司名称:苏州中软公司\r\n";
m_LayOut = m_LayOut BL(4) "///作者:\r\n";
m_LayOut = m_LayOut BL(4) "///创建日期:" System.DateTime.Now.ToShortDateString() "\r\n";
m_LayOut = m_LayOut BL(4) "///用途说明:\r\n";
m_LayOut = m_LayOut BL(4) "///修改记录:\r\n";
m_LayOut = m_LayOut BL(4) "///</comment>\r\n";
m_LayOut = m_LayOut BL(4) "public class " TableName "s : System.Collections.CollectionBase\r\n";
m_LayOut = m_LayOut BL(4) "{\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "///构造函数\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "public " TableName "s()\r\n"; //构造函数
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(12) "//TODO:在这里增加构造函数逻辑\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "///析构函数\r\n";
m_LayOut = m_LayOut BL(8) "///<summary>\r\n";
m_LayOut = m_LayOut BL(8) "~" TableName "s()\r\n"; //析构函数
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(12) "//TODO:在这里增加析构函数逻辑\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n\r\n";
m_LayOut = m_LayOut BL(8) "public void Remove(int index)\r\n"; //删除
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(12) "if(index>Counter-1||Counter<0)\r\n";
m_LayOut = m_LayOut BL(12) "{}\r\n";
m_LayOut = m_LayOut BL(12) "else\r\n";
m_LayOut = m_LayOut BL(12) "{\r\n";
m_LayOut = m_LayOut BL(16) "List.RemoveAt(index);\r\n";
m_LayOut = m_LayOut BL(12) "}\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n\r\n";
m_LayOut = m_LayOut BL(8) "public void Add(" TableName " m_" TableName ")\r\n"; //增加
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(12) "List.Add(" " m_" TableName ");\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n\r\n";
m_LayOut = m_LayOut BL(8) "public " TableName " this[int index]\r\n"; //集合的元素
m_LayOut = m_LayOut BL(8) "{\r\n";
m_LayOut = m_LayOut BL(12) "get\r\n";
m_LayOut = m_LayOut BL(12) "{\r\n";
m_LayOut = m_LayOut BL(16) "if(index <List.Count)\r\n";
m_LayOut = m_LayOut BL(16) "{\r\n";
m_LayOut = m_LayOut BL(20) "return (" TableName ")List[Index];\r\n";
m_LayOut = m_LayOut BL(16) "}\r\n";
m_LayOut = m_LayOut BL(16) "else\r\n";
m_LayOut = m_LayOut BL(16) "{\r\n";
m_LayOut = m_LayOut BL(16) "return null;\r\n";
m_LayOut = m_LayOut BL(16) "}\r\n";
m_LayOut = m_LayOut BL(12) "}\r\n";
m_LayOut = m_LayOut BL(12) "set\r\n";
m_LayOut = m_LayOut BL(12) "{\r\n";
m_LayOut = m_LayOut BL(16) "if(iIndex<List.Count)\r\n";
m_LayOut = m_LayOut BL(16) "{\r\n";
m_LayOut = m_LayOut BL(20) "List[index]=value;\r\n";
m_LayOut = m_LayOut BL(16) "}\r\n";
m_LayOut = m_LayOut BL(12) "}\r\n";
m_LayOut = m_LayOut BL(8) "}\r\n";
m_LayOut = m_LayOut BL(4) "}\r\n"; //class
m_LayOut = m_LayOut "}\r\n"; //namespace
this.txtLayOut.Text = m_LayOut;
}
}
#endregion
1:确认在“配置属性”中的“启用ASP.NET调试"为"True"
操作步骤:
VS环境里面,菜单-项目-项目属性(最下得选项)-配置属性(左边第二项)-Debugging-Enable Asp.Net Debugging 设置为True
作用:
确定调试器能过启动IIS来调试asp.net页面!
2:确认你的"web.config"中的"debug=true"
操作步骤
打开web.config文件,设置debug="true";
作用:配置调试器可以调试该应用程序
3:若你安装过wind2000 SP4后,则要在命令行执行"regsvr32 i aspnet_isap.dll"
操作步骤:
开始-运行-cmd-regsvr32 i aspnet_isap.dll
作用:
重新注册aspnet_isap.dll
4:在IIS里查看站点信息,选中"目录安全性",里面有"匿名访问和身份验证控制",再点击"编辑..",确认"集成Windows身份验证"选项被选中
操作步骤:
我的电脑-右击-管理-应用程序管理-IIS-默认网站-你得站点-右击-目录安全性-认证和访问方式-勾选匿名访问和身份验证控制,编辑-勾选确认"集成Windows身份验证“
作用:
匿名访问:此处设置不是为了解决你得调试问题,是为了能够使局域网或者广域网中其他用户通过输入你得Ip和网站名称来访问该网站
集成Windows身份验证:刚建立得网站身份验证方式为Windows要求必须用windows用户身份访问该网站,不更该IIS,将无法正常调试!
5:在IE选项->"安全设置"->"自定义级别"里有"用户验",确认选中"自动使用当前用户名和密码登录"
步骤上述已经详细
6:运行C:\WINNT\Microsoft.NET\Framework\v1.0.3705\aspnet_regiis.exe -i
操作步骤;
cd到C:\WINNT\Microsoft.NET\Framework\v1.0.3705\目录
aspnet_regiis.exe -i
或者start=all progames - visual studio.net 2003-visual studio.net tools - command prompt-aspnet_regiis.exe -i
作用:
重新注册当前得.net framework版本即(v1.0.3705)到iis,为了解决调试得时候出现您所运行得.net版本不是v1.1得问题
7:控制面板--管理工具--计算机管理--本地用户和组--用户,双击ASPNET用户,为其隶属于添加Administrators用户
在以前的ASP程序里我们经常用使用Response.Write动态输出网页Header信息,但在ASP.NET里这个所谓代码与UI分离的指导思想不再希望我们这样做了(当然如果您愿意还可以,这毕竟只是建议而已),以前见过别人用<title ranut="server" id="titleControl">Default Title</title>设置标题的,但本人认为不是很好,因为这会产生多余的id="titleControl" 个人感觉使用Literal控件控制比较好,因为它不会产生一个多余的字符:),也有人使用js的动态设置标题,但这你让搜索引擎怎么办?
动态控制Page页的Head信息其实很简单
先看演示: http://www.lvjiyong.com/demo/aspnet/setheader/
演示做的很简单,大家可以下了源码好好看,注解里面都有了
主要使用了Literal与PlaceHolder
方法放置在BasePage里,下次让WebForm继承BasePage类就可以调用了
使用Literal设置Title信息
使用PlaceHolder载入样式表与脚本
Literal允许我们直接设置文本信息,使用时我们先让程序查找是否有指定的Literal控件,如果有则设置Text
/**//// <summary>
/// 设置Head信息
/// </summary>
/// <param name="_name">控件</param>
/// <param name="_control">文本</param>
private void setHeader(string _control,string _text)
{
Literal obj = this.FindControl(_control) as Literal;
if(obj != null)
{
obj.Text = _text;
}
}
比如我们在Head区设置了<asp:Literal id="PageTitle" runat="server" />,我们可以这样设置标题
这里先准备一个方法
/**//// <summary>
/// 设置网页标题
/// </summary>
/// <param name="_title">网页标题</param>
protected void SetTitle(string _title)
{
setHeader("PageTitle","<title>" _title "</title>");
在WebFrom中我们就可以这样设置标题了
this.SetTitle("吕的部落格");
Description,Keywords等的方法一样,不过要设置Meta,这个就不讲了,可以看源码
下面我再说一下js与css的载入,这次我们用到的是PlaceHolder控件,为什么用这个不沿用Literal,自己想想
PlaceHolder一般只占用位置,方便我们动态加载控件,这样载入js与css就方便多了
首先了也是查找指定的PlaceHolder控件
/**//// <summary>
/// 查找LoadHeader的PlaceHolder容器
/// </summary>
/// <returns></returns>
private Control findHeader()
{
return this.FindControl("LoadHeader");
}再是动态加入控件
/**//// <summary>
/// 装载控件到PlaceHolder控件
/// </summary>
/// <param name="_obj"></param>
protected void LoadPlaceHolder(HtmlGenericControl _obj)
{
objHeader = findHeader() as Control;
//载入脚本文件
if(objHeader != null)
{
objHeader.Controls.Add(_obj);
}
}要载入CSS或JS我们先用HtmlGenericControl创建子控件然后加到PlaceHolder控件中
/**//// <summary>
/// 载入指定的样式表文件
/// </summary>
/// <param name="_cssPath">样式表文件地址</param>
protected void LoadCss(string _cssPath)
{
HtmlGenericControl objCss = new HtmlGenericControl("link");
objCss.Attributes["rel"] = "stylesheet";
objCss.Attributes["type"] = "text/css";
objCss.Attributes["href"] = _cssPath;
objCss.Attributes["media"] = "screen";
this.LoadPlaceHolder(objCss);
}
那我们在WebForm中要载入样式表只要使用
this.LoadCss("样式表地址");载入js一样,就不说了
在源码中我写的功能比这里说的强一点点,大家可以自己下了看看.
很多人会说语言只是语法的差异,事实上,大家忽略了一点选择了一种语言,语言的提供者一定会提供很多的系统库给这个语言.
接下来一个简单的例子来结合Jscript.net 和 C# 来实现对一个表达式的计算.
问题要求: 输入一串简单的表达式,输出值.
比如2 4*7 返回30
注意我们全部用.net 去实现,呵呵.
1.新建一个jscript文件, CustomEval.js
// JScript source code
class CustomEval
{
static function eval(strExp)
{
return eval(strExp);
}
}然后到.net 的command prompt,编译该js为一个.net 程序集
jsc /t:library CustomEval.js
然后就生成了一个CustomEval.dll 标准的.net程序集.
调用也很简单.
新建一个项目,引用该dll, 并且也引用MIcrosoft.Jscript.dll
如下代码:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(CustomEval.eval("2 4*7"));
}
}
呵呵,结果就出来了.
类似你用C# 可以用很多Microsoft.Visualbasic.*.dll 提供的功能. C# 利用VB的特性
1、现象
a.用localhost访问,正常
b.用IP地址访问,则出现403错误
2、分析
a.怀疑是ACL问题,设置Everyone为完全控制,问题仍无法解决
b.无意中访问了"WebForm1.aspx",再访问该主页,可以正常访问
c.原来无法访问的aspx都是从asp转换过来的
3、结论
a.访问任一从asp转换过来,变为aspx的网页,若新的aspx的网页中未包含“Codebehind="index.aspx.cs" AutoEventWireup="false" Inherits="IQTest.WebForm1"”部分,则会出现403错误
b.解决方法:一定要保证访问所有从asp转换过来的aspx的网页之前,访问任一包含“Codebehind”的页面;本质的原因是asp.net应用程序未能启动,造成IIS的拒绝访问
同理,可见当asp.net应用程序超时被回收,之后提交的页面也会出现此403错误!
注:不包含“Codebehind="index.aspx.cs" AutoEventWireup="false" Inherits="IQTest.WebForm1"的aspx页面可以正常访问。
使用.Net和C#开发Web应用程序往往能给我们很大的启示,尤其在开发相对简单的例行任务时就更是如此。例如,在许多时候,我们都需要有条件地显示一个网页的一部分。需要这么做的原因有许多,例如,根据用户的角色,有一部分是它不应当看到的。或者,我们也可以考虑搜索功能,只有点击了一个链接后,搜索选项才是可用的。
我们先来解释一下解决这一问题的方法,然后再详细地解释所使用的代码。在.Net中开发Web应用程序,我们既可以使用服务器端的Web控件(Web表单)也可以使用HTML控件。使用.NET开发Web应用程序的重点是服务器端控件。我们在本文中就使用了Web表单服务器端控件。
Panel是一个服务器端的Web表单控件,一个Panel控件就是HTML网页上的一个矩形区域,它是否可见可以在服务器端进行控制。因此,首先,我们可以从将HTML代码段放在一个Panel控件中,HTML代码段可以由服务器端控件和客户端控件组成。一旦我们将Panel控件的visibility属性设置为“false”,则整个HTML代码段就成为不可见的了。其次,我们可以使用名字为LinkButton的另一个Web表单控件,它本质上是一个超级链接,但通过服务器端的OnClick方法,它可以起到按钮的作用。在这种方法中,我们只要简单地访问Panel对象的C#语言表示,并将其visibility属性设置为true或false,网页就会自动地刷新自己。
在.NET中开发Web应用程序的一个重要差别是,网页上的每个控件都被表示为服务器端的一个.NET对象,而且这些对象(控件)的状态通过与服务器间的多次交互来维护,这就使我们能够对服务器端和客户端的事件作出反应。响应服务器端的事件时,百网页重新刷新时,其内部的所有对象(控件)也都会得到刷新。我们无需再绘制任何控件,这一切都是自动完成的。这种方法最有吸引力的是一个好的面向对象编程人员能够在一种编程语言模式中工作,而且可以方便地使用JavaScript,调试也非常简便。这种方法的一个小问题就是它不能使用FrontPage或Dreamweaver等HTML代码编辑器。一旦这个问题得到了解决,服务器端的编程模式就更完善了。
下面是编写本文中例子代码所需要的步骤:
·为HTML代码段获得Panel控件。
·将HTML代码置入Panel控件中。
·创建一个LinkButton控件。
·提供一个onClick函数。
·在按钮的点击函数中隐藏/显示Panel控件。
1、为HTML代码段获得Panel控件
打开网页(.aspx)的设计视图,并选择“Webforms控件”工具箱,从工具箱中拖出一个Panel控件到HTML网页的设计视图上。这时就会看到一个矩形框,发改变它的大小,直到能够容下你想输入的HTML代码段。
下面是HTML设计视图中Panel控件的定义:
<asp:panel id=TestPanel Width="398px" Height="171px" runat="server">
HTML GOES HERE
</asp:panel>
2、将我们的HTML代码输入到Panel控件中
在Panel控件中编写相关的HTML代码(或将HTML代码拖到Panel控件中),下面是一个例子:
<H2>An example HTML segment that is going to disappear </H2>
An example drop down
<asp:DropDownList id=ADropDownListBox runat="server"></asp:DropDownList>
</asp:panel>
3、创建一个LinkButton控件
我们需要对这一部分作一些解释。我们为什么会用LinkButton控件取代一个超级链接呢?超级链接意味着我们可以随意到包括当前的网页在内的任意网页上,但并不意味着我们要返回正在修改的网页。另外,也没有象OnClick这样能够处理超级链接的服务器端方法。
LinkButton的外观和风格与hyperlink相同,但它还有另外二点好处,即:
·点击时能够返回同一个网页。
·便于使用的OnClick方法。
下面是一个LinkButton控件定义的例子:
Change Appearance
</asp:LinkButton>
4、提供onClick函数
如果双击LinkButton控件,IDE就会自动地将我们引到服务器端该控件的OnClick方法处,在这里我们就可以编写隐藏Panel控件的代码。
5、在按钮的OnClick方法中隐藏/显示Panel控件
下面是OnClick方法的一个例子:
{
this.TestPanel.Visible = this.TestPanel.Visible ? false : true;
}
上面的代码是一个极好的知道如何维护自己状态的用品端编程模式的例子。当用户点击链接时,就会执行上面的代码,但开发人员并没有改变HTML网页的其他部分,控件本身知道如何刷新它们自己。
结论
下面是我从.NET模式中精选出来的非常有趣的特性:
·服务器端编程模式。
·Web表单的状态是自动维护的。
·高度一致的前、后端统一对象编程模式。
·用处很大的IDE能够提示每个方法和可能的参数。
·在网页的HTML视图中编写XML代码也有提示。
·配置所需要的统一的web.config。
尽管本文中的例子相当简单,即使使用传统的方法也能够非常简单地实现,但这种服务器端的编程模式说明了NET的一个有趣的特性,即能够自动维护其状态的一致的统一服务器端编程模式。
随着微软.NET的流行,ASP.NET越来越为广大开发人员所接受。作为ASP.NET的开发人员,我们不仅需要掌握其基本的原理,更要多多实践,从实践中获取真正的开发本领。在我们的实际开发中,往往基本的原理满足不了开发需求,我们更多的要积累一些开发技巧,本文就向大家介绍一些实用技巧,希望对大家的开发有所裨益。
1. ~ 的用法
一般的情况下,我们是使用./../ 这样的相对路径来确定和规划我们的资源(比如图片、资源文件),但这种方式下在我们部署应用的时候,可能会出错,另外对于.ascx的控件中如果包含了一个图片,而这个控件被我们在不同层次的两个目录的aspx文件分别引用时,问题就会出现了。
~/image/about.bmp 是一种非常好的方法,它以Web应用程序的根目录为起始点,这样使得比你使用./image/about.bmp这样的方式要更加灵活和方便。有一点不好,是这种方式是在ASP.NET运行时动态解析的,所以在IDE设计模式中,你可能不能预览它。
2. 在刷新和提交页面后,保存你的页面滚动条的位置
经常有这样的情况,我们需要用户提交一个表单,但是表单中有超过500 个?控件或文本框要填写,也就是说用户需要拉动IE的滚动条才能够填得完,那么假如用户正在可见IE范围的2/3处,选择了一个组合框的值,很不幸组合框是服务器端的,那么也就意味着页面会提交一次,而当用户再看见刷新过的页面时,页面确定在3/1的地方也就是显示在页面最开始的地方,用户只有拖动鼠标,然后接着刚刚的地方再填写剩下的250个控件,很不幸,370个控件又需要他选择一下?
用下面的方法可以很快地确定和记住你提交前的位置。
网上的Old Dog Learns New Tricks也有一个类似的例子Maintain Scroll Position in any Page Element,不过他使用了Web Behavior这意味着你需要使用一个.htc文件
Dim saveScrollPosition As New StringBuilder
Dim setScrollPosition As New StringBuilder
RegisterHiddenField("__SCROLLPOS", "0")
saveScrollPosition.Append("<script language='javascript'>")
saveScrollPosition.Append("function saveScrollPosition() {")
saveScrollPosition.Append(" document.forms[0].__SCROLLPOS.value = thebody.scrollTop;")
saveScrollPosition.Append("}")
saveScrollPosition.Append("thebody.onscroll=saveScrollPosition;")
saveScrollPosition.Append("</script>")
RegisterStartupScript("saveScroll", saveScrollPosition.ToString())
If (Page.IsPostBack = True) Then
setScrollPosition.Append("<script language='javascript'>")
setScrollPosition.Append("function setScrollPosition() {")
setScrollPosition.Append(" thebody.scrollTop = " & Request("__SCROLLPOS") & ";")
setScrollPosition.Append("}")
setScrollPosition.Append("thebody.onload=setScrollPosition;")
setScrollPosition.Append("</script>")
RegisterStartupScript("setScroll", setScrollPosition.ToString())
End If
End Sub
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
RetainScrollPosition()
End Sub
这招也非常实用,你可以制作两个不同的模板或表现形式,分别以.ascx控件的形式保存,运行时根据某个条件动态的选择使用其中的一个模板,另外ScottGu认为ItemDataBound方法也可以定制你显示的表现,比如加亮某个元素或是加一个促销广告图等等。
theme = DropDownList1.SelectedValue
DataList1.ItemTemplate = Page.LoadTemplate(theme & ".ascx") ---Cool
DataList1.DataSource = DS
DataList1.DataBind()
4. 设置服务器端控件的焦点
Dim scriptFunction As New StringBuilder
Dim scriptClientId As String
scriptClientId = controlToFocus.ClientID
scriptFunction.Append("<script language='javascript'>")
scriptFunction.Append("document.getElementById('" & scriptClientId & "').focus();")
scriptFunction.Append("</script>")
RegisterStartupScript("focus", scriptFunction.ToString())
End Sub
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If (Page.IsPostBack = False) Then
SetFocus(TextBox1)
End If
End Sub
5. 滚动DataGrid
这招就更简单了,有时候你的页面只有一个固定的地方,但是需要显示非常多的数据,亦或是也不定,但是只有固定的一个地方给你显示它了。这时你就可以用下面这招,自动出滚动条,而且适用许多控件。很简单将你的控件放在一个DIV中将overflow属性设置成auto
<asp:datagrid id=“MyGrid” runat=“server”/>
</div>
6. 动态创建控件
利用PlaceHolder控件,这东西在ASP.NET 2.0 Mutil-View和Master Page中运用的就更加多了。
Dim i as Integer
For i=0 to 4
Dim myUserControl as Control
myUserControl = Page.LoadControl(“foo.ascx”)
PlaceHolder1.Controls.Add(myUserControl)
PlaceHolder1.Controls.Add(New LiteralControl(“<br>”))
Next i
End Sub
7. 客户端代码的使用
1). 可以使用客户端的事件代码,但两者不能同名,服务器端代码的名是你可以控制的。对于非ASP.NET的标准控件的自定义控件必须实现IAttributeAccessor接口或从WebControl派生并且可用expando属性
ImageUrl=“start.jpg”
onMouseOver=“rollover(this);”
onMouseOut=“rollout(this)”
rolloversrc=“myrollover.jpg”
rolloutsrc=“myrollout.jpg”
runat=“server”/>
<input type=Button onClick=“return clientHandler()”
onServerClick=“Button1_Click” … />
2). 使用可以在Postback之前执行客户端代码,当然也可以取消这次Postback,另外也可以访问客户端该页所有的客户端控件。
RegisterOnSubmitStatement("foo", "return confirm('Are you sure you want to submit the order?');")
End Sub
3). 还有更复杂的我认为不实用,大家可以自己去看,主要是运用RegisterStartupScript和JavaScript的技术
以上文章介绍了一些ASP.NET中常用而且比较实用的技巧,希望能对大家的实际开发有所裨益!
网站的性能对于ASP.NET程序开发人员来说非常重要。一个优秀的网站虽然有美观的页面设计,完善的服务功能,但是打开网页时有长时间的延迟,用户最终将会无法忍受。尤其对于大型的电子商务网站而言,每秒钟有数万用户同时访问,没有良好的网站性能,根本无法满足庞大的需求。
ASP.NET作为全新一代的动态网页生成系统,它在平台性能方面与原有的ASP相比已有了一个本质的提高。但要在此基础上开发出专业水准的、符合生产标准的、受用户欢迎的web应用程序,还需要开发人员从编程的角度在页面、数据访问和字符串处理等各方面进行优化处理,以提高网站的总体性能。
本文将主要探讨在ASP.NET中与此相关的几种进行性能优化的方法及注意问题。
页面性能优化
1、会话状态的恰当选择
HTTP协议是一种无状态的通信协议,无法记录和识别来自不同客户端的请求,但在实际应用中系统却要维护来自客户端的不同请求之间的会话状态信息。ASP.NET通过将会话状态信息存储在进程、状态服务器或SQL Server数据库中来解决这个问题。
将会话状态信息保存在WEB服务器的内存中具有最佳的性能,速度很快,但是却缺乏会话状态信息跨越多个服务器的能力。若要在多个WEB服务器之间维护会话信息,可以使用状态服务器进行存储,这种方式由于可以将应用程序部署到多台服务器上而提高了系统的伸缩性和可靠性,但是以降低性能为代价。对于极其重要的会话信息,需要使用SQL Server存储方式,从而避免丢失重要的会话信息,但由此产生的工作负载比前两者大得多。
若不考虑状态信息的保留和多个服务器共享,应尽量选择保存在服务器的进程中,从而得到最佳的性能。
会话状态信息的存储方式选择通过web.config文件:
<sessionState
mode="InProc/StateServer/SqlServer" //存储方式由此行选择
stateConnectionString="tcpip=127.0.0.1:42424"
……
timeout="20"/>
2、服务器控件的优化选择
2.1 减少不必要的服务器控件
服务器控件带来的方便和功能是html控件所不能比拟的。但是每一个服务器控件都需要在服务器端创建相应的对象,是以牺牲服务器端的资源为代价的,过多的使用服务器控件会极大的影响程序性能。
很多情况下,简单地使用html标记或数据绑定即能够实现所需功能。比如<asp:Label>控件,若使用它来显示静态信息,则完全可用简单的标记来实现。如果html控件达不到所要实现的功能,而且在脚本语言如javascript、vbscript也不能实现的情况下,才考虑选择服务器控件。
2.2 禁用不必要的状态视图
服务器控件的状态视图属性能够自动的在页面往返过程中维护服务器控件的状态,减少开发者的工作量,但是需要占用大量的服务器内存资源。因此,在不需要服务器控件状态视图的情况下,应将其EnableViewState属性设置为false,如常用的<asp:Lable>和<asp:Button>控件。
2.3 Page.IsPostBack的运用
Page.IsPostBack用于记录页面是否从客户端返回,若为false表示初次运行,否则表示从客户端再次返回该页面。Page.IsPostBack的合理应用可以避免页面在往返过程中的一些不必要的操作。在Page_Load函数及一些只需要初始化一次的事件函数中均可以使用该属性来提高应用程序性能。
void Page_Load(Object o, EventArgs e)
{
if(! Page.IsPostBack)
{
conn=new SqlConnection("server=localhost;uid=sa;pwd=;database=data");
String sql="select * from student";
cmd.Fill(ds,"stu");
mydataGrid.DataBind();
}
}
以上代码将保证只有在首次访问该页面时对数据库进行读取并绑定。
2.4 合理使用DataGrid控件
DataGrid控件带有最强大的数据显示功能,还内置了对数据的修改、删除、添加、分页等很多功能。如果只需简单的显示数据, DataGrid并非最佳选择。DataGrid控件的分页功能,数据的存储方式(存储在viewstate中)等,虽然让程序开发者使用方便快捷,但由此产生的性能开销不容小视。
DataList控件比DataGrid功能少了很多。但自定义性强了很多。特有的多行数据显示还是比较方便的。DataGrid能实现的功能,它基本能实现。
Repeater控件功能最少,但自定义性非常强。由于减少了很多功能,对服务器的性能带来消耗最小。
因此,在只需简单显示数据列表时,选择Repeater或DataList控件同样可以达到目的,而且减轻了性能上的开销。
数据库访问性能优化
1、数据库的连接和关闭
访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。
连接池的大小是有限的,如果在连接池达到最大限度后仍要求创建连接,必然大大影响性能。因此,在建立数据库连接后只有在真正需要操作时才打开连接,使用完毕后马上关闭,从而尽量减少数据库连接打开的时间,避免出现超出连接限制的情况。
2、使用存储过程
存储过程是存储在服务器上的一组预编译的SQL语句,类似于DOS系统中的批处理文件。存储过程具有对数据库立即访问的功能,信息处理极为迅速。使用存储过程可以避免对命令的多次编译,在执行一次后其执行规划就驻留在高速缓存中,以后需要时只需直接调用缓存中的二进制代码即可。
另外,存储过程在服务器端运行,独立于ASP.NET程序,便于修改,最重要的是它可以减少数据库操作语句在网络中的传输。
3、优化查询语句
ASP.NET中ADO连接消耗的资源相当大,SQL语句运行的时间越长,占用系统资源的时间也越长。因此,尽量使用优化过的SQL语句以减少执行时间。比如,不在查询语句中包含子查询语句,充分利用索引等。
字符串操作性能优化
1、使用值类型的ToString方法
在连接字符串时,经常使用" "号直接将数字添加到字符串中。这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中。但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中。
使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能。
2、运用StringBuilder类
String类对象是不可改变的,对于String对象的重新赋值在本质上是重新创建了一个String对象并将新值赋予该对象,其方法ToString对性能的提高并非很显著。
在处理字符串时,最好使用StringBuilder类,其.NET 命名空间是System.Text。该类并非创建新的对象,而是通过Append,Remove,Insert等方法直接对字符串进行操作,通过ToString方法返回操作结果。
其定义及操作语句如下所示:
int num;
System.Text.StringBuilder str=new System.Text.StringBuilder(); //创建字符串
str.Append(num.ToString()); //添加数值num
Response.Write(str.ToString); //显示操作结果
ASP.NET应用程序性能测试
在对ASP.NET应用程序进行性能测试之前,应确保应用程序没有错误,而且功能正确。具体的性能测试可以采用以下工具进行:
Web Application Strees Tool (WAS)是Microsoft发布的一个免费测试工具,可以从http://webtool.rte.microsoft.com/上下载。它可以模拟成百上千个用户同时对web应用程序进行访问请求,在服务器上形成流量负载,从而达到测试的目的,可以生成平均TTFB、平均TTLB等性能汇总报告。
Application Center Test (ACT) 是一个测试工具,附带于Visual Studio.NET的企业版中,是Microsoft正式支持的web应用程序测试工具。它能够直观地生成图表结果,功能比WAS多,但不具备多个客户机同时测试的能力。
服务器操作系统"管理工具"中的"性能"计数器,可以对服务器进行监测以了解应用程序性能。
结论
对于网站开发人员来说,在编写ASP.NET应用程序时注意性能问题,养成良好的习惯,提高应用程序性能,至少可以推迟必需的硬件升级,降低网站的成本。


