ASP.NET常被忽視的一些細節

來源:互聯網
上載者:User

前段時間碰到一個問題:為什麼在ASP.NET程式中定時器有時候會不工作?

這個問題看起來很奇怪,代碼好像也沒錯,但就是結果與預期不一致。
其實這裡是ASP.NET應用程式中一個容易被忽略的經節。
後來想想,類似這樣的細節問題何止這一個,我今天就把我能想到的容易被忽視的細節問題都寫出來,希望大家小心這些問題。

想到我以前的部落格中也零散的說過了一些,所以這篇部落格中也把它們列出來了,
不過,對於以前談過的內容,這裡將只會簡略地說明。

HttpContext.Current並非無處不在

這個問題是我上個月的部落格中提到的問題,
原文連結:http://www.cnblogs.com/fish-li/archive/2013/04/06/3002940.html

在以下情形中訪問HttpContext.Current將會返回null
1. 定時器的回調。
2. Cache的移除通知。
3. APM模式下非同步完成回調。
4. 主動建立線程或者將任務交給線程池來執行。

所以,在寫類庫時,請注意這個問題。

Application_Start的異常與IIS傳統模式

在IIS6或者II7的傳統模式下運行ASP.NET程式時,如果Application_Start事件中拋出了未捕獲異常,
那麼 這個異常將顯示一次。

關於這個問題的更多細節介紹請點擊:http://www.cnblogs.com/fish-li/archive/2013/03/24/2979780.html

QueryString,Form允許重複的KEY

我們經常見到的集合,例如:Hashtable, Dictionary,它們都要求KEY是唯一的,然而,
HttpRequest的QueryString,Form集合執行個體卻 允許KEY重複,當遇到KEY重複時,通過索引器訪問集合時,
會將KEY對應的所有元素值用逗號拼接起來。

為什麼會這樣,因為這二個集合的類型是NameValueCollection,類似的,Headers集合也是這樣。

由於這個特殊性與我們常見的情形不一致,所以我們需要注意這個差別,當然了,有些時候我們還可以利用這個行為實現一些特殊的需求,
關於這個細節的更多介紹請參考:http://www.cnblogs.com/fish-li/archive/2011/12/06/2278463.html ,
在這篇部落格中,還介紹了HttpRequest的二個索引器也是值得我們注意的。

ashx的重用問題

很多ASP.NET的開發人員都應該建立過ashx檔案,例如下面這個:

public class Handler1 : IHttpHandler {    public bool IsReusable {        get {            return false;        }    }

我想不少人會對IsReusable這個屬性感到好奇,於是去查一下IHttpHandler的定義,找到這個解釋,

// 摘要://     擷取一個值,該值指示其他請求是否可以使用 System.Web.IHttpHandler 執行個體。//// 返回結果://     如果 System.Web.IHttpHandler 執行個體可再次使用,則為 true;否則為 false。bool IsReusable { get; }

看到可以重用,有些對效能關注的人可能會將它修改為返回true,其實改成什麼都一樣,因為它不起作用。

不起作用的原因在這篇部落格中有說明:http://www.cnblogs.com/fish-li/archive/2012/01/29/2331477.html

當前登入使用者資訊有時擷取不到

在ASP.NET中,提供了以下方法讓我們擷取目前使用者的資訊,例如:

if( HttpContext.Current != null ) {    // 檢查目前使用者是否已為一個已登入使用者    bool isAuthenticated = HttpContext.Current.Request.IsAuthenticated;    // 擷取當前請求的使用者名稱    string userName = HttpContext.Current.User.Identity.Name;}

不過,這段代碼放在不同的地方,效果卻截然不同。

最近就遇到一個問題:有人問我為什麼總是取不目前使用者的使用者名稱。
網站採用的是Windows身份認證,因此,所有的請求都是經過IIS認證過的,
理論上說,變數isAuthenticated應該返回true,而userName應該是當前請求的使用者名稱(Windows登入名稱),然而呢,在調試時,
isAuthenticated的值是false, 後面的代碼直接拋出一個Null 參考異常,因為User對象為null,太奇怪了,是嗎?

當出現這種情況時,我們應該檢查代碼在哪裡被調用的。
結果在我的追問下,發現代碼是在一個HttpModule中調用的,且發生在訂閱HttpApplication的BeginRequest事件中。
找到這裡,原因也就找到了,此時(在這個階段)還沒有經過ASP.NET的身份認證檢查,
User對象對象根本就沒有構造出來,
現在去訪問,當然取不到結果。

憑良心說,這個還真算不上ASP.NET留給我們的坑,只怪一些人對管線事件不瞭解。

Timer可能會不起作用

有時候我們會遇到一些諸如執行定時任務的需求,於是有些人可能會想到用定時器來實現,
在.net framework中,有二個Timer類型可以用於ASP.NET環境中,不過,Timer有可能會不起作用,
具體表現情況也會讓你難以描述:不知道在什麼時候定時器就停止工作了。

這個問題很奇怪:當你在偵錯模式下,定時器是一直能正常工作的,但當你把網站部署起來,
已耗用時間久一些,便會發現定時器沒有正常工作。

為什麼會這樣呢?
答案是:當網站在一段時間沒有請求後,進程會被IIS回收(釋放)。
所以,在ASP.NET程式不適合執行【長久性】的定時任務,除非你能接受定時器會停止工作。
類似的問題還有:在ASP.NET程式中將某個方法做為回調方法傳給Win32程式,發現回調沒有響應。

正是由於這個原因,建議將長久性的定時任務或者接收Win32回調的程式用Windows Service的程式來實現

Session與複雜資料類型

Session有三種工作模式,拿ASPX頁面來說,EnableSessionState指令有三個可選值:true, false, ReadOnly

EnableSessionState="false",這個容易理解:不使用Session。

EnableSessionState="ReadOnly",從字面上來說,就是Session是唯讀。
唯讀控制項不允許使用者修改,然而Session的唯讀模式是說:你可以改,但我不儲存你的修改。
這樣理解沒有問題吧。

EnableSessionState="true",表示Session支援可讀可寫。
當你更新了Session的內容之後,當前會話的所有Session資料將會被重新儲存。

進程內Session容易丟失,且不支援多台Web伺服器共用資料,因此選擇這種儲存方法的人不多,
大多數人會選擇狀態服務或者SQL Server來儲存,那麼這裡就有一個問題需要關注了:
當Session模式是EnableSessionState="true"時,如果你訪問了一個複雜物件(不是系統實值型別也不是字串),
不管你有沒有修改它,Session的儲存操作都會執行。
對於進程外Session,儲存操作意味著需要執行序列化,還可以會有網路傳輸的開銷,它們會影響效能。

如果上面的描述不容易理解的話,請看下面的範例程式碼:

string sessionValue = Session["s2"] as string;if( sessionValue == null ) {    Session["s2"] = "Fish Li";    sessionValue = Session["s2"] as string;}

當這個頁面首次運行時,Session被修改了,因此會有儲存的操作發生。但是後面的訪問就不會有儲存的動作。

再看另一段代碼:

// TestData是一個自訂類型。TestData sessionValue = Session["s1"] as TestData;if( sessionValue == null ) {    Session["s1"] = new TestData { IntValue = 5, StrValue = "Fish Li" };    sessionValue = Session["s1"] as TestData;}

此時每次執行這段代碼時,都會有儲存操作發生(只要是EnableSessionState="true")。

我再重申一遍:這個問題只有當EnableSessionState="true",且訪問複雜物件(不是系統實值型別也不是字串)才會發生。
對於進程內Session來說,這個問題的影響不大,但是對於進程外Session來說,會對效能產生一些影響,
到底有多大的影響,要根據Session的資料量以及使用者的並發度來決定。

列出這個問題只是想告訴大家:如果你確實需要使用Session,請盡量在Session中儲存【不可變】的簡單資料,
尤其是不要保持Session的預設設定(EnableSessionState="true")。

檢驗這個問題的方法是:實現一個自訂的SessionStateStoreProviderBase衍生類別,然後調試觀察。
SessionStateItemCollection的二個索引器也會給你一個答案。

DateTime的JSON序列化

在SP.NET3.5中,微軟為ASP.NET為設計了一個JSON序列化的工具類,
System.Web.Script.Serialization.JavaScriptSerializer,這個類的使用很廣泛,而且比WCF的那個JSON序列化類別的相容性要好。
不過,這個類有一個問題,在序列化DataTime類型時,它產生的結果會讓所有人感覺彆扭,
其實序列化的結果表現形式還個小問題,在前端寫個轉換函式就能解決,
然而,如果你需要 用序列化和還原序列化的方法來做對象的持久化,就會遇到問題,例如下面的代碼:

DateTime dt1 = DateTime.Now;JavaScriptSerializer jss = new JavaScriptSerializer();string json = jss.Serialize(dt1);DateTime dt2 = jss.Deserialize<DateTime>(json);context.Response.Write(dt1 == dt2);

瀏覽器顯示的結果會讓人感到很意外,竟然是:False

出現這個原因與JavaScript的時間格式有關,它使用了UTC時間,
不過,這個理由讓人感到難以接受,畢竟其它的還原序列化都能還原對象,例如二進位序列化和XML都能正確的還原對象。
沒辦法,這裡只能算是個坑了,所以,如果你要做對象的持久化操作,盡量不要選擇JSON序列化。

如果,您認為閱讀這篇部落格讓您有些收穫,不妨點擊一下右下角的【推薦】按鈕。
如果,您希望更容易地發現我的新部落格,不妨點擊一下右下角的【關注 Fish Li】。
因為,我的寫作熱情也離不開您的肯定支援。

感謝您的閱讀,如果您對我的部落格所講述的內容有興趣,請繼續關注我的後續部落格,我是Fish Li 。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.