程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> ASP編程 >> 關於ASP編程 >> 如何在ASP.NET應用程序中初始化

如何在ASP.NET應用程序中初始化

編輯:關於ASP編程

    每個程序都需要初始化的過程,用來讀取配置或者設置一些運行環境(變量),對於ASP.NET程序來說,又該在哪裡執行初始化的任務呢?

    我想應該絕大多數人都知道在Global.asax中執行初始化的過程,然而有些細節是我們需要關注的。

    本文用例

    在這篇博客的示例代碼中,AppInitializer包含了網站的初始化的實現代碼:

    1. public static class AppInitializer  
    2. {  
    3.     public static ConnectionStringSettings MyNorthwindConnectionSetting { get; private set; }  
    4.  
    5.     public static void Init()  
    6.     {  
    7.         // 讀取連接字符串。  
    8.         LoadConnectionString();  
    9.  
    10.         // 設置SQLSERVER緩存依賴通知。  
    11.         SetSqlDependency();  
    12.  
    13.         // 其它的初始化操作。  
    14.         OthersInit();  
    15.     }  
    16.  
    17.     static void LoadConnectionString()  
    18.     {  
    19.         ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings["MyNorthwind"];  
    20.         if( setting == null )  
    21.             throw new ConfigurationException("沒有配置MyNorthwind連接字符串。");  
    22.  
    23.         if( string.IsNullOrEmpty(setting.ConnectionString) )  
    24.             throw new ConfigurationException("沒有為MyNorthwind連接字符串指定內容。");  
    25.  
    26.         if( string.IsNullOrEmpty(setting.ProviderName) )  
    27.             throw new ConfigurationException("沒有為MyNorthwind連接字符串指定ProviderName 。");  
    28.  
    29.         // 保存讀取到的連接字符串,供程序使用。  
    30.         MyNorthwindConnectionSetting = setting;  
    31.     }  
    32.  
    33.     static void SetSqlDependency()  
    34.     {  
    35.         // 判斷SQLSERVER版本是否為 2005以上版本,  
    36.         // 是否開啟Service Broker的檢查代碼就不列出了。  
    37.  
    38.         SqlDependency.Start(MyNorthwindConnectionSetting.ConnectionString);  
    39.     }  
    40.  
    41.     static void OthersInit()  
    42.     {  
    43.         // 其它的初始化操作。  
    44.  
    45.         // 例如:  
    46.         // 1. 加載必要的緩存數據。  
    47.         // 2. 檢查上傳目錄是不存在。  
    48.         // 3. ...................  
    49.     }  

    這段代碼的意圖很清楚,一定要確保正確的配置了數據庫連接字符串,否則以異常的形式報告出來。

    示例程序還有一個頁面,Default.aspx

    1. <body> 
    2.     <form id="form1" runat="server"> 
    3.     <div> 
    4.         <h1>User Login</h1> 
    5.     </div> 
    6.  
    7.         <p style="line-height: 150%;"> 
    8.             UserName: <asp:TextBox ID="txtUserName" runat="server" Width="200px" Text="Fish Li"></asp:TextBox><br /> 
    9.             Password: <asp:TextBox ID="txtPassword" runat="server" Width="200px" TextMode="Password"></asp:TextBox><br /> 
    10.             <asp:Button ID="btnLogin" runat="server" Text="登錄" OnClick="btnLogin_Click" /> 
    11.         </p> 
    12.     </form> 
    13. </body> 

    其實就是一個登錄頁面,後台代碼為:

    1. protected void btnLogin_Click(object sender, EventArgs e)  
    2. {  
    3.     bool ok = false;  
    4.  
    5.     using( SqlConnection connection  
    6.         = new SqlConnection(AppInitializer.MyNorthwindConnectionSetting.ConnectionString) ) {  
    7.  
    8.         connection.Open();  
    9.  
    10.         // 其它的數據庫操作。  
    11.  
    12.         ok = true;  
    13.     }  
    14.  
    15.     if( ok )  
    16.         Response.Redirect("Default2.aspx");  

    你沒有想到的Global.asax怪事!

    或許有些人會這樣寫他們的初始化代碼:

    1. void Application_Start(object sender, EventArgs e)  
    2. {  
    3.     //在應用程序啟動時運行的代碼  
    4.     try {  
    5.         AppInitializer.Init();  
    6.     }  
    7.     catch( Exception ex ) {  
    8.         LogException(ex);  
    9.           
    10.         // .....................  
    11.     }  
    12. }  

    這段代碼有什麼問題呢?

    其實問題的線索在於:為什麼要加try....catch語句,是因為知道可能會發生異常嗎?

    如果真有異常情況發生,這樣處理後,後續的請求是不是會發生各種想像不到的錯誤?

    顯然這裡不能吃掉異常,要不然後面的請求肯定會有問題,因為它們依賴的設置沒有正確的初始化。

    好吧,那我去掉 try.....catch語句,這樣總該行了吧:

    1. void Application_Start(object sender, EventArgs e)  
    2. {  
    3.     //在應用程序啟動時運行的代碼  
    4.  
    5.     AppInitializer.Init();  
    6. }  

    還是看來一下真實的運行情況吧。

    噢,抱歉,我還真忘記了配置連接字符串,這個異常提示太給力了。

    現在就加上連接字符串嗎?

    別急,想像一下,如果這個網站是一個真實的在線網站,會是什麼情況呢?
    答案有二種:

    1. 另一個用戶也發起了一次請求。

    2. 當前用戶看到錯誤頁面後,重新刷新了一次當前頁面。

    現在我用Opera來扮演第二個浏覽用戶吧,還是打開同樣的網址。

    太奇怪了,第二個用戶居然能打開頁面,好吧,讓他登錄試試。

    結果第二個用戶看到的錯誤情況和第一個用戶完全不同。

    如果此時第一個用戶刷新他的浏覽器,發現頁面又可以顯示了,然而登錄時,會看到與第二個用戶一樣的異常信息。

    這個示例代碼實在太簡單了,我想維護人員根據NullReferenceException這個線索找下去,很快就能找到答案。如果初始化代碼再復雜一些,比如SetSqlDependency()中出現異常呢,那麼程序仍然能夠正常運行,但是我們期望的緩存依賴可能就沒有效果了,最終可能會產生性能問題,排查的難度就會大多了。

    記得以前做項目時,就遇到過這種情況,當時感到很奇怪,為什麼刷新一下就沒黃頁了,不過後面的錯誤就很折騰人了,最終也讓我總結了這個教訓。所以我建議:如果在初始化階段出現了異常,干脆就別讓程序繼續運行了,每個請求都直接顯示黃頁,直到排除故障為止。

    如何保證初始化異常一直顯示?

    當初始化發生異常時,如何保證初始化異常一直顯示呢?

    方法其實並不難,我們需要修改一下代碼:

    1. private static Exception s_initException;  
    2.  
    3. void Application_Start(object sender, EventArgs e)  
    4. {  
    5.     try {  
    6.         AppInitializer.Init();  
    7.     }  
    8.     catch( Exception ex ) {  
    9.         // 記下初始化的異常。  
    10.         s_initException = ex;  
    11.     }      
    12. }  
    13.  
    14. protected void Application_BeginRequest(object sender, EventArgs e)  
    15. {  
    16.     // 如果存在初始化異常,就拋出來。  
    17.     // 直到開發人員發現這個異常,並已解決了異常為止。  
    18.     if( s_initException != null )  
    19.         throw s_initException;  
    20. }  

    現在不管有多少個用戶來訪問,或者第一個訪問者刷新浏覽器多少次,都會看到同樣的異常信息:

    說明:Global.asax的這個問題在IIS7以上版本的集成模式下並不存在。

    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved