<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    網站開發

    asp.net
    隨筆 - 30, 文章 - 0, 評論 - 9, 引用 - 0
    數據加載中……

    置頂隨筆

    [置頂]解決downlist 等優先極高于其它控件,浮在其它控件上面

     <iframe style="position:absolute;z-index:9;width:expression(this.nextSibling.offsetWidth);height:expression(this.nextSibling.offsetHeight);top:expression(this.nextSibling.offsetTop);left:expression(this.nextSibling.offsetLeft);" frameborder="0" ></iframe>
      <div id="divTool" onmouseover="javascript:showdiv123()" onmouseout="javascript:HiddivTool()" class="class_title"  style="display:none">
    <table width="100" border="0"  align="center" cellpadding="0" cellspacing="0">
      <tr>
        <td height="20" colspan="2" bgcolor="ffffff" style="width: 100px" >&nbsp;&nbsp;<span class="t1" style="cursor:hand" name="layout/AddPage.aspx" onclick="javascript:openMyPage(this)">More tools</span></td>
      </tr>
      <tr>
        <td height="20" colspan="2"  bgcolor="ffffff"  style="width: 100px">&nbsp;&nbsp;<a href="#">About this tools</a></td>
      </tr><tr>
        <td height="8" colspan="2" bgcolor="ffffff" style="width: 100px"></td>
      </tr>
     
      </table>
    </div>

    posted @ 2007-12-26 14:35 風雨兼程 閱讀(328) | 評論 (0)編輯 收藏

    [置頂]IList GetCategories();的問題

    petshop4.0中的一段代碼  
       
      public   interface   ICategory   {  
       
      ///   <summary>  
      ///   Method   to   get   all   categories  
      ///   </summary>  
                      ///   <returns>Interface   to   Model   Collection   Generic   of   categories</returns>  
                 
                     
      IList<CategoryInfo>   GetCategories();  
                     
       
                      ///   <summary>  
                      ///   Get   information   on   a   specific   category  
                      ///   </summary>  
                      ///   <param   name="categoryId">Unique   identifier   for   a   category</param>  
                      ///   <returns>Business   Entity   representing   an   category</returns>  
                      CategoryInfo   GetCategory(string   categoryId);  
      }  
       
       
      我知道IList<CategoryInfo>是范型  
      表示list中的item是CategoryInfo對象  
       
       
      請問為什么用IList<CategoryInfo>  
      用List<CategoryInfo>可以嗎?  
       
      兩者有什么區別?謝謝  

    沒有什么區別,這樣寫靈活性大,實現ilist接口的類很多,你寫成list后,也許以后你要改成非list的,就會要改很多代碼
    舉個例子  
       
      RenderControlToString(DataList   L//Control   C)  
       
      你認為是寫control還是寫datalist代碼的通用性高?

      OOP編碼原則:盡可能用接口編程

    posted @ 2007-12-26 11:44 風雨兼程 閱讀(471) | 評論 (0)編輯 收藏

    [置頂]關于sqlhelper.cs

    public abstract class SqlHelper
              {
                  public static readonly string connectionString = ConfigurationManager.ConnectionStrings["SqlConnString"].ConnectionString;
            
                  SqlConnection conn;

                  #region open SqlConnection
                  public static void Open() {
                       conn = new SqlConnection(connectionString);
                       if (conn.State != ConnectionState.Open)
                          conn.Open();
                  }    
                  #endregion

                  #region close SqlConnection
                  public static void Close() {
                      if (conn != null)
                      {
                          conn.Close();
                          conn.Dispose();
                      }
                  }        
                  #endregion

                  #region prepare SqlCommand
                  private static void PrepareCommand(SqlCommand cmd, CommandType cmdType, string cmdText, SqlParameter[] cmdParms) {
                      Open();
                      cmd.Connection = conn;
                      cmd.CommandType = cmdType;
                      cmd.CommandText = cmdText;

                      if (cmdParms != null)
                      {
                          foreach (SqlParameter parm in cmdParms)
                              cmd.Parameters.Add(parm);
                      }
                  }
                  #endregion

                  #region parm cache
                  /*
                   使用一個哈希表來保存緩存的參數 只緩存參數名
                   哈希表的特點:一個鍵對應一個值key對value(為object需要類型轉化)        不能出現兩個相同的鍵 否則error
             
                   下面的哈希表parmCache定義為static即一次定義全局使用
                   所以可能會出現有人在讀的時候,有人在寫,一般會用Lock就像Asp中用Application["count"]來統計點擊數一樣
                   要先鎖后解鎖
                   但.net框架提供了Synchroized          sync和syncroize中文意思 同步,同時發生
                   來提供這一操作
                  */
                  private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());

                  public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters) {
                      parmCache[cacheKey] = commandParameters;
                  }

                  /*
                  1、為何要克隆呢 為何不直接return cachedParms
             
                  有一個參數數組
                  SqlParameter[] parms={
                  new SqlParameter("@num1",SqlDbType.Int,4),
                  new SqlParameter("@num2",SqlDbType.Int,4)
                  }
                  緩存該數組
                  用戶a和b都執行插入操作
                  a用戶插入了1,1
                  b用戶插入了2,2
                  如果不用克隆的話,參數數組只有一份
                  而2個用戶需要根據不同的情況賦于不同的值
                  所以就用了克隆了
            
                  2、(ICloneable)cachedParms[i]先將HashTable轉為ICloneable這樣HashTable就具有了Clone()克隆方法了
                  克隆一份后是什么類型呢,,當然要強制轉化為(SqlParameter)了
                  最后將它賦值給clonedParms[i]
                  */       
                  public static SqlParameter[] GetCachedParameters(string cacheKey) {
                      SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];

                      if (cachedParms == null)
                          return null;
                      SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];

                      for (int i = 0; i < cachedParms.Length; i++)
                          clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();

                      return clonedParms;
                  }
                  #endregion        
            
                  //below method support sqltext and procedure

                  #region ExecuteReader
                  /*
                   parms的作用,這也是一個知識點
                   舉例:
                   ExecuteReader(*,*,null)成功運行
                   ExecuteReader(*,*,new SqlParameter(*))成功運行
                   ExecuteReader(*,*,new SqlParameter(*),new SqlParameter(*))成功運行
                   ExecuteReader(*,*,{new SqlParameter(*),new SqlParameter(*),})成功運行
                   它讓參數類型和參數個數任意
                   這可給了不是一般的好處,你不必為SqlParameter和SqlParameter[]進行重載,寫上兩個函數
                   又為null寫上一個函數,因為null會不明確調用SqlParameter的函數還是SqlParameter[]的函數
                   啥你不知道我在說什么,打屁屁,那回去看看c++的函數重載
                   */
                  public static SqlDataReader ExecuteReader(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {
                
                      SqlCommand cmd = new SqlCommand();

                      try {
                          PrepareCommand(cmd, null, cmdType, cmdText, commandParameters);
                          SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                          cmd.Parameters.Clear();
                          return rdr;
                      }
                      catch {
                          Close();
                          throw;
                      }
                  }
                  #endregion

                  #region ExecuteNonQuery
                  public static void ExecuteNonQuery(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {

                      SqlCommand cmd = new SqlCommand();

                      PrepareCommand(cmd, cmdType, cmdText, commandParameters);
                      cmd.ExecuteNonQuery();
                      cmd.Parameters.Clear();

                      Close();
                  }
                  #endregion

                  #region ExecuteScalar
                  public static object ExecuteScalar(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {

                      SqlCommand cmd = new SqlCommand();

                      PrepareCommand(cmd, cmdType, cmdText, commandParameters);
                      object val = cmd.ExecuteScalar();
                      cmd.Parameters.Clear();

                      Close();
                      return val;
                  }
                  #endregion


              }
    }

    posted @ 2007-12-26 10:30 風雨兼程 閱讀(904) | 評論 (0)編輯 收藏

    2008年1月4日

    提高網站在Google中的排名 ——面向搜索引擎的網站設計

    Google排名優化-面向搜索引擎的網站設計


    內容摘要:
    目前中文網站在整個互聯網中的影響還比較小,這主要是由于中文網站總體的水平(技術上,內容上)都還相對落后造成的,最主要的表現有:

    1. 行業知識:不知道搜索引擎對吸引的新用戶的重要性,在搜索引擎排名服務中追求“傻瓜相關”,購買一些其實沒有太多實際意義的行業關鍵詞。其實能夠用戶輸入的關鍵詞越多,其目標性越強,這樣的客戶價值越高。用戶能夠直接定位到產品具體內容頁比到網站首頁有價值的多;
    2. 發布技術:網站的網頁進入Google的索引量非常小,主要是由于大量使用動態網頁造成的。需要將動態頁面鏈接改寫成靜態鏈接
    3. 頁面設計:頁面標題重復,關鍵詞不突出,過渡使用JavaScript腳本/圖片/Flash等不適合搜索引擎索引的非文本形式;
    而以上這些問題的根本原因還是網站自身缺乏日志統計分析造成:因此無法看到SEO對網站自身產生的巨大影響。

    SEO的目的是通過一些簡單的策略,讓網站自身的水平在互聯網中有一個真實的體現。
    網站結構設計中面向搜索引擎的優化注意事項包括:

    (注意:本網站設計本身就利用了其中一些方法)。

    什么是PageRank

    Google等新一帶搜索引擎的優勢之一在于不僅索引量很大,而且還將最好的結果排在搜索結果的最前面,具體的原理可以參考Google の秘密 - PageRank 徹底解説一文,PageRank簡單的說類似于科技論文中的引用機制:誰的論文被引用次數多,誰就是權威。在互聯網上PageRank就是基于網頁中相互鏈接關系的分析得出的。

    此外,從計算方法角度闡述PageRank機制還有這篇文章:http://pr.efactory.de/里面有更詳細的PageRank算法說明和各種清晰的小型個案分析:

    比如:子頁中導航條的重要性
    B <=> A => C  
    Vs  
    B <=> A <=> C   (好)

    頁面數量因素:
    B <=> A <=> C
    Vs
    F <=\   /=> G
    B <=> A <=> C   (好)
    D <=/   \=> E

    一個意想不到的結論:
    (B <=> A <=> C)      ( E <=> D <=> F)
    Vs
    (B <=> A <=> C)  <=> ( E <=> D <=> F)
    PageRank升高的只是被鏈接的2個首頁A和D,而網站子頁面的PageRank平均會略有下降。同時:一個網站進入Google的索引量越大其受類似因素影響越小。
    PageRank不對稱的頁面互鏈:
    Google會用BadRank之類的算法進行糾正,而且一個網頁著有來自“與其自身不相稱”的高PageRank站點的鏈接,而自身又缺少足夠數量和質量的反相鏈接的話,其PageRank會自動降低為0,A(pr=7) <=> B(pr=0)
    簡單的說就是:偶爾要被權威站點反相鏈接不算數,要被足夠多的權威站點引用才能提高自身網頁的PageRank。
    Web超鏈分析算法綜述(南京大學論文) 更多論文可以通過搜索:“filetype:pdf google pagerank anchor text bayesian”得到

    鏈接就是一切

    在互聯網的海洋中,最重要的就是互聯互通,不被其他網站引用的網站就是“信息孤島”。“酒好也怕藏的深”,也許這話說起來有點像垃圾郵件廣告,但事實就是這樣。所以如果做網站的目的不是孤芳自賞,就需要積極的推廣自己的網站。
    通過搜索引擎推廣自己需要注意以下幾個方面:

    1. 以量取勝:不一定加入傳統門戶網站的分類目錄才是網站推廣,來自其他網站的任何反相鏈接都是有用的
      網站推廣比較經典的方式就是加入比較大型門戶網站的分類目錄,比如:Yahoo!dmoz.org等。其實這里有一個誤區:不一定非要加入大型網站的分類目錄才是網站推廣,因為現在搜索引擎已經不再只是網站目錄的索引,而是更全面的網頁索引,所以無論來自其他網站任何地方的反相鏈接都是非常有價值的,哪怕是出現在新聞報道,論壇,郵件列表歸檔中。Blogger(Weblog的簡稱)們也許最深刻地理解了“鏈接就是一切”這句話的含義,由于Blog的內容之間有大量的相互鏈接(他們之間利用RSS很容易進行鏈接大量傳播),因此最經常被引用的Blog頁面在搜索引擎中的排名往往比一些大型商業網站的頁面還要高。而WIKI這樣的文檔管理系統更加突出了良好結構,良好引用的特征。而目前很多網站通過在各種WIKI/留言簿中灌注垃圾留言的方法,這種方式是非常不可取的。這種鏈接不穩定:
    2. 以質取勝:被PageRank高的網站引用能更快地提高PageRank
      數量只是關鍵因素之一,來自PageRank高的頁面的鏈接還能更快的提高被鏈接目標的PageRank,我只是將一些文章投稿在了ZDNet中國上,由于頁面上有文章出處鏈接,相應網頁和網站整體的PageRank過了一段時間后就有了很大的提升。有時候被什么樣的網站引用有時候比引用次數多更重要。這里我要特別感謝的是,當時ZDNet中國是唯一遵循了我的版權聲明的要求表明了文章出處,并且有反相鏈接的網站。
      按照這個原則:能夠名列Yahoo!和DMOZ這樣的大型權威目錄的頭2層是非常有價值的。
    3. 了解搜索引擎的"價值觀":
      Lucene簡介這篇文章被Jakarta.apache.org的lucene項目引用以后,這篇文章就成為了所有頁面中PageRank最高的頁面,而Google支持的一些項目,比如:Folding@Home,讓我一直懷疑他們對政府,教育和非盈利組織的站點有特別加分,畢竟.org .edu才代表了互聯網的實質:分權和共享。
      但更合理的解釋是:.org很多都是開放技術平臺的開發者,他們會在首頁這樣的地方加入Powered By Apache, Power by FreeBSD之類的鏈接表示對其他開源平臺的尊重,所以象Apache, PHP, FreeBSD這樣的開源站點在GOOGLE中都有非常高的PageRank。而在.edu這些站點中,很多都是學術性比較強的文檔,以超鏈接形式標明參考文獻的出處已經成為一種習慣,而這也無疑正是PageRank最好的依據。
      注意:不要通過Link Farm提高自身的站點排名:Google會懲罰那些主動鏈接到Link Farm站點以提高自身排名站點,相應站點的頁面將不會被收入到索引中。但如果你的頁面被別的Link Farm鏈接了也不必擔心,因為這種被動的鏈接是不會被懲罰的。
    4. 不要吝嗇給其他網站的鏈接:如果一個網頁只有大量的進入鏈接,而缺乏導出鏈接,也會被搜索引擎認為是沒有價值的站點。保證你的網站能夠幫助搜索引擎更準確地判斷哪些是對用戶最有價值的信息,也就是說如果你的網站只有外部反向鏈接而沒有導出鏈接的話,也會對你的網站在搜索結果中的表現帶來負面影響。當然網站中連一個導出鏈接都沒有的情況非常罕見,除非你是刻意這么做。正常情況下大家都會自然地在網頁中加上一些其他網站的鏈接,帶領訪問者去到我們認為重要或能夠提供更多有價值信息的地方,

    另外在推廣自己網站之前也許首先需要了解自己網站目前在一些搜索引擎中的知名度,原理非常簡單,可以參考如何評價網站的人氣一文。

    網站推廣只是手段,如何突出內容、讓需要相關信息的用戶能夠盡快的找到你的網站才是目的,PageRank高并不代表像Yahoo!這樣的門戶站點就能在所有搜索結果中排名靠前,因為搜索引擎的結果是搜索關鍵詞在頁面中的匹配度和頁面的PageRank相結合的排名結果。因此第二個要點:如何突出關鍵詞。

    如何突出關鍵詞:面向主題(Theme)的關鍵詞匹配

    1.  Theme Engine正在逐步超過PR,成為結果排序中更主要的因素,可以比較一下以下現象:
      • 為什么查“新聞”,“汽車”之類的文字,各種門戶網站的首頁不在第一位?要知道他們的頁面中都有相應頻道的鏈接文字的
      • 一篇新聞頁面中,搜索引擎如何不通過模板匹配,自動將新聞的主體和頁面中的頁頭,欄目導航條,頁尾等部分的內容區分開的?
      其實以上問題都可以歸結為網頁內容摘要的提取策略和關鍵詞在其中的命中:
      首先將能夠描述一個頁面內容的分成以下幾種類型:
      1. 鏈入文字描述:inbound link text
        http://www.searchenginedictionary.com/terms-inbound-link.shtml
      2. HTML頁面標題:title 好標題一般會將頁面中最重要的關鍵詞放在最前面,比如:ABC-10型吸塵器 - XX家電城
      3. HTML內容主體:content text
      4. 鏈出文字:outbound link text
      如果按照以下規則:
      一個頁面中關鍵詞命中權重:鏈入文字 > HTML標題文字 > HTML頁面主體內容 >> 出鏈文字,以上現象就比較好解釋了。
      鏈入文字是頁面上看不見的,但鏈入文字對被鏈接頁面有巨大的作用:在現代搜索引擎在關鍵詞匹配的過程中,匹配的過程不只看當前頁面的內容摘要:很大程度上,不只看這個網頁自己說自己有什么內容,還要看別人如何鏈接時,如何描述你的網站別人怎么稱呼你,比你自己說自己更重要。。
      比如查:“世界衛生組織”,返回結果中有 http://www.who.int/ 而這個頁面中是沒有中文的,之所以能匹配上,是因為很多鏈接它的中文網站使用了:<a >世界衛生組織</a>,所以,這個頁面中不存在的中文關鍵詞也成為了頁面摘要的一部分。這樣一想,就可以知道鏈出鏈接的文字其實是為被鏈接的子頻道首頁或者內容詳情頁服務的。對自身頁面的關鍵詞密度只有負面的影響,這也是Google建議一個頁面中鏈接不要超過100個的原因:他根本不索引100個鏈接以后的內容。按照以上規則,搜索引擎將一篇新聞詳情頁中的新聞內容提取出來就是把頁面上所有帶HTTP鏈接的文字都去掉,就是新聞的內容部分了,更精確一些可以通過取最長文本段落等策略實現;而很多網站首頁或頻道首頁中幾乎全部都是鏈接,經過搜索引擎分析的結果就是:什么內容也沒有,能夠被命中的關鍵詞僅僅是別人鏈接你用的“網站首頁”和頻道標題Title中的站點名稱等的幾個關鍵詞,而頁面中其他的文字則遠遠不如相應子頻道和具體內容頁面的匹配度高,而搜索引擎能夠通過以上規則,讓用戶更快的直接定位到有具體內容的內容詳情頁面。因此希望通過一個首頁,盡可能多的命中所有希望推廣的關鍵詞是不可能的。讓網頁盡可能多的進入搜索引擎的索引,然后把握好整個網站的主題風格是非常重要的,讓網站的主題關鍵詞能夠比較均勻的按照金字塔模式分布到網站中可以參考:網站的主題金字塔設計          網站名稱(用戶通過1-2個抽象關鍵詞)
               /       \
          子頻道1   子頻道2 (用戶通過2-3個關鍵詞命中)
         /    \      /    \
      產品1  產品2 文章1 文章2 (用戶通過3-4個關鍵詞命中:這種用戶最有價值)

    2. 不要空著標題:空著<title></title>無異于浪費了最有價值的一塊陣地;
      不要使用meta keywords/description
      傳統的頁面中,HTML頁面中會有類似以下的隱含信息,用于說明當前網頁的主要內容關鍵字:
      <header>
          <meta name="keyword" content="mp3 download music...">
      </header>
      后來由于這種人工添加關鍵詞的方式被濫用,大量網頁中為了提高被搜索引擎命中的概率,經常添加一些和實際網頁內容無關的熱門關鍵比如:“music mp3 download”等,所以新一代的搜索引擎已經不再關心頁面頭文件中的人工meta keyword聲明,而頁面標題在搜索引擎的關鍵詞的命中命中過程中往往有著更高的比重,如果一個關鍵詞在標題中命中會比在頁面中命中有更高的得分,從而在相應的搜索結果排名中更靠前。
    3. 標題長度和內容:不要過長,一般在40個字(80個字節)以內,并充分突出關鍵詞的比重;
      如果更長的標題搜索引擎一般會忽略掉,所以要盡可能將主要關鍵詞放在標題靠前的位置。省略掉不必要的形容詞吧,畢竟用戶主要通過名詞來找到需要的內容。標題內容:盡量用一些別人可以通過關鍵詞找到的字眼(也別太過頭,如果標題中的字眼超過1半內容中都沒有,有可能被搜索引擎排除出索引),因此基于web日志中來自其他搜索引擎的關鍵詞查詢統計非常必要。
    4. 如果網頁很多的話,盡量使用不同的網頁標題,爭取讓自己網站的內容更多的進入搜索引擎索引范圍;
      因為搜索引擎會根據頁面內容的相似度把一些內容當成重復頁面排除出索引范圍;
      http://www.chedong.com/phpMan.php是我的網站上的一個小應用:一個web界面的unix命令手冊(man page),在以前的設計中所有動態頁面使用的都是同樣的標題:"phpMan: man page /perldoc /info page web interface" ,Google索引了大約3000多個頁面,后來我將頁面標題改成了"phpMan:  [命令名]"這樣的格式,比如:"phpMan: ls",這樣大部分動態頁面的標題就都不一樣了,一個月后Google從這個頁面入口索引了大約6000個頁面。因此,如果網站中很多網頁都使用相同的標題,比如:“新聞頻道”,“論壇”,這些頁面中很大一部分就會被排重機制忽略掉。
    5. 除了<title></title>外,還可以用<h1></h1>標題行突出內容主題,加強標題的效果;
      在我的網站設計中:我會把用<h1>[標題]</h1>這樣的模板把標題突出顯示,而不是通過改變字體的方式突出標題。

    其他網站設計提示

    1. 靜態鏈接:Blog網站另外一個優勢在于其網頁是靜態鏈接:動態網頁占到整個互聯網內容的90%以上。各個搜索引擎其實能夠表現的都只不過是互聯網的冰山一角(3-5%),不同的只是誰讓優質網頁排名靠前的策略更優秀而已:大部分搜索引擎都認為靜態鏈接的網頁是優質網頁,Google在優先抓取索引的網頁中70%以上是不帶參數鏈接的靜態網頁。而且即使同樣的內容,靜態網頁也會比動態網頁權重高:很容易理解:query?a=1&b=2這樣的鏈接由于參數順序顛倒的query?b=2&a=1完全相同。盡量使用靜態網頁:目前能夠動態網頁進行全面的索引還比較難,而即使是Google也更不會索引所有的內容,因此很少會對參數超過2個的動態網頁進行進一步的抓取和分析。以下是一個phpBB論壇頁面返回的HTTP頭信息:
      HTTP/1.1 200 OK
          Date: Wed, 28 Jan 2004 12:58:54 GMT
          Server: Apache/1.3.29 (Unix) mod_gzip/1.3.26.1a PHP/4.3.4
          X-Powered-By: PHP/4.3.4
          Set-Cookie: phpBB_data=a%3A0%3A%7B%7D; expires=Thu, 27-Jan-2005 12:58:54 GMT; path=/;
          Set-Cookie: phpBB_sid=09f67a83ee108ecbf11e35bb6f36fcec; path=/;
          Content-Encoding: gzip
          Cache-Control: private, pre-check=0, post-check=0, max-age=0
          Expires: 0
          Pragma: no-cache
          Connection: close
          Content-Type: text/html
          
      為了避免隱私問題:Googlebot可以通過對頁面http header中的session id和session cookie進行一些甄別,這樣很多需要認證信息的論壇內容就無法進入索引了。
      總體上說Google喜歡新的,靜態的內容。因此無論從效率上講還是方便搜索引擎收錄:使用內容發布系統將網站內容發布成靜態網頁都是非常必要的,從某種程度上說google friendly = anonymous cache friendly。
      比如:http://www.chedong.com/phpMan.php/man/intro/3
      比http://www.chedong.com/phpMan.php?mode=man&parameter=intro&section=3這樣的鏈接更容易進入搜索引擎的索引。而且在URL中的命中也能突出關鍵詞。
    2. 能夠進入Google索引的頁面數量越多越好。用類似以下的腳本可以統計自己的網站被搜索引擎索引的情況。
      #!/bin/sh
          YESTERDAY=`date -d yesterday +%Y%m%d`
          # for FreeBSD: YESTERDAY=`date -v-1d +%Y%m%d`
          LOG_FILE='/home/apache/logs/access_log'
          grep -i Googlebot $LOG_FILE.$YESTERDAY|awk '{print $7}' |sort | uniq -c | sort -rn > spider/$YESTERDAY.googlebot.txt
          grep -i baiduspider $LOG_FILE.$YESTERDAY|awk '{print $7}' |sort | uniq -c | sort -rn > spider/$YESTERDAY.baiduspider.txt
          grep -i msnbot $LOG_FILE.$YESTERDAY|awk '{print $7}' |sort | uniq -c | sort -rn > spider/$YESTERDAY.msnbot.txt
          grep -i inktomi $LOG_FILE.$YESTERDAY|awk '{print $7}' |sort | uniq -c | sort -rn > spider/$YESTERDAY.inktomi.txt
          grep -i openbot $LOG_FILE.$YESTERDAY|awk '{print $7}' |sort |uniq -c | sort -rn > spider/$YESTERDAY.openbot.txt
          
    3. 網站目錄結構要扁平,因為每深一級目錄,PAGERANK降低1-2個檔次。假設首頁是3,其子可能目錄就是1了,更深可能就無法列入評級范圍了。
    4. 表現和內容的分離:“綠色”網頁
      網頁中的javascript和css盡可能和網頁分離,一方面提高代碼重用度(也方便頁面緩存),另外一方面,由于有效內容占網頁長度的百分比高,也能提高相關關鍵詞在頁面中的比重也增加了。總之,應該鼓勵遵循w3c的規范,使用更規范的XHTML和XML作為顯示格式便于內容更長時間的保存。
    5. 讓所有的頁面都有能夠快速入口:站點地圖,方便網頁爬蟲(spider)快速遍歷網站所有需要發布的內容。如果首頁就是用Flash或圖片進入的話,無異于將搜索引擎拒之門外,除了UI設計的用戶友好外,spider friendly也是非常重要的。
    6. 保持網站自身的健康:經常利用壞鏈檢查工具檢查網站中是否有死鏈。
    7. 保持網頁內容/鏈接的穩定性和持久性:在搜索引擎索引中網頁存在的歷史也是一個比較重要的因素,而且歷史比較久的網頁被鏈接的幾率越高。為了保證自己網頁能夠被比較持久的被其他網站的頁面引用,如果自己網頁中有鏈接更新時,最好能保留舊的頁面并做好鏈接轉向,以保持內容的連續性。要知道,把一個網站和內容在搜索引擎中的排名“培養”的很高是一件非常不容易的事情,誰都不希望好不容易自己的內容被別人找到了,點擊卻是“404 頁面不存在”吧,因此站點管理員對自身站點error.log的分析也是非常必要的。
    8. 文件類型因素:Google有對PDF, Word(Power Point, Excel), PS文檔的索引能力,由于這種文檔的內容比一般的HTML經過了更多的整理,學術價值一般比較高,所以這些類型的文檔天生就比一般的HTML類型的文檔 PageRank要高。因此,對于比較重要的文檔:技術白皮書,FAQ,安裝文檔等建議使用PDF PS等高級格式存取,這樣在搜索結果中也能獲得比較靠前的位置。
    9. 常常能發現門戶站點的一條新聞往往比其他站點的首頁排名還要靠前。因此一個站點總體PageRank提高了以后,往往自身一些并不重要的內容也會被同那些高PageRank的內容一起帶入被搜索引擎優先查詢的列表中。這樣經常造成很多大的開發站點的郵件列表歸檔往往比其他站點的首頁PageRank還要高。

    知己知彼——站點訪問統計/日志分析挖掘的重要性

    網站設計不僅僅只是被動的迎合搜索引擎的索引,更重要是充分利用搜索引擎帶來的流量進行更深層次的用戶行為分析。目前,來自搜索引擎關鍵詞統計幾乎是各種WEB日志分析工具的標準功能,相信商業日志統計工具在這方面應該會有更強化的實現。WEB日志統計這個功能如此重要,以至于新的RedHat 8中已經將日志分析工具webalizer作為標準的服務器配置應用之一。

    以Apache/webalizer為例,具體的做法如下:
    1. 記錄訪問來源:
      在Apache配置文件中設置日志格式為combined格式,這樣的日志中會包含擴展信息:其中有一個字段就是相應訪問的轉向來源: HTTP_REFERER,如果用戶是從某個搜索引擎的搜索結果中找到了你的網頁并點擊過來,日志中記錄的HTTP_REFERER就是用戶在搜索引擎結果頁面的URL,這個URL中包含了用戶查詢的關鍵詞。
    2. 在webalizer中缺省配置針對搜索引擎的統計:如何提取HTTP_REFERER中的關鍵詞
      webalizer中缺省有針對yahoo, google等國際流行搜索引擎的查詢格式:這里我增加了針對國內門戶站點的搜索引擎參數設置
      SearchEngine yahoo.com p=
      SearchEngine altavista.com q=
      SearchEngine google.com q=
      SearchEngine    sina.com.cn word=
      SearchEngine    baidu.com   word=
      SearchEngine    sohu.com    word=
      SearchEngine    163.com q=

    通過這樣設置webalizer統計時就會將HTTP_REFERER中來自搜索引擎的URL中的keyword提取出來,比如:所有來自 google.com鏈接中,參數q的值都將被作為關鍵詞統計下來:,從匯總統計結果中,就可以發現用戶是根據什么關鍵詞找到你的次數,以及找到你的用戶最感興趣的是那些關鍵詞等,進一步的,在webalizer中有設置還可以將統計結果倒出成CSV格式的日志,便于以后導入數據庫進行歷史統計,做更深層次的數據挖掘等。

    以前通過WEB日志的用戶分析主要是簡單的基于日志中的訪問時間/IP地址來源等,很明顯,基于搜索引擎關鍵詞的統計能得到的分析結果更豐富、更直觀。因此,搜索引擎服務的潛在商業價值幾乎是不言而喻的,也許這也是Yahoo! Altavista等傳統搜索引擎網站在門戶模式后重新開始重視搜索引擎市場的原因,看看Google的年度關鍵詞統計就知道了,在互聯網上有誰比搜索引擎更了解用戶對什么更感興趣呢?

    請看本站的反相鏈接統計:http://www.chedong.com/log/2003_6.log
    需要注意的是:由于Google針對Windows 2000中的IE使用的是UTF-8方式的編碼,因此很多統計有時候需要在UTF-8方式下查看才是正確字符顯示。從統計中能夠感受到:在使用水平比較高的IT開發人員中Google已經成為最常用的搜索引擎。而使用百度的用戶也已經大大超過了傳統的搜狐,新浪等門戶站點,因此傳統門戶網站在搜索引擎上的優勢將是非常脆弱的。而從技術的發展趨勢來看,以后還會有更多的利用互聯網媒體做更深層次數據挖掘的服務模式出現:

     

    轉載自cnblog.org——“突發”文字可能揭示社會趨勢

    在“新科學家”(New Scientist)在線雜志上,公布了康奈爾大學的一個新研究成果,引人注目,也許與Google 收購Pyra 的動機有關。

    這所大學的計算機科學家 Jon Klenberg 開發了一個計算機算法,能夠識別一篇文章中某些文字的“突發”增長,而且他發現,這些“突發”增長的文字可以用來快速識別最新的趨勢和熱點問題,因此能夠更有效地篩選重要信息。過去很多搜索技術都采用了簡單計算文字/詞組出現頻率的方法,卻忽略了文字使用增加的速率。

    Jon 特別指出,這種方法可以應用到大量Weblog上,以跟蹤社會趨勢,這對商業應用也很有潛力。例如,廣告商可以從成千上萬的個人Blog 中快速找到潛在的需求風尚。而且只要Blog 覆蓋話題范圍足夠大(實際上發展趨勢確實如此),這項技術對政治、社會、文化和經濟等領域也都會有實際意義了。

    雖然Google 新聞的內部算法至今沒有公開,但是人們猜測這種完全由機器所搜集的頭條新聞應當不是Google搜索引擎中慣用的鴿子算法,很可能與這種“突發”判斷算法有關。如此說來,Google收購Blog工具供應商的舉動確實還有更深層次的遠見了

    - NewScientist.com news,
    - 還沒有寫完這些介紹,在 SlashDot 上也看到了很多有關這個發現的討論

    附:Google官方的站點設計指南

    • Make a site with a clear hierarchy and text links. Every page should be reachable from at least one static text link.  讓網站有著清晰的結構和文本鏈接,所有的頁面至少要有一個靜態文本鏈接入口
      批注:盡量不要用圖片和JAVASCRIPT
    • Offer a site map to your users with links that point to the important parts of your site. If the site map is larger than 100 or so links, you may want to break the site map into separate pages.
      為用戶提供一個站點地圖:轉向網站的重要部分。如果站點地圖頁面超過100個鏈接,則需要將頁面分成多個頁面。
      批注:索引頁不要超過100個鏈接:SPIDER只考慮頁面中頭100個鏈接
    • Create a useful, information-rich site and write pages that clearly and accurately describe your content.
      用一些有用的,信息量豐富的站點,清晰并正確的描述你的信息。
    • Think about the words users would type to find your pages, and make sure that your site actually includes those words within it.
      想像用戶可能用來找到你的關鍵詞,并保證這些關鍵詞在網站中出現。
      批注:少用“最大”,“最好”之類的形容詞,用用戶最關心的詞,比如:下載,歌星名字,而不是一些抽象名詞。
    • Try to use text instead of images to display important names, content, or links. The Google crawler doesn't recognize text contained in images.
      盡可能使用文本,而不是圖片顯示重要的名稱,內容和鏈接。GOOGLE的機器人不認識圖片中的文字。
    • Make sure that your TITLE and ALT tags are descriptive and accurate.
      保證:頁面的TITLE和ALT標記正確的精確描述
    • Check for broken links and correct HTML.
      檢查壞鏈并修正這些HTML錯誤。
    • If you decide to use dynamic pages (i.e., the URL contains a '?' character), be aware that not every search engine spider crawls dynamic pages as well as static pages. It helps to keep the parameters short and the number of them small.
      如果你打算使用動態頁面:鏈接中包含"?",必須了解:并非所有的搜索引擎的機器人能想對待靜態頁面一樣對待動態頁面,保持動態頁面的參數盡可能的少也會很有幫助。
    • Keep the links on a given page to a reasonable number (fewer than 100).
      讓一個頁面中的鏈接少于100個。
      批注:用lynx -dump http://www.chedong.com 可以模擬從robot角度看到的頁面。其最后有鏈接統計

    輸出類似:

       [1]Google Free Search _______________________________ Google Search
       (_) Search WWW (_) Search chedong.com

       更 新 [2]站點地圖 / Site Map [3]留 言簿 / Guest Book [4]意見反饋 /
       Feed Back
        ...
    References

       Visible links
       1. http://www.google.com/services/free.html
       2. http://www.chedong.com/sitemap.html#sitemap
       3. http://www.chedong.com/guestbook/
       4. http://www.chedong.com/formmail.htm
        ...
       Hidden links:
      50. http://www.chedong.com/bbcweb/
        ...

    搜索引擎的宗旨在于提取互聯網中質量最好的內容提供給用戶,任何有利于幫助用戶獲得相對公正,優質內容的策略都是搜索引擎追求目標。PageRank是一個非常好的策略,但是并非所有策略都是基于非常復雜的算法。
    從搜索引擎看來什么是互聯網中“好”的內容呢?

    • 首先:互聯網大約是8G個網頁,而且以每天2M的速度增長的。其中80%以上是動態網頁,而占總量20%的靜態網頁就是一個相對比較簡單的過濾規則。
    • 其次:用戶友好(User friendly)也是很重要的方面,搜索引擎利用算法幫助提升這些優質網站,包括:通過CSS將內容和表現分離:較少的javascript和frame結構,spider本身也很難深入抓取這些網頁:Javascript和frame結構大部分是廣告。
    • 標題明確:無標題,重復標題或者標題SPAM(類似于:游戲游戲游戲游戲游戲游戲這樣的標題)進行過濾或降低得分頁面大小:因為頁面過大會導致用戶下載緩慢,所以很多引擎只計算頁面大小在100k以內的網頁。
    • 鏈接引用:不僅需要有鏈接鏈入,也需要幫助用戶找到其他更有價值的內容;
    • 文件類型:PDF和DOC等專業文檔和來自edu,gov等非贏利網站的內容;
    • 鏈入網站的文字:所有用戶不可見的因素全部被忽略。此外:用戶搜索的行為本身也被Google記錄,可能對目標網站的主題相關度有幫助。

     

    參考資料:

    面向Google搜索引擎的網站設計優化
    http://www.google-search-engine-optimization.com/



    如何評價一個網站的人氣
    http://www.chedong.com/tech/link_pop_check.html

    如何提高網站在Google中的排名——面向搜索引擎的廣告模式
    http://www.chedong.com/tech/google_ads.html

    如何提高網站在Google中的排名——面向搜索引擎的網站鏈接設計
    http://www.chedong.com/tech/google_url.html

    Google不斷改進相應的算法:HillTop
    Hilltop: A Search Engine based on Expert Documents

    Google の秘密 - PageRank 徹底解説
    http://www.kusastro.kyoto-u.ac.jp/~baba/wais/pagerank.html
    這篇文章是在查"Google PageRank"的時候查到的,這篇文章不僅有一個算法說明,也是一個Google的weblog,記錄了很多關于Google的新聞和一些市場動態信息。
    Google 的秘密- PageRank 徹底解說 中文版

    更詳細的PageRank算法說明:
    http://pr.efactory.de/

    WEB日志統計工具AWStats的使用:增加了Unicode的解碼和中國主要門戶搜索的定義
    http://www.chedong.com/tech/awstats.html

    Robots的說明:
    http://bar.baidu.com/robots/
    http://www.google.com/bot.html
    搜索引擎通過一種程序robot(又稱spider),自動訪問互聯網上的網頁并獲取網頁信息。您可以在您的網站中創建一個純文本文件 robots.txt,在這個文件中聲明該網站中哪些內容可以被robot訪問,哪些不可以。

    反Google站點:觀點也很有趣
    http://www.google-watch.org/

    關于Google的WebLog
    http://google.blogspace.com/

    關于Google的HillTop算法

    搜索引擎相關論壇
    http://searchengineforums.com/
    http://searchenginewatch.com
    http://www.webmasterworld.com/

    posted @ 2008-01-04 09:43 風雨兼程 閱讀(262) | 評論 (0)編輯 收藏

    2008年1月2日

    開發電子商務網站對數據庫表的設計

    系統分析

      功能需求分析

      (1):產品展示,按照分類展示全部產品,和對應的相關信息。

      (2):增加產品的展示相關度,諸如最新產品報道,網站的新聞,促銷信息。

      (3):購物車,跟蹤用戶的購物情況

      (4):結算中心:處理用戶帳單,購物處理

      (5):反饋互動區,可以留言

      (6):會員信息模塊,可以注冊

      數據需求分析

      數據庫表設計定為8個表實現:

      ccdot_user{用戶信息表}:

      ------szd_userid[PK]

      ------szd_username[用戶ID]

      ------szd_password[用戶密碼]

      ------szd_name[用戶真是信息]

      ------szd_question[丟失密碼問題]

      ------szd_answer[用戶回答答案,用于找密碼]

      ------szd_sex[性別]

      ------szd_phone[電話]

      ------szd_email[電子郵件]

      ------szd_address[地址]

      ------szd_post[郵編]

      ------szd_province[省份]

      ------szd_city[城市]

      ------szd_mark[標記]

      ccdot_aclass{產品大類}

      ------szd_aclassid[PK]

      ------szd_aclassname[名稱]

      ccdot_bclass{產品小類}

      ------szd_bclassid[pk]

      ------szd_aclassid[關聯大類szd_aclassid]

      ------szd_bclassname[名稱]

      ccdot_poduct{產品信息}

      ------szd_productid[pk]

      ------szd_bclassid[關聯小類的szd_bclassid]

      ------szd_pname[名稱]

      ------szd_pdetail[產品信息]

      ------szd_pprice[一般價格]

      ------szd_pmemderprice[會員價]

      ------szd_pfewprice[差價]

      ------szd_ppicture[圖片]

      ------szd_ptime[添加時間]

      ------szd_stock[產品庫存]

      ------szd_phit[產品點擊次數]

      ------szd_pdetail1[其他產品描述]

      ccdot_news{新聞}

      ------szd_newsid[PK]

      ------szd_title[標題]

      ------szd_content[內容]

      ------szd_time[添加時間]

      ------szd_type[類型]

      ccdot_guest{評論}

      ------szd_gid[PK]

      ------szd_gname[昵稱]

      ------szd_gcontent[留言內容]

      ------szd_productid[關聯產品的主鍵]

      ------szd_gtime[留言時間]

      ------szd_gip[留言者ip]

      ccdot_orderlist{訂單列表}

      ------szd_orderlistid[PK]

      ------szd_orderid[關聯詳細訂單的主鍵]

      ------szd_productid[關聯產品的主鍵]

      ------szd_quantity[所定數目]

      ------szd_unitcost[單價]

      ------szd_productname[產品名稱]

      ccdot_orders{訂單信息表}

      ------szd_orderid[PK]

      ------szd_userid[關聯用戶主鍵]

      ------szd_orderdate[訂單日期]

      ------szd_linkman[聯系人]

      ------szd_email[聯系人email]

      ------szd_phone[聯系電話]

      ------szd_postalcode[送貨處郵編]

      ------szd_address[送貨地址]

      ------szd_result[處理結果]

      ------szd_remark[備注]

      ------szd_songhuoqixian[送貨期限]

      ------szd_songhuofangshi[發貨方式]

      ------szd_fukuanfangshi[付款方式]

      ------szd_error[意外說明]

    posted @ 2008-01-02 15:20 風雨兼程 閱讀(351) | 評論 (0)編輯 收藏

    2007年12月26日

    petshop4.0設計說明asp.net初學者

    petshop4.0設計說明
    一、項目名稱及描述:(實現步驟為:4-3-6-5-2-1)
    1、WEB=表示層
    2、BLL=業務邏輯層
    3、IDAL=數據訪問層接口定義
    4、Model=業務實體
    5、DALFactory=數據層的抽象工廠(創建反射)
    6、SQLServerDAL=SQLServer數據訪問層 / OracleDAL=Oracle數據訪問層

    DBUtility 數據庫訪問組件基礎類

    二、項目引用關系
    1、Web 引用 BLL。
    2、BLL 引用 IDAL,Model,使用DALFactory創建實例。
    3、IDAL 引用 Model。
    4、Model 無引用。
    5、DALFactory 引用IDAL,通過讀取web.config里設置的程序集,加載類的實例,返回給BLL使用。
    6、SQLServerDAL 引用 Model和IDAL,被DALFactory加載的程序集,實現接口里的方法。


    三、實現步驟
    1、創建Model,實現業務實體。
    2、創建IDAL,實現接口。
    3、創建SQLServerDAL,實現接口里的方法。
    4、增加web.config里的配置信息,為SQLServerDAL的程序集。
    5、創建DALFactory,返回程序集的指定類的實例。
    6、創建BLL,調用DALFactory,得到程序集指定類的實例,完成數據操作方法。
    7、創建WEB,調用BLL里的數據操作方法。

    注意:
    1、web.config里的程序集名稱必須與SQLServerDAL里的輸出程序集名稱一致。
    2、DALFactory里只需要一個DataAccess類,可以完成創建所有的程序集實例。
    3、項目創建后,注意修改各項目的默認命名空間和程序集名稱。
    4、注意修改解決方案里的項目依賴。
    5、注意在解決方案里增加各項目引用。

    posted @ 2007-12-26 17:05 風雨兼程 閱讀(1565) | 評論 (0)編輯 收藏

    Getting Real 讀書筆記

    無論是創業還是做項目,無論是單機軟件還是 Web app,都需要遵循的就是滿足需求

    需求和開發的矛盾,至少在我看來,是產品開發中的主要矛盾。提需求的覺得產品沒有滿足需求,開發的覺得需求不明確或者胡來。最后的結果,要么是產品延期,要么是個破爛

    是否有一些方法或者經驗,可以指導我們更成功地開發 Web app 呢?或者不僅僅是開發,還包括設計,推廣,人事……作為創業或者實踐的一整套指導

    這就是我想推薦給大家的《Getting Real》。

    Getting Real 是著名的 37signals 公司(Ruby on Rails 的締造者)去年撰寫的一本書,主要內容是指導小型公司/團體成功地商業運作起 Web 產品,提供了包括相關理念,思路,人員,技術,方法論,實例等等許多信息,非常適合 Web 開發人員,產品人員和創業者參考。

    書專注于以下幾點:
    1. 成功的商業產品,以客戶利益和感受至上。
    2. 小型的團隊,高靈活性和適應性。
    3. 精簡的產品,夠用好用的功能。
    4. 高效的設計和開發過程,杜絕浪費時間,減少需求和開發的矛盾。
    5. 巧妙的推廣和售后支持。
    ……

    posted @ 2007-12-26 15:12 風雨兼程 閱讀(259) | 評論 (0)編輯 收藏

    層隨著鼠標移動

    var c = document.getElementById("divTool");
     c.style.position = "absolute";
     var eT = obj.offsetTop; 
        var eH = obj.offsetHeight+eT; 
     c.style.left = window.event.clientX-event.offsetX+document.documentElement.scrollLeft-20;
        c.style.top = window.event.clientY-event.offsetY+document.documentElement.scrollTop+eH-8;


     c.style.display = "block";

    posted @ 2007-12-26 14:44 風雨兼程 閱讀(563) | 評論 (0)編輯 收藏

    解決downlist 等優先極高于其它控件,浮在其它控件上面

     <iframe style="position:absolute;z-index:9;width:expression(this.nextSibling.offsetWidth);height:expression(this.nextSibling.offsetHeight);top:expression(this.nextSibling.offsetTop);left:expression(this.nextSibling.offsetLeft);" frameborder="0" ></iframe>
      <div id="divTool" onmouseover="javascript:showdiv123()" onmouseout="javascript:HiddivTool()" class="class_title"  style="display:none">
    <table width="100" border="0"  align="center" cellpadding="0" cellspacing="0">
      <tr>
        <td height="20" colspan="2" bgcolor="ffffff" style="width: 100px" >&nbsp;&nbsp;<span class="t1" style="cursor:hand" name="layout/AddPage.aspx" onclick="javascript:openMyPage(this)">More tools</span></td>
      </tr>
      <tr>
        <td height="20" colspan="2"  bgcolor="ffffff"  style="width: 100px">&nbsp;&nbsp;<a href="#">About this tools</a></td>
      </tr><tr>
        <td height="8" colspan="2" bgcolor="ffffff" style="width: 100px"></td>
      </tr>
     
      </table>
    </div>

    posted @ 2007-12-26 14:35 風雨兼程 閱讀(328) | 評論 (0)編輯 收藏

    在PetShop 4.0中ASP.NET緩存的實現

    PetShop作為一個B2C的寵物網上商店,需要充分考慮訪客的用戶體驗,如果因為數據量大而導致Web服務器的響應不及時,頁面和查詢數據遲遲得不到結果,會因此而破壞客戶訪問網站的心情,在耗盡耐心的等待后,可能會失去這一部分客戶。無疑,這是非常糟糕的結果。因而在對其進行體系架構設計時,整個系統的性能就顯得殊為重要。然而,我們不能因噎廢食,因為專注于性能而忽略數據的正確性。在PetShop 3.0版本以及之前的版本,因為ASP.NET緩存的局限性,這一問題并沒有得到很好的解決。PetShop 4.0則引入了SqlCacheDependency特性,使得系統對緩存的處理較之以前大為改觀。

    4.3.1  CacheDependency接口

    PetShop 4.0引入了SqlCacheDependency特性,對Category、Product和Item數據表對應的緩存實施了SQL Cache Invalidation技術。當對應的數據表數據發生更改后,該技術能夠將相關項從緩存中移除。實現這一技術的核心是SqlCacheDependency類,它繼承了CacheDependency類。然而為了保證整個架構的可擴展性,我們也允許設計者建立自定義的CacheDependency類,用以擴展緩存依賴。這就有必要為CacheDependency建立抽象接口,并在web.config文件中進行配置。

    在PetShop 4.0的命名空間PetShop.ICacheDependency中,定義了名為IPetShopCacheDependency接口,它僅包含了一個接口方法:
    public interface IPetShopCacheDependency
    {      
        AggregateCacheDependency GetDependency();
    }

    AggregateCacheDependency是.Net Framework 2.0新增的一個類,它負責監視依賴項對象的集合。當這個集合中的任意一個依賴項對象發生改變時,該依賴項對象對應的緩存對象都將被自動移除。
    AggregateCacheDependency類起到了組合CacheDependency對象的作用,它可以將多個CacheDependency對象甚至于不同類型的CacheDependency對象與緩存項建立關聯。由于PetShop需要為Category、Product和Item數據表建立依賴項,因而IPetShopCacheDependency的接口方法GetDependency()其目的就是返回建立了這些依賴項的AggregateCacheDependency對象。

    4.3.2  CacheDependency實現

    CacheDependency的實現正是為Category、Product和Item數據表建立了對應的SqlCacheDependency類型的依賴項,如代碼所示:
    public abstract class TableDependency : IPetShopCacheDependency
    {
        // This is the separator that's used in web.config
        protected char[] configurationSeparator = new char[] { ',' };

        protected AggregateCacheDependency dependency = new AggregateCacheDependency();
        protected TableDependency(string configKey)
        {
            string dbName = ConfigurationManager.AppSettings["CacheDatabaseName"];
            string tableConfig = ConfigurationManager.AppSettings[configKey];
            string[] tables = tableConfig.Split(configurationSeparator);

            foreach (string tableName in tables)
                dependency.Add(new SqlCacheDependency(dbName, tableName));
        }
        public AggregateCacheDependency GetDependency()
       {
            return dependency;
        }
    }

    需要建立依賴項的數據庫與數據表都配置在web.config文件中,其設置如下:
    <add key="CacheDatabaseName" value="MSPetShop4"/>
    <add key="CategoryTableDependency" value="Category"/>
    <add key="ProductTableDependency" value="Product,Category"/>
    <add key="ItemTableDependency" value="Product,Category,Item"/>

    根據各個數據表間的依賴關系,因而不同的數據表需要建立的依賴項也是不相同的,從配置文件中的value值可以看出。然而不管建立依賴項的多寡,其創建的行為邏輯都是相似的,因而在設計時,抽象了一個共同的類TableDependency,并通過建立帶參數的構造函數,完成對依賴項的建立。由于接口方法GetDependency()的實現中,返回的對象dependency是在受保護的構造函數創建的,因此這里的實現方式也可以看作是Template Method模式的靈活運用。例如TableDependency的子類Product,就是利用父類的構造函數建立了Product、Category數據表的SqlCacheDependency依賴:
    public class Product : TableDependency
    {
        public Product() : base("ProductTableDependency") { }
    }

    如果需要自定義CacheDependency,那么創建依賴項的方式又有不同。然而不管是創建SqlCacheDependency對象,還是自定義的CacheDependency對象,都是將這些依賴項添加到AggregateCacheDependency類中,因而我們也可以為自定義CacheDependency建立專門的類,只要實現IPetShopCacheDependency接口即可。

    4.3.3  CacheDependency工廠

    繼承了抽象類TableDependency的Product、Category和Item類均需要在調用時創建各自的對象。由于它們的父類TableDependency實現了接口IPetShopCacheDependency,因而它們也間接實現了IPetShopCacheDependency接口,這為實現工廠模式提供了前提。

    在PetShop 4.0中,依然利用了配置文件和反射技術來實現工廠模式。命名空間PetShop.CacheDependencyFactory中,類DependencyAccess即為創建IPetShopCacheDependency對象的工廠類:
    public static class DependencyAccess
    {       
        public static IPetShopCacheDependency CreateCategoryDependency()
        {
            return LoadInstance("Category");
        }
        public static IPetShopCacheDependency CreateProductDependency()
        {
            return LoadInstance("Product");
        }
        public static IPetShopCacheDependency CreateItemDependency()
        {
            return LoadInstance("Item");
        }
        private static IPetShopCacheDependency LoadInstance(string className)
        {
            string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
            string fullyQualifiedClass = path + "." + className;
            return (IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
        }
    }
    整個工廠模式的實現如圖4-3所示:

    4-3.gif
     圖4-3 CacheDependency工廠

    雖然DependencyAccess類創建了實現了IPetShopCacheDependency接口的類Category、Product、Item,然而我們之所以引入IPetShopCacheDependency接口,其目的就在于獲得創建了依賴項的AggregateCacheDependency類型的對象。我們可以調用對象的接口方法GetDependency(),如下所示:
    AggregateCacheDependency dependency = DependencyAccess.CreateCategoryDependency().GetDependency();

    為了方便調用者,似乎我們可以對DependencyAccess類進行改進,將原有的CreateCategoryDependency()方法,修改為創建AggregateCacheDependency類型對象的方法。

    然而這樣的做法擾亂了作為工廠類的DependencyAccess的本身職責,且創建IPetShopCacheDependency接口對象的行為仍然有可能被調用者調用,所以保留原有的DependencyAccess類仍然是有必要的。

    在PetShop 4.0的設計中,是通過引入Facade模式以方便調用者更加簡單地獲得AggregateCacheDependency類型對象。

    4.3.4  引入Facade模式

    利用Facade模式可以將一些復雜的邏輯進行包裝,以方便調用者對這些復雜邏輯的調用。就好像提供一個統一的門面一般,將內部的子系統封裝起來,統一為一個高層次的接口。一個典型的Facade模式示意圖如下所示:

    4-4.gif
    圖4-4 Facade模式

    Facade模式的目的并非要引入一個新的功能,而是在現有功能的基礎上提供一個更高層次的抽象,使得調用者可以直接調用,而不用關心內部的實現方式。以CacheDependency工廠為例,我們需要為調用者提供獲得AggregateCacheDependency對象的簡便方法,因而創建了DependencyFacade類:
    public static class DependencyFacade
    {
        private static readonly string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
        public static AggregateCacheDependency GetCategoryDependency()
        {
            if (!string.IsNullOrEmpty(path))
                return DependencyAccess.CreateCategoryDependency().GetDependency();
            else
                return null;
        }
        public static AggregateCacheDependency GetProductDependency()
        {
            if (!string.IsNullOrEmpty(path))
                return DependencyAccess.CreateProductDependency().GetDependency();
            else
                return null;
            }
        public static AggregateCacheDependency GetItemDependency()
        {
            if (!string.IsNullOrEmpty(path))
                return DependencyAccess.CreateItemDependency().GetDependency();
            else
                return null;
        }
    }

    DependencyFacade類封裝了獲取AggregateCacheDependency類型對象的邏輯,如此一來,調用者可以調用相關方法獲得創建相關依賴項的AggregateCacheDependency類型對象:
    AggregateCacheDependency dependency = DependencyFacade.GetCategoryDependency();

    比起直接調用DependencyAccess類的GetDependency()方法而言,除了方法更簡單之外,同時它還對CacheDependencyAssembly配置節進行了判斷,如果其值為空,則返回null對象。

    在PetShop.Web的App_Code文件夾下,靜態類WebUtility的GetCategoryName()和GetProductName()方法調用了DependencyFacade類。例如GetCategoryName()方法:
    public static string GetCategoryName(string categoryId)
    {
         Category category = new Category();
         if (!enableCaching)
                return category.GetCategory(categoryId).Name;

         string cacheKey = string.Format(CATEGORY_NAME_KEY, categoryId);

         // 檢查緩存中是否存在該數據項;
         string data = (string)HttpRuntime.Cache[cacheKey];
         if (data == null)
         {
               // 通過web.config的配置獲取duration值;
               int cacheDuration = int.Parse(ConfigurationManager.AppSettings["CategoryCacheDuration"]);
               // 如果緩存中不存在該數據項,則通過業務邏輯層訪問數據庫獲取;
               data = category.GetCategory(categoryId).Name;
               // 通過Facade類創建AggregateCacheDependency對象;
               AggregateCacheDependency cd = DependencyFacade.GetCategoryDependency();
               // 將數據項以及AggregateCacheDependency 對象存儲到緩存中;
               HttpRuntime.Cache.Add(cacheKey, data, cd, DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
          }
          return data;
    }

    GetCategoryName()方法首先會檢查緩存中是否已經存在CategoryName數據項,如果已經存在,就通過緩存直接獲取數據;否則將通過業務邏輯層調用數據訪問層訪問數據庫獲得CategoryName,在獲得了CategoryName后,會將新獲取的數據連同DependencyFacade類創建的AggregateCacheDependency對象添加到緩存中。

    WebUtility靜態類被表示層的許多頁面所調用,例如Product頁面:
    public partial class Products : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Page.Title = WebUtility.GetCategoryName(Request.QueryString["categoryId"]);
        }
    }

    顯示頁面title的邏輯是放在Page_Load事件方法中,因而每次打開該頁面都要執行獲取CategoryName的方法。如果沒有采用緩存機制,當Category數據較多時,頁面的顯示就會非常緩慢。

    4.3.5  引入Proxy模式

    業務邏輯層BLL中與Product、Category、Item有關的業務方法,其實現邏輯是調用數據訪問層(DAL)對象訪問數據庫,以獲取相關數據。為了改善系統性能,我們就需要為這些實現方法增加緩存機制的邏輯。當我們操作增加了緩存機制的業務對象時,對于調用者而言,應與BLL業務對象的調用保持一致。也即是說,我們需要引入一個新的對象去控制原來的BLL業務對象,這個新的對象就是Proxy模式中的代理對象。

    以PetShop.BLL.Product業務對象為例,PetShop為其建立了代理對象ProductDataProxy,并在GetProductByCategory()等方法中,引入了緩存機制,例如:
    public static class ProductDataProxy
    {

        private static readonly int productTimeout = int.Parse(ConfigurationManager.AppSettings["ProductCacheDuration"]);
        private static readonly bool enableCaching = bool.Parse(ConfigurationManager.AppSettings["EnableCaching"]);
           
        public static IList
    GetProductsByCategory(string category)
        {
            Product product = new Product();

            if (!enableCaching)
                return product.GetProductsByCategory(category);

            string key = "product_by_category_" + category;
            IList data = (IList )HttpRuntime.Cache[key];

            // Check if the data exists in the data cache
            if (data == null)
            {
                data = product.GetProductsByCategory(category);

                // Create a AggregateCacheDependency object from the factory
                AggregateCacheDependency cd = DependencyFacade.GetProductDependency();

                // Store the output in the data cache, and Add the necessary AggregateCacheDependency object
                HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(productTimeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
            }
            return data;
        }
    }

    與業務邏輯層Product對象的GetProductsByCategory()方法相比,增加了緩存機制。當緩存內不存在相關數據項時,則直接調用業務邏輯層Product的GetProductsByCategory()方法來獲取數據,并將其與對應的AggregateCacheDependency對象一起存儲在緩存中。

    引入Proxy模式,實現了在緩存級別上對業務對象的封裝,增強了對業務對象的控制。由于暴露在對象外的方法是一致的,因而對于調用方而言,調用代理對象與真實對象并沒有實質的區別。

    從職責分離與分層設計的角度分析,我更希望這些Proxy對象是被定義在業務邏輯層中,而不像在PetShop的設計那樣,被劃分到表示層UI中。此外,如果需要考慮程序的可擴展性與可替換性,我們還可以為真實對象與代理對象建立統一的接口或抽象類。然而,單以PetShop的表示層調用來看,采用靜態類與靜態方法的方式,或許更為合理。我們需要謹記,“過度設計”是軟件設計的警戒線。

    如果需要對UI層采用緩存機制,將應用程序數據存放到緩存中,就可以調用這些代理對象。以ProductsControl用戶控件為例,調用方式如下:
    productsList.DataSource = ProductDataProxy.GetProductsByCategory(categoryKey);

    productsList對象屬于自定義的CustomList類型,這是一個派生自System.Web.UI.WebControls.DataList控件的類,它的DataSource屬性可以接受IList集合對象。
    不過在PetShop 4.0的設計中,對于類似于ProductsControl類型的控件而言,采用的緩存機制是頁輸出緩存。我們可以從ProductsControl.ascx頁面的Source代碼中發現端倪:
    <%@ OutputCache Duration="100000" VaryByParam="page;categoryId" %>

    與ASP.NET 1.x的頁輸出緩存不同的是,在ASP.NET 2.0中,為ASP.NET用戶控件新引入了CachePolicy屬性,該屬性的類型為ControlCachePolicy類,它以編程方式實現了對ASP.NET用戶控件的輸出緩存設置。我們可以通過設置ControlCachePolicy類的Dependency屬性,來設置與該用戶控件相關的依賴項,例如在ProductsControl用戶控件中,進行如下的設置:
    protected void Page_Load(object sender, EventArgs e)
    {
        this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();
    }

    采用頁輸出緩存,并且利用ControlCachePolicy設置輸出緩存,能夠將業務數據與整個頁面放入到緩存中。這種方式比起應用程序緩存而言,在性能上有很大的提高。同時,它又通過引入的SqlCacheDependency特性有效地避免了“數據過期”的缺點,因而在PetShop 4.0中被廣泛采用。相反,之前為Product、Category、Item業務對象建立的代理對象則被“投閑散置”,僅僅作為一種設計方法的展示而“幸存”與整個系統的源代碼中。

    posted @ 2007-12-26 12:07 風雨兼程 閱讀(1276) | 評論 (1)編輯 收藏

    IList GetCategories();的問題

    petshop4.0中的一段代碼  
       
      public   interface   ICategory   {  
       
      ///   <summary>  
      ///   Method   to   get   all   categories  
      ///   </summary>  
                      ///   <returns>Interface   to   Model   Collection   Generic   of   categories</returns>  
                 
                     
      IList<CategoryInfo>   GetCategories();  
                     
       
                      ///   <summary>  
                      ///   Get   information   on   a   specific   category  
                      ///   </summary>  
                      ///   <param   name="categoryId">Unique   identifier   for   a   category</param>  
                      ///   <returns>Business   Entity   representing   an   category</returns>  
                      CategoryInfo   GetCategory(string   categoryId);  
      }  
       
       
      我知道IList<CategoryInfo>是范型  
      表示list中的item是CategoryInfo對象  
       
       
      請問為什么用IList<CategoryInfo>  
      用List<CategoryInfo>可以嗎?  
       
      兩者有什么區別?謝謝  

    沒有什么區別,這樣寫靈活性大,實現ilist接口的類很多,你寫成list后,也許以后你要改成非list的,就會要改很多代碼
    舉個例子  
       
      RenderControlToString(DataList   L//Control   C)  
       
      你認為是寫control還是寫datalist代碼的通用性高?

      OOP編碼原則:盡可能用接口編程

    posted @ 2007-12-26 11:44 風雨兼程 閱讀(471) | 評論 (0)編輯 收藏

    關于sqlhelper.cs

    public abstract class SqlHelper
              {
                  public static readonly string connectionString = ConfigurationManager.ConnectionStrings["SqlConnString"].ConnectionString;
            
                  SqlConnection conn;

                  #region open SqlConnection
                  public static void Open() {
                       conn = new SqlConnection(connectionString);
                       if (conn.State != ConnectionState.Open)
                          conn.Open();
                  }    
                  #endregion

                  #region close SqlConnection
                  public static void Close() {
                      if (conn != null)
                      {
                          conn.Close();
                          conn.Dispose();
                      }
                  }        
                  #endregion

                  #region prepare SqlCommand
                  private static void PrepareCommand(SqlCommand cmd, CommandType cmdType, string cmdText, SqlParameter[] cmdParms) {
                      Open();
                      cmd.Connection = conn;
                      cmd.CommandType = cmdType;
                      cmd.CommandText = cmdText;

                      if (cmdParms != null)
                      {
                          foreach (SqlParameter parm in cmdParms)
                              cmd.Parameters.Add(parm);
                      }
                  }
                  #endregion

                  #region parm cache
                  /*
                   使用一個哈希表來保存緩存的參數 只緩存參數名
                   哈希表的特點:一個鍵對應一個值key對value(為object需要類型轉化)        不能出現兩個相同的鍵 否則error
             
                   下面的哈希表parmCache定義為static即一次定義全局使用
                   所以可能會出現有人在讀的時候,有人在寫,一般會用Lock就像Asp中用Application["count"]來統計點擊數一樣
                   要先鎖后解鎖
                   但.net框架提供了Synchroized          sync和syncroize中文意思 同步,同時發生
                   來提供這一操作
                  */
                  private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());

                  public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters) {
                      parmCache[cacheKey] = commandParameters;
                  }

                  /*
                  1、為何要克隆呢 為何不直接return cachedParms
             
                  有一個參數數組
                  SqlParameter[] parms={
                  new SqlParameter("@num1",SqlDbType.Int,4),
                  new SqlParameter("@num2",SqlDbType.Int,4)
                  }
                  緩存該數組
                  用戶a和b都執行插入操作
                  a用戶插入了1,1
                  b用戶插入了2,2
                  如果不用克隆的話,參數數組只有一份
                  而2個用戶需要根據不同的情況賦于不同的值
                  所以就用了克隆了
            
                  2、(ICloneable)cachedParms[i]先將HashTable轉為ICloneable這樣HashTable就具有了Clone()克隆方法了
                  克隆一份后是什么類型呢,,當然要強制轉化為(SqlParameter)了
                  最后將它賦值給clonedParms[i]
                  */       
                  public static SqlParameter[] GetCachedParameters(string cacheKey) {
                      SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];

                      if (cachedParms == null)
                          return null;
                      SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];

                      for (int i = 0; i < cachedParms.Length; i++)
                          clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();

                      return clonedParms;
                  }
                  #endregion        
            
                  //below method support sqltext and procedure

                  #region ExecuteReader
                  /*
                   parms的作用,這也是一個知識點
                   舉例:
                   ExecuteReader(*,*,null)成功運行
                   ExecuteReader(*,*,new SqlParameter(*))成功運行
                   ExecuteReader(*,*,new SqlParameter(*),new SqlParameter(*))成功運行
                   ExecuteReader(*,*,{new SqlParameter(*),new SqlParameter(*),})成功運行
                   它讓參數類型和參數個數任意
                   這可給了不是一般的好處,你不必為SqlParameter和SqlParameter[]進行重載,寫上兩個函數
                   又為null寫上一個函數,因為null會不明確調用SqlParameter的函數還是SqlParameter[]的函數
                   啥你不知道我在說什么,打屁屁,那回去看看c++的函數重載
                   */
                  public static SqlDataReader ExecuteReader(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {
                
                      SqlCommand cmd = new SqlCommand();

                      try {
                          PrepareCommand(cmd, null, cmdType, cmdText, commandParameters);
                          SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                          cmd.Parameters.Clear();
                          return rdr;
                      }
                      catch {
                          Close();
                          throw;
                      }
                  }
                  #endregion

                  #region ExecuteNonQuery
                  public static void ExecuteNonQuery(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {

                      SqlCommand cmd = new SqlCommand();

                      PrepareCommand(cmd, cmdType, cmdText, commandParameters);
                      cmd.ExecuteNonQuery();
                      cmd.Parameters.Clear();

                      Close();
                  }
                  #endregion

                  #region ExecuteScalar
                  public static object ExecuteScalar(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {

                      SqlCommand cmd = new SqlCommand();

                      PrepareCommand(cmd, cmdType, cmdText, commandParameters);
                      object val = cmd.ExecuteScalar();
                      cmd.Parameters.Clear();

                      Close();
                      return val;
                  }
                  #endregion


              }
    }

    posted @ 2007-12-26 10:30 風雨兼程 閱讀(904) | 評論 (0)編輯 收藏

    2007年4月29日

    框架怎樣實現高度隨內容自動增高

    main.htm:

    <html> 
        <head> 
           <meta  http-equiv='Content-Type'  content='text/html;  charset=gb2312' /> 
           <meta  name='author'  content='F.R.Huang(meizz梅花雪)//www.meizz.com' /> 
           <title>iframe自適應加載的頁面高度</title> 
        </head> 
        
        <body>
            <div><iframe src="child.htm"></iframe></div>
        </body>
    </html>

    child.htm:

    <html> 
    <head> 
        <meta  http-equiv='Content-Type'  content='text/html;  charset=gb2312' /> 
        <meta  name='author'  content='F.R.Huang(meizz梅花雪)//www.meizz.com' /> 
        <title>iframe  自適應其加載的網頁(多瀏覽器兼容)</title> 
        <script type="text/javascript">
        <!--
        function iframeAutoFit()
        {
            try
            {
                if(window!=parent)
                {
                    var a = parent.document.getElementsByTagName("IFRAME");
                    for(var i=0; i<a.length; i++) //author:meizz
                    {
                        if(a[i].contentWindow==window)
                        {
                            var h1=0, h2=0;
                            a[i].parentNode.style.height = a[i].offsetHeight +"px";
                            a[i].style.height = "10px";
                            if(document.documentElement&&document.documentElement.scrollHeight)
                            {
                                h1=document.documentElement.scrollHeight;
                            }
                            if(document.body) h2=document.body.scrollHeight;

                            var h=Math.max(h1, h2);
                            if(document.all) {h += 4;}
                            if(window.opera) {h += 1;}
                            a[i].style.height = a[i].parentNode.style.height = h +"px";
                        }
                    }
                }
            }
            catch (ex){}
        }
        if(window.attachEvent)
        {
            window.attachEvent("onload",  iframeAutoFit);
            //window.attachEvent("onresize",  iframeAutoFit);
        }
        else if(window.addEventListener)
        {
            window.addEventListener('load',  iframeAutoFit,  false);
            //window.addEventListener('resize',  iframeAutoFit,  false);
        }
        //-->
        </script> 
    </head> 
    <body>
        <table border="1" width="200" style="height: 400px; background-color: yellow">
            <tr>
                <td>iframe  自適應其加載的網頁(多瀏覽器兼容,支持XHTML)</td>
            </tr>
        </table>
    </body> 
    </html>

     很多人反應在IE7里使用它會死機,那是因為在自適應高度時觸發了 window.onresize 事件,而這個事件又去調用這個調整 <iframe> 高度的函數,產生了死循環調用。

    posted @ 2007-04-29 18:03 風雨兼程 閱讀(999) | 評論 (1)編輯 收藏

    主站蜘蛛池模板: 精品久久久久国产免费| 久久亚洲中文字幕精品一区| 亚洲精品国产福利片| 爽爽爽爽爽爽爽成人免费观看| 亚洲日本视频在线观看| 国产拍拍拍无码视频免费| 亚洲乱码无码永久不卡在线 | 亚洲天堂2016| 黄页免费的网站勿入免费直接进入| 亚洲国产成人精品无码一区二区 | 99久久免费看国产精品| 亚洲an天堂an在线观看| 91香蕉国产线在线观看免费| 久久av无码专区亚洲av桃花岛| 久久青草免费91线频观看不卡| 午夜亚洲AV日韩AV无码大全| 国产情侣久久久久aⅴ免费| 亚洲一区二区三区夜色| 在线观看的免费网站| 亚洲男同gay片| 亚洲国产一级在线观看 | 精品亚洲A∨无码一区二区三区| 曰批全过程免费视频网址| 亚洲中文无码永久免| 四虎影永久在线高清免费| 一区二区三区精品高清视频免费在线播放 | 日本阿v免费费视频完整版| 亚洲精品无播放器在线播放| 亚洲国产成人久久精品99 | 中文字幕免费播放| 亚洲男人第一av网站| 日韩在线免费视频| 国产在亚洲线视频观看| 国产亚洲成av人片在线观看| 97青青草原国产免费观看| 亚洲五月综合缴情婷婷| 亚洲永久无码3D动漫一区| **aaaaa毛片免费| 亚洲av无码专区青青草原| 久久99亚洲综合精品首页| 我们的2018在线观看免费高清|