EntryController.cs 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. using System;
  2. using Newtonsoft.Json.Linq;
  3. using System.Web.Http;
  4. namespace ThCardReader
  5. {
  6. public class EntryController : ApiController
  7. {
  8. public JObject Get(string param)
  9. {
  10. JObject result = new JObject();
  11. if (param == null)
  12. {
  13. result.Add("code", 1001);
  14. result.Add("message", "参数为空!");
  15. return result;
  16. }
  17. string[] temps = param.Split(new char[] { '_' });
  18. // 检查两段式前缀(如 jiangsu_face、jiangsu_qrcode)
  19. string type;
  20. if (temps.Length >= 2 && temps[0].Equals("jiangsu") &&
  21. (temps[1].Equals("face") || temps[1].Equals("qrcode")))
  22. {
  23. type = temps[0] + "_" + temps[1]; // 组合成 jiangsu_face 或 jiangsu_qrcode
  24. }
  25. else
  26. {
  27. type = temps[0]; // 单段前缀
  28. }
  29. if (type.Equals("qrcode"))
  30. {
  31. result = NationalEcBusiness.ReadQrCode(temps[1]);
  32. }
  33. else if (type.Equals("qrcode2"))
  34. {
  35. result = NationalEcBusiness.ReadQrCode2(temps[1]);
  36. }
  37. else if (type.Equals("face"))
  38. {
  39. result = NationalEcBusiness.ReadFace(temps[1]);
  40. }
  41. else if (type.Equals("sicard"))
  42. {
  43. result = SsCardBusiness.ReadSiCard();
  44. }
  45. else if (type.Equals("idcard"))
  46. {
  47. result = SsCardBusiness.ReadIdCard();
  48. }
  49. else if (type.Equals("idcard2"))
  50. {
  51. result = NationalEcBusiness.ReadIdCard(temps[1]);
  52. }
  53. else if (type.Equals("huashi"))
  54. {
  55. // 华视读卡器调用
  56. string action = temps.Length > 1 ? temps[1] : "readcard";
  57. // 检查是否是业务代码格式(5位数字),如果是则默认为readcard操作
  58. if (temps.Length > 1 && IsBusinessCode(temps[1]))
  59. {
  60. action = "readcard"; // 业务代码不影响华视读卡器操作,默认读卡
  61. }
  62. if (action.Equals("init"))
  63. {
  64. int port = temps.Length > 2 ? int.Parse(temps[2]) : 1001;
  65. result = HuaShiIdCardBusiness.Initialize(port);
  66. }
  67. else if (action.Equals("readcard"))
  68. {
  69. // URL调用时启用自动关闭,模拟SSCard.dll的无状态行为
  70. var huashiResult = HuaShiIdCardBusiness.ReadIdCard("", true);
  71. result = ConvertHuaShiDataToStandardFormat(huashiResult);
  72. }
  73. else if (action.Equals("continuous"))
  74. {
  75. // URL调用时启用自动关闭,模拟SSCard.dll的无状态行为
  76. var huashiResult = HuaShiIdCardBusiness.ReadIdCardContinuous("", true);
  77. result = ConvertHuaShiDataToStandardFormat(huashiResult);
  78. }
  79. else if (action.Equals("status"))
  80. {
  81. result = HuaShiIdCardBusiness.GetDeviceStatus();
  82. }
  83. else if (action.Equals("close"))
  84. {
  85. result = HuaShiIdCardBusiness.Close();
  86. }
  87. else
  88. {
  89. result.Add("code", 1001);
  90. result.Add("message", "华视读卡器操作【" + action + "】错误!允许的操作为【init、readcard、continuous、status、close】");
  91. }
  92. }
  93. else if (type.Equals("jiangsu_face"))
  94. {
  95. // 江苏医保刷脸授权获取医保身份 - 使用NationECCode.dll与泰和完全一致
  96. // URL格式: http://localhost:8321/readcard/entry?param=jiangsu_face_${nowbiztype}
  97. string businessType = temps.Length > 2 ? temps[2] : "01101"; // 从URL参数获取业务类型(第3段)
  98. // 验证业务类型格式
  99. if (!JiangSuSocialCardBusiness.IsValidBusinessType(businessType))
  100. {
  101. result.Add("success", false);
  102. result.Add("code", 1001);
  103. result.Add("message", $"江苏医保刷脸业务类型【{businessType}】无效!支持的业务类型:01101(门诊挂号)、01301(门诊结算)、02121(药店购药)等");
  104. result.Add("type", "face");
  105. result.Add("device", "江苏医保刷脸认证器(NationECCode.dll)");
  106. result.Add("businessType", businessType);
  107. }
  108. else
  109. {
  110. result = JiangSuSocialCardBusiness.ReadFace(businessType); // 使用NationECCode.dll与泰和完全一致
  111. // 转换为前端期望的格式
  112. result = ConvertJiangSuFaceAuthToStandardFormat(result);
  113. }
  114. }
  115. else if (type.Equals("jiangsu_qrcode"))
  116. {
  117. // 江苏医保电子凭证解码(独立入口)
  118. string businessType = temps.Length > 2 ? temps[2] : "01101"; // 从URL参数获取业务类型(第3段)
  119. // 验证业务类型格式
  120. if (!JiangSuSocialCardBusiness.IsValidBusinessType(businessType))
  121. {
  122. result.Add("success", false);
  123. result.Add("code", 1001);
  124. result.Add("message", $"江苏医保电子凭证业务类型【{businessType}】无效!支持的业务类型:01101(门诊挂号)、01301(门诊结算)、02121(药店购药)等");
  125. result.Add("type", "qrcode");
  126. result.Add("device", "江苏医保电子凭证解码器");
  127. }
  128. else
  129. {
  130. result = JiangSuSocialCardBusiness.ReadElectronicCertificate(businessType);
  131. // 转换为前端期望的格式
  132. result = ConvertJiangSuElectronicCertificateToStandardFormat(result);
  133. }
  134. }
  135. else if (type.Equals("jiangsu"))
  136. {
  137. // 江苏医保社保卡读取
  138. string action = temps.Length > 1 ? temps[1] : "readcard";
  139. // 检查是否是业务代码格式(5位数字),如果是则默认为readcard操作
  140. if (temps.Length > 1 && IsBusinessCode(temps[1]))
  141. {
  142. action = "readcard"; // 业务代码不影响江苏医保读卡操作,默认读卡
  143. }
  144. if (action.Equals("init"))
  145. {
  146. result = JiangSuSocialCardBusiness.Initialize();
  147. }
  148. else if (action.Equals("readcard"))
  149. {
  150. result = JiangSuSocialCardBusiness.ReadSocialCard(false);
  151. // 转换为前端期望的格式
  152. result = ConvertJiangSuDataToStandardFormat(result);
  153. }
  154. else if (action.Equals("readcard_pin"))
  155. {
  156. result = JiangSuSocialCardBusiness.ReadSocialCard(true);
  157. result = ConvertJiangSuDataToStandardFormat(result);
  158. }
  159. else if (action.Equals("verifypin"))
  160. {
  161. result = JiangSuSocialCardBusiness.VerifyCardPIN();
  162. }
  163. else if (action.Equals("changepin"))
  164. {
  165. result = JiangSuSocialCardBusiness.ChangeCardPIN();
  166. }
  167. else if (action.Equals("status"))
  168. {
  169. result = JiangSuSocialCardBusiness.GetDeviceStatus();
  170. }
  171. else if (action.Equals("reset"))
  172. {
  173. result = JiangSuSocialCardBusiness.ResetSystemState();
  174. }
  175. else if (action.Equals("getpersoninfo"))
  176. {
  177. result = JiangSuSocialCardBusiness.GetPersonInfo("socialcard", "");
  178. }
  179. else if (action.Equals("checkdll"))
  180. {
  181. result = JiangSuSocialCardBusiness.CheckDllExists();
  182. }
  183. else if (action.Equals("qrcode") || action.Equals("ec"))
  184. {
  185. // 江苏医保电子凭证解码
  186. string businessType = temps.Length > 2 ? temps[2] : "01101"; // 默认门诊挂号
  187. // 验证业务类型格式
  188. if (!JiangSuSocialCardBusiness.IsValidBusinessType(businessType))
  189. {
  190. result.Add("success", false);
  191. result.Add("code", 1001);
  192. result.Add("message", $"江苏医保电子凭证业务类型【{businessType}】无效!支持的业务类型:01101(门诊挂号)、01301(门诊结算)、02121(药店购药)等");
  193. result.Add("type", "qrcode");
  194. result.Add("device", "江苏医保电子凭证解码器");
  195. }
  196. else
  197. {
  198. result = JiangSuSocialCardBusiness.ReadElectronicCertificate(businessType);
  199. // 转换为前端期望的格式(电子凭证不需要特殊转换,保持原格式)
  200. result = ConvertJiangSuElectronicCertificateToStandardFormat(result);
  201. }
  202. }
  203. else
  204. {
  205. result.Add("success", false);
  206. result.Add("code", 1001);
  207. result.Add("message", "江苏医保操作【" + action + "】错误!允许的操作为【init、readcard、readcard_pin、verifypin、changepin、status、reset、getpersoninfo、checkdll、qrcode、ec】");
  208. }
  209. }
  210. else
  211. {
  212. result.Add("code", 1001);
  213. result.Add("message", "读卡类别【" + type + "】错误!允许的类别为【sicard、idcard、idcard2、qrcode、qrcode2、face、huashi、jiangsu、jiangsu_qrcode、jiangsu_face】");
  214. }
  215. return result;
  216. }
  217. /// <summary>
  218. /// 判断字符串是否是业务代码格式(5位数字)
  219. /// </summary>
  220. /// <param name="code">要检查的字符串</param>
  221. /// <returns>是否是业务代码</returns>
  222. private bool IsBusinessCode(string code)
  223. {
  224. if (string.IsNullOrEmpty(code) || code.Length != 5)
  225. {
  226. return false;
  227. }
  228. // 检查是否是5位数字
  229. foreach (char c in code)
  230. {
  231. if (!char.IsDigit(c))
  232. {
  233. return false;
  234. }
  235. }
  236. return true;
  237. }
  238. /// <summary>
  239. /// 将华视读卡器的数据格式转换为前端期望的"^"分隔字符串格式
  240. /// </summary>
  241. /// <param name="huashiResult">华视读卡器返回的JSON数据</param>
  242. /// <returns>转换后的标准格式</returns>
  243. private JObject ConvertHuaShiDataToStandardFormat(JObject huashiResult)
  244. {
  245. JObject result = new JObject();
  246. try
  247. {
  248. // 如果华视读卡器返回错误,直接返回错误信息
  249. if ((int)huashiResult["code"] != 200)
  250. {
  251. return huashiResult;
  252. }
  253. // 提取华视读卡器返回的数据
  254. var data = huashiResult["data"];
  255. if (data == null)
  256. {
  257. result.Add("code", 1001);
  258. result.Add("message", "华视读卡器返回数据为空");
  259. return result;
  260. }
  261. // 按照前端期望的顺序组装数据:
  262. // str1[0] = IDNumber (身份证号)
  263. // str1[1] = Name (姓名)
  264. // str1[2] = Sex (性别)
  265. // str1[3] = Nation (民族)
  266. // str1[4] = Birthday (生日)
  267. // str1[5] = Address (地址)
  268. // str1[6] = IDIssued (签发机关)
  269. // str1[7] = IssuedData + ValidDate (签发日期+有效期,连续)
  270. // str1[8] = Base64Photo (照片Base64)
  271. string idNumber = data["idCode"]?.ToString() ?? "";
  272. string name = data["name"]?.ToString() ?? "";
  273. string sex = data["sex"]?.ToString() ?? "";
  274. string nation = data["nation"]?.ToString() ?? "";
  275. string birthday = data["birthday"]?.ToString() ?? "";
  276. string address = data["address"]?.ToString() ?? "";
  277. string department = data["department"]?.ToString() ?? "";
  278. string startDate = data["startDate"]?.ToString() ?? "";
  279. string endDate = data["endDate"]?.ToString() ?? "";
  280. // 组合签发日期和有效期 (前端会用substring分割)
  281. string dateInfo = startDate + endDate;
  282. // 获取照片的Base64数据
  283. string base64Photo = data["photoBase64"]?.ToString() ?? "";
  284. // 按照前端期望的顺序用"^"连接
  285. string formattedData = string.Join("^", new string[] {
  286. idNumber, // [0] 身份证号
  287. name, // [1] 姓名
  288. sex, // [2] 性别
  289. nation, // [3] 民族
  290. birthday, // [4] 生日
  291. address, // [5] 地址
  292. department, // [6] 签发机关
  293. dateInfo, // [7] 签发日期+有效期
  294. base64Photo, // [8] 照片Base64
  295. "", // [9] 预留空位,确保split后数组有足够元素
  296. "" // [10] 预留空位
  297. });
  298. result.Add("code", 200);
  299. result.Add("message", "华视读卡器读取成功(已转换为标准格式)");
  300. result.Add("data", formattedData);
  301. result.Add("device", "华视电子身份证读卡器");
  302. result.Add("originalType", "huashi_idcard");
  303. }
  304. catch (System.Exception ex)
  305. {
  306. result.Add("code", 1001);
  307. result.Add("message", $"华视数据格式转换异常: {ex.Message}");
  308. }
  309. return result;
  310. }
  311. /// <summary>
  312. /// 将江苏医保社保卡的数据格式转换为前端期望的"^"分隔字符串格式
  313. /// </summary>
  314. /// <param name="jiangsuResult">江苏医保返回的JSON数据</param>
  315. /// <returns>转换后的标准格式</returns>
  316. private JObject ConvertJiangSuDataToStandardFormat(JObject jiangsuResult)
  317. {
  318. JObject result = new JObject();
  319. try
  320. {
  321. // 如果江苏医保返回错误,直接返回错误信息
  322. if (!(bool)jiangsuResult["success"] || (int)jiangsuResult["code"] != 200)
  323. {
  324. // 保持原有的success和code字段,但调整为前端期望的格式
  325. result.Add("code", jiangsuResult["code"]);
  326. result.Add("message", jiangsuResult["message"]);
  327. result.Add("device", "江苏医保社保卡读卡器");
  328. return result;
  329. }
  330. // 提取江苏医保返回的数据
  331. var data = jiangsuResult["data"];
  332. if (data == null)
  333. {
  334. result.Add("code", 1001);
  335. result.Add("message", "江苏医保返回数据为空");
  336. return result;
  337. }
  338. // 按照前端期望的顺序组装社保卡数据:
  339. // str1[0] = CardNumber (社保卡号)
  340. // str1[1] = Name (姓名)
  341. // str1[2] = IDNumber (身份证号)
  342. // str1[3] = Sex (性别)
  343. // str1[4] = Nation (民族)
  344. // str1[5] = Birthday (生日)
  345. // str1[6] = Address (地址)
  346. // str1[7] = IssueDate (发卡日期)
  347. // str1[8] = ValidDate (有效期)
  348. // str1[9] = Department (发卡机构)
  349. // str1[10] = Photo (照片Base64)
  350. string cardNumber = data["cardNumber"]?.ToString() ?? "";
  351. string name = data["name"]?.ToString() ?? "";
  352. string idNumber = data["idNumber"]?.ToString() ?? "";
  353. string sex = data["sex"]?.ToString() ?? "";
  354. string nation = data["nation"]?.ToString() ?? "";
  355. string birthday = data["birthday"]?.ToString() ?? "";
  356. string address = data["address"]?.ToString() ?? "";
  357. string issueDate = data["issueDate"]?.ToString() ?? "";
  358. string validDate = data["validDate"]?.ToString() ?? "";
  359. string department = data["department"]?.ToString() ?? "";
  360. string photo = data["photo"]?.ToString() ?? "";
  361. // 按照前端期望的顺序用"^"连接(社保卡格式)
  362. string formattedData = string.Join("^", new string[] {
  363. cardNumber, // [0] 社保卡号
  364. name, // [1] 姓名
  365. idNumber, // [2] 身份证号
  366. sex, // [3] 性别
  367. nation, // [4] 民族
  368. birthday, // [5] 生日
  369. address, // [6] 地址
  370. issueDate, // [7] 发卡日期
  371. validDate, // [8] 有效期
  372. department, // [9] 发卡机构
  373. photo, // [10] 照片Base64
  374. "", // [11] 预留空位
  375. "" // [12] 预留空位
  376. });
  377. result.Add("code", 200);
  378. result.Add("message", "江苏医保社保卡读取成功(已转换为标准格式)");
  379. result.Add("data", formattedData);
  380. result.Add("device", "江苏医保社保卡读卡器");
  381. result.Add("originalType", "jiangsu_socialcard");
  382. }
  383. catch (System.Exception ex)
  384. {
  385. result.Add("code", 1001);
  386. result.Add("message", $"江苏医保数据格式转换异常: {ex.Message}");
  387. }
  388. return result;
  389. }
  390. /// <summary>
  391. /// 将江苏医保电子凭证解码结果转换为前端期望的格式
  392. /// </summary>
  393. /// <param name="jiangsuEcResult">江苏医保电子凭证解码返回的JSON数据</param>
  394. /// <returns>转换后的标准格式</returns>
  395. private JObject ConvertJiangSuElectronicCertificateToStandardFormat(JObject jiangsuEcResult)
  396. {
  397. JObject result = new JObject();
  398. try
  399. {
  400. // 如果江苏医保电子凭证解码返回错误,直接返回错误信息
  401. if (!(bool)jiangsuEcResult["success"] || (int)jiangsuEcResult["code"] != 200)
  402. {
  403. // 保持原有的字段,确保前端能正确处理
  404. result.Add("code", jiangsuEcResult["code"]);
  405. result.Add("message", jiangsuEcResult["message"]);
  406. result.Add("device", jiangsuEcResult["device"]);
  407. result.Add("type", jiangsuEcResult["type"]);
  408. // 添加其他可能的错误信息字段
  409. if (jiangsuEcResult["jiangsuErrorCode"] != null)
  410. result.Add("jiangsuErrorCode", jiangsuEcResult["jiangsuErrorCode"]);
  411. if (jiangsuEcResult["jiangsuErrorMessage"] != null)
  412. result.Add("jiangsuErrorMessage", jiangsuEcResult["jiangsuErrorMessage"]);
  413. if (jiangsuEcResult["suggestion"] != null)
  414. result.Add("suggestion", jiangsuEcResult["suggestion"]);
  415. return result;
  416. }
  417. // 电子凭证解码成功,保持原格式返回(前端直接使用JSON格式)
  418. result.Add("code", jiangsuEcResult["code"]);
  419. result.Add("message", jiangsuEcResult["message"]);
  420. result.Add("device", jiangsuEcResult["device"]);
  421. result.Add("type", jiangsuEcResult["type"]);
  422. result.Add("originalType", jiangsuEcResult["originalType"]);
  423. result.Add("timestamp", jiangsuEcResult["timestamp"]);
  424. // 保持电子凭证的JSON数据格式(前端期望JSON而不是^分隔的字符串)
  425. result.Add("data", jiangsuEcResult["data"]);
  426. // 添加兼容字段:让前端可以统一处理
  427. result.Add("readCardResult", jiangsuEcResult["readCardResult"]);
  428. // 保留江苏医保相关信息
  429. if (jiangsuEcResult["businessType"] != null)
  430. result.Add("businessType", jiangsuEcResult["businessType"]);
  431. if (jiangsuEcResult["interfaceVersion"] != null)
  432. result.Add("interfaceVersion", jiangsuEcResult["interfaceVersion"]);
  433. if (jiangsuEcResult["jiangsuOriginalData"] != null)
  434. result.Add("jiangsuOriginalData", jiangsuEcResult["jiangsuOriginalData"]);
  435. }
  436. catch (System.Exception ex)
  437. {
  438. result.Add("code", 1001);
  439. result.Add("message", $"江苏医保电子凭证数据格式转换异常: {ex.Message}");
  440. result.Add("device", "江苏医保电子凭证解码器");
  441. result.Add("type", "qrcode");
  442. result.Add("exception", ex.GetType().Name);
  443. }
  444. return result;
  445. }
  446. /// <summary>
  447. /// 将江苏医保刷脸授权结果转换为前端期望的格式
  448. /// </summary>
  449. /// <param name="jiangsuFaceAuthResult">江苏医保刷脸授权返回的JSON数据</param>
  450. /// <returns>转换后的标准格式</returns>
  451. private JObject ConvertJiangSuFaceAuthToStandardFormat(JObject jiangsuFaceAuthResult)
  452. {
  453. JObject result = new JObject();
  454. try
  455. {
  456. // 刷脸授权直接返回原JSON格式,不需要转换为^分隔字符串
  457. // 因为刷脸返回的是结构化的医保身份信息,前端期望JSON格式
  458. result.Add("code", jiangsuFaceAuthResult["code"]);
  459. result.Add("message", jiangsuFaceAuthResult["message"]);
  460. result.Add("type", "face");
  461. result.Add("data", jiangsuFaceAuthResult["data"]?.ToString());
  462. result.Add("sign", jiangsuFaceAuthResult["sign"]);
  463. // 保留江苏医保特有字段
  464. if (jiangsuFaceAuthResult["device"] != null)
  465. result.Add("device", jiangsuFaceAuthResult["device"]);
  466. if (jiangsuFaceAuthResult["businessType"] != null)
  467. result.Add("businessType", jiangsuFaceAuthResult["businessType"]);
  468. if (jiangsuFaceAuthResult["timestamp"] != null)
  469. result.Add("timestamp", jiangsuFaceAuthResult["timestamp"]);
  470. if (jiangsuFaceAuthResult["authNo"] != null)
  471. result.Add("authNo", jiangsuFaceAuthResult["authNo"]);
  472. if (jiangsuFaceAuthResult["interfaceVersion"] != null)
  473. result.Add("interfaceVersion", jiangsuFaceAuthResult["interfaceVersion"]);
  474. }
  475. catch (System.Exception ex)
  476. {
  477. result.Add("code", 1001);
  478. result.Add("message", $"江苏医保刷脸授权数据格式转换异常: {ex.Message}");
  479. result.Add("device", "江苏医保刷脸认证器");
  480. result.Add("type", "face");
  481. result.Add("exception", ex.GetType().Name);
  482. }
  483. return result;
  484. }
  485. /// <summary>
  486. /// 江苏工伤联网结算接口 - POST方式
  487. /// POST /api/entry/workinjury
  488. /// </summary>
  489. [HttpPost]
  490. [Route("api/entry/workinjury")]
  491. [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions]
  492. [System.Security.SecurityCritical]
  493. public JObject PostWorkInjury([FromBody] JObject request)
  494. {
  495. // 立即创建基础响应,确保总是有返回值
  496. JObject result = new JObject();
  497. result["debug_entry_time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
  498. result["debug_method_entered"] = true;
  499. result["debug_stage"] = "方法入口";
  500. try
  501. {
  502. // 添加调试信息确保响应不为空
  503. result["debug_timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
  504. result["debug_step"] = "Controller方法开始执行";
  505. result["debug_stage"] = "开始处理";
  506. // 检查请求体
  507. if (request == null)
  508. {
  509. result["success"] = false;
  510. result["code"] = 1001;
  511. result["message"] = "请求体不能为空";
  512. result["device"] = "江苏工伤联网接口";
  513. result["debug_step"] = "请求体为空";
  514. // 添加传入参数(即使是null)
  515. result["request_parameters"] = null;
  516. return result;
  517. }
  518. result["debug_step"] = "请求体检查通过";
  519. result["debug_request"] = request;
  520. // 获取操作类型
  521. string action = request["action"]?.ToString()?.ToLower() ?? "";
  522. result["debug_action"] = action;
  523. result["debug_step"] = "解析action参数";
  524. if (string.IsNullOrEmpty(action))
  525. {
  526. result["success"] = false;
  527. result["code"] = 1002;
  528. result["message"] = "action参数不能为空";
  529. result["device"] = "江苏工伤联网接口";
  530. result["debug_step"] = "action参数为空";
  531. // 添加传入参数
  532. result["request_parameters"] = request;
  533. return result;
  534. }
  535. result["debug_step"] = $"准备执行action: {action}";
  536. // 根据操作类型处理不同的请求
  537. switch (action)
  538. {
  539. case "init":
  540. result["debug_step"] = "执行初始化操作";
  541. result["debug_stage"] = "准备调用HandleWorkInjuryInit";
  542. // 添加立即返回测试 - 如果问题在DLL调用,我们先确保基础流程正常
  543. if (request["test_mode"] != null && request["test_mode"].ToString() == "immediate_return")
  544. {
  545. result["success"] = true;
  546. result["code"] = 200;
  547. result["message"] = "测试模式:立即返回成功";
  548. result["device"] = "江苏工伤联网接口";
  549. result["debug_step"] = "测试模式立即返回";
  550. result["test_config"] = request["config"];
  551. // 添加传入参数
  552. result["request_parameters"] = request;
  553. break;
  554. }
  555. try
  556. {
  557. var initResult = HandleWorkInjuryInit(request);
  558. if (initResult != null)
  559. {
  560. // 替换为HandleWorkInjuryInit的结果并保留debug信息
  561. PreserveDebugInfo(result, initResult);
  562. result = initResult;
  563. result["debug_controller_step"] = "初始化操作完成";
  564. // 添加传入参数
  565. result["request_parameters"] = request;
  566. }
  567. else
  568. {
  569. result["success"] = false;
  570. result["code"] = 1007;
  571. result["message"] = "HandleWorkInjuryInit返回null";
  572. result["device"] = "江苏工伤联网接口";
  573. result["debug_step"] = "HandleWorkInjuryInit返回null";
  574. // 添加传入参数
  575. result["request_parameters"] = request;
  576. }
  577. }
  578. catch (System.Exception initEx)
  579. {
  580. result["success"] = false;
  581. result["code"] = 1008;
  582. result["message"] = $"调用HandleWorkInjuryInit异常: {initEx.Message}";
  583. result["device"] = "江苏工伤联网接口";
  584. result["debug_step"] = "HandleWorkInjuryInit调用异常";
  585. result["debug_error"] = initEx.Message;
  586. // 添加传入参数
  587. result["request_parameters"] = request;
  588. }
  589. break;
  590. case "transaction":
  591. result["debug_step"] = "执行交易操作";
  592. var transactionResult = HandleWorkInjuryTransaction(request);
  593. if (transactionResult != null)
  594. {
  595. // 替换为HandleWorkInjuryTransaction的结果并保留debug信息
  596. PreserveDebugInfo(result, transactionResult);
  597. result = transactionResult;
  598. result["debug_controller_step"] = "交易操作完成";
  599. // 添加传入参数
  600. result["request_parameters"] = request;
  601. }
  602. break;
  603. case "health":
  604. result["debug_step"] = "执行健康检查";
  605. var healthResult = JiangSuWorkInjuryBusiness.HealthCheck();
  606. if (healthResult != null)
  607. {
  608. PreserveDebugInfo(result, healthResult);
  609. result = healthResult;
  610. result["debug_controller_step"] = "健康检查完成";
  611. // 添加传入参数
  612. result["request_parameters"] = request;
  613. }
  614. break;
  615. case "stats":
  616. var statsResult = JiangSuWorkInjuryBusiness.GetTransactionStatistics();
  617. if (statsResult != null)
  618. {
  619. PreserveDebugInfo(result, statsResult);
  620. result = statsResult;
  621. // 添加传入参数
  622. result["request_parameters"] = request;
  623. }
  624. break;
  625. case "signin_status":
  626. var signinStatusResult = JiangSuWorkInjuryBusiness.GetSignInStatus();
  627. if (signinStatusResult != null)
  628. {
  629. PreserveDebugInfo(result, signinStatusResult);
  630. result = signinStatusResult;
  631. // 添加传入参数
  632. result["request_parameters"] = request;
  633. }
  634. break;
  635. case "batch_upload":
  636. var batchUploadResult = HandleWorkInjuryBatchUpload(request);
  637. if (batchUploadResult != null)
  638. {
  639. PreserveDebugInfo(result, batchUploadResult);
  640. result = batchUploadResult;
  641. // 添加传入参数
  642. result["request_parameters"] = request;
  643. }
  644. break;
  645. case "complete_process":
  646. var completeProcessResult = HandleWorkInjuryCompleteProcess(request);
  647. if (completeProcessResult != null)
  648. {
  649. PreserveDebugInfo(result, completeProcessResult);
  650. result = completeProcessResult;
  651. // 添加传入参数
  652. result["request_parameters"] = request;
  653. }
  654. break;
  655. case "retry":
  656. var retryResult = HandleWorkInjuryRetry(request);
  657. if (retryResult != null)
  658. {
  659. PreserveDebugInfo(result, retryResult);
  660. result = retryResult;
  661. // 添加传入参数
  662. result["request_parameters"] = request;
  663. }
  664. break;
  665. case "reverse":
  666. var reverseResult = HandleWorkInjuryReverse(request);
  667. if (reverseResult != null)
  668. {
  669. PreserveDebugInfo(result, reverseResult);
  670. result = reverseResult;
  671. // 添加传入参数
  672. result["request_parameters"] = request;
  673. }
  674. break;
  675. default:
  676. result["success"] = false;
  677. result["code"] = 1003;
  678. result["message"] = $"不支持的操作类型: {action}";
  679. result["device"] = "江苏工伤联网接口";
  680. result["supportedActions"] = "init, transaction, health, stats, signin_status, batch_upload, complete_process, retry, reverse";
  681. // 添加传入参数
  682. result["request_parameters"] = request;
  683. break;
  684. }
  685. }
  686. catch (System.AccessViolationException avEx)
  687. {
  688. // 保存原有的debug信息
  689. string debugEntryTime = result["debug_entry_time"]?.ToString();
  690. bool? debugMethodEntered = result["debug_method_entered"]?.ToObject<bool>();
  691. string debugStage = result["debug_stage"]?.ToString();
  692. string debugTimestamp = result["debug_timestamp"]?.ToString();
  693. string debugStep = result["debug_step"]?.ToString();
  694. JToken debugRequest = result["debug_request"];
  695. string debugAction = result["debug_action"]?.ToString();
  696. result = new JObject(); // 重新创建以确保不为空
  697. result["success"] = false;
  698. result["code"] = 9001;
  699. result["message"] = "DLL访问冲突异常 - 可能是JSSiInterface.dll问题";
  700. result["device"] = "江苏工伤联网接口";
  701. result["exception"] = "AccessViolationException";
  702. result["debug_step"] = "Controller捕获访问冲突异常";
  703. result["debug_error"] = avEx.Message;
  704. result["debug_stacktrace"] = avEx.StackTrace;
  705. // 恢复原有的debug信息
  706. if (!string.IsNullOrEmpty(debugEntryTime))
  707. result["debug_entry_time"] = debugEntryTime;
  708. if (debugMethodEntered.HasValue)
  709. result["debug_method_entered"] = debugMethodEntered.Value;
  710. if (!string.IsNullOrEmpty(debugStage))
  711. result["debug_stage"] = debugStage;
  712. if (!string.IsNullOrEmpty(debugTimestamp))
  713. result["debug_timestamp"] = debugTimestamp;
  714. if (debugRequest != null)
  715. result["debug_request"] = debugRequest;
  716. if (!string.IsNullOrEmpty(debugAction))
  717. result["debug_action"] = debugAction;
  718. // 添加传入参数
  719. result["request_parameters"] = request;
  720. }
  721. catch (System.Runtime.InteropServices.SEHException sehEx)
  722. {
  723. // 保存原有的debug信息
  724. string debugEntryTime = result["debug_entry_time"]?.ToString();
  725. bool? debugMethodEntered = result["debug_method_entered"]?.ToObject<bool>();
  726. string debugStage = result["debug_stage"]?.ToString();
  727. string debugTimestamp = result["debug_timestamp"]?.ToString();
  728. string debugStep = result["debug_step"]?.ToString();
  729. JToken debugRequest = result["debug_request"];
  730. string debugAction = result["debug_action"]?.ToString();
  731. result = new JObject(); // 重新创建以确保不为空
  732. result["success"] = false;
  733. result["code"] = 9002;
  734. result["message"] = "结构化异常处理错误 - DLL调用失败";
  735. result["device"] = "江苏工伤联网接口";
  736. result["exception"] = "SEHException";
  737. result["debug_step"] = "Controller捕获SEH异常";
  738. result["debug_error"] = sehEx.Message;
  739. result["debug_stacktrace"] = sehEx.StackTrace;
  740. // 恢复原有的debug信息
  741. if (!string.IsNullOrEmpty(debugEntryTime))
  742. result["debug_entry_time"] = debugEntryTime;
  743. if (debugMethodEntered.HasValue)
  744. result["debug_method_entered"] = debugMethodEntered.Value;
  745. if (!string.IsNullOrEmpty(debugStage))
  746. result["debug_stage"] = debugStage;
  747. if (!string.IsNullOrEmpty(debugTimestamp))
  748. result["debug_timestamp"] = debugTimestamp;
  749. if (debugRequest != null)
  750. result["debug_request"] = debugRequest;
  751. if (!string.IsNullOrEmpty(debugAction))
  752. result["debug_action"] = debugAction;
  753. // 添加传入参数
  754. result["request_parameters"] = request;
  755. }
  756. catch (System.Exception ex)
  757. {
  758. // 保存原有的debug信息
  759. string debugEntryTime = result["debug_entry_time"]?.ToString();
  760. bool? debugMethodEntered = result["debug_method_entered"]?.ToObject<bool>();
  761. string debugStage = result["debug_stage"]?.ToString();
  762. string debugTimestamp = result["debug_timestamp"]?.ToString();
  763. string debugStep = result["debug_step"]?.ToString();
  764. JToken debugRequest = result["debug_request"];
  765. string debugAction = result["debug_action"]?.ToString();
  766. result = new JObject(); // 重新创建以确保不为空
  767. result["success"] = false;
  768. result["code"] = 1000;
  769. result["message"] = $"工伤联网接口处理异常: {ex.Message}";
  770. result["device"] = "江苏工伤联网接口";
  771. result["exception"] = ex.GetType().Name;
  772. result["debug_step"] = "Controller捕获一般异常";
  773. result["debug_error"] = ex.Message;
  774. result["debug_stacktrace"] = ex.StackTrace;
  775. result["debug_exception_details"] = ex.ToString();
  776. // 恢复原有的debug信息
  777. if (!string.IsNullOrEmpty(debugEntryTime))
  778. result["debug_entry_time"] = debugEntryTime;
  779. if (debugMethodEntered.HasValue)
  780. result["debug_method_entered"] = debugMethodEntered.Value;
  781. if (!string.IsNullOrEmpty(debugStage))
  782. result["debug_stage"] = debugStage;
  783. if (!string.IsNullOrEmpty(debugTimestamp))
  784. result["debug_timestamp"] = debugTimestamp;
  785. if (debugRequest != null)
  786. result["debug_request"] = debugRequest;
  787. if (!string.IsNullOrEmpty(debugAction))
  788. result["debug_action"] = debugAction;
  789. // 添加传入参数
  790. result["request_parameters"] = request;
  791. }
  792. // 确保返回的result不为null并且有基本结构
  793. if (result == null)
  794. {
  795. result = new JObject();
  796. result["success"] = false;
  797. result["code"] = 9999;
  798. result["message"] = "未知错误 - result为null";
  799. result["device"] = "江苏工伤联网接口";
  800. result["debug_step"] = "result为null保护";
  801. // 添加传入参数
  802. result["request_parameters"] = request;
  803. }
  804. // 强制确保必要字段存在
  805. if (result["success"] == null)
  806. {
  807. result["success"] = false;
  808. result["debug_forced_success"] = "强制添加success字段";
  809. }
  810. if (result["code"] == null)
  811. {
  812. result["code"] = 8000;
  813. result["debug_forced_code"] = "强制添加code字段";
  814. }
  815. if (result["device"] == null)
  816. {
  817. result["device"] = "江苏工伤联网接口";
  818. result["debug_forced_device"] = "强制添加device字段";
  819. }
  820. // 确保有时间戳
  821. if (result["debug_timestamp"] == null)
  822. {
  823. result["debug_final_timestamp"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
  824. }
  825. // 添加最终保护标记
  826. result["debug_method_exit"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
  827. result["debug_return_confirmed"] = true;
  828. return result;
  829. }
  830. /// <summary>
  831. /// 处理工伤联网初始化请求
  832. /// </summary>
  833. private JObject HandleWorkInjuryInit(JObject request)
  834. {
  835. // 立即创建基础响应,确保总是有返回值
  836. JObject result = new JObject();
  837. result["debug_handler_entry"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
  838. result["debug_handler_stage"] = "HandleWorkInjuryInit进入";
  839. try
  840. {
  841. result["debug_handler_stage"] = "解析配置参数";
  842. var configObj = request["config"];
  843. JObject initResult = null;
  844. if (configObj != null)
  845. {
  846. result["debug_handler_stage"] = "使用自定义配置";
  847. // 使用自定义配置
  848. var config = new JiangSuWorkInjuryBusiness.WorkInjuryConfig
  849. {
  850. FixmedinsCode = configObj["fixmedinsCode"]?.ToString() ?? "SQ201348",
  851. FixmedinsName = configObj["fixmedinsName"]?.ToString() ?? "沭阳铭和医院",
  852. ReceiverSysCode = configObj["receiverSysCode"]?.ToString() ?? "JSYTH",
  853. InterfaceVersion = configObj["interfaceVersion"]?.ToString() ?? "V2.1",
  854. OperatorType = configObj["operatorType"]?.ToString() ?? "1",
  855. DefaultOperator = configObj["defaultOperator"]?.ToString() ?? "001",
  856. DefaultOperatorName = configObj["defaultOperatorName"]?.ToString() ?? "系统管理员",
  857. LogPath = configObj["logPath"]?.ToString() ?? "logs/workinjury/"
  858. };
  859. result["debug_handler_stage"] = "准备调用Initialize(config)";
  860. initResult = JiangSuWorkInjuryBusiness.Initialize(config);
  861. }
  862. else
  863. {
  864. result["debug_handler_stage"] = "使用默认配置";
  865. initResult = JiangSuWorkInjuryBusiness.Initialize();
  866. }
  867. result["debug_handler_stage"] = "Initialize调用完成";
  868. // 确保返回的结果不为空
  869. if (initResult == null)
  870. {
  871. result["success"] = false;
  872. result["code"] = 1005;
  873. result["message"] = "初始化返回结果为null";
  874. result["device"] = "江苏工伤联网接口";
  875. result["debug_handler_stage"] = "初始化结果为null";
  876. return result;
  877. }
  878. // 将调试信息合并到初始化结果中
  879. initResult["debug_handler_complete"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
  880. initResult["debug_handler_stage"] = "成功返回";
  881. return initResult;
  882. }
  883. catch (System.AccessViolationException avEx)
  884. {
  885. result["success"] = false;
  886. result["code"] = 1006;
  887. result["message"] = $"工伤联网初始化访问冲突异常: {avEx.Message}";
  888. result["device"] = "江苏工伤联网接口";
  889. result["exception"] = "AccessViolationException";
  890. result["debug_handler_stage"] = "HandleWorkInjuryInit捕获访问冲突";
  891. result["debug_error"] = avEx.Message;
  892. return result;
  893. }
  894. catch (System.Exception ex)
  895. {
  896. result["success"] = false;
  897. result["code"] = 1004;
  898. result["message"] = $"工伤联网初始化处理异常: {ex.Message}";
  899. result["device"] = "江苏工伤联网接口";
  900. result["exception"] = ex.GetType().Name;
  901. result["debug_handler_stage"] = "HandleWorkInjuryInit捕获一般异常";
  902. result["debug_error"] = ex.Message;
  903. result["debug_stacktrace"] = ex.StackTrace;
  904. return result;
  905. }
  906. }
  907. /// <summary>
  908. /// 处理工伤联网交易请求
  909. /// </summary>
  910. private JObject HandleWorkInjuryTransaction(JObject request)
  911. {
  912. try
  913. {
  914. string transactionName = request["transactionName"]?.ToString() ?? "";
  915. if (string.IsNullOrEmpty(transactionName))
  916. {
  917. var result = new JObject();
  918. result["success"] = false;
  919. result["code"] = 1005;
  920. result["message"] = "transactionName参数不能为空";
  921. result["device"] = "江苏工伤联网接口";
  922. return result;
  923. }
  924. object businessParams = request["businessParams"]?.ToObject<object>();
  925. string identifyMode = request["identifyMode"]?.ToString() ?? "1";
  926. string qrCodeInfo = request["qrCodeInfo"]?.ToString() ?? "";
  927. string operatorId = request["operatorId"]?.ToString() ?? "";
  928. string operatorName = request["operatorName"]?.ToString() ?? "";
  929. return JiangSuWorkInjuryBusiness.ProcessWorkInjuryTransaction(
  930. transactionName, businessParams, identifyMode, qrCodeInfo, operatorId, operatorName);
  931. }
  932. catch (System.Exception ex)
  933. {
  934. var result = new JObject();
  935. result["success"] = false;
  936. result["code"] = 1006;
  937. result["message"] = $"工伤联网交易处理异常: {ex.Message}";
  938. result["device"] = "江苏工伤联网接口";
  939. return result;
  940. }
  941. }
  942. /// <summary>
  943. /// 处理工伤联网批量上传请求
  944. /// </summary>
  945. private JObject HandleWorkInjuryBatchUpload(JObject request)
  946. {
  947. try
  948. {
  949. var prescriptionsArray = request["prescriptions"]?.ToObject<object[]>();
  950. if (prescriptionsArray == null || prescriptionsArray.Length == 0)
  951. {
  952. var result = new JObject();
  953. result["success"] = false;
  954. result["code"] = 1007;
  955. result["message"] = "prescriptions参数不能为空";
  956. result["device"] = "江苏工伤联网接口";
  957. return result;
  958. }
  959. string patientId = request["patientId"]?.ToString() ?? "";
  960. string visitNo = request["visitNo"]?.ToString() ?? "";
  961. return JiangSuWorkInjuryBusiness.BatchUploadPrescriptions(prescriptionsArray, patientId, visitNo);
  962. }
  963. catch (System.Exception ex)
  964. {
  965. var result = new JObject();
  966. result["success"] = false;
  967. result["code"] = 1008;
  968. result["message"] = $"工伤联网批量上传处理异常: {ex.Message}";
  969. result["device"] = "江苏工伤联网接口";
  970. return result;
  971. }
  972. }
  973. /// <summary>
  974. /// 处理工伤联网完整流程请求
  975. /// </summary>
  976. private JObject HandleWorkInjuryCompleteProcess(JObject request)
  977. {
  978. try
  979. {
  980. object patientInfo = request["patientInfo"]?.ToObject<object>();
  981. object[] feeDetails = request["feeDetails"]?.ToObject<object[]>();
  982. return JiangSuWorkInjuryBusiness.CompleteWorkInjuryProcess(patientInfo, feeDetails);
  983. }
  984. catch (System.Exception ex)
  985. {
  986. var result = new JObject();
  987. result["success"] = false;
  988. result["code"] = 1009;
  989. result["message"] = $"工伤联网完整流程处理异常: {ex.Message}";
  990. result["device"] = "江苏工伤联网接口";
  991. return result;
  992. }
  993. }
  994. /// <summary>
  995. /// 处理工伤联网智能重试请求
  996. /// </summary>
  997. private JObject HandleWorkInjuryRetry(JObject request)
  998. {
  999. try
  1000. {
  1001. string transactionName = request["transactionName"]?.ToString() ?? "";
  1002. if (string.IsNullOrEmpty(transactionName))
  1003. {
  1004. var result = new JObject();
  1005. result["success"] = false;
  1006. result["code"] = 1010;
  1007. result["message"] = "transactionName参数不能为空";
  1008. result["device"] = "江苏工伤联网接口";
  1009. return result;
  1010. }
  1011. object businessParams = request["businessParams"]?.ToObject<object>();
  1012. int maxRetries = request["maxRetries"]?.ToObject<int>() ?? 3;
  1013. int baseDelayMs = request["baseDelayMs"]?.ToObject<int>() ?? 1000;
  1014. return JiangSuWorkInjuryBusiness.SmartRetryTransaction(transactionName, businessParams, maxRetries, baseDelayMs);
  1015. }
  1016. catch (System.Exception ex)
  1017. {
  1018. var result = new JObject();
  1019. result["success"] = false;
  1020. result["code"] = 1011;
  1021. result["message"] = $"工伤联网智能重试处理异常: {ex.Message}";
  1022. result["device"] = "江苏工伤联网接口";
  1023. return result;
  1024. }
  1025. }
  1026. /// <summary>
  1027. /// 处理工伤联网冲正请求
  1028. /// </summary>
  1029. private JObject HandleWorkInjuryReverse(JObject request)
  1030. {
  1031. try
  1032. {
  1033. string originalMessageId = request["originalMessageId"]?.ToString() ?? "";
  1034. if (string.IsNullOrEmpty(originalMessageId))
  1035. {
  1036. var result = new JObject();
  1037. result["success"] = false;
  1038. result["code"] = 1012;
  1039. result["message"] = "originalMessageId参数不能为空";
  1040. result["device"] = "江苏工伤联网接口";
  1041. return result;
  1042. }
  1043. return JiangSuWorkInjuryBusiness.ReverseTransactionByRecord(originalMessageId);
  1044. }
  1045. catch (System.Exception ex)
  1046. {
  1047. var result = new JObject();
  1048. result["success"] = false;
  1049. result["code"] = 1013;
  1050. result["message"] = $"工伤联网冲正处理异常: {ex.Message}";
  1051. result["device"] = "江苏工伤联网接口";
  1052. return result;
  1053. }
  1054. }
  1055. /// <summary>
  1056. /// 保留调试信息到结果中
  1057. /// </summary>
  1058. private void PreserveDebugInfo(JObject target, JObject source)
  1059. {
  1060. if (source["debug_entry_time"] != null) target["debug_entry_time"] = source["debug_entry_time"];
  1061. if (source["debug_method_entered"] != null) target["debug_method_entered"] = source["debug_method_entered"];
  1062. if (source["debug_stage"] != null) target["debug_stage"] = source["debug_stage"];
  1063. if (source["debug_timestamp"] != null) target["debug_timestamp"] = source["debug_timestamp"];
  1064. if (source["debug_step"] != null) target["debug_step"] = source["debug_step"];
  1065. if (source["debug_request"] != null) target["debug_request"] = source["debug_request"];
  1066. if (source["debug_action"] != null) target["debug_action"] = source["debug_action"];
  1067. if (source["debug_error"] != null) target["debug_error"] = source["debug_error"];
  1068. if (source["debug_stacktrace"] != null) target["debug_stacktrace"] = source["debug_stacktrace"];
  1069. if (source["debug_exception_details"] != null) target["debug_exception_details"] = source["debug_exception_details"];
  1070. if (source["debug_controller_step"] != null) target["debug_controller_step"] = source["debug_controller_step"];
  1071. if (source["debug_handler_entry"] != null) target["debug_handler_entry"] = source["debug_handler_entry"];
  1072. if (source["debug_handler_stage"] != null) target["debug_handler_stage"] = source["debug_handler_stage"];
  1073. if (source["debug_handler_complete"] != null) target["debug_handler_complete"] = source["debug_handler_complete"];
  1074. if (source["test_config"] != null) target["test_config"] = source["test_config"];
  1075. }
  1076. }
  1077. }