如何利用「自訂例外狀況」處理無法繼續執行的錯誤

try-catch 幾乎是每天必碰的程式碼,新手程式設計師應該很容易瞭解 try-catch 該怎麼使用,但不見得能深入思考「為什麼」要有 例外狀況(Exception) 的存在,存在的理由很多,但我個人認為最重要也最單純的理由是『例外狀況試圖不讓你的程式繼續執行下去』,這聽起來像是個廢話,但或許有人沒有認真的想過這個問題,而這樣的一個理由在面對日常程式開發上又有什麼重大的影響呢?

程序導向的程式開發架構下,錯誤處理都是靠 if-then-else 等於法,有時後會讓程式又臭又長變的難以維護也難以閱讀,到了物件導向程式設計的世界裡,有時也會難逃這種狀況,畢竟對人腦的思路來說「物件導向」一直都是「不人性化」的,我們學習物件導向技術就是為了克服人性,尋求一個更有結構、更有效率、更易於管理維護的解決方案。

在不熟悉物件導向程式設計時,通常都會用好多層的 if-then-else 處理各種例外狀況,為的不就是『當錯誤發生時不要執行到自己覺得不應該執行的程式碼』嗎?如果你今天寫程式的過程中,研判物件執行到某種狀態「有可能」造成程式發生不穩定的情況時,你就應該不要再繼續執行下去,否則一錯再錯的情況下,就會有更多狀況不可遇測了,這時你可以單純的 return value (也許是 null 之類的),或你也可以丟出一個例外狀況(Exception)

丟出例外狀況單純的 return value 有些不太一樣的地方,也就在於「例外狀況」可以包含比原本從方法(method) 或 函式(function) 「回傳資料」時有更多的資訊可以傳遞給呼叫者(Caller),這也是使用「例外狀況」最大的好處

相對的 Exception 最大的壞處也是相同的地方,因為越多的資訊傳遞帶來的卻是記憶體耗用、CPU 運算資源耗用等負面影響,所以當一個物件「有可能」頻繁的發生 Exception 時,這時就必須考慮運用其他的方式或設計範式(Design Pattern)來處理例外狀況帶來的效能問題,建議可以參考閱讀 MSDN 文章的【例外狀況和效能 / Exceptions and Performance】章節。

舉一個最常見的例子:Int32 ( int )

.NET 1.1 版的 Int32 成員中有個常用的 靜態方法(method) 叫 Int32.Parse 方法,這個方法相信大家也很常用,他可以傳入一個字串(System.String),解析後轉換成 Int32 型別,當轉換失敗時就會丟出一個 FormatException,但字串的型態何其多,很容易就會傳入「非數字」的字串,這時就「有可能」造成頻繁的發生例外狀況並造成效能衝擊。

從 .NET 2.0 開始,Int32 成員就多了一個 Int32.TryParse 靜態方法,主要的目的就是讓呼叫者不會頻繁的接收到過多且不需要的例外狀況,也徹底解決例外狀況帶來的效能問題。

前面都是講例外狀況的基本概念,終於要進入正題了:自訂例外狀況

在設計自訂例外狀況時建議可參考 .NET Framework 開發人員手冊設計自訂例外狀況 章節,依照上述的方針進行設計有助於您寫出正確且有用的例外型別。

標準的自訂例外型別範本如下 ( 參照自 MSDN 的 設計自訂例外狀況 章節 ):

public class NewException : BaseException, ISerializable {
public NewException() {
// Add implementation.
}
public NewException(string message) {
// Add implementation.
}
public NewException(string message, Exception inner) {
// Add implementation.
}
// This constructor is needed for serialization.
protected NewException(SerializationInfo info, StreamingContext context) {
// Add implementation.
}
}

我另外提供一個我自己寫過的自訂例外型別範例,這是一個當「使用者不存在」時所使用的例外狀況,當登入作業無法完成時,基本上不能再讓程式執行下去,所以我就丟出一個例外中斷程式執行。但事實上我在使用時並非讓應用程式因為例外狀況而自動關閉,而是用 try-catch 取得完整的例外資訊後顯示適當的錯誤訊息,範例程式如下:

class UserNotFoundException : Exception, ISerializable
{
public UserNotFoundException()
: base("使用者不存在") { }
public UserNotFoundException(string message)
: base(message) { }
public UserNotFoundException(string message, Exception inner)
: base(message, inner) { }
protected UserNotFoundException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}

在第一個建構子帶入一個預設的錯誤訊息,也就是當執行到下列程式時,由呼叫者取得的例外資訊就會包含這個例外型別提供的預設錯誤訊息:

throw new UserNotFoundException();

實際上 Exception 型別可以攜帶的資料還有更多,在 Exception 成員就可以看到其他內建的屬性,像是 HelpLink 可以儲存這個例外狀況相關聯的連結,Source 可以儲存造成錯誤的應用程式或物件名稱,InnerException 可以儲存造成這個例外的例外物件,Data 屬性型別為 IDictionary,可以儲存任意任何提供關於此例外狀況的額外使用者定義資訊。

例外狀況有這麼多的資訊可以傳遞,相信在程式開發上會有非常大的幫助,但也要小心隨之而來的效能衝擊,只要妥善掌握例外狀況開發的原則相信能夠寫出較合理的例外狀況處理程式。

相關連結

  

此文章由 will 發表於 2009/9/30 下午 12:31:07

永久連結 | 評論 (2) | 此文章的RSSRSS comment feed |

分類: .Net | C#

標籤: , , ,

收藏:

介紹好用工具:PowerCommands for Reflector [含使用教學]

我想家喻戶曉的 .NET Reflector 工具應該不用我多做介紹,但昨天無意間發現一個不錯的 Reflector 外掛工具叫做 PowerCommands for Reflector,當安裝完成後會多出將近 20 個貼心小功能 (陸續增加中…),讓你在使用Reflector 的時候多出一些功能選項協助你瀏覽 .NET 組件。

如何安裝 PowerCommands for Reflector ( 共 4 個步驟 )

1. 先進入下載專區下載最新版程式 ( 有區分 x86 與 x64 架構 )

    1. 先進入 PowerCommands for Reflector 下載專區下載最新版程式 ( 有區分 x86 與 x64 架構 )

2. 解壓縮下載的檔案至 Reflector 安裝目錄
    備註: Reflector 為綠色軟體,你只要將檔案解壓縮至 Reflector 所在目錄即可

    2. 解壓縮下載的檔案至 Reflector 安裝目錄

3. 開啟 .NET Reflector 並點選 [View] / [Add-Ins…] 選單

3. 開啟 .NET Reflector 並點選 [View] / [Add-Ins…] 選單

4. 將 Reflector.PowerCommands.dll 組件新增到 Add-Ins 清單中

4. 將 Reflector.PowerCommands.dll 組間新增到 Add-Ins 清單中

如何使用 PowerCommands for Reflector

PowerCommands for Reflector 外掛程式將所有功能打散在 Reflector 工具的每一個角落,所以你沒辦法在同一個地方使用所有功能,以下我用不同區域做分類解釋各功能:

 

[ 主選單區 ]

1. Open Zip ( 直接開啟 ZIP 壓縮檔內的 .NET 組件 )

開啟時會自動由 PowerCommands for Reflector 解壓縮組件至 [我的文件] 目錄下的 Reflector\Unzipped 目錄下,此功能只是方便你不用先執行解壓縮動作而已。

Red Gate's .NET Reflector :: Open Zip

2. Assembly List Import/Export ( 匯入/匯出組件清單 )

當你有多個 組件清單(Assembly List) 時,你可以將這些清單匯出儲存起來,並將匯出的 XML 檔帶到其他台電腦後匯入,跟團隊其他成員分享不同的組件清單。

另外我也順帶講一下 組件清單(Assembly List) 的使用教學:

先建立組件清單名稱

Red Gate's .NET Reflector :: Open List Red Gate's .NET Reflector :: Open List :: Add New List

選取後會開始另一組組件清單並讓你設定另一批組件

Red Gate's .NET Reflector :: Start 'New List 1' Assembly List

日後你可以直接用 [File] / [Open List] 載入不同專案的組件清單。

而透過 Assembly List Import/Export 的功能就可以讓你匯出整份組件清單,並且可隨時匯入組件清單到其他電腦,匯入後可利用 [File] / [Open List]  (或用快速鍵 Ctrl + L ) 載入被匯入的組件清單。

Red Gate's .NET Reflector :: [Tools] / [Import/Export Assembly List] / [Export]

以下是匯出時的畫面

Red Gate's .NET Reflector :: [Tools] / [Import/Export Assembly List]

3. Reorder Assemblies ( 重新排序組件列表 )

將目前的組件清單以命名空間的字母順序進行排序。此功能除了出現在主選單外,也會出現在組件列表的滑鼠右鍵選單中。

4. Collapse All ( 收起所有組件列表的開啟狀態 )

將所有樹狀結構中已開啟的項目全部收合起來。此功能除了出現在主選單外,也會出現在組件列表的滑鼠右鍵選單中。

Red Gate's .NET Reflector :: Reorder Assemblies

5. Bookmarks Menu ( 書籤選單 )

書籤功能其實是 Reflector 內建的功能,在選取到你想要的組件、類別或成員後按下 Ctrl + K 即可建立書籤,下次開啟 Reflector 時就可以直接透過書籤跳到那個位置,但沒安裝 PowerCommands for Reflector 之前你必須按下 F2 開啟書籤視窗後才能選取書籤,安裝 PowerCommands for Reflector 後就可以直接透過主選單選取書籤,操作上的確比較方便。

Red Gate's .NET Reflector :: Bookmarks Menu

 

[ 命名空間層級’s 滑鼠右鍵選單區 ]

[ 命名空間層級’s 滑鼠右鍵選單區 ]

6. Create Assembly Binding Redirect ( 建立組件繫結重新導向 )

組件繫結重新導向功能在實務上不是很常用到,但需要的人就可以利用這個功能幫你建立組件繫結重新導向的 XML 定義,其實算是個貼心的小工具。

假設你選取 System.Web, Version 2.0.0.0 這個組件並點選 [Create Binding Redirect] 選項,這時會出現 Versions 對話框,當你希望應用程式可以改變組件繫結的版本時就可以直接在 New Version 欄位輸入要轉向的版本編號,然後再按下 Copy To Clipboard 即可將設定內容複製到剪貼簿中,然後再到應用程式組態檔中貼上 (Ctrl + V) 該設定即可。詳情請見: 設定組件繫結重新導向 & Introduction to Versioning and BindingRedirect

Create Assembly Binding Redirect ( 建立組件繫結重新導向 )

7. Create Shortcut

當你選取命名空間、組件、類別或類別成員時,按下 [Create Shortcut] 會在你的桌面建立一個快捷項目(Shortcut),下次要開啟 Reflector 時只要點選這個項目就可開啟 Reflector 並自動開啟到當時建立的那個位置。此功能同時也會出現在 [組件層級’s 滑鼠右鍵選單區]、[類別層級’s 滑鼠右鍵選單區] 與 [類別成員層級’s 滑鼠右鍵選單區]。

桌面快捷項目(Shortcut)

 

[ 組件層級’s 滑鼠右鍵選單區 ]

[ 組件層級’s 滑鼠右鍵選單區 ] 

8. Run ( 執行該組件 )

當你選取的組件是「可執行檔」時,才會出現 Run 這個選項,點選後會直接執行該組件。

9. Open VS2005/VS2008/VS2010 Command Prompt ( 開啟該組件所在位置的命令提示字元 )

開啟命令提示字元(cmd.exe),開啟後直接進入組件所在目錄。

10. Open Windows Explorer ( 開啟該組件所在位置的檔案總管 )

開啟檔案總管,開啟後直接進入組件所在目錄。

11. Open with ILDasm ( 以 ILDasm 工具開啟該組件 )

開啟 ILDasm 工具,並直接載入該組件。

12. Open With ( 以其他外部程式開啟檔案 )

以其他外部程式開啟組件檔,你可以自行定義一些外部的應用程式 (例如 Visual Studio 2008) 直接開啟組件、類別、類別成員、資源檔、…等等。如果你點選類別類別成員並利用 Open With 功能開啟時,PowerCommands for Reflector 會幫你將 Reflector 反解過的原始碼儲存到 [我的文件] 目錄下的 Reflector\Exports 目錄下。此功能同時也會出現在 [類別層級’s 滑鼠右鍵選單區] 與 [類別成員層級’s 滑鼠右鍵選單區] 與 [組件資源’s 滑鼠右鍵選單區]。

Open With External Application ( 以其他外部程式開啟檔案 )

13. Copy Path ( 複製組件路徑 )

此功能讓你複製組件所在的完整路徑檔名所在目錄路徑

 

[ 類別層級’s 滑鼠右鍵選單區 ]

[ 類別層級’s 滑鼠右鍵選單區 ]

14. Enum Viewer ( 列舉檢視器 )

Reflector 預設就可以檢視所有列舉項目(Enum),但列舉項目無法依照字母排序,也無法強制顯示列舉實際的數值,利用 Enum Viewer 讓你可以在主選單的 [View] / [Options] 中可設定列舉顯示的方式:

Red Gate's .NET Reflector :: Enum Viewer 讓你可以在主選單的 [View] / [Options] 中可設定列舉顯示的方式

 Red Gate's .NET Reflector :: Enum Viewer 讓你可以在主選單的 [View] / [Options] 中可設定列舉顯示的方式

15. Bit Flag Converter ( 位元旗標轉換器 )

只要有標上 [Flags] 屬性 (Attribute) 的 列舉型別 (enum) 都可以使用這個功能,其實只是一個簡單的二進位計算機而已。例如 System.Data.CommandBehavior 列舉就是一個標有 [Flags] 的型別,點選 Bit Flag Converter 後就會出現該列舉的所有清單,當你點選完後就會出現你勾選的項目做 Bit Mask 運算後的結果 (十進位)。

Red Gate's .NET Reflector :: Bit Flag Converter ( 位元旗標轉換器 )

 

[ 類別成員層級’s 滑鼠右鍵選單區 ]

[ 類別成員層級’s 滑鼠右鍵選單區 ]

16. Email Code ( 轉寄程式碼 )

此功能可將你選取的類別成員程式碼透過 mailto: 通訊協定開啟預設的本機郵件軟體 (例如: Outlook),並將程式碼填入到郵件內容中,方便你快速轉寄程式碼給其他人。

 

[ 組件資源’s 滑鼠右鍵選單區 ]

Red Gate's .NET Reflector :: Open with Paint ( 以小畫家開啟該圖片 ) Red Gate's .NET Reflector :: Save As RESX ( 將 .resources 資源檔儲存成 *.resx 檔 )

17. Open with Paint ( 以小畫家開啟該圖片 )

當選取的組件資源圖片類型的檔案時就可直接以小畫家開啟該圖片。

18. Save As RESX ( 將 .resources 資源檔儲存成 *.resx 檔 )

當選取的組件資源是 *.resources 格式時,使用此功能就能將該資源儲存成 XML 格式的 *.resx 資源檔。

---

我的天啊,這篇文章花了我整整三個小時撰寫,比我預期的撰寫時間還長,不過一條一條的測試/試用之後也對 Reflector 有了更深一層的認識,算是利用 PowerCommands for Reflector 精通了 Reflector 所有操作技巧吧,收穫頗多。 ^_^

相關連結

  

此文章由 will 發表於 2009/9/29 上午 09:23:22

永久連結 | 評論 (0) | 此文章的RSSRSS comment feed |

分類: 介紹好用工具 | .Net

標籤: , ,

收藏:

Unity Application Block 與 ASP.NET MVC 學習資源整理

Inversion of control (IoC) 與 Dependency injection (DI) 是我接觸 ASP.NET MVC 之後才注意到的一門學問,對其概念十分著迷,但由於中文資訊非常少且概念也有點抽象,所以遲遲沒有上手。上個週末花了不少時間研讀相關資料,並著手寫 Code 練習套用在 ASP.NET MVC 專案中,也算小有心得,特別將一些我看過的文章、資料整理一下,方便有心學習的人。

Unity Application Block 是微軟 Enterprise Library 中多個 Application Block 中的一部份,專注於實做 Dependency injection 容器,並支援 constructor, property, and method call 注入,目前實做 DI 的函示庫很多,但由於微軟的文件資源較為豐富,所以我就以 Unity 為入門學習的套件。

由於 DI ( IoC ) 算是個設計樣式 (Design Pattern),所以如果日後想要切換不同的 DI Framework 的話其實也不會太困難,因為觀念都是相通的,只要能理解運作的基本觀念,並且至少熟悉一套 DI Framework 就不會有太大問題,本文最後面有 各家實做的 Dependency Injection 框架比較 供各位參考。

以下是我研讀過的資料,或許對想學習 Unity / DI / IoC 的人來說會有幫助:

觀念建立

 

入門教學

 

官方網站

 

相關下載

 

範例程式

 

相關文章

 

部落格

 

各家實做的 Dependency Injection 框架比較

  

此文章由 will 發表於 2009/9/28 上午 12:26:55

永久連結 | 評論 (6) | 此文章的RSSRSS comment feed |

分類: ASP.NET MVC

標籤: , , , ,

收藏:

如何關閉 PowerCommands for VS2008 的 Undo Close 視窗

PowerCommands 在裝好之後每次只要重新開啟專案都會自動開啟 Undo Close 視窗,像我通常習慣沒用到的視窗就全部關閉,而 Undo Close 每次都會自動開啟讓我覺得很不是滋味,之前網友 ChrisTorng留言告知解決方法,不過我現在的電腦是 Windows 7 (x64) 的環境,導致機碼位置改變了,所以決定寫一篇文章來記錄修改的方式。

 PowerCommands for VS2008 的 Undo Close 工具視窗

[ 手動修改的方式 ]

  1. 開啟 regedit.exe 程式
  2. 刪除以下機碼
    • 在 x86 作業系統下的機碼路徑
      • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\9.0\ToolWindows\{eccc9e97-fd3b-4c15-af76-ef71a71d8b17}\Visibility
    • 在 x64 作業系統下的機碼路徑
      • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0\ToolWindows\{eccc9e97-fd3b-4c15-af76-ef71a71d8b17}\Visibility

[ 自動修改的方式 ]

直接下載我製作的機碼檔,下載後解壓縮並點選合併後即可:

備註:此機碼檔同時可刪除 x86 與 x64 環境下的機碼,所以下載一個檔即可。

合併機碼 

相關連結

  

此文章由 will 發表於 2009/9/27 上午 12:33:13

永久連結 | 評論 (0) | 此文章的RSSRSS comment feed |

分類: Visual Studio

標籤: , ,

收藏:

推薦使用 Microsoft Anti-Cross Site Scripting Library v3.1

雖然我之前已經寫過一篇【 推薦使用 Microsoft Anti-Cross Site Scripting Library V3.0 】文章,而且這次 Anti-XSS Library v3.1 也只有小幅新增功能,但這次新增的兩個方法(Methods)卻是我盼望許久的功能,終於被我給等到了。我覺得任何開發 ASP.NET Web 應用程式的人都應該注意並使用這一套強大的 Anti-XSS Library,絕對有助於提升你現有 Web 應用程式的安全性。

本次改版新增的 Methods 分別是:

  1. AntiXss.GetSafeHtml 方法:將傳入的 HTML 視為一整個頁面進行過濾。
  2. AntiXss.GetSafeHtmlFragment 方法:將傳入的 HTML 視為一個 HTML 片段進行過濾。

Anti_XSS Library Help

這兩個新增的方法 (Methods) 都是用來將傳入的字串/文字轉換成「安全的 HTML 語法」,並且支援 串流 (Stream) 處理,所以當要處理大量 HTML 字串時也非常有效率,且被轉換過的 HTML 語法也會被 正規化 (Normalize) 處理,讓非標準的 HTML 變成標準的 HTML 語法/格式。

所謂「安全的 HTML 語法」是指當傳入的 HTML 包含任何被判定為危險的(malicious)內容就會自動被刪除,用以保證最後得到的 HTML 語法是絕對安全的 HTML 版本,讓你日後就算程式寫在爛也不受 XSS 攻擊的威脅,其中包括惡意的 HTML 標籤 (例如: script, iframe, link,meta, …)、惡意的 HTML 屬性 (例如: onload, onclick, …)、惡意的 CSS 屬性 (各位知道在 CSS 中可以插入 JavaScript 執行嗎? 如下範例: )

<STYLE type="text/css">BODY{background:url("javascript:alert('XSS')")}</STYLE>

能在CSS 執行 JavaScript 是很多人不知道的開發技巧,但這同時也是駭客最愛玩的 XSS 遊戲,不過這語法在新版的瀏覽器中都被移除了,目前已知支援這語法的瀏覽器有 萬惡的 IE6.0IE7.0Firefox 2.0Opera 9.02 等,有認識朋友還在用 IE6/7 的人趕快請他們升級吧。

我寫了一支簡單的驗證程式,想探探 Anti-XSS Library v3.1 過濾惡意 HTML 的能力,我沒寫得很複雜,單純只是想看看轉換出來的結果如何。

程式碼如下:

轉換出來的結果是:

<div style="color:red; background:#FFF">OK </div>

當我試圖將 CSS 的 background 換成 url 的格式

轉換出來的結果是:

<div style="color:red">OK </div>

我也更進一步測試了 XSS (Cross Site Scripting) Cheat Sheet 所列的所有 XSS 攻擊情境,也確認 Anti-XSS Library 幾乎可以防禦所有的 XSS 手法 (除了一些非常非常舊的瀏覽器的XSS弱點之外),Anti-XSS Library 過濾 HTML 的精準度無庸置疑的好、執行速度也恨快,不管怎樣都比你自己過濾 HTML 還來的安全,這畢竟是發展好多年、經過無數次驗證過的 Anti-XSS Library 版本,而且這還是完全開放原始碼的專案,有興趣研究、驗證 Anti-XSS Library 的人可以到這裡下載最新版原始碼。

上段提到的一些非常非常舊的瀏覽器的XSS弱點講的是在 Netscape 4.0 中的一種非常特殊、詭異的 JavaScript 寫法竟然也能運作,如下範例:

<BR SIZE="&{alert('XSS')}">

說實在的,沒認真研究過 XSS 的人不會想到 XSS 有多少花招可以玩,你光看 XSS (Cross Site Scripting) Cheat Sheet 所列的所有 XSS 攻擊情境就非常有趣了,很多你想都沒想到的攻擊手法,還有 Ultimate XSS CSS injection 也是很有創意的攻擊手法。

一般人在接受網頁表單送出 HTML 時,如果要限制特定標籤才能寫入到資料庫時,或許會使用類似【清除字串中的HTML標籤利用RegExp進階版】的作法,但這樣的限制並不完整,還是非常容易被 XSS 攻擊,只要透過 HTML Attribute Injection 或 CSS Injection 就能攻擊成功,所以建議的作法是:

  1. 先用 Anti-XSS Library v3.1 支援的 AntiXss.GetSafeHtml 或 AntiXss.GetSafeHtmlFragment 方法過濾一遍所有輸入的 HTML 字串。
  2. 然後再過濾不想支援的 HTML 標籤,這個時候再使用【清除字串中的HTML標籤利用RegExp進階版】作法就非常完美了。

今天一整個下午都在研究 Anti-XSS Library v3.1,我發現裡面有個 HtmlToHtml Class 主要負責過濾 HTML 工作,而且寫的非常有彈性,當中有個 委派 (delegate) 屬性 HtmlTagCallback 可以用來自訂過濾特定標籤的程式邏輯,透過這種方式實做過濾標籤的功能也會比用 Regex 實做來的好,只可惜在 Anti-XSS Library v3.1 中將 HtmlToHtml 類別標注為 internal 所以沒辦法直接使用。由於 Anti-XSS Library v3.1 是開放原始碼(MS-PL),如果有需要的人還是可以將這些類別移到自己的專案中使用。

相關連結

  

此文章由 will 發表於 2009/9/26 下午 05:42:04

永久連結 | 評論 (3) | 此文章的RSSRSS comment feed |

分類: Security | ASP.NET | .Net | Web | ASP.NET MVC

標籤: , ,

收藏: