異常處理模塊是大型系統必備的一個組件,精心設計的異常處理模塊可提升系統的健壯性。下面從我理解的角度,談談異常處理的方方面面。個人設計僅僅限定於Windows Forms,供參考。html
.NET 框架定義不少異常類型,ERP系統中根據實際的須要,咱們再增長一些自定義的異常類型。程序員
數據庫訪問異常:LLBL Gen Pro已經定義幾種常見的異常類型,常見的異常類型及其做用簡介。數據庫
ORMConcurrencyException 併發異常,更新實體時實體已經被刪除,刪除時有約束沒法刪除
ORMEntityOutOfSyncException. (Adapter) 實體保存以後沒有從新讀取,使用它的屬性時拋出ORMEntityIsDeletedException 實體已經刪除,但仍然訪問它的屬性
ORMFieldIsNullException. 在實體的屬性值設爲NULL以後,仍然去訪問它的屬性性
ORMEntityValidationException 自定義異常
ORMFieldIsReadonlyException 給只讀的屬性賦值
ORMInheritanceInfoException 查詢執行過程當中檢測到錯誤
ORMQueryConstructionException ORM框架構造動態查詢(Dynamic Query Engine )失敗時ORMQueryExecutionException ORM框架執行動態查詢(Dynamic Query Engine )失敗時
ORMRelationException 關係設定錯誤
ORMSecurityException 用於受權(Authorization)失敗後
ORMValueTypeMismatchException 屬性的值與類型不匹配服務器
業務邏輯異常: 定義應用程序中的業務邏輯異常類型架構
AccessDeniedException 模塊或功能當前登入用戶無權限訪問
CrystalReportException 水晶報表的運行庫加載失敗,報表鏈接數據庫失敗,報表公式解析失敗等異常
EntityValidationException 業務對象驗證失敗
FieldValidationException 業務對象的屬性驗證失敗
LicenseException 許可證受權異常
FtpException: 文件服務器鏈接失敗或受權失敗等異常
併發
在系統拋出異常時,咱們須要知道拋出異常的程序的完整信息,好比程序版本,最後更新時間,發生異常的堆棧等,有了這些信息,技術支持或程序員能夠快速定位異常,分析可能的緣由。框架
爲此目的,定義一個異常信息封裝類,包含傳入異常,封裝更豐富的異常信息。ide
public sealed class ExceptionDetail { private System.Exception _exception; private void Initialize() { if (this._exception != null) { builder = builder.Append(format).Replace("\n", "\r\n"); builder.Append(string.Format("Date: {0} {1}\r\n", DateTime.Today.ToShortDateString(), DateTime.Now.ToLongTimeString())); builder.Append(string.Format("Version: {0} ({1})\r\n", AssemblyVersion.Version, File.GetLastWriteTime(typeof(AssemblyVersion).Assembly.Location))); builder.Append(string.Format("Source: {0}\r\n", innerException.Source)); builder.Append(string.Format("Class: {0}\r\n", (innerException.TargetSite != null) ? innerException.TargetSite.DeclaringType.ToString() : null)); builder.Append(string.Format("Member Type: {0}\r\n", (innerException.TargetSite != null) ? innerException.TargetSite.MemberType.ToString() : null)); builder.Append(string.Format("Member Name: {0}\r\n", innerException.TargetSite)); builder.Append(string.Format("Exception Type: {0}\r\n", innerException.GetType().FullName)); builder.Append(string.Format("Data: {0}\r\n", obj2)); builder.Append("\r\n"); builder.Append(string.Format("Exception: {0}", message)); } } }
對Windows Forms程序,能夠經過兩個屬性設定完成對系統異常的捕獲。ui
CustomExceptionHandler eh = new CustomExceptionHandler(); Application.ThreadException += new ThreadExceptionEventHandler(eh.OnThreadException); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
CustomExceptionHandler 是一個處理異常信息密封類,源代碼以下,目的是爲了統一系統的異常錯誤提示界面。this
internal sealed class CustomExceptionHandler { public bool IsDebug = false; public CustomExceptionHandler() { } //Handle the exception event public void OnThreadException(object sender, ThreadExceptionEventArgs t) { if (IsDebug)
Debug.Assert(false, t.Exception.Message, t.Exception.StackTrace); DialogResult result = DialogResult.Cancel; try { result = this.ShowThreadExceptionDialog(t.Exception); } catch { try { result = MessageBox.Show(string.Format("{0}\r\n\r\n{1}", t.Exception.Message, t.Exception.StackTrace), "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { Application.Exit(); } } if (result == DialogResult.Abort) Application.Exit(); } private DialogResult ShowThreadExceptionDialog(Exception e) { return DialogResult.Cancel; } }
異常顯示對話框顯示異常,參考下面的界面。
保存新實體對象時,判斷數據是否重複:
if (salesContract.IsNew) { ISalesContractManager salesContractManager = CreateProxyInstance<ISalesContractManager>(); if (salesContractManager.IsSalesContractExist(salesContract.ContractNo)) throw new RecordDuplicatedException(salesContract.ContractNo, "Cotract No. is already used"); }
發生屬性改變事件時,觸發驗證:
public override bool ValidateFieldValue(IEntityCore involvedEntity, int fieldIndex, object value) { bool result = base.ValidateFieldValue(involvedEntity, fieldIndex, value); if (!result) return false; switch ((SalesContractFieldIndex) fieldIndex) { case SalesContractFieldIndex.CustomerNo: return this.ValidateCustomerNo((string) value); } return true; } private bool ValidateCustomerNo(string value) { if (!string.IsNullOrEmpty(value)) { ICustomerManager customerManager = ClientProxyFactory.CreateProxyInstance<ICustomerManager>(); customerManager.ValidateCustomerNo(Shared.CurrentUserSessionId, value); } return true; }
Windows Forms異常處理的核心部分在本篇的第三部分,設置捕獲系統拋出的異常。