异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提升系统的健壮性。下面从我理解的角度,谈谈异常处理的方方面面。个人设计仅仅限定于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异常处理的核心部分在本篇的第三部分,设置捕获系统抛出的异常。