PDC Videos

[来源:Robert McLaws] Bill Gates的keynote speech中播放的一个叫《Bill Gates Goes to College》的录像在网上转播时被过滤掉了,但在现场的LonghornBlogs.com的Robert McLaws把它录了下来,现在他的blog上提供了网址供观看

Exclusive: BillG Goes To College

[来源:Karsten Januszewski ] 另一个录像是North Face公司做的演示,在其中展示了在Windows Vista下使用XAML写的程序的惊人的效果,他们声称,之前,他们只是web developer,从没写过Windows Applications和3D应用

LINQ非常酷

读完文档,I am in awe,虽然感觉这玩意带来的编程模型的变化会很大

对DLINQ的基于属性的做法

[Table(Name=”Customers”)]
public class Customer
{
 [Column(Id=true)]
 public string CustomerID;
 [Column]
 public string City;
}

不是很认同,因为这样把relational database schema与对象模型耦合在一起了,这也是我不喜欢Gentle.NET的原因

比较一下C#,VB的Query syntax,(更正,谢谢Ninputer)

IEnumerable<string> expr = from s in names 
                                           where s.Length == 5
                                           orderby s
                                           select s.ToUpper();

Dim expr As IEnumerable(Of String) = Select s.ToUpper() _
                                                            From s in names _
                                                            Where s.Length = 5 _
                                                            Order By s

感觉VB更自然些,也许VB将会成为“programming language of choice”?

New features in C# 3.0

Anders Hejlsberg接受Channel 9的采访,谈到如何把数据编程与对象编程统一起来

也参考

The LINQ Project

上面有 LINQ的技术预览,包括示范程序,白皮书文档,hands-on labs以及为使用LINQ技术编程所需的编译器支持,可以在Visual Studio 2005 下使用

MSDN上的C# 将来版本网站罗列了很多资源,包括,

C# 3.0 Language Specification

这篇blog提到了下面这些new features

http://blogs.sarkhouston.com/jrobertson/archive/2005/07/19/2742.aspx

Extension methods
Lambda expressions
Type inference and implicit types
Anonymous types
Expression Trees
Concurrency
Object Initializers
Dynamic Typing

9月22日MSDN将有个聊天活动,讨论C# 3.0的new features

C# 3.0 Language Enhancements

【小题大做】 Magic Page (2) : Refactoring

下面是对上贴里的编码的初浅的重构,

  1. AuthorList.aspx:

<%@ Page Language=”C#” AutoEventWireup=”false” CodeBehind=”AuthorList.aspx.cs” Inherits=”JoyCode.AuthorListPage” %>
<html>
<head>
</head>
<body style=”font: 10pt verdana”>

  <form id=”Form1″ runat=”server”>

    <h3><font face=”Verdana”>Updating a Row of Data w/ Validation</font></h3>

    <span id=”Message” EnableViewState=”false” style=”font: arial 11pt;” runat=”server”/><p>

    <ASP:DataGrid id=”MyDataGrid” runat=”server”
      Width=”800″
      BackColor=”#ccccff”
      BorderColor=”black”
      ShowFooter=”false”
      CellPadding=3
      CellSpacing=”0″
      Font-Name=”Verdana”
      Font-Size=”8pt”
      HeaderStyle-BackColor=”#aaaadd”
    >

      <Columns>
        <asp:EditCommandColumn EditText=”Edit” CancelText=”Cancel” UpdateText=”Update”  ItemStyle-Wrap=”false”/>
        <asp:BoundColumn HeaderText=”au_id” SortExpression=”au_id” ReadOnly=”True” DataField=”au_id” ItemStyle-Wrap=”false”/>
        <asp:TemplateColumn HeaderText=”au_lname” SortExpression=”au_lname”>
          <ItemTemplate>
            <asp:Label ID=”Label1″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “au_lname”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <nobr>
            <asp:TextBox runat=”server” id=”edit_LName” Text='<%# DataBinder.Eval(Container.DataItem, “au_lname”) %>’/>
            <asp:RequiredFieldValidator id=”au_lnameReqVal”
                ControlToValidate=”edit_LName”
                Display=”Dynamic”
                Font-Name=”Verdana” Font-Size=”12″
                runat=server>
                    &nbsp;
            </asp:RequiredFieldValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”au_fname” SortExpression=”au_fname”>
          <ItemTemplate>
            <asp:Label ID=”Label2″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “au_fname”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <nobr>
            <asp:TextBox runat=”server” id=”edit_FName” Text='<%# DataBinder.Eval(Container.DataItem, “au_fname”) %>’/>
            <asp:RequiredFieldValidator id=”au_fnameReqVal”
                ControlToValidate=”edit_FName”
                Display=”Dynamic”
                Font-Name=”Verdana” Font-Size=”12″
                runat=server>
                    &nbsp;

            </asp:RequiredFieldValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”phone” SortExpression=”phone”>
          <ItemTemplate>
            <asp:Label ID=”Label3″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “phone”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <nobr>
            <asp:TextBox runat=”server” id=”edit_Phone” Text='<%# DataBinder.Eval(Container.DataItem, “phone”) %>’/>
            <asp:RequiredFieldValidator id=”phoneReqVal”
                ControlToValidate=”edit_Phone”
                Display=”Dynamic”
                Font-Name=”Verdana” Font-Size=”12″
                runat=server>
                    &nbsp;*
            </asp:RequiredFieldValidator>
            <asp:RegularExpressionValidator id=”phoneRegexVal”
                ControlToValidate=”edit_Phone”
                ValidationExpression=”[0-9]{3} [0-9]{3}-[0-9]{4}”
                Display=”Dynamic”
                Font-Name=”Arial” Font-Size=”11″
                runat=server>
                    * Phone must be in form: XXX XXX-XXXX <br>
            </asp:RegularExpressionValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”address” SortExpression=”address”>
          <ItemTemplate>
            <asp:Label ID=”Label4″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “address”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:TextBox runat=”server” id=”edit_Address” Text='<%# DataBinder.Eval(Container.DataItem, “address”) %>’/>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”city” SortExpression=”city”>
          <ItemTemplate>
            <asp:Label ID=”Label5″ runat=”server” Text='<%# DataBinder.Eval(Conta
iner.DataItem, “city”) %>’/>
          </ItemTemplate>
   &n
bsp;      <EditItemTemplate>
            <asp:TextBox runat=”server” id=”edit_City” Text='<%# DataBinder.Eval(Container.DataItem, “city”) %>’/>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”state” SortExpression=”state”>
          <ItemTemplate>
            <asp:Label ID=”Label6″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “state”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:DropDownList runat=”server” id=”edit_State”>
                  <asp:ListItem>CA</asp:ListItem>
                  <asp:ListItem>IN</asp:ListItem>
                  <asp:ListItem>KS</asp:ListItem>
                  <asp:ListItem>MD</asp:ListItem>
                  <asp:ListItem>MI</asp:ListItem>
                  <asp:ListItem>OR</asp:ListItem>
                  <asp:ListItem>TN</asp:ListItem>
                  <asp:ListItem>UT</asp:ListItem>
            </asp:DropDownList>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”zip” SortExpression=”zip”>
          <ItemTemplate>
            <asp:Label ID=”Label7″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “zip”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:TextBox runat=”server” id=”edit_Zip” Text='<%# DataBinder.Eval(Container.DataItem, “zip”) %>’/>
            <asp:RegularExpressionValidator id=”RegularExpressionValidator1″
                ASPClass=”RegularExpressionValidator” ControlToValidate=”edit_Zip”
                ValidationExpression=”[0-9]{5}”
                Display=”Dynamic”
                Font-Name=”Arial” Font-Size=”11″
                runat=server>
                    * Zip Code must be 5 numeric digits <br>
            </asp:RegularExpressionValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”contract” SortExpression=”contract”>
          <ItemTemplate>
            <asp:Label ID=”Label8″ runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “contract”, “{0}”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:CheckBox runat=”server” id=”edit_Contract” Checked='<%# DataBinder.Eval(Container.DataItem, “contract”)

%>’/>
          </EditItemTemplate>
        </asp:TemplateColumn>
      </Columns>

    </ASP:DataGrid>

  </form>

</body>
</html>

  1. AuthorList.aspx.cs:

using System;
using System.Data;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using JoyCode;

namespace JoyCode
{

    public class AuthorListPage : System.Web.UI.Page
    {
        AuthorManager am;

 protected HtmlGenericControl Message;
      protected DataGrid MyDataGrid;

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            this.Load += new EventHandler(Page_Load);
            this.MyDataGrid.EditCommand += new DataGridCommandEventHandler(MyDataGrid_Edit);
            this.MyDataGrid.UpdateCommand += new DataGridCommandEventHandler(MyDataGrid_Update);
            this.MyDataGrid.CancelCommand += new DataGridCommandEventHandler(MyDataGrid_Cancel);
            this.MyDataGrid.ItemDataBound += new DataGridItemEventHandler(MyDataGrid_ItemDataBound);

            this.MyDataGrid.AutoGenerateColumns = false;
            this.MyDataGrid.DataKeyField = “au_id”;

            am = new AuthorManager();

        }
        protected void Page_Load(Object Src, EventArgs E)
        {
         
            if (!IsPostBack)
                BindGrid();

        }

        public void MyDataGrid_Edit(Object sender, DataGridCommandEventArgs E)
        {
            MyDataGrid.EditItemIndex = (int)E.Item.ItemIndex;
            BindGrid();
        }

        public void MyDataGrid_Cancel(Object sender, DataGridCommandEventArgs E)
        {
            MyDataGrid.EditItemIndex = -1;
            BindGrid();
        }

        public void MyDataGrid_Update(Object sender, DataGridCommandEventArgs E)
        {
            if (Page.IsValid)
            {
                string id = MyDataGrid.DataKeys[(int)E.Item.ItemIndex].ToString();

                String[] cols = { “LName”, “FName”, “Phone”, “Address”, “City”, “Zip” };
                String[] vals = new String[cols.Length];

                for (int i = 0; i < cols.Length; i++)
                {
                    String colvalue = ((TextBox)E.Item.FindControl(“edit_” + cols[i])).Text;
                    vals[i] = colvalue;
                }

                string lname = vals[0];
                string fname = vals[1];
                string phone = vals[2];
                string address = vals[3];
                string city = vals[4];
                string zip = vals[5];

                string state = ((DropDownList)E.Item.FindControl(“edit_State”)).SelectedItem.ToString();

                bool contract = ((CheckBox)E.Item.FindControl(“edit_Contract”)).Checked;

                try
                {
                    am.UpdateAuthor(id, lname, fname, phone, address, city, state, zip, contract);
                    Message.InnerHtml = “<b>Record Updated</b><br>”;
                    MyDataGrid.EditItemIndex = -1;
                }
                catch (RecordExistException ex)
                {
                   
                   Message.InnerHtml = “ERROR: ” + ex.Message;
                    Message.Style[“color”] = “red”;
                }
                catch(UnknownException ex)
                {
                    Message.InnerHtml = “ERROR: Could not update record, please ensure the fields are correctly filled out”;
                    Message.Style[“color”] = “red”;
                }

                BindGrid();
            }
            else
            {
                Message.InnerHtml = “ERROR: Please check each field for error conditions.”;
                Message.Style[“color”] = “red”;
            }
        }

        private void MyDataGrid_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.EditItem)
            {
                for (int i = 0; i < e.Item.Controls.Count; i++)
                {
                    try
                    {
                        if (e.Item.Controls[i].Controls[1]  is TextBox)
                        {
                            TextBox tb = (TextBox)e.Item.Controls[i].Controls[1];
                            tb.Text = Server.HtmlDecode(tb.Text);//这里是否算?
                        }
                        else if (e.Item.Controls[i].Controls[1]  is DropDownList)
                        {
                            DropDownList ddl = e.Item.Controls[i].Controls[1] as DropDownList;
                            string state = (String)((DataRowView)e.Item.DataItem)[“state”];
                            ListItem li = ddl.Items.FindByText(state);
                            if (li != null)
                            {
                                   ddl.SelectedIndex = ddl.Items.IndexOf(li);
                            }

                        }

                    }
                    catch
                    {

                    }
                }
            }
        }

        public void BindGrid()
        {
           
            MyDataGrid.DataSource = am.GetAuthors();
            MyDataGrid.DataBind();
        }

    }
}

  1. Author.cs:

using System;
using System.Data;
using System.Web;
using System.Runtime.Serialization;
using System.Data.SqlClient;

namespace JoyCode
{

    public class UnknownException : ApplicationException
    {
        public UnknownException() {}
        public UnknownException(string message) : base(message) {}
        protected UnknownException(SerializationInfo info, StreamingContext context) : base(info,context) {}
        public UnknownException(string message, Exception innerException) : base(message, innerException) {}

    }

    public class RecordExistException : ApplicationException
    {
        public RecordExistException() { }
        public RecordExistException(string message) : base(message) { }
        protected RecordExistException(SerializationInfo info, StreamingContext context) : base(info, context) { }
        public RecordExistException(string message, Exception innerException) : base(message, innerException) { }

    }

    public class AuthorManager
    {
        SqlConnection myConnection;
        public AuthorManager()
        {
            myConnection = new SqlConnection(System.Configuration.ConfigurationSettings.AppSettings[“ConnectionString”]);
        }

        public DataView GetAuthors()
        {
            SqlDataAdapter myCommand = new SqlDataAdapter(“select * from Authors”, myConnection);

            DataSet ds = new DataSet();
            myCommand.Fill(ds, “Authors”);
            return ds.Tables[“Authors”].DefaultView;

        }

        public void UpdateAuthor(string id, string lname, string fname, string phone, string address, string city, string

state, string zip, bool contract)
        {
            String updateCmd = “UPDATE Authors SET au_id = @Id, au_lname = @LName, au_fname = @FName, phone = @Phone, “
        + “address = @Address, city = @City, state = @State, zip = @Zip, contract = @Contract where au_id = @Id”;

            SqlCommand myCommand = new SqlCommand(updateCmd, myConnection);

            myCommand.Parameters.Add(new SqlParameter(“@Id”, SqlDbType.NVarChar, 11)).Value = id;
            myCommand.Parameters.Add(new SqlParameter(“@LName”, SqlDbType.NVarChar, 40)).Value =

HttpUtility.HtmlEncode(lname);
            myCommand.Parameters.Add(new SqlParameter(“@FName”, SqlDbType.NVarChar, 20)).Value =

HttpUtility.HtmlEncode(fname);
            myCommand.Parameters.Add(new SqlParameter(“@Phone”, SqlDbType.NChar, 12)).Value = HttpUtility.HtmlEncode(phone);
            myCommand.Parameters.Add(new SqlParameter(“@Address”, SqlDbType.NVarChar, 40)).Value =

HttpUtility.HtmlEncode(address);
            myCommand.Parameters.Add(new SqlParameter(“@City”, SqlDbType.NVarChar, 20)).Value = HttpUtility.HtmlEncode(city);
            myCommand.Parameters.Add(new SqlParameter(“@State”, SqlDbType.NChar, 2)).Value = HttpUtility.HtmlEncode(state);
            myCommand.Parameters.Add(new SqlParameter(“@Zip”, SqlDbType.NChar, 5)).Value = HttpUtility.HtmlEncode(zip);
            myCommand.Parameters.Add(new SqlParameter(“@Contract”, SqlDbType.Int)).Value = contract;

            try
            {
                myCommand.Connection.Open();
                myCommand.ExecuteNonQuery();
           
            }
            catch (SqlException e)
            {
                if (e.Number == 2627)
                    throw new RecordExistException(“A record already exists with the same primary key”);
                else
                    throw new UnknownException();
            }
            finally
            {
                if (myCommand.Connection != null && myCommand.Connection.State == ConnectionState.Open)
                    myCommand.Connection.Close();
            }
           
        }
    }
}

 

  1. web.config:
    <configuration>
       <appSettings>
      <add key=”ConnectionString” value=”server=(local)\NetSDK;database=pubs;Trusted_Connection=yes”/>
      </appSettings>
    </configuration>

可以看出AuthorList.aspx.cs里纯粹是操作View里的对象以及Controller的编码,不再包含Model的编码。这些编码已经被移到另一个类,这个类完全可以属于一个新的类库项目。原先对SQL异常的处理,也改成了Model类抛出跟应用有关的异常。

当然,还有很多不满意之处,譬如AuthorList.aspx里的DataBinder.Eval里,还包含着数据库表的字段名(!),AuthorList.aspx.cs里对MyDataGrid里模板里的控件的处理也显得有些不干净。Author.cs类居然依赖System.Web (因为用了System.Web.HttpUtility类),SQL语句的处理也不满意,想象一下假如有很多这样的类的话,编码会有很多重复。依赖于web.config里的设置也不好,因为这样或多或少意味着这个类跟当前的aspx页的部署关系

【小题大做】 Antipattern: Magic Page

Bruce Tate 在他的书《Bitter Java》里谈到了Server-side Java 中的 antipatterns ,其中一个叫做“Magic Servlet” 。在这个Servlet 里,混杂了model,view和controller的编码,搞得责任不清,维护或扩展起来很麻烦。

其实在ASP.NET世界里也一样,如果你在论坛上混长了,类似下面的编码随处可见,我们不妨叫它为 “ Magic Page”, 。问题是,这些红字的语句是否应该出现在这里?

(:我知道这是个样品程序而已,求全责备恐怕是有点荒唐,但类似的编码在论坛上的帖子里经常出现,到底是什么原因呢?是程序员技术不精还是模仿造成的?)

<%@ Import Namespace=”System.Data” %>
<%@ Import Namespace=”System.Data.SqlClient” %>

<html>

<head>

    SqlConnection myConnection;
    public Hashtable StateIndex;

    protected void Page_Load(Object Src, EventArgs E)
    {
        myConnection = new SqlConnection(“server=(local)\NetSDK;database=pubs;Trusted_Connection=yes”);

        if (!IsPostBack)
            BindGrid();

        StateIndex = new Hashtable();
        StateIndex[“CA”] = 0;
        StateIndex[“IN”] = 1;
        StateIndex[“KS”] = 2;
        StateIndex[“MD”] = 3;
        StateIndex[“MI”] = 4;
        StateIndex[“OR”] = 5;
        StateIndex[“TN”] = 6;
        StateIndex[“UT”] = 7;
    }

    public void MyDataGrid_Edit(Object sender, DataGridCommandEventArgs E)
    {
        MyDataGrid.EditItemIndex = (int)E.Item.ItemIndex;
        BindGrid();
    }

    public void MyDataGrid_Cancel(Object sender, DataGridCommandEventArgs E)
    {
        MyDataGrid.EditItemIndex = -1;
        BindGrid();
    }

    public void MyDataGrid_Update(Object sender, DataGridCommandEventArgs E)
    {
        if (Page.IsValid)
        {
            String updateCmd = “UPDATE Authors SET au_id = @Id, au_lname = @LName, au_fname = @FName, phone = @Phone, “
                + “address = @Address, city = @City, state = @State, zip = @Zip, contract = @Contract where au_id = @Id”;

            SqlCommand myCommand = new SqlCommand(updateCmd, myConnection);

            myCommand.Parameters.Add(new SqlParameter(“@Id”, SqlDbType.NVarChar, 11));
            myCommand.Parameters.Add(new SqlParameter(“@LName”, SqlDbType.NVarChar, 40));
            myCommand.Parameters.Add(new SqlParameter(“@FName”, SqlDbType.NVarChar, 20));
            myCommand.Parameters.Add(new SqlParameter(“@Phone”, SqlDbType.NChar, 12));
            myCommand.Parameters.Add(new SqlParameter(“@Address”, SqlDbType.NVarChar, 40));
            myCommand.Parameters.Add(new SqlParameter(“@City”, SqlDbType.NVarChar, 20));
            myCommand.Parameters.Add(new SqlParameter(“@State”, SqlDbType.NChar, 2));
            myCommand.Parameters.Add(new SqlParameter(“@Zip”, SqlDbType.NChar, 5));
            myCommand.Parameters.Add(new SqlParameter(“@Contract”, SqlDbType.NVarChar,1));

            myCommand.Parameters[“@Id”].Value = MyDataGrid.DataKeys[(int)E.Item.ItemIndex];

            String[] cols = {“LName”,”FName”,”Phone”,”Address”,”City”,”Zip”};

            for (int i=0; i            {
                String colvalue = ((TextBox)E.Item.FindControl(“edit_” + cols[i])).Text;
                myCommand.Parameters[“@” + cols[i]].Value = Server.HtmlEncode(colvalue);
            }

            myCommand.Parameters[“@State”].Value = ((DropDownList)E.Item.FindControl(“edit_State”)).SelectedItem.ToString();

            if (((CheckBox)E.Item.FindControl(“edit_Contract”)).Checked = true)
                myCommand.Parameters[“@Contract”].Value = “1”;
            else
                myCommand.Parameters[“@Contract”].Value = “0”;

            myCommand.Connection.Open();

            try
            {
                myCommand.ExecuteNonQuery();
                Message.InnerHtml = “Record Updated
” + updateCmd;
                MyDataGrid.EditItemIndex = -1;
            }
            catch (SqlException e)
            {
                if (e.Number == 2627)
                    Message.InnerHtml = “ERROR: A record already exists with the same primary key”;
                else
                    Message.InnerHtml = “ERROR: Could not update record, please ensure the fields are correctly filled out”;
                Message.Style[“color”] = “red”;
            }

            myCommand.Connection.Close();

            BindGrid();
        }
        else
        {
            Message.InnerHtml = “ERROR: Please check each field for error conditions.”;
            Message.Style[“color”] = “red”;
        }
    }

    private void MyDataGrid_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.EditItem)
        {
            for (int i = 0; i             {
                try
                {
                    if (e.Item.Controls[i].Controls[1].GetType().ToString() == “System.Web.UI.WebControls.TextBox”)
                    {
                        TextBox tb = (TextBox)e.Item.Controls[i].Controls[1];
                        tb.Text = Server.HtmlDecode(tb.Text);
                    }
                }
                catch
                {
                   
                }
            }
        }
    }

    public void BindGrid()
    {
        SqlDataAdapter myCommand = new SqlDataAdapter(“select * from Authors”, myConnection);

        DataSet ds = new DataSet();
        myCommand.Fill(ds, “Authors”);

        MyDataGrid.DataSource=ds.Tables[“Authors”].DefaultView;
        MyDataGrid.DataBind();
    }

</head>

<body style=”font: 10pt verdana”>

  <form runat=”server”>

    <h3><font face=”Verdana”>Updating a Row of Data w/ Validation</font></h3>

    <span id=”Message” EnableViewState=”false” style=”font: arial 11pt;” runat=”server”/><p>

    <ASP:DataGrid id=”MyDataGrid” runat=”server”
      Width=”800″
      BackColor=”#ccccff”
      BorderColor=”black”
      ShowFooter=”false”
      CellPadding=3
      CellSpacing=”0″
      Font-Name=”Verdana”
      Font-Size=”8pt”
      HeaderStyle-BackColor=”#aaaadd”
      OnEditCommand=”MyDataGrid_Edit”
      OnCancelCommand=”MyDataGrid_Cancel”
      OnUpdateCommand=”MyDataGrid_Update”
      DataKeyField=”au_id”
      AutoGenerateColumns=”false”
      OnItemDataBound=”MyDataGrid_ItemDataBound”
    >

      <Columns>
        <asp:EditCommandColumn EditText=”Edit” CancelText=”Cancel” UpdateText=”Update”  ItemStyle-Wrap=”false”/>
        <asp:BoundColumn HeaderText=”au_id” SortExpression=”au_id” ReadOnly=”True” DataField=”au_id” ItemStyle-Wrap=”false”/>
        <asp:TemplateColumn HeaderText=”au_lname” SortExpression=”au_lname”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “au_lname”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <nobr>
            <asp:TextBox runat=”server” id=”edit_LName” Text='<%# DataBinder.Eval(Container.DataItem, “au_lname”) %>’/>
            <asp:RequiredFieldValidator id=”au_lnameReqVal”
                ControlToValidate=”edit_LName”
                Display=”Dynamic”
                Font-Name=”Verdana” Font-Size=”12″
                runat=server>
                    &nbsp;
            </asp:RequiredFieldValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”au_fname” SortExpression=”au_fname”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “au_fname”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <nobr>
            <asp:TextBox runat=”server” id=”edit_FName” Text='<%# DataBinder.Eval(Container.DataItem, “au_fname”) %>’/>
            <asp:RequiredFieldValidator id=”au_fnameReqVal”
                ControlToValidate=”edit_FName”
                Display=”Dynamic”
                Font-Name=”Verdana” Font-Size=”12″
                runat=server>
                    &nbsp;

            </asp:RequiredFieldValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”phone” SortExpression=”phone”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “phone”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <nobr>
            <asp:TextBox runat=”server” id=”edit_Phone” Text='<%# DataBinder.Eval(Container.DataItem, “phone”) %>’/>
            <asp:RequiredFieldValidator id=”phoneReqVal”
                ControlToValidate=”edit_Phone”
                Display=”Dynamic”
                Font-Name=”Verdana” Font-Size=”12″
                runat=server>
                    &nbsp;*
            </asp:RequiredFieldValidator>
            <asp:RegularExpressionValidator id=”phoneRegexVal”
                ControlToValidate=”edit_Phone”
                ValidationExpression=”[0-9]{3} [0-9]{3}-[0-9]{4}”
                Display=”Dynamic”
                Font-Name=”Arial” Font-Size=”11″
                runat=server>
                    * Phone must be in form: XXX XXX-XXXX <br>
            </asp:RegularExpressionValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”address” SortExpression=”address”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “address”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:TextBox runat=”server” id=”edit_Address” Text='<%# DataBinder.Eval(Container.DataItem, “address”) %>’/>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”city” SortExpression=”city”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “city”) %>’/>
   &n
bsp;      </ItemTemplate>
          <EditItemTemplate>
            <asp:TextBox runat=”server” id=”edit_City” Text='<%# DataBinder.Eval(Container.DataItem, “city”) %>’/>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”state” SortExpression=”state”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “state”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:DropDownList runat=”server” SelectedIndex=’<%# StateIndex[(String)((DataRowView)Container.DataItem)[“state”]] %>‘ id=”edit_State”>
                  <asp:ListItem>CA</asp:ListItem>
                  <asp:ListItem>IN</asp:ListItem>
                  <asp:ListItem>KS</asp:ListItem>
                  <asp:ListItem>MD</asp:ListItem>
                  <asp:ListItem>MI</asp:ListItem>
                  <asp:ListItem>OR</asp:ListItem>
                  <asp:ListItem>TN</asp:ListItem>
                  <asp:ListItem>UT</asp:ListItem>
            </asp:DropDownList>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”zip” SortExpression=”zip”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “zip”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:TextBox runat=”server” id=”edit_Zip” Text='<%# DataBinder.Eval(Container.DataItem, “zip”) %>’/>
            <asp:RegularExpressionValidator id=”RegularExpressionValidator1″
                ASPClass=”RegularExpressionValidator” ControlToValidate=”edit_Zip”
                ValidationExpression=”[0-9]{5}”
                Display=”Dynamic”
                Font-Name=”Arial” Font-Size=”11″
                runat=server>
                    * Zip Code must be 5 numeric digits <br>
            </asp:RegularExpressionValidator>
          </EditItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn HeaderText=”contract” SortExpression=”contract”>
          <ItemTemplate>
            <asp:Label runat=”server” Text='<%# DataBinder.Eval(Container.DataItem, “contract”, “{0}”) %>’/>
          </ItemTemplate>
          <EditItemTemplate>
            <asp:CheckBox runat=”server” id=”edit_Contract” Checked='<%# DataBinder.Eval(Container.DataItem, “contract”) %>’/>
          </EditItemTemplate>
        </asp:TemplateColumn>
      </Columns>

    </ASP:DataGrid>

  </form>

</body>
</html>

跟本帖子的主题不相关,在上面的例程中,还有一个不懂的地方是,每次更新一条数据,为什么需要对整个DataGrid做DataBind()?为什么不能对当前这个DataGridItem做重新DataBind()?(DataGridItem是支持DataBind()的,但无法改变当前这个DataGridItem的ItemType)。。。。。。我的看法是,选择是否对整个DataGrid重新做DataBind()应该是高层次的policy,应该由应用的需求或程序员来决定,而不应该通过控件来强制执行

【ASP.NET 2.0 Trivia】MaintainScrollPositionOnPostBack

页面很长的话,要在PostBack后保持PostBack前的页面位置,在ASP.NET 1.*里可以使用SmartNavigation。但SmartNavigation有不少问题,包括在IE外的浏览器里不工作等。对此,解决方案是,在页面PostBack前,通过客户端脚本和隐藏控件记住当前页面位置,在PostBack后,把页面位置赋值给隐藏控件,然后在页面装载后用客户端脚本来设置页面位置,譬如可以参考CodeProejct上的这篇文章

Crossbrowser SmartNavigation Alternative

ASP.NET 2.0里提供了这样的一个方案,可以通过设置

<%@ Page MaintainScrollPositionOnPostBack=”true”  %>

或在编码里设置

Page.MaintainScrollPositionOnPostBack = true;

或在web.config里设置

<pages maintainScrollPositionOnPostBack=”true” />

来达成。

Reflector查看,在Page类的ProcessRequestMain里有这样的一句

if (this.MaintainScrollPositionOnPostBack)
{
 this.LoadScrollPosition();
}

在LoadScrollPosition()里,

internal void LoadScrollPosition()
{
 if ((this._previousPagePath == null) && (this._requestValueCollection != null))
 {
 string text1 = this._requestValueCollection[“__SCROLLPOSITIONX”];
 if ((text1 != null) && !int.TryParse(text1, out this._scrollPositionX))
 {
  this._scrollPositionX = 0;
 }
 string text2 = this._requestValueCollection[“__SCROLLPOSITIONY”];
 if ((text2 != null) && !int.TryParse(text2, out this._scrollPositionY))
 {
  this._scrollPositionY = 0;
 }
 }
}
 

从提交值里的__SCROLLPOSITIONX和__SCROLLPOSITIONY获取值并且存到成员变量里,然后在BeginFormRender(由HtmlForm的RenderChildren调用)里输出到页面

if (this.MaintainScrollPositionOnPostBack && !this._requireScrollScript)
{
 this.ClientScript.RegisterHiddenField(“__SCROLLPOSITIONX”, this._scrollPositionX.ToString(CultureInfo.InvariantCulture));
 this.ClientScript.RegisterHiddenField(“__SCROLLPOSITIONY”, this._scrollPositionY.ToString(CultureInfo.InvariantCulture));
 this.ClientScript.RegisterStartupScript(typeof(Page), “PageScrollPositionScript”, “\r\ntheForm.oldSubmit = theForm.submit;\r\ntheForm.submit = WebForm_SaveScrollPositionSubmit;\r\n\r\ntheForm.oldOnSubmit = theForm.onsubmit;\r\ntheForm.onsubmit = WebForm_SaveScrollPositionOnSubmit;\r\n” + (this.IsPostBack ? “\r\ntheForm.oldOnLoad = window.onload;\r\nwindow.onload = WebForm_RestoreScrollPosition;\r\n” : string.Empty), true);
 this.RegisterWebFormsScript();
 this._requireScrollScript = true;
}

看一下页面输出,有下面这样的语句

/WebSite5/WebResource.axd?d=oNWBOJESyPoXDbbBArijOg2&t=632619935818125000
……

 
 
……

<!–

–>

theForm.oldSubmit = theForm.submit;
theForm.submit = WebForm_SaveScrollPositionSubmit; //

theForm.oldOnSubmit = theForm.onsubmit;
theForm.onsubmit = WebForm_SaveScrollPositionOnSubmit; //

theForm.oldOnLoad = window.onload;
window.onload = WebForm_RestoreScrollPosition; //// –>

WebResource.axd提供了对应的脚本

function WebForm_GetScrollX() {
    if (__nonMSDOMBrowser) {
        return window.pageXOffset;
    }
    else {
        if (document.documentElement && document.documentElement.scrollLeft) {
            return document.documentElement.scrollLeft;
        }
        else if (document.body) {
            return document.body.scrollLeft;
        }
    }
    return 0;
}

function WebForm_GetScrollY() {
    if (__nonMSDOMBrowser) {
        return window.pageYOffset;
    }
    else {
        if (document.documentElement && document.documentElement.scrollTop) {
            return document.documentElement.scrollTop;
        }
        else if (document.body) {
            return document.body.scrollTop;
        }
    }
    return 0;
}

function WebForm_SaveScrollPositionSubmit() {
    if (__nonMSDOMBrowser) {
        theForm.elements[‘__SCROLLPOSITIONY’].value = window.pageYOffset;
        theForm.elements[‘__SCROLLPOSITIONX’].value = window.pageXOffset;

    }
    else {
        theForm.__SCROLLPOSITIONX.value = WebForm_GetScrollX();
        theForm.__SCROLLPOSITIONY.value = WebForm_GetScrollY();
    }
    if ((typeof(this.oldSubmit) != “undefined”) && (this.oldSubmit != null)) {
        return this.oldSubmit();
    }
    return true;
}

function WebForm_SaveScrollPositionOnSubmit() {
    theForm.__SCROLLPOSITIONX.value = WebForm_GetScrollX();
    theForm.__SCROLLPOSITIONY.value = WebForm_GetScrollY();
    if ((typeof(this.oldOnSubmit) != “undefined”) && (this.oldOnSubmit != null)) {
        return this.oldOnSubmit();
    }
    return true;
}

function WebForm_RestoreScrollPosition() {
    if (__nonMSDOMBrowser) {
        window.scrollTo(theForm.elements[‘__SCROLLPOSITIONX’].value, theForm.elements[‘__SCROLLPOSITIONY’].value);
    }
    else {
        window.scrollTo(theForm.__SCROLLPOSITIONX.value, theForm.__SCROLLPOSITIONY.value);
    }
    if ((typeof(theForm.oldOnLoad) != “undefined”) && (theForm.oldOnLoad != null)) {
        return theForm.oldOnLoad();
    }
    return true;
}

这个方案应该对常用的浏览器都有效

ASP.NET 2.0 里的VirtualPathProvider

ASP.NET 2.0  快速入门教程里很简要地提到了VirtualPathProvider,听上去很powerful,查看了一下文档,大概是说,

“。。。。
The VirtualPathProvider类提供了一套方法以在一个Web 应用里实现虚拟文件系统。在虚拟文件系统里,文件和文件夹是由一个 data store 来管理的,而不是由通常的服务器操作系统的文件系统所管理。譬如,你可以使用虚拟文件系统来在 SQL Server 数据库里存储内容。

在这个虚拟文件系统里,你可以存储下面这些文件
1。ASP.NET 页面, master页面,用户控件以及其他对象
2。以.htm 和.jpg为扩展名的.标准的网页
3。映射到BuildProvider实例的任何自定义扩展文件
4。存在App_Theme文件夹的任何赋名的 theme

但不能存储那些产生application-level assemblies的文件和文件夹,譬如不能存储
1。Global.asax
2。Web.config
3。应用级的文件夹,Bin,App_Code, App_GlobalResources,以及App_LocalResources
4。应用的数据文件夹,App_Data.

。。。”

文档提供了一个例子,通过一个 DataSet 对象里的信息实现一个虚拟文件系统。

看完后并没有留下很深的印象,直到看到了Scott Guthrie的演示里的例子,由一个Access文件提供的文件系统时,真的感觉这东西真的很酷,感兴趣者可以去Scott Guthrie的网站下载对应的PPT和编码例子。

ASP.NET 2.0 Tips/Tricks Slides + Demos

下面是我依样画葫芦写的一个简单的Provider例子,主要是用来验证可以使用codefile。想要试着运行的话,生成一个虚拟目录,然后建立一个App_Code文件夹,把下面内容存成一个.cs文件,然后在浏览器里访问

http://localhost/你的应用名字/abc/def.aspx

应用名字后面的文件夹子,文件名是任意的,只要是以.aspx结尾

===============================

using System;
using System.IO;
using System.Text;
using System.Web.Caching;
using System.Web.Hosting;
using System.Collections;

namespace JoyCode
{

    class SimpleVirtualFile : VirtualFile
    {

        string path;
        public SimpleVirtualFile(string virtualPath) : base(virtualPath)
        {
            path = virtualPath.ToLower();
        }

        public override bool IsDirectory
        {
            get
            {
                if(path.EndsWith(“.aspx”) || path.EndsWith(“.cs”))
                    return false;
                return true;
            }
        }

        public override Stream Open()
        {
           string Html = @”<%@ Page Language=””C#”” CodeFile=””Test.aspx.cs”” Inherits=””ASPNET20.Test_aspx””%>
hello world: <%=DateTime.Now%><BR>”;

            string Code = @”using System;
using System.Web.UI;

namespace ASPNET20
{
  public partial class Test_aspx : Page
  {
 void Page_Load(Object sender, EventArgs e)
        {
            Response.Write(“”hello world from Test_aspx.Page_Load:”” + DateTime.Now + “”<BR>””);
        }
  }
}
        “;

            Stream stream = null;
            if (!IsDirectory)
            {
                if (path.EndsWith(“.aspx”))
                    stream = new MemoryStream(Encoding.ASCII.GetBytes(Html));
                else if (path.EndsWith(“.cs”))
                    stream = new MemoryStream(Encoding.ASCII.GetBytes(Code));
            }

            if (stream != null)
                stream.Seek(0, SeekOrigin.Begin);

            return stream;
        }
    }

    public class SimpleVirtualPathProvider : VirtualPathProvider
    {

        public static void AppInitialize()
        {
            SimpleVirtualPathProvider provider = new SimpleVirtualPathProvider();
            HostingEnvironment.RegisterVirtualPathProvider(provider);
        }

        public override bool FileExists(string virtualPath)
        {
            virtualPath = virtualPath.ToLower();

            if (virtualPath.EndsWith(“.aspx”) || virtualPath.EndsWith(“.cs”))
                return true;
            else
                return false;
        }

        public override bool DirectoryExists(string virtualDir)
        {
            return !FileExists(virtualDir);
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            return new SimpleVirtualFile(virtualPath);
        }

        //this prevents an error if you have a path with folder names
        //参考Valvert 在下面这个帖子里的答复
        //http://forums.asp.net/921762/ShowPost.aspx
        public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            return null;
        }
    }
}

改变ASP.NET 2.0中的Membership的密码要求

看到这个问题,答案是需要在配置文件里修改MembershipProvider的设置,

<connectionStrings>
  <add name=”MySqlConnection” connectionString=”Data Source=MySqlServer;Initial Catalog=aspnetdb;Integrated Security=SSPI;” />
</connectionStrings>
<system.web>
…..
<membership defaultProvider=”SqlProvider” userIsOnlineTimeWindow=”15″>
    <providers>
      <clear />
      <add
        name=”SqlProvider”
        type=”System.Web.Security.SqlMembershipProvider”
        connectionStringName=”MySqlConnection”
        applicationName=”MyApplication”
        minRequiredNonalphanumericCharacters=”0″
        minRequiredPasswordLength=”6″
        passwordStrengthRegularExpression=”……” />
    </providers>
</membership>

参考MSDN文章

How To: Use Membership in ASP.NET 2.0

How To: Use Forms Authentication with SQL Server in ASP.NET 2.0

以及Mark Michaelis这个blog:

Passwords in VS 2005 Beta 2’s Personal Website Starter Kit

ASP.NET 2.0中几个对象的主要方法/事件流程

根据Lutz Roeder的Reflector对System.Web.dll的反编译,下面是HttpApplication,Page和Control对象的主要方法和事件的流程

     PostBack
     Page/Control Event
     CallBack
HttpApplication Page Control
BeginRequest    
AuthenticateRequest    
DefaultAuthentication    
PostAuthenticateRequest    
AuthorizeRequest    
PostAuthorizeRequest    
ResolveRequestCache    
PostResolveRequestCache    
MapHttpHandler Construct  
PostMapRequestHandler    
AcquireRequestState (Session)    
PostAcquireRequestState    
PreRequestHandlerExecute    
CallHandler

DeterminePostBackMode

 
LoadScrollPosition  
PerformPreInit
PreInit
–InitializeThemes
–ApplyMasterPage
 
InitRecursive
(–ResolveAdapter
–ApplySkin
Init
–TrackViewState)
ResolveAdapter
InitRecursive
ApplySkin
Init
TrackViewState
InitComplete

 
LoadAllState
–LoadPageStateFromPersistenceMedium
–LoadViewStateRecursive

LoadControlStateInternal
–LoadControlState

LoadViewStateRecursive
–LoadViewState
ProcessPostData  
PreLoad  
LoadRecursive
(–Load)
LoadRecursive
Load
ProcessPostData  
RaiseChangedEvents  
RaisePostBackEvent  
LoadComplete  
RaiseCallbackEvent
–return

 
PreRenderRecursiveInternal
(–PreRender)

PreRenderRecursiveInternal
PreRender
ExecuteRegisteredAsyncTasks **  
PerformPreRenderComplete
PreRenderComplete
 
SaveAllState
–SaveViewStateRecursive
–SavePageStateToPersistenceMedium
SaveControlStateInternal
–SaveControlState
SaveViewState
–SaveViewStateRecursive
SaveStateComplete  
RenderControl

RenderControl
–RenderControlInternal
—-Render
——RenderChildren
——–RenderChildrenInternal
PostRequestHandlerExecute    
ReleaseRequestState (Session)    
PostReleaseRequestState    
CallFilter — Response.FilterOutput    
UpdateRequestCache    
PostUpdateRequestCache    
EndRequest    

** 参考 Jeff Prosise在MSND杂志10月期的文章
Asynchronous Pages in ASP.NET 2.0