JerryMouseLi

工程中实际问题解决两例——基于C#

1. try catch的妙用

1.1 遇到问题的现象

机房动环监控系统,添加了100多个站点,新加设备无法同步,界面点同步,通信服务会报错退出
同步设备操作如下:

通信异常如下:

大概意思是字典缓存中查无此值(根据键找)。

1.2 原因分析

其实每个比较大的bug都是系统设计不合理的地方,同时也是下次系统设计的宝贵经验。
同时需要阐明的是bug只要能复现,就一定能解决,或者是从正面解决,或者是策略解决(受限于资源或者网络的时候)。
主要从日志(文件打印或者命令窗口打印),数据库,代码三个层面。

1.2.1 先从数据库入手

找到数据库中历史数据插入的表deviceData,会不会因为有些字段为非空了,导致插入失败。全字段允许为空,结果依然报错;

1.2.2 代码日志逐级打印结合数据库

根据窗体报错的行数970,598,以及数据库中的PesudoDevice表,结合系统设计的逻辑,大体流程如下:请求设备上报数据,根据协议设备将上报数据格式(配置规则),平台将协议模板序列化保存到PesudoDevice表的content字段中。采集的数据会按照告警规则与信号点规则,保存到businessSignal与activeAlarm表中去。

其中主要的两个类型如下:
某机房的所有业务设备

    /// <summary>
    /// 业务设备模板内容
    /// </summary>
    public class PseudoDeviceTemplateContext
    {
        /// <summary>
        /// 物理设备
        /// </summary>
        public List<string> ConcreteDeviceIDs { get; set; }
        /// <summary>
        /// 测点列表
        /// </summary>
        public List<PseudoDeviceTemplateSignal> Signals { get; set; }
    }

单个信号点的类型

    /// <summary>
    /// 业务设备模板测点定义
    /// </summary>
    public class PseudoDeviceTemplateSignal
    {
        /// <summary>
        /// 物理设备ID
        /// </summary>
        public string  ConcreteDeviceID{get;set;}
        /// <summary>
        /// 物理设备名称
        /// </summary>
        public string  ConcreteDeviceName{get;set;}
        /// <summary>
        /// 物理设备类型ID
        /// </summary>
        public string  ConcreteDeviceTypeID {get;set;}
        /// <summary>
        /// 物理设备类型ID
        /// </summary>
        public string ConcreteDeviceTypeName { get; set; }
        /// <summary>
        /// 测点ID
        /// </summary>
        public string SignalID { get; set; }
        /// <summary>
        /// 通道ID
        /// </summary>
        public string ChannelID { get; set; }
        /// <summary>
        /// 通道名称
        /// </summary>
         public string ChannelName  {get;set;}
        /// <summary>
        /// 通道类型
        /// </summary>
         public int? ChannelType  {get;set;}
        /// <summary>
        /// 测点名称
        /// </summary>
         public string SignalName{get;set;}
        /// <summary>
        /// 测点类型ID
        /// </summary>
          public string SignalTypeID{get;set;}
        /// <summary>
        /// 单位ID
        /// </summary>
          public string UnitMeasureID { get; set; }
        /// <summary>
        /// 告警条件列表
        /// </summary>
          public List<SignalAlarmCondition> AlarmConditions { get; set; }
        /// <summary>
        /// 存储条件列表
        /// </summary>
        public List<DeviceDataStoreRule> DeviceDataStoreRules { get; set; }
        /// <summary>
        /// 精度
        /// </summary>
        public string MinPrecision { get; set; }

          /// <summary>
          /// 标称值
          /// </summary>
          public double? Stander { get; set; }

          /// <summary>
          /// 标称值
          /// </summary>
          public int? IsSaveHis { get; set; }

          /// <summary>
          /// 标称值
          /// </summary>
          public double? MaxVal { get; set; }

          /// <summary>
          /// 标称值
          /// </summary>
          public double? MinVal { get; set; }

          /// <summary>
          /// 标称值
          /// </summary>
          public int? IsControl { get; set; }

          /// <summary>
          /// 标称值
          /// </summary>
          public long? DataID { get; set; }

          /// <summary>
          /// 父数据ID
          /// </summary>
          public long? ParentDataID { get; set; }
    }

1.2.3 原因分析

经过前端接口状态查询,数据库sql查询,日志逐级打印,最终定位某同步失败站点数据表PesudoDevice的content字段为空,原来应该为设备ID集合与协议模板解析规则。因为该设备协议模板较大,而序列化json比较耗时,此时设备的轮询报文到来,导致解析异常,从而程序崩溃。

1.2.4 解决方案

原因找准确了,解决方法其实很简单,只要把一开始解析异常的代码try catch异常。等解析规则存储完毕了,自然就能把信号点解析准确。
异常崩溃代码;

 PseudoDeviceStatus data;
            this.DPServiceObj.GetPseudoDeviceRealData(task.DstPseudoDeviceID, task.DstSignalID, out  data );

解决异常代码:

            PseudoDeviceStatus data=null;
            try
            {
                this.DPServiceObj.GetPseudoDeviceRealData(task.DstPseudoDeviceID, task.DstSignalID, out data);
            }
            catch (Exception e)            
            {
                log.ErrorFormat("获取设备实时数据失败:{0}",e);
            }

分析问题时间用了很久,对问题理解透彻了以后,解决问题并不需要几行代码。

1.2.5 问题解决

数据同步成功结果

2. json长度限制带来的困惑

2.1 现象描述

随着站点(含待测点)添加越来越多,单次加载遇到瓶颈,无法将全部数据单次加载。

2.2 问题分析

2.2.1 第一步,查看对应告警预案接口,报服务器错误

2.2.2 第二步,查看接口返回结果预览

错误提示为返回字符串长度超过了json的默认最大长度,这个问题已经遇到过,设置下json序列化的最大长度即可轻松解决。

2.2.3 问题解决

问题代码

        /// <summary>
        /// 获取设备树
        /// </summary>
        /// <returns></returns>
        public ActionResult GetAlarmPlanDevTree()
        {
            List<object> children = new List<object>();

            List<Area> areas = DevicesTreeHelper.GetAreaStation();
            foreach (Area a in areas)
            {
                children.Add(GetATreeData(a, true));
            }
            return Json(children);
        }

问题解决代码

        /// <summary>
        /// 获取设备树
        /// </summary>
        /// <returns></returns>
        public ActionResult GetAlarmPlanDevTree()
        {
            List<object> children = new List<object>();

            List<Area> areas = DevicesTreeHelper.GetAreaStation();
            foreach (Area a in areas)
            {
                children.Add(GetATreeData(a, true));
            }
            return new JsonResult() { Data = children, MaxJsonLength = int.MaxValue, ContentType = "application/json" };
        }

解决之后所有测点信号加载成功

3. 小结

遇到问题并不可怕,只要能复现,根据具体提示,逐级打印日志,分析数据库,问题就能迎刃而解,在此做个记录,下次类似问题遇到能有印象,快速定位解决。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://www.cnblogs.com/JerryMouseLi/p/15545356.html

相关文章:

猜你喜欢