异常处理

未知异常处理

      对于未知异常,系统采用全局统一捕获的方式进行。一般情况下,代码中不会出现try...catch代码段。当发生未知异常时系统将其类型、操作人账号、以及异常内容存入数据表中。全局统一捕获写在Program类中,代码如下:

        /// <summary>
        
/// 统一捕获异常,非UI线程
        
/// </summary>
        
/// <param name="sender">sender</param>
        
/// <param name="e">异常</param>
        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if (e.ExceptionObject is System.Exception)
            {
                CommonService.CommonClient systemLog = new CommonService.CommonClient();
                systemLog.SaveLogInfo(e.ExceptionObject.ToString(), LoginInfo.CurrentUser.Account, e.ExceptionObject.GetType().ToString());
                systemLog.Close();
                CSMS2.Infrastructure.Helpers.AlterHelper.MessageBoxShowError(e.ExceptionObject.ToString());
            }
        }

        /// <summary>
        
/// 统一捕获异常,UI线程
        
/// </summary>
        
/// <param name="sender">sender</param>
        
/// <param name="e">异常</param>
        static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            CommonService.CommonClient systemLog = new CommonService.CommonClient();
            systemLog.SaveLogInfo(e.Exception.ToString(), LoginInfo.CurrentUser.Account, e.Exception.GetType().ToString());
            systemLog.Close();
            CSMS2.Infrastructure.Helpers.AlterHelper.MessageBoxShowError(e.Exception.ToString());
        }

      由此可见对于所有的除数据库连接方面的异常,系统都会将异常信息记录数据库。这样可以比较方便的进行查询,对于数据连接方面的问题,系统判断出后,会在右下角提示“您已断网”。

已知异常

     对于已知异常,系统做法比较复杂。因为已知的异常都是由开发人员根据需要,做特定处理的。框架规定了一些特殊类型,必须调用什么方法。下面一一举例说明:

  • WCF的异常处理

     对于WCF的客户端调用,都会使用类似如下方式进行:

                BiaoWuGLService.IBiaoWuGL client = ServiceProxyFactory.Create<BiaoWuGLService.IBiaoWuGL>("BasicHttpBinding_IBiaoWuGL");
                DataTable dt = client.FuHeDJ_ChaXun(searchDTO);

这时ServiceProxyFactory工厂类会自动进行异常的捕获和处理,这样就避免了每个开发人员都手工的写一大堆冗余的try...catch代码段。

那么ServiceProxyFactory工厂类是怎么进行异常处理的那,让我们看下代码片段:

        /// <summary>
        
/// 重写调用方法
        
/// </summary>
        
/// <param name="msg">通讯数据信息</param>
        
/// <returns></returns>
        public override IMessage Invoke(IMessage msg)
        {
            T channel = ChannelFactoryCreator.Create<T>(this._endpointName).CreateChannel();
            IMethodCallMessage methodCall = (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn = null;
            object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
            methodCall.Args.CopyTo(copiedArgs, 0);
            try
            {
                object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs);
                methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                (channel as ICommunicationObject).Close();
            }
            catch (Exception ex)
            {
                if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException)
                {
                    (channel as ICommunicationObject).Abort();
                }
                if (ex.InnerException != null)
                {
                    methodReturn = new ReturnMessage(ex.InnerException, methodCall);
                }
                else
                {
                    methodReturn = new ReturnMessage(ex, methodCall);
                }
            }
            return methodReturn;
        }

  由上面代码可以看出,当发生超时或通信异常时,代理会调用终止方法。否则会抛出对应的异常。

  • 对于事务的异常处理

     通常当事务发生异常时,都要回滚所有操作。由此框架通过委托方法提供了一些通用的方法供开发人员调用。

        /// <summary>
        
/// 回调函数,可以不写try catch代码
        
/// </summary>
        
/// <param name="account"></param>
        
/// <param name="func"></param>
        
/// <returns></returns>
        public static bool InvokeOracleTransaction(string account, Func<OracleTransaction, bool> func)
        {
            bool result = false;
            using (OracleConnection conn = new OracleConnection(Platform.Configuration.ConfigHelper.BusinessConnString))
            {
                conn.Open();
                OracleTransaction tran = conn.BeginTransaction(IsolationLevel.ReadCommitted);

                try
                {
                    result = func(tran);
                    if (result)
                    {
                        tran.Commit();
                    }
                    else
                    {
                        tran.Rollback();
                    }
                }
                catch (Exception ex)
                {
                    SystemLog.SaveLogInfo(ex.ToString(), account, ex.GetType().ToString());
                    tran.Rollback();
#if DEBUG
                    throw ex;
#else
                    return false;
#endif
                }
            }
            return result;
        }

由上可以发现,当事务异常时会回滚所有操作,并记录日志。开发人员只需调用该方法,并传入相应的事务和方法即可。

  • 一些控件的异常

     比如扫描控件、Grid控件系统都会将原异常捕获,然后加上特殊的中文描述,使得客户和开发人员能够比较方便的判断异常的成因。

                try
                {
                    // 设置鼠标
                    this.Cursor = Cursors.Default;

                    // 抹去框架
                    
//Graphics g = this.CreateGraphics();
                    
//DrawSelectionFrame(g);
                    
//g.Dispose();

                    
// 标准化点
                    NormalizePoints(ref startImgP, ref endImgP);

                    size.Width = endImgP.X - startImgP.X + 1;
                    size.Height = endImgP.Y - startImgP.Y + 1;
                    rec.Size = size;
                    Crop cp = new Crop(rec);
                    // 剪切图像
                    ApplyFilter(cp);
                }
                catch (Exception ex)
                {
                    if (this.languageType == "zh-CN")
                        MessageBox.Show("对不起!切图出错:" + ex.Message, "系统提示");
                    else
                        MessageBox.Show("Cutting image error:" + ex.Message, "System Information"); 
                
                }
  • 一般的业务操作的异常

     对于一般业务操作,系统会记录异常,并将message向上抛出,然后由对应的界面决定到底返回什么错误信息给客户。这里的message已经是经过加工后的消息了,具体怎么加工是由开发人员根据情况处理的。

        /// <summary>
        
/// 工单登记
        
/// </summary>
        
/// <param name="message"></param>
        
/// <param name="dto"></param>
        
/// <param name="login"></param>
        
/// <returns></returns>
        public static bool DengJi(out string message, FuHeDJDTO dto, Entity.BW_YUYUEXX yuyuexx, UploadEntity[] uploadEntityList, Entity.LoginInfo login)

     上面是对于工单登记的方法接口,如有错误会已out message的形式返回。

原文地址:https://www.cnblogs.com/zyizyizyi/p/2669195.html