解析大型.NET ERP系統 設計異常處理模組

weixin_30924079發表於2015-08-14

異常處理模組是大型系統必備的一個元件,精心設計的異常處理模組可提高系統的健壯性。下面從我理解的角度,談談異常處理的方方面面。我的設計僅僅限定於Windows Forms,供參考。

1 定義異常型別

.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: 檔案伺服器連線失敗或授權失敗等異常

2 封裝異常資訊

在系統丟擲異常時,我們需要知道丟擲異常的程式的完整資訊,比如程式版本,最後更新時間,發生異常的堆疊等,有了這些資訊,技術支援或程式設計師可以快速定位異常,分析可能的原因。

為此目的,定義一個異常資訊封裝類,包含傳入異常,封裝更豐富的異常資訊。

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));
            }
      }
}

 

3  捕獲系統丟擲的異常

對Windows Forms程式,可以通過兩個屬性設定完成對系統異常的捕獲。

CustomExceptionHandler eh = new CustomExceptionHandler();
Application.ThreadException += new ThreadExceptionEventHandler(eh.OnThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

CustomExceptionHandler 是一個處理異常資訊密封類,原始碼如下,目的是為了統一系統的異常錯誤提示介面。

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; } }
 

異常顯示對話方塊顯示異常,參考下面的介面。

image

 

4  程式中可通過throw語句丟擲異常,實現N層回滾

儲存新實體物件時,判斷資料是否重複:

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異常處理的核心部分在本篇的第三部分,設定捕獲系統丟擲的異常。

相關文章