解析大型.NET ERP系统 设计异常处理模块
异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提高系统的健壮性。下面从我理解的角度,谈谈异常处理的方方面面。我的设计仅仅限定于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;
- }
- }
异常显示对话框显示异常,参考下面的界面。
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异常处理的核心部分在本篇的第三部分,设置捕获系统抛出的异常。
解析大型.NET ERP系统 设计异常处理模块的更多相关文章
- 解析大型.NET ERP系统 设计通用Microsoft Excel导入功能
做企业管理软件很难避免与Microsoft Excel打交道,常常是软件做好了,客户要求说再做一个Excel导入功能.导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到 ...
- 解析大型.NET ERP系统 十三种界面设计模式
成熟的ERP系统的界面应该都是从模板中拷贝出来的,各类功能的界面有规律可遵循.软件界面设计模式化或是艺术性的创作,我认可前者,模式化的界面客户容易举一反三,降低学习门槛.除了一些小部分的功能界面设计特 ...
- 解析大型.NET ERP系统 权限模块设计与实现
权限模块是ERP系统的核心模块之一,完善的权限控制机制给系统增色不少.总结我接触过的权限模块,以享读者. 1 权限的简明定义 ERP权限管理用一句简单的话来说就是:谁 能否 做 那些 事. 文句 含义 ...
- 解析大型.NET ERP系统架构设计 Framework+ Application 设计模式
我对大型系统的理解,从数量上面来讲,源代码超过百万行以上,系统有超过300个以上的功能,从质量上来讲系统应该具备良好的可扩展性和可维护性,系统中的功能紧密关联.除去业务上的复杂性,如何设计这样的一个协 ...
- 解析大型.NET ERP系统 业务逻辑设计与实现
根据近几年的制造业软件开发经验,以我开发人员的理解角度,简要说明功能(Feature)是如何设计与实现的,供参考. 因架构的不同,技术实现上会有所差异,我的经验仅限定于Windows Form程序. ...
- 解析大型.NET ERP系统 分布式应用模式设计与实现
C/S架构的应用程序,将一些复杂的计算逻辑由客户端转移到服务器端可以改善性能,同时也为了其它方面的控制..NET Remoting在局域网内调用的性能相当不错.ERP系统中基于.NET Remotin ...
- 解析大型.NET ERP系统 20条数据库设计规范
数据库设计规范是个技术含量相对低的话题,只需要对标准和规范的坚持即可做到.当系统越来越庞大,严格控制数据库的设计人员,并且有一份规范书供执行参考.在程序框架中,也有一份强制性的约定,当不遵守规范时报错 ...
- 解析大型.NET ERP系统 通用附件管理功能
大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...
- 解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计
ERP系统的单据具备标准的功能,这里的单据可翻译为Bill,Document,Entry,具备相似的工具条操作界面.通过设计可复用的基类,子类只需要继承基类窗体即可完成单据功能的程序设计.先看标准的销 ...
随机推荐
- Socket聊天程序——客户端
写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...
- 【.net 深呼吸】启动一个进程并实时获取状态信息
地球人和火星人都知道,Process类既可以获取正在运行的进程,也可以启动一个新的进程.在79.77%应用场合,我们只需要让目标进程顺利启动就完事了,至于它执行了啥,有没有出错,啥时候退出就不管了. ...
- WPF 微信 MVVM 【续】修复部分用户无法获取列表
看过我WPF 微信 MVVM这篇文章的朋友,应该知道我里面提到了我有一个小号是无法获取列表的,始终也没找到原因. 前两天经过GitHub上h4dex大神的指导,知道了原因,是因为微信在登录以后,web ...
- Android之常见问题集锦Ⅱ
Android问题集锦Ⅰ:http://www.cnblogs.com/AndroidJotting/p/4608025.html EditText输入内容改变事件监听 _edit.addTextCh ...
- 用javascript 写个函数返回一个页面里共使用了多少种HTML 标签
今天我无意间看到一个面试题: 如何用javascript 写个函数返回一个页面里共使用了多少种HTML 标签? 不知你看到 是否蒙B了,如果是我 面试,肯定脑子嗡嗡的响.... 网上搜了搜也没有找到答 ...
- $ORACLE_HOME变量值末尾多“/”惹的祸
之前一直误以为$ORACLE_HOME变量的路径中末尾多写一个"/"不会有影响. 今天做实验时碰到一个情景,发现并不是这样. 环境:OEL 5.7 + Oracle 10.2.0. ...
- 【SAP业务模式】之ICS(一):业务详述
PS:本专题系列讲述如何在SAP系统中实现ICS的业务模式,本系列博文系原创,如要转载引用,请保持原文一致并注明出处! SAP系统自身功能非常强大,支持多种业务模式,通过前台后台的配置就可以实现多种效 ...
- BZOJ 1597: [Usaco2008 Mar]土地购买 [斜率优化DP]
1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4026 Solved: 1473[Submit] ...
- jsp
-----------------
- 闭区间套定理(Nested intervals theorem)
① ②这里用到了极限与不等关系 ③如果a≠b,那么便不会有$\lim _{n\rightarrow \infty }\left| I_n \right| =0$ ④如果还存在一点c在内,那么同样也不会 ...