2005年08月03日

//C#资源管理器源码
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;

namespace myTree
{
 /// <summary>
 /// Form1 的摘要说明。
 /// </summary>
  public class Form1 : System.Windows.Forms.Form
  {
    private System.Windows.Forms.ImageList TreeImageList;
    private System.Windows.Forms.MainMenu mainMenu1;
    private System.Windows.Forms.MenuItem menuItem1;
    private System.Windows.Forms.ListView listView1;
    private System.Windows.Forms.TextBox textBox1;
    private System.Windows.Forms.TreeView treeView1;
    private System.Windows.Forms.Panel panel2;
    private System.Windows.Forms.Panel panel1;
    private System.Windows.Forms.Splitter splitter1;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.ImageList LisrimageList;
    private System.Windows.Forms.ImageList LisrimageList2;
    private System.Windows.Forms.StatusBar statusBar1;
    private System.Windows.Forms.StatusBarPanel statusBarPanel1;
    private System.Windows.Forms.StatusBarPanel statusBarPanel2;
    private System.Windows.Forms.MenuItem menuItem2;
    private System.Windows.Forms.MenuItem menuItem3;
    private System.Windows.Forms.MenuItem menuItem4;
    private System.Windows.Forms.MenuItem menuItem5;
    private System.Windows.Forms.MenuItem menuItem6;
    private System.Windows.Forms.MenuItem menuItem7;
    private System.Windows.Forms.Label label1;
    private System.ComponentModel.IContainer components;

 public Form1()
 {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();

   Icon ic0=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",15);
   TreeImageList.Images.Add(ic0);
   Icon ic1=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",5);
   TreeImageList.Images.Add(ic1);
   Icon ic2=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",7);
   TreeImageList.Images.Add(ic2);
   Icon ic3=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",11);
   TreeImageList.Images.Add(ic3);

   Icon ic4=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",3);
   TreeImageList.Images.Add(ic4);
   Icon ic5=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",4);
   TreeImageList.Images.Add(ic5);
   Icon ic6=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",101);
   TreeImageList.Images.Add(ic6);


   GetDrive();
 }

 /// <summary>
 /// 清理所有正在使用的资源。
 /// </summary>
 protected override void Dispose( bool disposing )
 {
   if( disposing )
   {
  if (components != null)
  {
    components.Dispose();
  }
   }
   base.Dispose( disposing );
 }

  #region Windows Form Designer generated code
 /// <summary>
 /// 设计器支持所需的方法 – 不要使用代码编辑器修改
 /// 此方法的内容。
 /// </summary>
 private void InitializeComponent()
 {
   this.components = new System.ComponentModel.Container();
   this.TreeImageList = new System.Windows.Forms.ImageList(this.components);
   this.mainMenu1 = new System.Windows.Forms.MainMenu();
   this.menuItem1 = new System.Windows.Forms.MenuItem();
   this.menuItem2 = new System.Windows.Forms.MenuItem();
   this.menuItem3 = new System.Windows.Forms.MenuItem();
   this.menuItem4 = new System.Windows.Forms.MenuItem();
   this.menuItem5 = new System.Windows.Forms.MenuItem();
   this.menuItem6 = new System.Windows.Forms.MenuItem();
   this.menuItem7 = new System.Windows.Forms.MenuItem();
   this.listView1 = new System.Windows.Forms.ListView();
   this.textBox1 = new System.Windows.Forms.TextBox();
   this.treeView1 = new System.Windows.Forms.TreeView();
   this.panel2 = new System.Windows.Forms.Panel();
   this.label1 = new System.Windows.Forms.Label();
   this.button1 = new System.Windows.Forms.Button();
   this.panel1 = new System.Windows.Forms.Panel();
   this.splitter1 = new System.Windows.Forms.Splitter();
   this.LisrimageList = new System.Windows.Forms.ImageList(this.components);
   this.LisrimageList2 = new System.Windows.Forms.ImageList(this.components);
   this.statusBar1 = new System.Windows.Forms.StatusBar();
   this.statusBarPanel1 = new System.Windows.Forms.StatusBarPanel();
   this.statusBarPanel2 = new System.Windows.Forms.StatusBarPanel();
   this.panel2.SuspendLayout();
   this.panel1.SuspendLayout();
   ((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).BeginInit();
   ((System.ComponentModel.ISupportInitialize)(this.statusBarPanel2)).BeginInit();
   this.SuspendLayout();
   //
   // TreeImageList
   //
   this.TreeImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
   this.TreeImageList.ImageSize = new System.Drawing.Size(16, 16);
   this.TreeImageList.TransparentColor = System.Drawing.Color.Transparent;
   //
   // mainMenu1
   //
   this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                     this.menuItem1,
                     this.menuItem2,
                     this.menuItem3,
                     this.menuItem4});
   //
   // menuItem1
   //
   this.menuItem1.Index = 0;
   this.menuItem1.Text = "文件";
   //
   // menuItem2
   //
   this.menuItem2.Index = 1;
   this.menuItem2.Text = "编辑";
   //
   // menuItem3
   //
   this.menuItem3.Index = 2;
   this.menuItem3.Text = "显隐";
   this.menuItem3.Click += new System.EventHandler(this.menuItem3_Click);
   //
   // menuItem4
   //
   this.menuItem4.Index = 3;
   this.menuItem4.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                     this.menuItem5,
                     this.menuItem6,
                     this.menuItem7});
   this.menuItem4.Text = "列表方式";
   //
   // menuItem5
   //
   this.menuItem5.Index = 0;
   this.menuItem5.Text = "大图标";
   this.menuItem5.Click += new System.EventHandler(this.menuItem5_Click);
   //
   // menuItem6
   //
   this.menuItem6.Index = 1;
   this.menuItem6.Text = "小图标";
   this.menuItem6.Click += new System.EventHandler(this.menuItem6_Click);
   //
   // menuItem7
   //
   this.menuItem7.Index = 2;
   this.menuItem7.Text = "详细列表";
   this.menuItem7.Click += new System.EventHandler(this.menuItem7_Click);
   //
   // listView1
   //
   this.listView1.Activation = System.Windows.Forms.ItemActivation.OneClick;
   this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
   this.listView1.Location = new System.Drawing.Point(221, 25);
   this.listView1.Name = "listView1";
   this.listView1.Size = new System.Drawing.Size(491, 381);
   this.listView1.TabIndex = 3;
   this.listView1.View = System.Windows.Forms.View.SmallIcon;
   this.listView1.ItemActivate += new System.EventHandler(this.listView1_ItemActivate);
   //
   // textBox1
   //
   this.textBox1.Dock = System.Windows.Forms.DockStyle.Top;
   this.textBox1.Name = "textBox1";
   this.textBox1.Size = new System.Drawing.Size(712, 25);
   this.textBox1.TabIndex = 5;
   this.textBox1.Text = "";
   //
   // treeView1
   //
   this.treeView1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
  | System.Windows.Forms.AnchorStyles.Left)
  | System.Windows.Forms.AnchorStyles.Right);
   this.treeView1.ImageIndex = -1;
   this.treeView1.ItemHeight = 18;
   this.treeView1.Location = new System.Drawing.Point(0, 29);
   this.treeView1.Name = "treeView1";
   this.treeView1.SelectedImageIndex = -1;
   this.treeView1.Size = new System.Drawing.Size(216, 349);
   this.treeView1.TabIndex = 1;
   this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect_1);
   this.treeView1.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView1_BeforeExpand_1);
   //
   // panel2
   //
   this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
   this.panel2.Controls.AddRange(new System.Windows.Forms.Control[] {
                   this.label1,
                   this.button1});
   this.panel2.Dock = System.Windows.Forms.DockStyle.Top;
   this.panel2.Name = "panel2";
   this.panel2.Size = new System.Drawing.Size(216, 28);
   this.panel2.TabIndex = 0;
   //
   // label1
   //
   this.label1.Dock = System.Windows.Forms.DockStyle.Left;
   this.label1.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));
   this.label1.Name = "label1";
   this.label1.Size = new System.Drawing.Size(56, 24);
   this.label1.TabIndex = 1;
   this.label1.Text = "文件夹";
   this.label1.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
   //
   // button1
   //
   this.button1.Dock = System.Windows.Forms.DockStyle.Right;
   this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
   this.button1.Location = new System.Drawing.Point(188, 0);
   this.button1.Name = "button1";
   this.button1.Size = new System.Drawing.Size(24, 24);
   this.button1.TabIndex = 0;
   this.button1.Text = "X";
   this.button1.Click += new System.EventHandler(this.button1_Click);
   //
   // panel1
   //
   this.panel1.Controls.AddRange(new System.Windows.Forms.Control[] {
                   this.treeView1,
                   this.panel2});
   this.panel1.Dock = System.Windows.Forms.DockStyle.Left;
   this.panel1.Location = new System.Drawing.Point(0, 25);
   this.panel1.Name = "panel1";
   this.panel1.Size = new System.Drawing.Size(216, 381);
   this.panel1.TabIndex = 6;
   //
   // splitter1
   //
   this.splitter1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
   this.splitter1.Location = new System.Drawing.Point(216, 25);
   this.splitter1.Name = "splitter1";
   this.splitter1.Size = new System.Drawing.Size(5, 381);
   this.splitter1.TabIndex = 7;
   this.splitter1.TabStop = false;
   //
   // LisrimageList
   //
   this.LisrimageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
   this.LisrimageList.ImageSize = new System.Drawing.Size(16, 16);
   this.LisrimageList.TransparentColor = System.Drawing.Color.Transparent;
   //
   // LisrimageList2
   //
   this.LisrimageList2.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
   this.LisrimageList2.ImageSize = new System.Drawing.Size(16, 16);
   this.LisrimageList2.TransparentColor = System.Drawing.Color.Transparent;
   //
   // statusBar1
   //
   this.statusBar1.Location = new System.Drawing.Point(0, 406);
   this.statusBar1.Name = "statusBar1";
   this.statusBar1.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
                      this.statusBarPanel1,
                      this.statusBarPanel2});
   this.statusBar1.Size = new System.Drawing.Size(712, 22);
   this.statusBar1.TabIndex = 8;
   this.statusBar1.Text = "statusBar1";
   //
   // statusBarPanel1
   //
   this.statusBarPanel1.BorderStyle = System.Windows.Forms.StatusBarPanelBorderStyle.None;
   this.statusBarPanel1.Text = "statusBarPanel1";
   this.statusBarPanel1.Width = 132;
   //
   // statusBarPanel2
   //
   this.statusBarPanel2.BorderStyle = System.Windows.Forms.StatusBarPanelBorderStyle.None;
   this.statusBarPanel2.Text = "statusBarPanel2";
   this.statusBarPanel2.Width = 132;
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(8, 18);
   this.ClientSize = new System.Drawing.Size(712, 428);
   this.Controls.AddRange(new System.Windows.Forms.Control[] {
                  this.listView1,
                  this.splitter1,
                  this.panel1,
                  this.textBox1,
                  this.statusBar1});
   this.Menu = this.mainMenu1;
   this.Name = "Form1";
   this.Text = "我的资源管理器–曲郑生设计–2002.9";
   this.panel2.ResumeLayout(false);
   this.panel1.ResumeLayout(false);
   ((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).EndInit();
   ((System.ComponentModel.ISupportInitialize)(this.statusBarPanel2)).EndInit();
   this.ResumeLayout(false);

 }
  #endregion

 /// <summary>
 /// 应用程序的主入口点。
 /// </summary>
 [STAThread]
 static void Main()
 {
   Application.Run(new Form1());
 }

//*************************************************************************************
 [DllImport("Shell32.dll")]
 public static extern int ExtractIcon(IntPtr h,string strx,int ii);

 [DllImport("Shell32.dll")]
 public static extern int SHGetFileInfo(string pszPath,uint dwFileAttributes,ref SHFILEINFO psfi,uint cbFileInfo, uint uFlags);

 public struct SHFILEINFO
 {
   public IntPtr hIcon; 
   public int   iIcon; 
   public uint dwAttributes;
   public char szDisplayName;
   public char szTypeName;
 }
 

 string strFilePath="";
//*************************************************************************************
 
 protected virtual Icon myExtractIcon(string FileName,int iIndex)
 {
   try
   {
  IntPtr hIcon=(IntPtr)ExtractIcon(this.Handle,FileName,iIndex);
  if(! hIcon.Equals(null))
  {
    Icon icon=Icon.FromHandle(hIcon);
    return icon;
  }
   }
   catch(Exception ex)
   { MessageBox.Show(ex.Message,"错误提示",0,MessageBoxIcon.Error);}
   return null;
 }
//*************************************************************************************

 protected virtual void SetIcon(ImageList imageList,string FileName,bool tf)
 {
   SHFILEINFO fi=new SHFILEINFO();
   if(tf==true)
   {
  int iTotal=(int)SHGetFileInfo(FileName,0,ref fi,100,  16640);//SHGFI_ICON|SHGFI_SMALLICON
  try
  {
    if(iTotal >0)
    {
   Icon ic=Icon.FromHandle(fi.hIcon);
   imageList.Images.Add(ic);
   //return ic;
    }
  }
  catch(Exception ex)
  { MessageBox.Show(ex.Message,"错误提示",0,MessageBoxIcon.Error);}
   }
   else
   {
  int iTotal=(int)SHGetFileInfo(FileName,0,ref fi,100,  257);
  try
  {
    if(iTotal >0)
    {
   Icon ic=Icon.FromHandle(fi.hIcon);
   imageList.Images.Add(ic);
   //return ic;
    }
  }
  catch(Exception ex)
  { MessageBox.Show(ex.Message,"错误提示",0,MessageBoxIcon.Error);}
   }
   // return null;
 }
//*************************************************************************************

 public void GetDrive()
 {
   treeView1.ImageList=TreeImageList;
 
   treeView1.BeginUpdate();
   treeView1.Nodes.Clear();

   TreeNode RootNode=new TreeNode("我的电脑",0,0);
   treeView1.Nodes.Add(RootNode);
 
   int iImageIndex=2;  int iSelectedIndex=2;
   string[] astrDrives = Directory.GetLogicalDrives();

   foreach (string str in astrDrives)
   {
  if(str == "A:\\")
  { iImageIndex=1;  iSelectedIndex=1;}
  else if(str == "G:\\")
  { iImageIndex=3;  iSelectedIndex=3;}
  else
  { iImageIndex=2;  iSelectedIndex=2;}

  TreeNode tnDrive = new TreeNode(str, iImageIndex,iSelectedIndex);
  treeView1.Nodes[0].Nodes.Add(tnDrive);
  AddDirectories(tnDrive);

  if(str == "C:\\")
  { treeView1.SelectedNode=tnDrive;}
   }
   treeView1.EndUpdate();
 }
//*************************************************************************************

 void AddDirectories(TreeNode tn)
 {
   tn.Nodes.Clear();

   string strPath=tn.FullPath;
   strPath=strPath.Remove(0,5);

   //获得当前目录
   DirectoryInfo   dirinfo = new DirectoryInfo(strPath);
   DirectoryInfo[] adirinfo;
   try
   {
  adirinfo = dirinfo.GetDirectories();
   }
   catch
   { return;}

      int iImageIndex=4;  int iSelectedIndex=5;
   foreach (DirectoryInfo di in adirinfo)
   {
  if(di.Name=="RECYCLER"||di.Name=="RECYCLED"||di.Name=="Recycled")
  {iImageIndex=6;  iSelectedIndex=6;}
  else
  {iImageIndex=4;  iSelectedIndex=5;}

  TreeNode tnDir = new TreeNode(di.Name, iImageIndex, iSelectedIndex);
  tn.Nodes.Add(tnDir);
   }


/*
   //获得当前目录下的所有文件
   FileInfo[] dirFiles;
   dirFiles=dirinfo.GetFiles();
   int iCount=7;

   foreach (FileInfo fi in dirFiles)
   {
  //得到每个文件的图标
  string str=fi.FullName;
  try
  {
    SetIcon(TreeImageList,str,false);
  }
  catch(Exception ex)
  { MessageBox.Show(ex.Message,"错误提示",0,MessageBoxIcon.Error);}
       
  TreeNode tnDir = new TreeNode(fi.Name, iCount, iCount);
  tn.Nodes.Add(tnDir);

  iCount++;
   }
*/
 }
//*************************************************************************************
 //在大图标、小图标、详细列表切换时调用
 protected virtual void ListViewAB(int iii)
 {
   if(iii==1)
   {
  LisrimageList2.ImageSize=new Size(32,32);
  listView1.LargeImageList=LisrimageList2;
  
  if(listView1.View==View.Details||listView1.View==View.SmallIcon)
  {listView1.View=View.LargeIcon;}
   }
   else if(iii==2)
   {
  if(listView1.View==View.Details||listView1.View==View.LargeIcon)
  {listView1.View=View.SmallIcon;}
   }
   else
   {
  if(listView1.View==View.LargeIcon||listView1.View==View.SmallIcon)
  {listView1.View=View.Details;}
   }
 }
//*************************************************************************************
 private void treeView1_BeforeExpand_1(object sender, System.Windows.Forms.TreeViewCancelEventArgs e)
 {
   //base.OnBeforeExpand(e);

   treeView1.BeginUpdate();

   foreach (TreeNode tn in e.Node.Nodes)
   { AddDirectories(tn);}

   treeView1.EndUpdate();
 }

//*************************************************************************************

 protected virtual void InitList(TreeNode tn)
 {
   this.statusBarPanel1.Text="正在刷新文件夹,请稍等…..";
   this.Cursor=Cursors.WaitCursor;

   this.LisrimageList2.Images.Clear();
   this.LisrimageList.Images.Clear();
   listView1.SmallImageList=LisrimageList;
   Icon ic0=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",3);
   LisrimageList.Images.Add(ic0);。
   LisrimageList2.Images.Add(ic0);

   listView1.Clear();
   //设置列表框的表头
   listView1.Columns.Add("文件名",160,HorizontalAlignment.Left);
   listView1.Columns.Add("文件大小",120,HorizontalAlignment.Left);
   listView1.Columns.Add("创建时间",120,HorizontalAlignment.Left);
   listView1.Columns.Add("访问时间",200,HorizontalAlignment.Left);

 
   string strPath=tn.FullPath;
   strPath=strPath.Remove(0,5);
   //获得当前目录下的所有文件
   DirectoryInfo curDir=new DirectoryInfo(strPath);//创建目录对象。
   FileInfo[] dirFiles;
   try
   {
     dirFiles=curDir.GetFiles();
   }
   catch  { return;}

   string []arrSubItem=new string[4];
   //文件的创建时间和访问时间。
   int iCount=0;    int iconIndex=1;//用1,而不用0是要让过0号图标。
   foreach(FileInfo fileInfo in dirFiles)
   {
  string strFileName=fileInfo.Name;          
           
  //如果不是文件pagefile.sys
  if(! strFileName.Equals("pagefile.sys"))
  {
    arrSubItem[0]=strFileName;
    arrSubItem[1]=fileInfo.Length+" 字节";
    arrSubItem[2]=fileInfo.CreationTime.ToString();
    arrSubItem[3]=fileInfo.LastAccessTime.ToString();
  }
  else
  { arrSubItem[1]="未知大小"; arrSubItem[2]="未知日期"; arrSubItem[3]="未知日期";}
  

      //得到每个文件的图标
  string str=fileInfo.FullName;
  try
  {
    SetIcon(LisrimageList,str,false);
    SetIcon(LisrimageList2,str,true);
  }
  catch(Exception ex)
  { MessageBox.Show(ex.Message,"错误提示",0,MessageBoxIcon.Error);}
       

       //插入列表项   
  ListViewItem LiItem=new ListViewItem(arrSubItem,iconIndex);
  listView1.Items.Insert(iCount,LiItem);

  iCount++;
  iconIndex++;
   }
   strFilePath=strPath;
   textBox1.Text=strPath;
   this.statusBarPanel1.Text=strPath;
   this.statusBarPanel2.Text="文件数量: " + iCount.ToString()+"个";
   this.Cursor=Cursors.Arrow;

 

   //以下是向列表框中插入目录,不是文件。获得当前目录下的各个子目录。
   int iItem=0;

   DirectoryInfo Dir=new DirectoryInfo(strPath);
   foreach(DirectoryInfo di in Dir.GetDirectories())
   {  
     ListViewItem LiItem=new ListViewItem(di.Name,0);
  listView1.Items.Insert(iItem,LiItem);
  iItem++;
   }

 }
 //*************************************************************************************

 protected virtual void InitList2(string strName)
 {
   this.statusBarPanel1.Text="正在刷新文件夹,请稍等…..";
   this.Cursor=Cursors.WaitCursor;

   this.LisrimageList2.Images.Clear();
   this.LisrimageList.Images.Clear();
   listView1.SmallImageList=LisrimageList;
   Icon ic0=myExtractIcon("%SystemRoot%\\system32\\shell32.dll",3);
   LisrimageList.Images.Add(ic0);
   LisrimageList2.Images.Add(ic0);

   listView1.Clear();
   //设置列表框的表头
   listView1.Columns.Add("文件名",160,HorizontalAlignment.Left);
   listView1.Columns.Add("文件大小",120,HorizontalAlignment.Left);
   listView1.Columns.Add("创建时间",120,HorizontalAlignment.Left);
   listView1.Columns.Add("访问时间",200,HorizontalAlignment.Left);

 
   //获得当前目录下的所有文件
   DirectoryInfo curDir=new DirectoryInfo(strName);//创建目录对象。
   FileInfo[] dirFiles;
   try
   {
  dirFiles=curDir.GetFiles();
   }
   catch  { return;}

   string []arrSubItem=new string[4];
   //文件的创建时间和访问时间。
   int iCount=0;    int iconIndex=1;//用1,而不用0是要让过0号图标。
   foreach(FileInfo fileInfo in dirFiles)
   {
  string strFileName=fileInfo.Name;          
           
  //如果不是文件pagefile.sys
  if(! strFileName.Equals("pagefile.sys"))
  {
    arrSubItem[0]=strFileName;
    arrSubItem[1]=fileInfo.Length+" 字节";
    arrSubItem[2]=fileInfo.CreationTime.ToString();
    arrSubItem[3]=fileInfo.LastAccessTime.ToString();
  }
  else
  { arrSubItem[1]="未知大小"; arrSubItem[2]="未知日期"; arrSubItem[3]="未知日期";}
  

  //得到每个文件的图标
  string str=fileInfo.FullName;
  try
  {
    SetIcon(LisrimageList,str,false);
    SetIcon(LisrimageList2,str,true);
  }
  catch(Exception ex)
  { MessageBox.Show(ex.Message,"错误提示",0,MessageBoxIcon.Error);}
       

  //插入列表项   
  ListViewItem LiItem=new ListViewItem(arrSubItem,iconIndex);
  listView1.Items.Insert(iCount,LiItem);

  iCount++;
  iconIndex++;//必须加在listView1.Items.Insert(iCount,LiItem);
   }
   strFilePath=strName;//把路径赋值于全局变量strFilePath

   textBox1.Text=strName;
   this.statusBarPanel2.Text="文件数量: " + iCount.ToString()+"个";
   this.Cursor=Cursors.Arrow;

 

   //以下是向列表框中插入目录,不是文件。获得当前目录下的各个子目录。
   int iItem=0;//调用listView1.Items.Insert(iItem,LiItem);时用。不能使用iconIndex。

   DirectoryInfo Dir=new DirectoryInfo(strName);//创建目录对象。
   foreach(DirectoryInfo di in Dir.GetDirectories())
   {  
  ListViewItem LiItem=new ListViewItem(di.Name,0);
  listView1.Items.Insert(iItem,LiItem);
  iItem++;
   }

 }
//*************************************************************************************

    private void treeView1_AfterSelect_1(object sender, System.Windows.Forms.TreeViewEventArgs e)
 {
   if(e.Node.Text=="我的电脑")   
   { return;}

   InitList(e.Node);
 }
//*************************************************************************************

    private void button1_Click(object sender, System.EventArgs e)
 {
    this.panel1.Hide();
 }
//*************************************************************************************

    private void listView1_ItemActivate(object sender, System.EventArgs e)
 {
   string str=Path.Combine(strFilePath,listView1.FocusedItem.Text);
   try
   {
  if(listView1.FocusedItem.SubItems.Count>1)
  { System.Diagnostics.Process.Start(str); }
  else
  { InitList2(str); }
   }
   catch  { return;}
 }
//*************************************************************************************
 private void menuItem3_Click(object sender, System.EventArgs e)
 {
   this.panel1.Visible=! panel1.Visible;
 }
//*************************************************************************************
    private void menuItem5_Click(object sender, System.EventArgs e)
 {
   ListViewAB(1);
 }
//*************************************************************************************
    private void menuItem6_Click(object sender, System.EventArgs e)
 {
   ListViewAB(2);
 }
//*************************************************************************************
    private void menuItem7_Click(object sender, System.EventArgs e)
 {
   ListViewAB(3);
 }
//*************************************************************************************

  }
}

/* Copyright all(c) 2005 ZhongFeng, http://blog.csdn.net/SW515 */
 public class ValidateCode : System.Web.UI.Page
 {
  private void Page_Load(object sender, System.EventArgs e)
  {
   this.CreateCheckCodeImage(GenerateCheckCode());
  }

  #region web 窗体设计器生成的代码
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN: 该调用是 asp.NET web 窗体设计器所必需的。
   //
   InitializeComponent();
   base.OnInit(e);
  }
 
  /// <summary>
  /// 设计器支持所需的方法 – 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {   
   this.Load += new System.EventHandler(this.Page_Load);
  }
  #endregion

  private string GenerateCheckCode()
  {
   int number;
   char code;
   string checkCode = String.Empty;

   System.Random random = new Random();

   for(int i=0; i<5; i++)
   {
    number = random.Next();

    if(number % 2 == 0)
     code = (char)(‘0′ + (char)(number % 10));
    else
     code = (char)(‘A’ + (char)(number % 26));

    checkCode += code.ToString();
   }

   Response.Cookies.Add(new HttpCookie("CheckCode", checkCode));

   return checkCode;
  }

  private void CreateCheckCodeImage(string checkCode)
  {
   if(checkCode == null || checkCode.Trim() == String.Empty)
    return;

   System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * 12.5)), 22);
   Graphics g = Graphics.FromImage(image);

   try
   {
    //生成随机生成器
    Random random = new Random();

    //清空图片背景色
    g.Clear(Color.White);

    //画图片的背景噪音线
    for(int i=0; i<25; i++)
    {
     int x1 = random.Next(image.Width);
     int x2 = random.Next(image.Width);
     int y1 = random.Next(image.Height);
     int y2 = random.Next(image.Height);

     g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
    }

    Font font = new System.Drawing.Font("Arial", 12, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic));
    System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
    g.DrawString(checkCode, font, brush, 2, 2);

    //画图片的前景噪音点
    for(int i=0; i<100; i++)
    {
     int x = random.Next(image.Width);
     int y = random.Next(image.Height);

     image.SetPixel(x, y, Color.FromArgb(random.Next()));
    }

    //画图片的边框线
    g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width – 1, image.Height – 1);

    System.IO.MemoryStream ms = new System.IO.MemoryStream();
    image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
    Response.ClearContent();
    Response.ContentType = "image/Gif";
    Response.BinaryWrite(ms.ToArray());
   }
   finally
   {
    g.Dispose();
    image.Dispose();
   }
  }
 }


本文介绍如何在asp.net中创建用户控件,控件属性的动态修改以及控件的事件出发机制。

简介
asp.net的服务端控件使得web开发工作变得更为简单,功能更为强大。我们介绍过如何在asp.net页面中使用服务端控件。但是,如果服务端没有所要求的控件时该怎么办呢?

当然,asp.net不会给你变出一个莫须有的控件。事实上,可以动手作自己的控件来取代.net提供的控件。这种控件就是用户控件,也正是本文讨论的话题。

编写第一个用户控件
有人认为,知道如何使用服务端控件可不一定说明编写用户控件是件容易的事。

事实上,编写一个基本用户控件(有时也称之为pagelets)并让asp.net页面象使用服务端控件那样使用这些控件的确是件简单的事。这里有一个简单示例:

basic.ascx
<p>
this is a user control… really!
</p>

这就是一个用户控件!看到这里,我想你会说我该不是喝醉了,头脑不清楚吧。但这段代码的确就是易于被使用的一个用户控件。尽管这个控件没有作什么事,却是关于什么是用户控件的一个很好说明。事情并不象想像得那么复杂。注意后缀.ascx,它告诉网页这是一个用户控件。它没有什么特别含义,只是不让iis去直接执行这段代码。

现在我们来创建一个用户控件,看下面的例子:

basic.aspx
<%@ page language=vb %>
<%@ register tagprefix=asp101samps tagname=sometext
src=basic.ascx %>

<html>
<head>
<title>asp.net user control sample – basic</title>
</head>
<body bgcolor=#ffffff>

<asp101samps:sometext runat=server />

</body>
</html>

这段代码输出标准html页面,显示用户控件里的文字而不是标记。
那么它是怎么实现的呢?关键就在注册(register)说明。要注册控件,先要定义三个属性:

tagprefix
定义控件位置的命名空间。有了命名空间制约,就可以在同一个网页里使用不同功能的同名控件。

tagname
指向所使用控件的名字。在同一个命名空间里的控件名是唯一的。控件名一般都表明控件的功能。

src
指向控件的资源文件。资源文件使用虚路径(control.ascx 或 /path/control.ascx),不能使用物理路径(c:\path\control.ascx.)。

控件注册之后,就可以象其它服务端控件一样被使用。通过定义目标前缀(tagprefix)和目标名(tagname),就可以象使用服务端内建控件一样地进行使用。同时也确定了使用服务端运行(runat=server)方式。下面是网页调用用户控件的基本方式:
<tagprefix:tagname runat=server />


给用户控件增加属性并赋值
下面我给控件加上两个属性,一个是color,另一个是text。

properties.ascx
<script language=vb runat=server>
public color as string = black
public text as string = this is a user control… really!
</script>

<p>
<font color=<%= color %>>
<%= text %>
</font>
</p>

这样就可以使用和改变控件的色彩和文字了。可以在初始化时赋值,还可以动态地修改这二个属性。

在同一个网页里可以重复调用这个控件并使用不同的属性值:
properties.aspx
<%@ page language=vb %>
<%@ register tagprefix=asp101samps tagname=sometext
src=properties.ascx %>

<script language=vb runat=server>
sub page_load(sender as object, e as eventargs)
userctrl1.color = green
userctrl1.text = this controls properties were _
& set programmatically!
end sub
</script>

<html>
<head>
<title>asp.net user control sample – properties</title>
</head>
<body bgcolor=#ffffff>

<asp101samps:sometext runat=server />

<asp101samps:sometext color=red runat=server />

<asp101samps:sometext text=this is quite cool! runat=server />

<asp101samps:sometext color=blue text=aint it? runat=server />

<asp101samps:sometext id=userctrl1 runat=server />

</body>
</html>


还想再好些,用户控件是否能够有事件句柄呢?
用户控件几乎可以作任何事。下面的代码示范控件如何触发page_load事件。有了事件句柄,就不用多写其它的维护代码来控制控件的运行。控件可以自己触发事件。

在下面的代码中,封装了一个asp的textbox控件。我将我的控件名属性与textbox的内容挂钩。

events.ascx
<script language=vb runat=server>
sub page_load(src as object, e as eventargs)
dim strinitialtext as string = please enter a name!

if page.ispostback then
if txtname.text = strinitialtext
txtname.text =
end if
else
txtname.text = strinitialtext
end if
end sub

public property name as string
get
return txtname.text
end get
set
txtname.text = value
end set
end property
</script>

name: <asp:textbox id=txtname runat=server />

<asp:requiredfieldvalidator controltovalidate=txtname
id=valtxtname display=dynamic runat=server>
please enter a name!
</asp:requiredfieldvalidator>


events.aspx
<%@ page language=vb clienttarget=downlevel %>
<%@ register tagprefix=asp101samps tagname=sometext
src=properties.ascx %>
<%@ register tagprefix=asp101samps tagname=textbox
src=events.ascx %>

<script language=vb runat=server>
sub page_load(sender as object, e as eventargs)
txtlabel.text =

the textbox control handles its own stuff
in its own page_load event handler.
end sub

sub btnsubmit_click(sender as object, e as eventargs)
sets the label to the textboxs text
txtlabel.text = txtname.name

i dont need to worry about validation since
my user control does it for me.
end sub
</script>

<html>
<head>
<title>asp.net user control sample – validation & events</title>
</head>
<body bgcolor=#ffffff>

<form runat=server>

<asp101samps:textbox id=txtname runat=server />

<br />

<asp:button id=btnsubmit onclick=btnsubmit_click
text=submit runat=server />

</form>

<asp101samps:sometext id=txtlabel runat=server />

</body>
</html>

转载,这就是关于用户控件和应用的说明。无论你认为它是否简单,它肯定比使用传统asp要容易。

 

当我要写一个MD5算法的程序时,发现中英文的语言描述都有一些不确切的地方,某些个细节
讲得不清楚,或者说很费解。最后不得不拿出C语言的源程序来调试,这对于理解算法是很不
利的。于是就总结了一下我摸索到的一些要点。

1.来历
MD5的全称是message-digest algorithm 5(信息-摘要算法,在90年代初由mit laboratory
for computer science和rsa data security inc的ronald l. rivest开发出来,
经md2、md3和md4发展而来。http://www.ietf.org/rfc/rfc1321.txt,是一份最权威的文档,
由ronald l. rivest在1992年8月向ieft提交。

2.用途
MD5的作用是对一段信息(message)生成信息摘要(message-digest),该摘要对该信息具有
唯一性,可以作为数字签名。用于验证文件的有效性(是否有丢失或损坏的数据),对用户
密码的加密,在哈希函数中计算散列值。

3.特点
输入一个任意长度的字节串,生成一个128位的整数。由于算法的某些不可逆特征,在加密应用
上有较好的安全性。并且,MD5算法的使用不需要支付任何版权费用。

4.说明
唯一性和不可逆性都不是绝对的,从理论上分析是一种多对一的关系,但两个不同的信息产生
相同摘要的概率很小。不可逆是指从输出反推输入所需的运算量和计算时间太大,使用穷搜字
典的方法又需要太多的存储空间。

5.算法描述

算法输入是一个字节串,每个字节是8个bit.
算法的执行分为以下几个步骤:

第一步,补位:
MD5算法先对输入的数据进行补位,使得数据的长度(以byte为单位)对64求余的结果是56。
即数据扩展至LEN=K*64+56个字节,K为整数。
补位方法:补一个1,然后补0至满足上述要求。相当于补一个0×80的字节,再补值
为0的字节。这一步里总共补充的字节数为0~63个。

第二步,附加数据长度:
用一个64位的整数表示数据的原始长度(以bit为单位),将这个数字的8个字节按低位的在前,
高位在后的顺序附加在补位后的数据后面。这时,数据被填补后的总长度为:
  LEN = K*64+56+8=(K+1)*64 Bytes。

※注意那个64位整数是输入数据的原始长度而不是填充字节后的长度,我就在这里栽了跟头.

第三步,初始化MD5参数:
有四个32位整数变量 (A,B,C,D) 用来计算信息摘要,每一个变量被初始化成以下
以十六进制数表示的数值,低位的字节在前面。
  word A: 01 23 45 67
  word B: 89 ab cd ef
  word C: fe dc ba 98
  word D: 76 54 32 10
※注意低位的字节在前面指的是Little Endian平台上内存中字节的排列方式,
而在程序中书写时,要写成:
  A=0×67452301
  B=0xefcdab89
  C=0×98badcfe
  D=0×10325476

第四步,定义四个MD5基本的按位操作函数:
X,Y,Z为32位整数。
  F(X,Y,Z) = (X and Y) or (not(X) and Z)
  G(X,Y,Z) = (X and Z) or (Y and not(Z))
  H(X,Y,Z) = X xor Y xor Z
  I(X,Y,Z) = Y xor (X or not(Z))

再定义四个分别用于四轮变换的函数。
设Mj表示消息的第j个子分组(从0到15),<<<s表示循环左移s位,则四种操作为:
  FF(a,b,c,d,Mj,s,ti)表示a=b+((a+(F(b,c,d)+Mj+ti)<<<s)
  GG(a,b,c,d,Mj,s,ti)表示a=b+((a+(G(b,c,d)+Mj+ti)<<<s)
  HH(a,b,c,d,Mj,s,ti)表示a=b+((a+(H(b,c,d)+Mj+ti)<<<s)
  II(a,b,c,d,Mj,s,ti)表示a=b+((a+(I(b,c,d)+Mj+ti)<<<s)


第五步,对输入数据作变换。
处理数据,N是总的字节数,以64个字节为一组,每组作一次循环,每次循环进行四轮操作。
要变换的64个字节用16个32位的整数数组M[0 ...15]表示。而数组T[1 ... 64]表示一组常数,
T[i]为4294967296*abs(sin(i))的32位整数部分,i的单位是弧度,i的取值从1到64。
具体过程如下:

/* 设置主循环变量 */
For i = 0 to N/16-1 do

/*每循环一次,把数据原文存放在16个元素的数组X中. */
For j = 0 to 15 do
Set X[j] to M[i*16+j].
end /结束对J的循环

/* Save A as AA, B as BB, C as CC, and D as DD.
*/
AA = A
BB = B
CC = C
DD = D

/* 第1轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD  0  7  1]  [DABC  1 12  2]  [CDAB  2 17  3]  [BCDA  3 22  4]
[ABCD  4  7  5]  [DABC  5 12  6]  [CDAB  6 17  7]  [BCDA  7 22  8]
[ABCD  8  7  9]  [DABC  9 12 10]  [CDAB 10 17 11]  [BCDA 11 22 12]
[ABCD 12  7 13]  [DABC 13 12 14]  [CDAB 14 17 15]  [BCDA 15 22 16]


/* 第2轮* */
/* 以 [abcd k s i]表示如下操作
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD  1  5 17]  [DABC  6  9 18]  [CDAB 11 14 19]  [BCDA  0 20 20]
[ABCD  5  5 21]  [DABC 10  9 22]  [CDAB 15 14 23]  [BCDA  4 20 24]
[ABCD  9  5 25]  [DABC 14  9 26]  [CDAB  3 14 27]  [BCDA  8 20 28]
[ABCD 13  5 29]  [DABC  2  9 30]  [CDAB  7 14 31]  [BCDA 12 20 32]

/* 第3轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD  5  4 33]  [DABC  8 11 34]  [CDAB 11 16 35]  [BCDA 14 23 36]
[ABCD  1  4 37]  [DABC  4 11 38]  [CDAB  7 16 39]  [BCDA 10 23 40]
[ABCD 13  4 41]  [DABC  0 11 42]  [CDAB  3 16 43]  [BCDA  6 23 44]
[ABCD  9  4 45]  [DABC 12 11 46]  [CDAB 15 16 47]  [BCDA  2 23 48]


/* 第4轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD  0  6 49]  [DABC  7 10 50]  [CDAB 14 15 51]  [BCDA  5 21 52]
[ABCD 12  6 53]  [DABC  3 10 54]  [CDAB 10 15 55]  [BCDA  1 21 56]
[ABCD  8  6 57]  [DABC 15 10 58]  [CDAB  6 15 59]  [BCDA 13 21 60]
[ABCD  4  6 61]  [DABC 11 10 62]  [CDAB  2 15 63]  [BCDA  9 21 64]

/* 然后进行如下操作 */
A = A + AA
B = B + BB
C = C + CC
D = D + DD

Next i /* 结束对I的循环*/

第六步,输出结果。
A,B,C,D连续存放,共16个字节,128位。按十六进制依次输出这个16个字节。


最后,用程序语言实现算法后,可以输入以下几个信息对程序作一个简单的测试,
看看程序有没有错误。
 MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
 MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
 MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
 MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
 MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
 MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
d174ab98d277d9f5a5611c2c9f419d9f
  MD5 ("123456789012345678901234567890123456789012345678901234567890123456789
01234567890") = 57edf4a22be3c955ac49da2e2107b67a


MD5算法之C#程序

MD5算法比较特别,最适合用汇编语言来写,好多高级语言对之无能无力或效率极低。
比如我最开始尝试用Python和Euphoria编写,发现不太容易。相比而言,C#作为C家簇
中新兴的一门.net语言,功能比较全面。花了一晚上的工夫终于用C#最先实现了MD5。
主要是由于对算法的一些细节不太注意,结果输出总是不对,调试了好长时间。

[code]
//源文件:md5.cs
// MD5 Alogrithm
// by rufi 2004.6.20 http://rufi.yculblog.com/
using System;
using System.Collections;
using System.IO;

public class MD5 {
  //static state variables
  private static UInt32 A;
  private static UInt32 B;
  private static UInt32 C;
  private static UInt32 D;

  //number of bits to rotate in tranforming
  private const int  S11 = 7;
  private const int  S12 = 12;
  private const int  S13 = 17;
  private const int  S14 = 22;
  private const int  S21 = 5;
  private const int  S22 = 9;
  private const int  S23 = 14;
  private const int  S24 = 20;
  private const int  S31 = 4;
  private const int  S32 = 11;
  private const int  S33 = 16;
  private const int  S34 = 23;
  private const int  S41 = 6;
  private const int  S42 = 10;
  private const int  S43 = 15;
  private const int  S44 = 21;


  /* F, G, H and I are basic MD5 functions.
   * 四个非线性函数:
   *
   * F(X,Y,Z) =(X&Y)|((~X)&Z)
   * G(X,Y,Z) =(X&Z)|(Y&(~Z))
   * H(X,Y,Z) =X^Y^Z
   * I(X,Y,Z)=Y^(X|(~Z))
   *
   * (&与,|或,~非,^异或)
   */
  private static UInt32 F(UInt32 x,UInt32 y,UInt32 z){
    return (x&y)|((~x)&z);
  }
  private static UInt32 G(UInt32 x,UInt32 y,UInt32 z){
    return (x&z)|(y&(~z));
  }
  private static UInt32 H(UInt32 x,UInt32 y,UInt32 z){
    return x^y^z;
  }
  private static UInt32 I(UInt32 x,UInt32 y,UInt32 z){
    return y^(x|(~z));
  }

  /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
   * Rotation is separate from addition to prevent recomputation.
   */
  private static void FF(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + F(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }
  private static void GG(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + G(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }
  private static void HH(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + H(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }
  private static void II(ref UInt32 a,UInt32 b,UInt32 c,UInt32 d,UInt32 mj,int s,UInt32 ti){
    a = a + I(b,c,d) + mj + ti;
    a = a << s | a >> (32-s);
    a += b;
  }

  private static void MD5_Init(){
    A=0x67452301;  //in memory, this is 0x01234567
    B=0xefcdab89;  //in memory, this is 0x89abcdef
    C=0x98badcfe;  //in memory, this is 0xfedcba98
    D=0x10325476;  //in memory, this is 0x76543210
  }

  private static UInt32[] MD5_Append(byte[] input){
    int zeros=0;
    int ones =1;
    int size=0;
    int n = input.Length;
    int m = n%64;
    if( m < 56 ){
      zeros = 55-m;
      size=n-m+64;
    }
    else if (m==56){
      zeros = 0;
      ones = 0;
      size=n+8;
    }
    else{
      zeros = 63-m+56;
      size=n+64-m+64;
    }

    ArrayList bs = new ArrayList(input);
    if(ones==1){
      bs.Add( (byte)0x80 ); // 0x80 = $10000000
    }
    for(int i=0;i<zeros;i++){
      bs.Add( (byte)0 );
    }

    UInt64 N = (UInt64) n * 8;
    byte h1=(byte)(N&0xFF);
    byte h2=(byte)((N>>8)&0xFF);
    byte h3=(byte)((N>>16)&0xFF);
    byte h4=(byte)((N>>24)&0xFF);
    byte h5=(byte)((N>>32)&0xFF);
    byte h6=(byte)((N>>40)&0xFF);
    byte h7=(byte)((N>>48)&0xFF);
    byte h8=(byte)(N>>56);
    bs.Add(h1);
    bs.Add(h2);
    bs.Add(h3);
    bs.Add(h4);
    bs.Add(h5);
    bs.Add(h6);
    bs.Add(h7);
    bs.Add(h8);
    byte[] ts=(byte[])bs.ToArray(typeof(byte));

    /* Decodes input (byte[]) into output (UInt32[]). Assumes len is
     * a multiple of 4.
     */
    UInt32[] output = new UInt32[size/4];
    for(Int64 i=0,j=0;i<size;j++,i+=4){
      output[j]=(UInt32)(ts[i] | ts[i+1]<<8 | ts[i+2]<<16 | ts[i+3]<<24);
    }
    return output;
  }
  private static UInt32[] MD5_Trasform(UInt32[] x){

    UInt32 a,b,c,d;

    for(int k=0;k<x.Length;k+=16){
      a=A;
      b=B;
      c=C;
      d=D;
   
      /* Round 1 */
      FF (ref a, b, c, d, x[k+ 0], S11, 0xd76aa478); /* 1 */
      FF (ref d, a, b, c, x[k+ 1], S12, 0xe8c7b756); /* 2 */
      FF (ref c, d, a, b, x[k+ 2], S13, 0x242070db); /* 3 */
      FF (ref b, c, d, a, x[k+ 3], S14, 0xc1bdceee); /* 4 */
      FF (ref a, b, c, d, x[k+ 4], S11, 0xf57c0faf); /* 5 */
      FF (ref d, a, b, c, x[k+ 5], S12, 0x4787c62a); /* 6 */
      FF (ref c, d, a, b, x[k+ 6], S13, 0xa8304613); /* 7 */
      FF (ref b, c, d, a, x[k+ 7], S14, 0xfd469501); /* 8 */
      FF (ref a, b, c, d, x[k+ 8], S11, 0x698098d8); /* 9 */
      FF (ref d, a, b, c, x[k+ 9], S12, 0x8b44f7af); /* 10 */
      FF (ref c, d, a, b, x[k+10], S13, 0xffff5bb1); /* 11 */
      FF (ref b, c, d, a, x[k+11], S14, 0x895cd7be); /* 12 */
      FF (ref a, b, c, d, x[k+12], S11, 0x6b901122); /* 13 */
      FF (ref d, a, b, c, x[k+13], S12, 0xfd987193); /* 14 */
      FF (ref c, d, a, b, x[k+14], S13, 0xa679438e); /* 15 */
      FF (ref b, c, d, a, x[k+15], S14, 0x49b40821); /* 16 */

      /* Round 2 */
      GG (ref a, b, c, d, x[k+ 1], S21, 0xf61e2562); /* 17 */
      GG (ref d, a, b, c, x[k+ 6], S22, 0xc040b340); /* 18 */
      GG (ref c, d, a, b, x[k+11], S23, 0x265e5a51); /* 19 */
      GG (ref b, c, d, a, x[k+ 0], S24, 0xe9b6c7aa); /* 20 */
      GG (ref a, b, c, d, x[k+ 5], S21, 0xd62f105d); /* 21 */
      GG (ref d, a, b, c, x[k+10], S22,  0x2441453); /* 22 */
      GG (ref c, d, a, b, x[k+15], S23, 0xd8a1e681); /* 23 */
      GG (ref b, c, d, a, x[k+ 4], S24, 0xe7d3fbc8); /* 24 */
      GG (ref a, b, c, d, x[k+ 9], S21, 0x21e1cde6); /* 25 */
      GG (ref d, a, b, c, x[k+14], S22, 0xc33707d6); /* 26 */
      GG (ref c, d, a, b, x[k+ 3], S23, 0xf4d50d87); /* 27 */
      GG (ref b, c, d, a, x[k+ 8], S24, 0x455a14ed); /* 28 */
      GG (ref a, b, c, d, x[k+13], S21, 0xa9e3e905); /* 29 */
      GG (ref d, a, b, c, x[k+ 2], S22, 0xfcefa3f8); /* 30 */
      GG (ref c, d, a, b, x[k+ 7], S23, 0x676f02d9); /* 31 */
      GG (ref b, c, d, a, x[k+12], S24, 0x8d2a4c8a); /* 32 */

      /* Round 3 */
      HH (ref a, b, c, d, x[k+ 5], S31, 0xfffa3942); /* 33 */
      HH (ref d, a, b, c, x[k+ 8], S32, 0x8771f681); /* 34 */
      HH (ref c, d, a, b, x[k+11], S33, 0x6d9d6122); /* 35 */
      HH (ref b, c, d, a, x[k+14], S34, 0xfde5380c); /* 36 */
      HH (ref a, b, c, d, x[k+ 1], S31, 0xa4beea44); /* 37 */
      HH (ref d, a, b, c, x[k+ 4], S32, 0x4bdecfa9); /* 38 */
      HH (ref c, d, a, b, x[k+ 7], S33, 0xf6bb4b60); /* 39 */
      HH (ref b, c, d, a, x[k+10], S34, 0xbebfbc70); /* 40 */
      HH (ref a, b, c, d, x[k+13], S31, 0x289b7ec6); /* 41 */
      HH (ref d, a, b, c, x[k+ 0], S32, 0xeaa127fa); /* 42 */
      HH (ref c, d, a, b, x[k+ 3], S33, 0xd4ef3085); /* 43 */
      HH (ref b, c, d, a, x[k+ 6], S34,  0x4881d05); /* 44 */
      HH (ref a, b, c, d, x[k+ 9], S31, 0xd9d4d039); /* 45 */
      HH (ref d, a, b, c, x[k+12], S32, 0xe6db99e5); /* 46 */
      HH (ref c, d, a, b, x[k+15], S33, 0x1fa27cf8); /* 47 */
      HH (ref b, c, d, a, x[k+ 2], S34, 0xc4ac5665); /* 48 */

      /* Round 4 */
      II (ref a, b, c, d, x[k+ 0], S41, 0xf4292244); /* 49 */
      II (ref d, a, b, c, x[k+ 7], S42, 0x432aff97); /* 50 */
      II (ref c, d, a, b, x[k+14], S43, 0xab9423a7); /* 51 */
      II (ref b, c, d, a, x[k+ 5], S44, 0xfc93a039); /* 52 */
      II (ref a, b, c, d, x[k+12], S41, 0x655b59c3); /* 53 */
      II (ref d, a, b, c, x[k+ 3], S42, 0x8f0ccc92); /* 54 */
      II (ref c, d, a, b, x[k+10], S43, 0xffeff47d); /* 55 */
      II (ref b, c, d, a, x[k+ 1], S44, 0x85845dd1); /* 56 */
      II (ref a, b, c, d, x[k+ 8], S41, 0x6fa87e4f); /* 57 */
      II (ref d, a, b, c, x[k+15], S42, 0xfe2ce6e0); /* 58 */
      II (ref c, d, a, b, x[k+ 6], S43, 0xa3014314); /* 59 */
      II (ref b, c, d, a, x[k+13], S44, 0x4e0811a1); /* 60 */
      II (ref a, b, c, d, x[k+ 4], S41, 0xf7537e82); /* 61 */
      II (ref d, a, b, c, x[k+11], S42, 0xbd3af235); /* 62 */
      II (ref c, d, a, b, x[k+ 2], S43, 0x2ad7d2bb); /* 63 */
      II (ref b, c, d, a, x[k+ 9], S44, 0xeb86d391); /* 64 */

      A+=a;
      B+=b;
      C+=c;
      D+=d;
    }
    return new UInt32[]{A,B,C,D};
  }
  public static byte[] MD5Array(byte[] input){
    MD5_Init();
    UInt32[] block = MD5_Append(input);
    UInt32[] bits = MD5_Trasform(block);

    /* Encodes bits (UInt32[]) into output (byte[]). Assumes len is
     * a multiple of 4.
         */
    byte[] output=new byte[bits.Length*4];
    for(int i=0,j=0;i<bits.Length;i++,j+=4){
      output[j] = (byte)(bits[i] & 0xff);
      output[j+1] = (byte)((bits[i] >> 8) & 0xff);
      output[j+2] = (byte)((bits[i] >> 16) & 0xff);
      output[j+3] = (byte)((bits[i] >> 24) & 0xff);
    }
    return output;
  }

  public static string ArrayToHexString(byte[] array,bool uppercase){
    string hexString="";
    string format="x2";
    if(uppercase){
      format="X2";
    }
    foreach(byte b in array){
      hexString += b.ToString(format);
    }
    return hexString;
  }

  public static string MDString(string message){
    char[] c = message.ToCharArray();
    byte[] b = new byte[c.Length];
    for(int i=0;i<c.Length;i++){
      b[i]=(byte)c[i];
    }
    byte[] digest = MD5Array(b);
    return ArrayToHexString(digest,false);
  }
  public static string MDFile(string fileName){
    FileStream fs=File.Open(fileName,FileMode.Open,FileAccess.Read);
    byte[] array=new byte[fs.Length];
    fs.Read(array,0,(int)fs.Length);
    byte[] digest = MD5Array(array);
    fs.Close();
    return ArrayToHexString(digest,false);
  }

  public static string Test(string message){
    return "rnMD5 (""+message+"") = " + MD5.MDString(message);
  }
  public static string TestSuite(){   
    string s = "";
    s+=Test("");
    s+=Test("a");
    s+=Test("abc");
    s+=Test("message digest");
    s+=Test("abcdefghijklmnopqrstuvwxyz");
    s+=Test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    s+=Test("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
    return s;   
  }
}
[/code]

 转载,技术性资料收藏,如获至宝!

最近在写学工部的网站,和其它网站一样,也有用户登录/注销之类的操作。用户登录/注销我一般使用Session来做,以往的经验告诉我,直接在每个页面的CodeBehind里写Session的管理代码虽然可行,但是很麻烦,相同的代码会重复很多遍,不易维护和修改。因此这次就想写个类,专门处理用Session管理用户登录状态的操作。

首先定义两个接口
 
   /// <summary>
   /// 这里定义了用户的实体
   /// </summary>
   public interface IUserInfo
   {
       int UserID { get; set; }
       string UserName { get; set; }
       string Password { get; set; }
       string RealName { get; set; }
       string Email { get; set; }
       string IdentityNumber { get; set; }
       string BizPosition { get; set; }
       /// <summary>
       /// 1:Success;0:Fail;-1:N/A;
       /// </summary>
       int IsLoginSuccess{ get; set; }
   }
   /// <summary>
   /// 这里定义了用户状态管理的必要操作
   /// </summary>
   public interface IUserManagement
   {
       bool IsLogin { get; set; }
       void Login(IUserInfo u);
       void Login(string UserName, string Password);
       void Logoff();
       void PersistInSession();
       IUserInfo GetFromSession();
   }

下面是类的具体代码:
   public sealed class User : IUserManagement, IUserInfo
   {

       #region IUserInfo Members

       /// <summary>
       /// 1:Success;0:Fail;-1:N/A;
       /// </summary>
       public int IsLoginSuccess
       {
           get{return m_IsLoginSuccess;}
           set{m_IsLoginSuccess=value;}
       }

       //IUserInfo中用户实体的几个读写器的实现
       private int m_UserID;

       public int UserID
       {
           get { return m_UserID; }
           set { m_UserID = value; }
       }

       private string m_UserName;

       public string UserName
       {
           get { return m_UserName; }
           set { m_UserName = value; }
       }

       private string m_Password;

       public string Password
       {
           get { return m_Password; }
           set { m_Password = value; }
       }

       private string m_Email;

       public string Email
       {
           get { return m_Email; }
           set { m_Email = value; }
       }

       private string m_RealName;

       public string RealName
       {
           get { return m_RealName; }
           set { m_RealName = value; }
       }

       private string m_IdentityNumber;

       public string IdentityNumber
       {
           get { return m_IdentityNumber; }
           set { m_IdentityNumber = value; }
       }

       private string m_BizPosition;

       public string BizPosition
       {
           get { return m_BizPosition; }
           set { m_BizPosition = value; }
       }

       //读写器实现完毕

       #endregion

       #region IUserManagement Members

       public void Login(string UserName, string Password)
       {
           if (UserBr.Login(UserName, Password, out m_UserID))
           {
               this.IsLogin = true;
               this.IsLoginSuccess=1;
               this.GetUser(m_UserID); //验证通过后,填充实体类
           }
           else
           {
               this.IsLogin = false;
               this.IsLoginSuccess=0;
           }
       }

       public void Logoff()
       {
           this.IsLogin = false;
           this.IsLoginSuccess=-1;
           HttpContext hc = HttpContext.Current;
           if(hc.Session["User"]!=null)
               hc.Session["User"]=null;
       }

       //取代构造函数
       public static User CreateInstance()
       {
           return new User();
       }

       void IUserManagement.Login(IUserInfo u)
       {
           this.Login(u.UserName, u.Password);
       }

       public void PersistInSession()
       {
           HttpContext hc = HttpContext.Current;
           if (hc.Session["User"] == null)
               hc.Session.Add("User", this);
           else
               hc.Session["User"] = this;
       }

       public IUserInfo GetFromSession()
       {
           HttpContext hc = HttpContext.Current;
           if(hc.Session["User"]==null)
               hc.Session.Add("User",User.CreateInstance());
           return hc.Session["User"] as IUserInfo;
       }

       public bool IsLogin
       {
           get { return m_IsLogin; }
           set { m_IsLogin = value; }
       }

       #endregion

       //填充实体类。这里又去数据库取了一次数据,有点浪费,
       //实际上可以在验证用户名密码的时候一起把数据取回来的。
       //但是懒得改了。
       public void GetUser(int UserID)
       {
           UserBr = new tbl_UserBR();
           try
           {
               tbl_UserDataSet UserDS = UserBr.GetByID(UserID);
               if (UserDS.tbl_User.Rows.Count > 0)
               {
                   tbl_UserRow userRow = (tbl_UserRow)
UserDS.tbl_User.Rows[0];
                   this.RealName = userRow.RealName;
                   this.UserName = userRow.UserName;
                   this.BizPosition = userRow.BizPosition;
                   this.Email = userRow.Email;
                   this.IdentityNumber = userRow.IdentityNumber;
               }
               else
               {
                   throw new ApplicationException("No User Found of ID:" +
UserID.ToString());
               }
           }
           catch (Exception exp)
           {
               throw exp;
           }
       }


       private User()
       {
           this.m_IsLogin = false;
           this.m_IsLoginSuccess=-1;
           UserBr=new tbl_UserBR();
       }


       private tbl_UserBR UserBr;

       private bool m_IsLogin;

       private int m_IsLoginSuccess;
   }

代码完。
使用这个User类,使得用户登录和注销的过程简单了很多。
验证用户登录的代码:
private IUserManagement u;
u = User.CreateInstance();
u.Login(txtUserName.Text, txtPassword.Text);
u.PersistInSession();
this.Response.Redirect("index.aspx");

注销的代码:
if(u==null)
   u=User.CreateInstance();
u.Logoff();
this.Response.Redirect("index.aspx");

Page_Load的代码:
           if (!Page.IsPostBack)
           {
               u = User.CreateInstance();
               IUserInfo uinfo = u.GetFromSession();
               if (uinfo.IsLoginSuccess == -1)
               {
                   //还未登录,显示默认首页。
                   return;
               }
               if (uinfo.IsLoginSuccess == 1)
               {
                   //登录成功,显示欢迎首页。
                   return;
               }
               if (uinfo.IsLoginSuccess == 0)
               {
                   //登录失败,显示失败提示。
                   return;
               }
           }

刚才测试了一下,功能没什么问题。
但是设计上还是有些不太满意。
talenTium建议说:
”但我觉得这养开销有点大
每次验证都要一个新User实例
可以考虑只加一个验证类,静态方法也可以”
我也觉得User类完全可以在全局范围内做成Signleton的。
还值得改进一下。

(转载)

 

一.前言:

存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。总的来说,存储过程具有以下一些优点:

◆存储过程允许标准组件式编程

◆存储过程能够实现较快的执行速度

◆存储过程能够减少网络流量

◆存储过程可被作为一种安全机制来充分利用

本文作者将向大家介绍.NET数据库应用程序中存储过程的应用,以及如何将它与ADO.NET中的SqlDataAdapter对象、DataSet对象等结合使用以提高.NET数据库应用程序的总体性能。

二.系统要求:

开发工具:Visual Studio.NET

数据库管理系统:SQL Server 2000(其中包含了示例程序所用到的Pubs数据库)

三.创建一个简单的存储过程:

这里我将向大家介绍如何运用Visual Studio.NET IDE来创建存储过程。运用Visual Studio.NET IDE创建存储过程是非常容易和直观的,你只要在服务器资源管理器中导向到Pubs数据库并展开节点,就会发现包括存储过程在内的各种数据库对象,如图1所示。
 

在存储过程节点上点击右键便可弹出一个菜单,其中包含了“新建存储过程”的命令。新建一个存储过程后,IDE中的代码编辑窗口便出现如下所示的代码模板:

 

CREATE PROCEDURE dbo.StoredProcedure1
/*
(
@parameter1 datatype = default value,
@parameter2 datatype OUTPUT )
*/
AS
/* SET NOCOUNT ON */
RETURN
 


上面的代码模板符合简化的创建存储过程的语法规则,完整的语法规则如下:

CREATE PROC [ EDURE ] procedure_name [ ; number ]
[ { @parameter data_type }
[ VARYING ] [ = default ] [ OUTPUT ]
] [ ,...n ]
[ WITH
{ RECOMPILE | ENCRYPTION | RECOMPILE , ENCRYPTION } ]
[ FOR REPLICATION ]
AS sql_statement [ ...n ]
 


限于篇幅,各个参数的含义在此就不多作介绍了,有兴趣的读者可以参考有关SQL Server 2000数据库管理系统的资料。

下面我对该代码模板中的各个语法成分略作介绍。CREATE PROCEDURE声明创建一个存储过程,后面跟着该存储过程的名称。“/*……*/”中的成分是该存储过程的参数,可包括输入参数和输出参数。AS关键字后面的内容是该存储过程的主体部分,其中是任何数量和类型的包含在存储过程中的SQL语句。RETURN关键字表明存储过程结束并能返回整型状态值给调用者。下面我们就来创建一个简单的不带参数的存储过程并运用之:

CREATE PROCEDURE dbo.up_GetPublisherInfo
AS
SELECT pub_id, pub_name, city, state, country
FROM publishers
RETURN


 

 

创建以上存储过程后,保存之。保存完毕,与该存储过程相对应的节点就会出现在服务器资源管理器中。同时请注意代码编辑窗口中的CREATE关键字变为ALTER关键字了,该关键字是用于更改任何现有的存储过程的。要运行上述存储过程,只要点击其节点并在右键弹出菜单中选择“运行存储过程”,运行的结果图示如下:

 

四.创建一个带参数的存储过程:

以上我们创建了一个简单的不带参数的存储过程,而在实际的应用中往往会用到很多带有参数的存储过程。带有参数的存储过程一般是用于更新数据或是插入数据的。下面我们可以运用同样的操作方法创建一个带参数的存储过程:

 

CREATE PROCEDURE dbo.up_UpdatePublisherInfo
(
@pub_id char (4),
@pub_name varchar (40),
@city varchar (20),
@state char (2),
@country varchar (30)
)
AS
UPDATE publishers
SET pub_name = @pub_name, city = @city, state = @state,
 country = @country
WHERE ( pub_id = @pub_id )
RETURN
 

 

在上面的创建存储过程的代码中,我们通过在名称前添加一个“@”标志来声明存储过程的局部变量-参数,同时还声明了各个参数的类型,确定了各个参数的方向值,也即表明该参数是输入型的还是输出型的或者是输入输出型的或者是返回值型的。用户通过相应的存储过程名称以及正确有效的参数便可调用该存储过程了。还有,你可以通过运用OUTPUT关键字在参数中添加输出型的参数,具体方法请参考上面的语法规则。输出型的参数能返回给调用者相关的信息。

上面的存储过程能更新publishers表中相应出版商的信息。你可以通过点击该存储过程的节点,在右键弹出菜单中选择“运行存储过程”来执行它。一旦执行,IDE中便弹出一个输入出版商信息的对话框(如图3所示)。在该对话框中填入正确有效的更新信息,注意pub_id的值在原来的表中必须存在,然后点击“确定”按钮便可更新数据了。

五.创建简单存储过程的数据库应用程序:

下面我们就运用上述的不带参数的存储过程来一个数据库应用程序,其中还用到了ADO.NET中的SqlDataAdapter对象以及DataSet对象。其中的SqlDataAdapter对象作为SQL Server数据库和DataSet对象的桥梁将两者联系在一起。SqlDataAdapter对象包含了两个常用的方法:Fill()方法和Update()方法。其中的Fill()方法能从数据库中获取相应数据并填充到DataSet对象中,而Update()方法顾名思义就是更新数据集的意思了。在调用Fill()方法以前,我们必须设置好SqlDataAdapter对象的SelectCommand属性,该属性其实是一个SqlCommand对象。SelectCommand属性中包含有效的SQL语句,并能据此从数据库中获取相应数据并填充到DataSet对象中。

首先,我们创建一个Windows Forms应用程序,编程语言为C#。在Visual Studio.NET中创建一个新的项目后,给该项目添加一个新的类-Publishers类,该类封装了连接到后台数据库并获取数据集对象的业务逻辑。步骤如下:

1.添加必要的命名空间引用:using System.Data.SqlClient;

2.给该类添加如下一些必要的变量:

private SqlConnection cnPubs;
private SqlCommand cmdPubs;
private SqlDataAdapter daPubs;
private DataSet dsPubs;
 


3.在该类的构造函数中完成连接后台数据库,获取SqlDataAdapter对象等业务逻辑:

public Publishers()
{
try
{
// 创建一个数据库连接对象
cnPubs = new SqlConnection( "server=localhost;integrated security=true;database=pubs" );
// 创建一个SqlCommand对象,并指明其命令类型为存储过程
cmdPubs = new SqlCommand();
cmdPubs.Connection = cnPubs;
cmdPubs.CommandType = CommandType.StoredProcedure;
cmdPubs.CommandText = "up_GetPublisherInfo";
// 创建一个SqlDataAdapter对象,设定其SelectCommand属性为上面的SqlCommand对象
daPubs = new SqlDataAdapter();
daPubs.SelectCommand = cmdPubs;
// 创建一个DataSet对象
dsPubs = new DataSet();
}
catch( Exception ) {}
}
 

4.最后为该类提供一个GetPublisherInfo()方法,该方法用SqlDataAdapter对象填充DataSet对象并返回填充后的DataSet对象,方法如下(值得注意的是:SqlDataAdapter对象会隐式地打开数据库连接并在获取数据后隐式地关闭连接,这就是说DataSet对象是工作在非连接模式下的。而当你显式地打开数据库连接并获取数据后,SqlDataAdapter对象并不会将该连接关闭):

public DataSet GetPublisherInfo()
{
// 调用SqlDataAdapter对象的Fill()方法并返回数据集对象
daPubs.Fill( dsPubs );
return dsPubs;
}
 

完成Publishers类的设计后,我们给主窗体添加一个DataGrid控件并用它来显示DataSet对象中的数据。首先给主窗体类添加如下成员变量:

private Publishers pubs;
private DataSet ds;
之后,修改主窗体类的构造函数如下:
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
// pubs = new Publishers();
ds = pubs.GetPublisherInfo();
dataGrid1.DataSource = ds.Tables[0];
}
 

这样该应用程序一启动主窗体的DataGrid控件中便显示了运用上述不带参数的存储过程从Pubs数据库中获取的相应数据,程序运行图示如下:

六.创建带参数的存储过程的数据库应用程序:

上面我们创建了一个不带参数的存储过程的应用程序,下面我们就来创建一个更加复杂的数据库应用程序。在实际的数据库应用中,我们往往需要获取数据并更新、插入或删除数据,这时我们就需要用到带有参数的存储过程了,同时在运用SqlDataAdapter对象时,我们会调用它的Update()方法。该Update()方法会自动根据DataSet对象中的DataTable对象内各条记录的变化情况完成相应操作。SqlDataAdapter对象还包含了UpdateCommand、InsertCommand、DeleteCommand等属性,这些属性其实都是SqlCommand对象。Update()方法会根据操作的类型选用相应的属性。

在运用带有参数的存储过程建立数据库应用程序时,我们一般都要用到SqlParameter类,该类封装了各种与Sql参数相关的属性和方法。其中的属性包括了ParameterName,SqlDBType,Direction,Size,Value,SourceColumn以及SourceVersion等。其中ParameterName,SqlDBType,Direction,Size等属性是用于匹配存储过程中定义的参数的。比如下面定义的SqlParameter对象就是用来匹配前面定义的up_UpdatePublisherInfo存储过程中的“@pub_id”参数的。

SqlParameter updParam = new SqlParameter( "@pub_id", SqlDbType.Char, 4 );

在上面的定义中,虽然Direction属性没有明确地给出,但是它的默认值为Input,所以也就满足了我们的需要。而如果一个SqlParameter对象的Direction属性为InputOutput或Output或ReturnValue,那么其Direction属性就必须明确地说明了,比如下面的代码就明确地声明了一个SqlParameter对象的Direction属性为Output。

oParam.Direction = ParameterDirection.Output;

其中的SourceColumn属性是用于匹配一个DataTable对象中的DataColumn对象的,这种匹配能在调用Update()方法更新DataTable对象时隐式地导入所需的SqlParameter对象。如果在定义时没有声明该属性,那么你必须在代码中显式地说明SqlParameter对象的SourceColumn属性。

其中的SourceVersion属性的默认值是DataRow对象相应字段中的当前值,也就是要更新到数据库中的值。当然,SourceVersion属性也可以指向DataRow对象相应字段中的原始值,也即从数据库中获取的初始值。在数据库事务处理系统中,数据的同步性问题非常重要,下面我们来建立一个能检测数据同步性的存储过程。

 

CREATE PROCEDURE dbo.up_UpdatePublisherName
(
@pub_id char(4),
@pub_name varchar(40),
@Original_pub_name varchar(40)
)
AS
if exists(select pub_id
 from publishers
where (pub_id = @pub_id) AND (pub_name = @Original_pub_name))
Begin
 UPDATE publishers SET pub_name = @pub_name
 WHERE (pub_id = @pub_id)
End
RETURN
 


接着,我们在上面的应用程序中调用该存储过程以更新发行商的名称。首先,在原有应用程序的基础上完善其业务逻辑类-Publishers类:

1.添加一个新的SqlCommand对象,该对象能作为SqlDataAdapter对象的 UpdateCommand属性被使用:
private SqlCommand cmdUpdPubs;
2.更新该类的构造函数Publishers()函数,添加以下内容:
// 创建另一个SqlCommand对象,该对象引用更新发行商名称的存储过程
cmdUpdPubs = new SqlCommand();
cmdUpdPubs.Connection = cnPubs;
cmdUpdPubs.CommandType = CommandType.StoredProcedure;
cmdUpdPubs.CommandText = "up_UpdatePublisherName";
// 为上面的SqlCommand对象添加必要的参数
cmdUpdPubs.Parameters.Add( "@pub_id", SqlDbType.Char, 4, "pub_id" );
cmdUpdPubs.Parameters.Add( "@pub_name", SqlDbType.VarChar, 40, "pub_name" );
SqlParameter updParam = new SqlParameter
( "@Original_pub_name", SqlDbType.VarChar, 40, "pub_name" );
updParam.SourceVersion = DataRowVersion.Original;
cmdUpdPubs.Parameters.Add( updParam );
3.指定SqlDataAdapter对象的UpdateCommand属性为上面定义的SqlCommand对象:
daPubs.UpdateCommand = cmdUpdPubs;
4.添加方法UpdatePublisherName():
public void UpdatePublisherName( DataSet dsChanges )
{
// 更新所有改动
daPubs.Update( dsChanges );
}
 


应用程序的业务逻辑类完善之后,在主窗体上添加一个名为“更新数据集”的按钮,并添加该按钮的事件响应函数如下:

private void button1_Click(object sender, System.EventArgs e) { if( ds.HasChanges() ) { pubs.UpdatePublisherName( ds.GetChanges() ); ds.Clear(); ds = pubs.GetPublisherInfo(); } } 


到此为止,应用程序的业务逻辑类和主窗体类都已经更新完毕,现在的应用程序能根据用户的改用更新数据库中的相关内容了。


七.总结:

本文向大家介绍了存储过程的基本知识以及在.NET数据库应用程序中如何结合SqlDataAdapter对象、DataSet对象等构建数据驱动的应用程序。在本文中,我们运用到了两类存储过程:一类为简单的不带参数的存储过程,其运用方法相对容易;另一类为带有参数的存储过程,在调用该类存储过程时还得运用到SqlParameter对象。同时,我们不难发现将数据更新业务逻辑封装在存储过程中是一种很好的设计方法,它能提高应用程序的可管理性、可扩展性以及数据库的安全性。类似的,插入数据以及删除数据的业务逻辑也可以封装在存储过程中并以相似的方法在应用程序中被运用。最后,希望本文对大家有不少帮助。
 

端口可分为3大类:
1) 公认端口(Well Known Ports):从0到1023,它们紧密绑定于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。
2) 注册端口(Registered Ports):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。
3) 动态和/或私有端口(Dynamic and/or Private Ports):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。但也有例外:SUN的RPC端口从32768开始。
  本节讲述通常TCP/UDP端口扫描在防火墙记录中的信息。记住:并不存在所谓ICMP端口。如果你对解读ICMP数据感兴趣,请参看本文的其它部分。
  0 通常用于分析操作系统。这一方法能够工作是因为在一些系统中“0”是无效端口,当你试图使用一种通常的闭合端口连接它时将产生不同的结果。一种典型的扫描:使用IP地址为0.0.0.0,设置ACK位并在以太网层广播。
  1 tcpmux 这显示有人在寻找SGI Irix机器。Irix是实现tcpmux的主要提供者,缺省情况下tcpmux在这种系统中被打开。Iris机器在发布时含有几个缺省的无密码的帐户,如lp, guest, uucp, nuucp, demos, tutor, diag, EZsetup, OutOfBox, 和4Dgifts。许多管理员安装后忘记删除这些帐户。因此Hacker们在Internet上搜索tcpmux并利用这些帐户。
  7 Echo 你能看到许多人们搜索Fraggle放大器时,发送到x.x.x.0和x.x.x.255的信息。
  常见的一种DoS攻击是echo循环(echo-loop),攻击者伪造从一个机器发送到另一个机器的UDP数据包,而两个机器分别以它们最快的方式回应这些数据包。(参见Chargen)
  另一种东西是由DoubleClick在词端口建立的TCP连接。有一种产品叫做“Resonate Global Dispatch”,它与DNS的这一端口连接以确定最近的路由。
  Harvest/squid cache将从3130端口发送UDP echo:“如果将cache的source_ping on选项打开,它将对原始主机的UDP echo端口回应一个HIT reply。”这将会产生许多这类数据包。
  11 sysstat 这是一种UNIX服务,它会列出机器上所有正在运行的进程以及是什么启动了这些进程。这为入侵者提供了许多信息而威胁机器的安全,如暴露已知某些弱点或帐户的程序。这与UNIX系统中“ps”命令的结果相似
  再说一遍:ICMP没有端口,ICMP port 11通常是ICMP type=11
  19 chargen 这是一种仅仅发送字符的服务。UDP版本将会在收到UDP包后回应含有垃圾字符的包。TCP连接时,会发送含有垃圾字符的数据流知道连接关闭。Hacker利用IP欺骗可以发动DoS攻击。伪造两个chargen服务器之间的UDP包。由于服务器企图回应两个服务器之间的无限的往返数据通讯一个chargen和echo将导致服务器过载。同样fraggle DoS攻击向目标地址的这个端口广播一个带有伪造受害者IP的数据包,受害者为了回应这些数据而过载。
  21 ftp 最常见的攻击者用于寻找打开“anonymous”的ftp服务器的方法。这些服务器带有可读写的目录。Hackers或Crackers 利用这些服务器作为传送warez (私有程序) 和pr0n(故意拼错词而避免被搜索引擎分类)的节点。
  22 ssh PcAnywhere建立TCP和这一端口的连接可能是为了寻找ssh。这一服务有许多弱点。如果配置成特定的模式,许多使用RSAREF库的版本有不少漏洞。(建议在其它端口运行ssh)
  还应该注意的是ssh工具包带有一个称为make-ssh-known-hosts的程序。它会扫描整个域的ssh主机。你有时会被使用这一程序的人无意中扫描到。
  UDP(而不是TCP)与另一端的5632端口相连意味着存在搜索pcAnywhere的扫描。5632(十六进制的0×1600)位交换后是0×0016(使进制的22)。
  23 Telnet 入侵者在搜索远程登陆UNIX的服务。大多数情况下入侵者扫描这一端口是为了找到机器运行的操作系统。此外使用其它技术,入侵者会找到密码。
  25 smtp 攻击者(spammer)寻找SMTP服务器是为了传递他们的spam。入侵者的帐户总被关闭,他们需要拨号连接到高带宽的e-mail服务器上,将简单的信息传递到不同的地址。SMTP服务器(尤其是sendmail)是进入系统的最常用方法之一,因为它们必须完整的暴露于Internet且邮件的路由是复杂的(暴露+复杂=弱点)。
  53 DNS Hacker或crackers可能是试图进行区域传递(TCP),欺骗DNS(UDP)或隐藏其它通讯。因此防火墙常常过滤或记录53端口。
  需要注意的是你常会看到53端口做为UDP源端口。不稳定的防火墙通常允许这种通讯并假设这是对DNS查询的回复。Hacker常使用这种方法穿透防火墙。
  67和68 Bootp和DHCP UDP上的Bootp/DHCP:通过DSL和cable-modem的防火墙常会看见大量发送到广播地址255.255.255.255的数据。这些机器在向DHCP服务器请求一个地址分配。Hacker常进入它们分配一个地址把自己作为局部路由器而发起大量的“中间人”(man-in-middle)攻击。客户端向68端口(bootps)广播请求配置,服务器向67端口(bootpc)广播回应请求。这种回应使用广播是因为客户端还不知道可以发送的IP地址。
  69 TFTP(UDP) 许多服务器与bootp一起提供这项服务,便于从系统下载启动代码。但是它们常常错误配置而从系统提供任何文件,如密码文件。它们也可用于向系统写入文件。
  79 finger Hacker用于获得用户信息,查询操作系统,探测已知的缓冲区溢出错误,回应从自己机器到其它机器finger扫描。
  98 linuxconf 这个程序提供linux boxen的简单管理。通过整合的HTTP服务器在98端口提供基于Web界面的服务。它已发现有许多安全问题。一些版本setuid root,信任局域网,在/tmp下建立Internet可访问的文件,LANG环境变量有缓冲区溢出。此外因为它包含整合的服务器,许多典型的HTTP漏洞可能存在(缓冲区溢出,历遍目录等)
  109 POP2 并不象POP3那样有名,但许多服务器同时提供两种服务(向后兼容)。在同一个服务器上POP3的漏洞在POP2中同样存在。
  110 POP3 用于客户端访问服务器端的邮件服务。POP3服务有许多公认的弱点。关于用户名和密码交换缓冲区溢出的弱点至少有20个(这意味着Hacker可以在真正登陆前进入系统)。成功登陆后还有其它缓冲区溢出错误。
  111 sunrpc portmap rpcbind Sun RPC PortMapper/RPCBIND。访问portmapper是扫描系统查看允许哪些RPC服务的最早的一步。常见RPC服务有:rpc.mountd, NFS, rpc.statd, rpc.csmd, rpc.ttybd, amd等。入侵者发现了允许的RPC服务将转向提供服务的特定端口测试漏洞。
  记住一定要记录线路中的daemon, IDS, 或sniffer,你可以发现入侵者正使用什么程序访问以便发现到底发生了什么。
  113 Ident auth 这是一个许多机器上运行的协议,用于鉴别TCP连接的用户。使用标准的这种服务可以获得许多机器的信息(会被Hacker利用)。但是它可作为许多服务的记录器,尤其是FTP, POP, IMAP, SMTP和IRC等服务。通常如果有许多客户通过防火墙访问这些服务,你将会看到许多这个端口的连接请求。记住,如果你阻断这个端口客户端会感觉到在防火墙另一边与e-mail服务器的缓慢连接。许多防火墙支持在TCP连接的阻断过程中发回RST,着将回停止这一缓慢的连接。
  119 NNTP news 新闻组传输协议,承载USENET通讯。当你链接到诸如:news://comp.security.firewalls/. 的地址时通常使用这个端口。这个端口的连接企图通常是人们在寻找USENET服务器。多数ISP限制只有他们的客户才能访问他们的新闻组服务器。打开新闻组服务器将允许发/读任何人的帖子,访问被限制的新闻组服务器,匿名发帖或发送spam。
  135 oc-serv MS RPC end-point mapper Microsoft在这个端口运行DCE RPC end-point mapper为它的DCOM服务。这与UNIX 111端口的功能很相似。使用DCOM和/或RPC的服务利用机器上的end-point mapper注册它们的位置。远端客户连接到机器时,它们查询end-point mapper找到服务的位置。同样Hacker扫描机器的这个端口是为了找到诸如:这个机器上运行Exchange Server吗?是什么版本?
  这个端口除了被用来查询服务(如使用epdump)还可以被用于直接攻击。有一些DoS攻击直接针对这个端口。
  137 NetBIOS name service nbtstat (UDP) 这是防火墙管理员最常见的信息,请仔细阅读文章后面的NetBIOS一节
  139 NetBIOS File and Print Sharing 通过这个端口进入的连接试图获得NetBIOS/SMB服务。这个协议被用于Windows“文件和打印机共享”和SAMBA。在Internet上共享自己的硬盘是可能是最常见的问题。
  大量针对这一端口始于1999,后来逐渐变少。2000年又有回升。一些VBS(IE5 VisualBasic Scripting)开始将它们自己拷贝到这个端口,试图在这个端口繁殖。
  143 IMAP 和上面POP3的安全问题一样,许多IMAP服务器有缓冲区溢出漏洞运行登陆过程中进入。记住:一种Linux蠕虫(admw0rm)会通过这个端口繁殖,因此许多这个端口的扫描来自不知情的已被感染的用户。当RadHat在他们的Linux发布版本中默认允许IMAP后,这些漏洞变得流行起来。Morris蠕虫以后这还是第一次广泛传播的蠕虫。
  这一端口还被用于IMAP2,但并不流行。
  已有一些报道发现有些0到143端口的攻击源于脚本。
  161 SNMP(UDP) 入侵者常探测的端口。SNMP允许远程管理设备。所有配置和运行信息都储存在数据库中,通过SNMP客获得这些信息。许多管理员错误配置将它们暴露于Internet。Crackers将试图使用缺省的密码“public”“private”访问系统。他们可能会试验所有可能的组合。
  SNMP包可能会被错误的指向你的网络。Windows机器常会因为错误配置将HP JetDirect remote management软件使用SNMP。HP OBJECT IDENTIFIER将收到SNMP包。新版的Win98使用SNMP解析域名,你会看见这种包在子网内广播(cable modem, DSL)查询sysName和其它信息。
  162 SNMP trap 可能是由于错误配置
  177 xdmcp 许多Hacker通过它访问X-Windows控制台,它同时需要打开6000端口。
  513 rwho 可能是从使用cable modem或DSL登陆到的子网中的UNIX机器发出的广播。这些人为Hacker进入他们的系统提供了很有趣的信息。
  553 CORBA IIOP (UDP) 如果你使用cable modem或DSL VLAN,你将会看到这个端口的广播。CORBA是一种面向对象的RPC(remote procedure call)系统。Hacker会利用这些信息进入系统。
  600 Pcserver backdoor 请查看1524端口
  一些玩script的孩子认为他们通过修改ingreslock和pcserver文件已经完全攻破了系统– Alan J. Rosenthal.
  635 mountd Linux的mountd Bug。这是人们扫描的一个流行的Bug。大多数对这个端口的扫描是基于UDP的,但基于TCP的mountd有所增加(mountd同时运行于两个端口)。记住,mountd可运行于任何端口(到底在哪个端口,需要在端口111做portmap查询),只是Linux默认为635端口,就象NFS通常运行于2049端口。
  1024 许多人问这个端口是干什么的。它是动态端口的开始。许多程序并不在乎用哪个端口连接网络,它们请求操作系统为它们分配“下一个闲置端口”。基于这一点分配从端口1024开始。这意味着第一个向系统请求分配动态端口的程序将被分配端口1024。为了验证这一点,你可以重启机器,打开Telnet,再打开一个窗口运行“natstat -a”,你将会看到Telnet被分配1024端口。请求的程序越多,动态端口也越多。操作系统分配的端口将逐渐变大。再来一遍,当你浏览Web页时用“netstat”查看,每个Web页需要一个新端口。
 ?ersion 0.4.1, June 20, 2000
  http://www.robertgraham.com/pubs/firewall-seen.html
  Copyright 1998-2000 by Robert Graham (mailto:firewall-seen1@robertgraham.com.
  All rights reserved. This document.nbspmay only be reproduced (whole or
in part) for non-commercial purposes. All reproductions must
contain this copyright notice and must not be altered, except by
permission of the author.
  1025 参见1024
  1026 参见1024
  1080 SOCKS
  这一协议以管道方式穿过防火墙,允许防火墙后面的许多人通过一个IP地址访问Internet。理论上它应该只允许内部的通信向外达到Internet。但是由于错误的配置,它会允许Hacker/Cracker的位于防火墙外部的攻击穿过防火墙。或者简单地回应位于Internet上的计算机,从而掩饰他们对你的直接攻击。WinGate是一种常见的Windows个人防火墙,常会发生上述的错误配置。在加入IRC聊天室时常会看到这种情况。
 ?114 SQL
  系统本身很少扫描这个端口,但常常是sscan脚本的一部分。
  1243 Sub-7木马(TCP)
  参见Subseven部分。
  1524 ingreslock后门
  许多攻击脚本将安装一个后门Sh*ll 于这个端口(尤其是那些针对Sun系统中Sendmail和RPC服务漏洞的脚本,如statd, ttdbserver和cmsd)。如果你刚刚安装了你的防火墙就看到在这个端口上的连接企图,很可能是上述原因。你可以试试Telnet到你的机器上的这个端口,看看它是否会给你一个Sh*ll 。连接到600/pcserver也存在这个问题。
  2049 NFS
  NFS程序常运行于这个端口。通常需要访问portmapper查询这个服务运行于哪个端口,但是大部分情况是安装后NFS 杏谡飧龆丝冢?acker/Cracker因而可以闭开portmapper直接测试这个端口。
  3128 squid
  这是Squid HTTP代理服务器的默认端口。攻击者扫描这个端口是为了搜寻一个代理服务器而匿名访问Internet。你也会看到搜索其它代理服务器的端口:8000/8001/8080/8888。扫描这一端口的另一原因是:用户正在进入聊天室。其它用户(或服务器本身)Q9750406也会检验这个端口以确定用户的机器是否支持代理。请查看5.3节。
  5632 pcAnywere
  你会看到很多这个端口的扫描,这依赖于你所在的位置。当用户打开pcAnywere时,它会自动扫描局域网C类网以寻找可能得代理(译者:指agent而不是proxy)。Hacker/cracker也会寻找开放这种服务的机器,所以应该查看这种扫描的源地址。一些搜寻pcAnywere的扫描常包含端口22的UDP数据包。参见拨号扫描。
  6776 Sub-7 artifact
  这个端口是从Sub-7主端口分离出来的用于传送数据的端口。例如当控制者通过电话线控制另一台机器,而被控机器挂断时你将会看到这种情况。因此当另一人以此IP拨入时,他们将会看到持续的,在这个端口的连接企图。(译者:即看到防火墙报告这一端口的连接企图时,并不表示你已被Sub-7控制。)
  6970 RealAudio
  RealAudio客户将从服务器的6970-7170的UDP端口接收音频数据流。这是由TCP7070端口外向控制连接设置的。
  13223 PowWow
  PowWow 是Tribal Voice的聊天程序。它允许用户在此端口打开私人聊天的连接。这一程序对于建立连接非常具有“进攻性”。它会“驻扎”在这一TCP端口等待回应。这造成类似心跳间隔的连接企图。如果你是一个拨号用户,从另一个聊天者手中“继承”了IP地址这种情况就会发生:好象很多不同的人在测试这一端口。这一协议使用“OPNG”作为其连接企图的前四个字节。
  17027 Conducent
  这是一个外向连接。这是由于公司内部有人安装了带有Conducent "adbot" 的共享软件。Conducent "adbot"是为共享软件显示广告服务的。使用这种服务的一种流行的软件是Pkware。有人试验:阻断这一外向连接不会有任何问题,但是封掉IP地址本身将会导致adbots持续在每秒内试图连接多次而导致连接过载:

机器会不断试图解析DNS名─ads.conducent.com,即IP地址216.33.210.40 ;216.33.199.77 ;216.33.199.80 ;216.33.199.81;216.33.210.41。(译者:不知NetAnts使用的Radiate是否也有这种现象)
  27374 Sub-7木马(TCP)
  参见Subseven部分。
  30100 NetSphere木马(TCP)
  通常这一端口的扫描是为了寻找中了NetSphere木马。
  31337 Back Orifice “elite”
  Hacker中31337读做“elite”/ei’li:t/(译者:法语,译为中坚力量,精华。即3=E, 1=L, 7=T)。因此许多后门程序运行于这一端口。其中最有名的是Back Orifice。曾经一段时间内这是Internet上最常见的扫描。现在它的流行越来越少,其它的木马程序越来越流行。
  31789 Hack-a-tack
  这一端口的UDP通讯通常是由于"Hack-a-tack"远程访问木马(RAT, Remote Access Trojan)。这种木马包含内置的31790端口扫描器,因此任何31789端口到317890端口的连接意味着已经有这种入侵。(31789端口是控制连接,317890端口是文件传输连接)
  32770~32900 RPC服务
  Sun Solaris的RPC服务在这一范围内。详细的说:早期版本的Solaris(2.5.1之前)将portmapper置于这一范围内,即使低端口被防火墙封闭仍然允许Hacker/cracker访问这一端口。扫描这一范围内的端口不是为了寻找portmapper,就是为了寻找可被攻击的已知的RPC服务。
  33434~33600 traceroute
  如果你看到这一端口范围内的UDP数据包(且只在此范围之内)则可能是由于traceroute。参见traceroute部分。
  41508 Inoculan
  早期版本的Inoculan会在子网内产生大量的UDP通讯用于识别彼此。参见
  http://www.circlemud.org/~jelson/software/udpsend.html
  http://www.ccd.bnl.gov/nss/tips/inoculan/index.html
(二) 下面的这些源端口意味着什么?
  端口1~1024是保留端口,所以它们几乎不会是源端口。但有一些例外,例如来自NAT机器的连接。参见1.9。
  常看见紧接着1024的端口,它们是系统分配给那些并不在乎使用哪个端口连接的应用程序的“动态端口”。
Server Client 服务 描述
  1-5/tcp 动态 FTP 1-5端口意味着sscan脚本
  20/tcp 动态 FTP FTP服务器传送文件的端口
  53 动态 FTP DNS从这个端口发送UDP回应。你也可能看见源/目标端口的TCP连接。
  123 动态 S/NTP 简单网络时间协议(S/NTP)服务器运行的端口。它们也会发送到这个端口的广播。
  27910~27961/udp 动态 Quake Quake或Quake引擎驱动的游戏在这一端口运行其服务器。因此来自这一端口范围的UDP包或发送至这一端口范围的UDP包通常是游戏。
  61000以上 动态 FTP 61000以上的端口可能来自Linux NAT服务器(IP Masquerade)

  在技术更新的进程中, 仍然有一些人死抱着已经过了气的东西不放. 也有一些人虽然进入到新的世界, 但仍摆脱不了陈旧的习惯. 我没有用”陋习”这个词, 因为我对这个词也非常反感.

  新技术应该有新技术的做法, 进入ASP.NET的世界, 就应该把以往的习惯改正, 全新的进入新的世界.

  以下列举的都是错误的做法, 请不要误以为是推荐的做法而进行推广:

  1. 使用server side include给ASPX引入共同的页面构图.
在ASP.NET的机制下, 应使用ASCX(web user control)来实现. ASCX提供了更多可控制接口. 并且更重要的是, ASCX是一个类. 一个实实在在的类. 可以全面控制它.

  2.不使用web.config
  web.config提供了非常丰富的配置管理接口. 是一个应用程序最核心的部分. 但是很多人的web.config往往是空的. 或者就从来没有修改过.

  3.使用Response.Write向前端输出消息
  ASP.NET平台下的Response和ASP的Response有很大的不同. 虽然表示同一含义, 但用法上已经大不相同. Response.Write的内容只会输出到页的最前端. 向前端输出消息的正确方法是使用PlaceHolder.

  4.使用一系列session管理用户连接状态
  这种方法在ASP里被滥用. 在ASP.NET环境下, 正确的做法应该是设计一个类. 结构化地保存数据. 将对session或者cookie的访问封装起来.

  5.使用session验证身份
  这几乎是通病. ASP.NET提供了一组用于用户身份验证的API. 类型是forms验证或者windows验证. 这一点quick start有一节讲解得很清楚. 可以绝大部分人还是依靠给session赋值来保持用户身份验证状态.

  6.使用Response.Redirect重定向页
  这一点在必要的时候可以使用. 但不可滥用. 事实证明滥用重定向将导致逻辑上的严重混乱. 这是在以页为程序单元的时候的做法. 使用front controller模式将使用户的操作逻辑集中起来]

  7.使用太多ASPX页
  ASP环境下的程序单元只有*.asp页, ASP.NET可不是这样, 还有后端的类库, ASCX等等. 应将业务逻辑分别集中在不同的单元, 而不应该一项操作使用一个ASPX. 更多时候ASPX将做为ASCX或者custom control的容器而管理页内逻辑. ASPX重用ASCX的同时, ASPX也做为统一的页构图重用.

  8.在多个逻辑单元之间复制代码并修改相应逻辑
重用. 重用. 重用. 处理此类问题的原则是不出现任何相同或相似的过程. 如果你用上面的方法, 一旦出现重大逻辑更改, 带来的结果将是灾难性的.

  9.害怕使用DataSet.
  很多人被DataSet吓坏了. 认为”肯定”影响性能. 但连最初的尝试都不敢. 他们总认为他们的产品一定重大, 设计上应该”慎重”. 他们往往使用ArrayList或者设计低级的类来保存集合数据. 进行艰难的数据倒入工作.

  10.对“性能”过多注意.
  对ASP.NET ViewState的机制特别不满. 或者总是挖空心思迫害人家. 反倒把自己弄得很累. 如果在对付ViewState的同时多注意少连几次数据库也许更文明些.

  11.应用程序根目录很乱.
  ASP.NET是开发项目. 不是网站. 应该把不同的资源分类放置. 例如把所有静态资源(样式表, 脚本, 图像)组织到一起. 甚至可以写一组API来管理他们. ASPX应该放在一起. ASCX应该放在一起. .*.cs呢? 应该把他们放到另外一个project里.

  12.不厌其烦的写访问数据库的过程
应该把这工作交给DataAccess Application Block. 你自己还要开关connection, 何苦呢.

  13.自己写的东西最靠得住.
  事实往往正好相反. 多注意使用人家写好的产品. 又不收你钱, 何苦那么爱面子呢.

  14. 胡乱命名ASPX文件名
  这是最让人痛苦的了. ASPX文件名不仅需要容易识别. 还应该遵循一定规则. 因为behind每个ASPX都会有一个同名的类, 想象一下, 多难受. 另外大部分人不知道管理自己的项目的name space. 让人好像看到一本帐一样.

  15.从来不作继承或派生
  一些具有相同行为的类, 应该从公共的基类派生出来. 实际意义上, 我们的ASPX应该有一个基类PageBase. 因为总有一些公共的特性需要抽象出来.

  16.零property
  他们的类(ASPX所对应)里只有private method. 不公开自己的任何秘密. 可以这一定是JAVA的遗老干的事.

  17. 零ASCX
  不用说, 他还没学会ASP.NET

  18.使用DreamWeaver“画“ASPX
  这批人是美工. 甚至有一些人在非常陶醉地讨论如何更好地“整合“ DreamWeaver和Visual Studio.

  19.只熟悉System.Web.UI.WebControl和System.Data.SqlClient应该还有一些值得熟悉的类库.

  20.零注释
  这些都是心里很明白的快手. 一任IDE生成的缺省注释横在那里不管.

  21.零事件
  对“事件驱动“一无所知. 只知道在Page_Load()里写过程. 或者双击一个按钮写Xxx_Clock()过程. 在他们的程序里看不到event和delegate.

(转载)

2005年03月31日
在 ASP.NET 中使用代码隐藏方法来设计Web 窗体,可使页代码能够更清晰地从 HTML 内容中分离到完全单独的文件中。
通常一个 @page 指令如下:

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="WebApplication1.WebForm1" %>

其中有三个属性(Inherits、Src、CodeBehind)非常容易混淆,下面分别给予说明。

Inherits

Inherits 属性用于定义当前 Web 窗体所继承的代码隐藏类(该类是 System.Web.UI.Page 的派生类)。
这个 inherits 属性只用于采用代码隐藏方式编写的 Web 窗体,也就是,如果你的代码全都是在 Web 窗体的 
<script runat="server"></script> 标签中,就不必用这个属性了。 

Src

Src 属性用于指定“代码(隐藏)文件”在文件系统中的位置,以便于 ASP.NET Framework 用 Just-In-Time (JIT) 
编译器动态编译 Web 窗体时能够找到它。用 Inherits 指明的类,就是放在这个类代码(隐藏)文件中。
通常 ASP.NET Framework 使用这些类时,首先会到已编译的程序集中查找,
如果找不到就会把在 Src 属性中提供的代码文件重新编译,所以 Src 属性和 Inherits 属性并不互斥。

需要说明的是,Visual Studio .NET 并不使用 Src 属性,
这就意味着 Visual Studio .NET 总是指望你用“生成”菜单中的生成操作来产生已编译的程序集
(通常是编译成DLL放在\bin目录中,这样一来,在发布应用系统时,就可以不用发布源代码了),
而以后不会发生需要动态编译的情况。所以如果你是在 Visual Studio .NET IDE 中开发的话,
要时常注意用“重新生成”功能来编译发生变动的类,否则,将会发生诸如找不到类呀什么的一系列问题。

Codebehind

呵呵,Codebehind 属性并不是一个真正的 ASP.NET 属性,在ASP.NET 文档中是找不到它的。
它其实只是一个 Visual Studio .NET 属性,
Visual Studio .NET 就是借用这个属性来很好地跟踪管理项目中的 Web 窗体和与之相对的代码隐藏文件,
比如当你在设计环境中往 Web 窗体上放入一个服务器控件时,
Visual Studio .NET 将自动找到与该 Web 窗体相对应的代码隐藏文件,并自动插入相关的代码。
因此,用 Visual Studio .NET 作开发时,不可轻率地将 Codebehind 属性换成 Src 属性,他们的功能作用不同。
2005年03月13日

我当前所吃的东东都固定为食物,所以一点也不惊讶,这一周的主题为cookies。

 
Cookies用于存储特定用户信息,它提供了Web程序中一种有用的方式。多年以来,JavaScript开发人员已经进行了有关cookie的大量工作。同样,ASP.NET通过System.Web空间名称也提供了cookie的访问。虽然你不应该使用cookie来存储一些敏感性的数据,但是,它们是处理锁细数据的一个极好的选择,比如颜色参数选择或者最后一次访问日期。

传递cookies
cookie是存储在客户端计算机的一个小文件。如果你是一个Windows用户,可以在用户路径中查看Cookies路径,即为Documents And Settings路径。这一路径包含这一文件名称的文本文件:

username @ Web site domain that created the cookie

(用户名称@建立cookie的站点域名)

.NET System.Web空间名称包含三个类,你可以使用它们来处理客户端的Cookies:

HttpCookie:提供一个建立和操作独立HTTP cookies的安全类型的方式。

HttpResponse:Cookies属性允许客户端cookies被操作。

HttpRequest:Cookies属性允许访问客户端操作的cookies。

HttpResponse和HttpRequest对象的Cookies属性将返回一个HttpCookieCollection对象,它包含着,将单独的cookies添加到集合(collection)中,以及从集合(collection)获得一个单独的cookies。

HttpCookie类
HttpCookie类针对于客户存储之用而建立的单独cookies。一旦HttpCookie对象被建立,你可以将其添加到HttpResponse对象的Cookies属性中。同样的,你可以通过HttpRequest对象访问现有的cookies。HttpCookie类包含以下的公有属性:

Domain(域名):获得或设置与cookie有关的域名,可用于限制特定区域的cookie访问。

Expires(期限):获得或设置cookie的终止日期和时间,你可以将其设置为一个过去的日期以自动终止或者删除cookie。

Names(名称):获得或设置cookie名称。

Path(路径):获得或设置cookie的虚拟路径。这一属性允许你限制cookie范围,也就是说,访问cookie只能限制于一个特定的文件夹或者路径。设置这一属性限制为只能访问特定路径和该路径下的所有文件。

Secure(安全):发信号以表示是否使用Secure Sockets Layer (SSL)来发送cookie值。

Value(值):获得或设置一个单独的cookie值。

Values(信息):返回包含在cookie中的key/value的一个集合。

虽然这些还不是一个最详尽的列表,但它提供了处理cookies所需要的东西。对于这些属性的使用,以下VB.NET范例给予最好的理解:

Dim testCookie As New HttpCookie(“LastVisited”)

testCookie.Value = DateTime.Now.ToString

testCookie.Expires = DateTime.Now.AddDays(7)

testCookie.Domain = “builder.com”

Response.Cookies.Add(testCookie)

这一代码段建立了一个名为LastVisited的新的cookie,并赋予当前日期和时间的值。同样的,cookie终止期限设置为一个星期,相关的范围为populated。一旦建立对象,通过Response.Cookies对象的Add方法就可以将对象添加到客户端的cookies集合。HttpCookie构造函数中的方法有两种:

HttpCookie objectName = New HttpCookie(“cookieName”)

HttpCookie objectName = New HttpCookie(“cookieName”, “cookieValue”)

同样,Response对象包含一个SetCookie方法,这一方法可以接受一个HttpCookie对象。

我的cookie在哪里?
一旦cookies被保存在客户端,有多种不同的方法以提供你访问它们。如果你知道cookie名称,可以使用HttpResponse对象很容易地访问它的值。以下VB.NET行显示了与cookie有关的值:

 
 

Response.Write(Request.Cookies(“LastVisitied”).Value)

 

除此之外,可以通过一个HttpCookieCollection对象访问cookies的完整列表。这就使得cookie列表可以用一个for循环来访问。以下C#代码说明了这样的例子:

HttpCookieCollection cookies;

HttpCookie oneCookie;

cookies = Request.Cookies;

string[] cookieArray = cookies.AllKeys;

for (int i=0; I < cookieArray.Length; i++) {

oneCookie = cookies[cookieArray[i]];

Response.Write(oneCookie.Name + ” – ” + oneCookie.Value);

}

 

VB.NET中相应的代码如下:

 

Dim i As Integer

Dim oneCookie As HttpCookie

For i = 0 To Request.Cookies.Count – 1

oneCookie = Request.Cookies(i)

Response.Write(oneCookie.Name + ” – ” + oneCookie.Value)

Next I

稳定也是一个观点
cookie文件存放在客户端机器,所以你的用户可以任意删除或更改。此外,用户还可以使cookies无效化。基于此原因,请记住不要依赖cookie数据。你应该将重要的信息保存在服务器──特别是一个数据库中。

在一个cookie中存储关键信息被认为是一种低级的程序设计,因为这些信息很容易被泄露,原因是这些信息位于客户机器的一个文件中。在这一点,一种方法就是使用SSL,这是一种可以避免敏感信息的更好方法。

 

我可以使用cookies吗?
用户可以在自己的浏览器上无效化cookie支持。你可以在自己的代码中访问这些设置以决定是否支持cookies。Request对象满足了这一想法,以下VB.NET代码显示了这一过程:

 

If Request.Browser.Cookies = True Then

‘ 使用cookies

Else

‘没有cookie支持

End If

 

可以联合代码来使用cookie值。以下C#代码段对cookie支持进行了测试,并相应地将结果显示在一个文本框:

if (Request.Browser.Cookies == true)

{

if (Request.Cookies["LastVisited1"] == null)

{

HttpCookie newCookie = new HttpCookie(“LastVisited1″,DateTime.Now.ToString());

newCookie.Expires = DateTime.Now.AddYears(1);

Response.Cookies.Add(newCookie);

this.txtName.Text = “Is this your first time?”;

} else {

this.txtName.Text = “We haven’t seen you since ” +

 Request.Cookies["LastVisited1"].Value;

}  }

 

你可以将这一代码段添加到ASP.NET页中的Page_Load事件。

保存数据的另一方式
ASP.NET提供了保存特定用户数据的多种方法。其中一个老方法就是cookies。对于敏感数据,虽然cookies不是最好的方法,但它是诸如颜色参数选择、最后一次访问日期等亲和力选项(benign items)的最佳选择。虽然这些敏感数据重要,但当用户的计算机崩溃时数据丢失,这也不是世界的末日。