最近一个小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();
       
    }
存在问题:效率不高,回调到客户端的数据量比较大

posted on 2006-12-07 17:14  优雅小猪  阅读(654)  评论(0编辑  收藏  举报

导航