最近一个小web项目(主站web管理工具)想到的一些东西
这两天赶出了一个主站web的管理工具,其主要功能对已有的主站web进行管理,包括局站管理,通道,用户管理等。功能很简单,没有几张页面。因为是第二次做web项目,做的过程中或有些所得,或有些问题需要进一步研究,总之先记录下来,免得时间久了忘记。
1.使用css控制界面外观
前面的那个web项目,布局主要是靠table实现的,用一个或者多个table,把页面分成多个区域,对每个区域设置不同的样式。这次做之前,网上查了一些资料,发现用css来控制界面的输出更加流行,并且事实上也更加容易控制,因为把界面表现和界面内容分离开了,样式定义放在一个单独的css文件里面,html文件代码看起来也更加清楚。
网上找到一篇入门文章,讲的是用css+div,进行网页布局,看看当作入门也是不错的。我这次很多代码也是参考这篇文章的:
http://www.tblog.com.cn/article.asp?id=283
2.让页面缓存数据
一个页面的全局变量,如果页面postback了,变量数据就会丢失。页面控件上的数据之所以postback后还存在,靠的是viewstate。但自己定义的变量不能通过viewstate记住,所以要通过其他办法来解决了。
以前我的一个办法是使用session。但这个办法没有大规模去验证其可靠性和效率,不知道很多地方去用会不会出问题。(前面是用vb去访问session的,c#中如何做?)
这次我用了一个方法,就是把要记住的全局变量转换为一个字符串来表达(因为这个全局变量的类型比较简单,把各个属性用字符串连接,中间间隔以符号,很容易转换和还原),然后把这个字符串赋值给某个页面控件的某个属性(我的是listbox的每个item的value),这样postback的时候实际上是借了该listbox的viewstate的东风,得以使值不丢失。不知道这样做是不是很不专业,呵呵。
另外要试试是否可以把这个机制封装起来,用其他控件来保存,比如hiddenfield,转化的接口也要更加通用,这样用起来方便一点。
这是用于一个页面存数据的。如果要对于一个连接存,现在只知道用session(profile?可能和session差不多)。Session状态应该存储在两个地方,分别是客户端和服务器端。客户端只负责保存相应网站的SessionID,而其他的Session信息则保存在服务器端。在ASP中,客户端的SessionID实际是以Cookie的形式存储的。如果用户在浏览器的设置中选择了禁用Cookie,那末他也就无法享受Session的便利之处了,甚至造成不能访问某些网站。为了解决以上问题,在ASP.NET中客户端的Session信息存储方式分为:Cookie和Cookieless两种。
3.页面之间数据传递
上面提到了session的应用。突然想到在asp.net各个页面之间传递数据有一个方法,其中之一就是session。
现在知道的方法如下:
a.session
session的访问,在page中可以直接用Session访问,在其他自定义类中,可以通过 HttpContext.Current.Session["CustomerID"]来访问。(两者有何区别?)
如果在项目中各个地方想访问session直接使用session的话,可能会导致失控(如session的名称管理等)。
想了一个办法,建立了一个静态类,专门用来保存整个会话过程中的数据的:
类的定义:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public static class DataCache
{
public static string CustomerID
{
get
{
return (string)HttpContext.Current.Session["CustomerID"];
}
set
{
HttpContext.Current.Session["CustomerID"] = value;
}
}
}
赋值
DataCache.CustomerID = this.TextBox1.Text.Trim();
访问
this.Label1.Text = "Welcome " + DataCache.CustomerID;
这样,就对外面的代码隐藏了DataCache是通过session保存数据这个信息。甚至也可以将DataCache保存信息的机制做成其他的,都不会影响外部的调用(如做成frofile)
由于DataCache是静态类,所有会话都会使用同一个DataCache,会不会有临界区问题?
应该是不会的,虽然DataCache是同一个,但DataCache实际访问的Session却每个都是独立的,故不会有。
b.querystring
c.使用server.transfer
似乎不是很方便
4.GridView的使用
GirdView为aps.net2.0新增,具有强大的功能。
1.dataview绑定到gridview(用dataview比datatable好,因为dataview更加好控制)
首先构建一个datatable,并且添加数据行:
private void MakeTable()
{
// Create a new DataTable.
System.Data.DataTable table = new DataTable("MyTable");
// Declare variables for DataColumn and DataRow objects.
DataColumn column;
DataRow row;
// Create new DataColumn, set DataType,
// ColumnName and add to DataTable.
column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.ColumnName = "Column 1";
column.ReadOnly = true;
column.Unique = true;
// Add the Column to the DataColumnCollection.
table.Columns.Add(column);
// Create second column.
column = new DataColumn();
column.DataType = System.Type.GetType("System.String");
column.ColumnName = "Column 2";
column.AutoIncrement = false;
column.Caption = "Column 2";
column.ReadOnly = false;
column.Unique = false;
// Add the column to the table.
table.Columns.Add(column);
// Make the ID column the primary key column.
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = table.Columns["Column 1"];
table.PrimaryKey = PrimaryKeyColumns;
// Instantiate the DataSet variable.
dataSet = new DataSet();
// Add the new DataTable to the DataSet.
dataSet.Tables.Add(table);
// Create three new DataRow objects and add
// them to the DataTable
for (int i = 0; i <= 2; i++)
{
row = table.NewRow();
row["Column 1"] = i;
row["Column 2"] = "name" + i;
table.Rows.Add(row);
}
}
在pageload中进行绑定:
MakeTable();
view = new DataView(dataSet.Tables["MyTable"]);
GridView1.DataSource = view;
GridView1.DataBind();
其中,dataSet为全局变量
2.加入自己定义的列(TemplateField)
<Columns>
<asp:TemplateField >
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text="Please edit"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
在c#中访问该列:
然后在服务端代码中这样访问该列:
TextBox txt = (TextBox)GridView1.Rows[0].Cells[0].Controls[1];
或者
TextBox txtBOX = (TextBox)GridView1.Rows[0].FindControl("TextBox1");
而访问普通的boundfield只要GridView1.Rows[0].Cells[0].text就可以了。
也可以将templatefield列绑定数据库数据:
<Columns>
<asp:TemplateField >
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Country") %>' ></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
也可以在c#代码中进行数据库绑定(datatable),并且用代码进行templatefield的添加并显示绑定数据:
1。定义一个类,实现ITemplate接口
public class LabelTemplateField : ITemplate
{
//A variable to hold the type of ListItemType.
ListItemType _templateType;
//A variable to hold the column name.
string _columnName;
//Constructor where we define the template type and column name.
public LabelTemplateField(ListItemType type, string colname)
{
//Stores the template type.
_templateType = type;
//Stores the column name.
_columnName = colname;
}
void ITemplate.InstantiateIn(System.Web.UI.Control container)
{
switch (_templateType)
{
case ListItemType.Header:
break;
case ListItemType.Item:
Label lb = new Label();
lb.ID = "Label1";
lb.DataBinding += new EventHandler(lb_DataBinding); //Attaches the data binding event.
container.Controls.Add(lb); //Adds the newly created textbox to the
container.
break;
case ListItemType.EditItem:
break;
case ListItemType.Footer:
break;
}
}
void lb_DataBinding(object sender, EventArgs e)
{
Label txtdata = (Label)sender;
GridViewRow container = (GridViewRow)txtdata.NamingContainer;
object dataValue = DataBinder.Eval(container.DataItem, _columnName);
if (dataValue != DBNull.Value)
{
txtdata.Text = dataValue.ToString();
}
}
}
2。绑定数据,添加templatefield列(在pageload事件中)
GridView1.DataSource = view;
TemplateField tf1 = new TemplateField();
tf1.HeaderText = "Column 1";
tf1.ItemTemplate = new LabelTemplateField(ListItemType.Item, "Column 1");
GridView1.Columns.Add(tf1);
GridView1.DataBind();
3.使用hyperlinkfield
加入hyperlinkfield,并导航:
<asp:hyperlinkfield datatextfield="UnitPrice"
datatextformatstring="{0:c}"
datanavigateurlfields="ProductID"
datanavigateurlformatstring="~\details.aspx?ProductID={0}"
headertext="Price"
target="_blank" />
在c#代码中访问之:
HyperLink href = (HyperLink)row.Cells[0].Controls[0];
string txt = href.Text;
4.刷新绑定的数据
如果只是简单页面回送,并不会在gridview中刷新数据。
需要在服务端调用gridview.databind,数据才能被刷新
5.IIS虚拟网站的建立
由于这个web管理工具具有很高的权限,为了安全性考虑,需要将其部署在内网环境中,外网用户是不能访问的。
所以需要在IIS中新建一个网站(XP自带的IIS不能建立多个网站?)。
首先建立一个本地目录,里面放置页面文件。然后建立一个网站。有几个默认参数需要改变一下,不然是不能进行asp.net访问的。
在网站主目录中,要勾上:读取,目录浏览,记录访问,索引资源
在执行权限中选择:纯教本。
访问地址如下:http://192.168.1.2:5150,后面不需要跟虚拟网站的名称。
6.asp.net脚本回调
asp.net脚本回调提供了一种无页面刷新交换数据的机制。
实现步骤
a.需要脚本回调的页面实现接口:ICallbackEventHandler。
如果实现了该接口,就要实现两个方法:
(1) string ICallbackEventHandler.GetCallbackResult()
(2) void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
b.在页面的源里,用javascript编写本地代码:
<script type="text/javascript">
setTimeout("TimeTick()",1000);
function TimeTick()
{
CallServer("refresh");
setTimeout("TimeTick()",1000);
}
function CallServer(obj)
{
context = gridspan;
arg =obj ;
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;
}
function ReceiveServerData(rValue,context)
{
if (rValue!='')
context.innerHTML = rValue;
}
</script>
以上javascript中,timetick是一个定时器,定时去调用CallServer函数。CallServer调用了
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;
是关键,其输入参数中,arg为传递到服务器端的参数,告诉服务器要做什么事情。
ReceiveServerData是回调函数名,context是传入的一个控件名称,可以在回调函数中访问这个context。一般使用span。
c.执行流程:
首先由客户端的javascript发起请求(b),进入服务端的RaiseCallbackEvent函数,在这里进行一系列的处理。
然后教本回调机制会自动调用GetCallbackResult,该函数返回一个string,可以是一个普通的string,也可以是一段html写
成的代码,用于控制客户端显示界面
d.GetCallbackResult返回html的string,用于控制界面显示:
public string RenderControl(Control control)
{
System.IO.StringWriter writer1=new System.IO.StringWriter
(System.Globalization.CultureInfo.InvariantCulture);
HtmlTextWriter writer2=new HtmlTextWriter(writer1);
control.RenderControl(writer2);
writer2.Flush();
writer2.Close();
return writer1.ToString();
}
存在问题:效率不高,回调到客户端的数据量比较大