SfisWebServiceClient.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. using System.Text;
  6. using System.Xml;
  7. namespace TeamAAS_VP.Core.Sfis
  8. {
  9. public class SfisWebServiceClient
  10. {
  11. private readonly SfisConfig _config;
  12. private readonly object _invokeSync = new object();
  13. public event Action<string> OnLog;
  14. public bool IsLoggedIn { get; private set; }
  15. public SfisWebServiceClient(SfisConfig config)
  16. {
  17. _config = config ?? throw new ArgumentNullException(nameof(config));
  18. }
  19. public SfisResponse Login()
  20. {
  21. var response = Invoke("WTSP_LOGINOUT", new Dictionary<string, object>
  22. {
  23. { "programId", _config.ProgramId },
  24. { "programPassword", _config.ProgramPassword },
  25. { "op", _config.OperatorId },
  26. { "password", _config.OperatorPassword ?? string.Empty },
  27. { "device", _config.Device },
  28. { "TSP", _config.TspName },
  29. { "status", 1 }
  30. });
  31. if (response.IsSuccess)
  32. IsLoggedIn = true;
  33. return response;
  34. }
  35. public SfisResponse Logout()
  36. {
  37. var response = Invoke("WTSP_LOGINOUT", new Dictionary<string, object>
  38. {
  39. { "programId", _config.ProgramId },
  40. { "programPassword", _config.ProgramPassword },
  41. { "op", _config.OperatorId },
  42. { "password", _config.OperatorPassword ?? string.Empty },
  43. { "device", _config.Device },
  44. { "TSP", _config.TspName },
  45. { "status", 2 }
  46. });
  47. IsLoggedIn = false;
  48. return response;
  49. }
  50. public SfisResponse CheckRoute(string isn, int type, string checkFlag = null, string checkData = null)
  51. {
  52. return Invoke("WTSP_CHKROUTE", new Dictionary<string, object>
  53. {
  54. { "programId", _config.ProgramId },
  55. { "programPassword", _config.ProgramPassword },
  56. { "ISN", isn },
  57. { "device", _config.Device },
  58. { "checkFlag", checkFlag ?? string.Empty },
  59. { "checkData", checkData ?? string.Empty },
  60. { "type", type }
  61. });
  62. }
  63. public SfisResponse GetVersion(string isn, string type, string chkData = null, string chkData2 = null)
  64. {
  65. return Invoke("WTSP_GETVERSION", new Dictionary<string, object>
  66. {
  67. { "programId", _config.ProgramId },
  68. { "programPassword", _config.ProgramPassword },
  69. { "ISN", isn },
  70. { "device", _config.Device },
  71. { "type", type ?? string.Empty },
  72. { "ChkData", chkData ?? string.Empty },
  73. { "ChkData2", chkData2 ?? string.Empty }
  74. });
  75. }
  76. public SfisResponse SendResult(string isn, string data, int status, string errorCode = null)
  77. {
  78. return Invoke("WTSP_RESULT", new Dictionary<string, object>
  79. {
  80. { "programId", _config.ProgramId },
  81. { "programPassword", _config.ProgramPassword },
  82. { "ISN", isn },
  83. { "error", errorCode ?? string.Empty },
  84. { "device", _config.Device },
  85. { "TSP", _config.TspName },
  86. { "data", data },
  87. { "status", status },
  88. { "CPKFlag", string.Empty }
  89. });
  90. }
  91. public SfisResponse SendInputData(string data, int type)
  92. {
  93. return Invoke("WTSP_SSD_INPUTDATA", new Dictionary<string, object>
  94. {
  95. { "programId", _config.ProgramId },
  96. { "programPassword", _config.ProgramPassword },
  97. { "device", _config.Device },
  98. { "data", data },
  99. { "type", type }
  100. });
  101. }
  102. public SfisResponse Invoke(string methodName, IDictionary<string, object> parameters)
  103. {
  104. lock (_invokeSync)
  105. {
  106. if (_config.UseDryRun())
  107. return InvokeDryRun(methodName, parameters);
  108. ValidateLiveConfig();
  109. string soapAction = _config.SoapNamespace.TrimEnd('/') + "/" + methodName;
  110. string envelope = BuildSoapEnvelope(methodName, parameters);
  111. OnLog?.Invoke("SFIS 调用 " + methodName);
  112. var request = (HttpWebRequest)WebRequest.Create(_config.ServiceUrl);
  113. request.Method = "POST";
  114. request.ContentType = "text/xml; charset=utf-8";
  115. request.Headers.Add("SOAPAction", "\"" + soapAction + "\"");
  116. request.Timeout = _config.TimeoutMs;
  117. request.ReadWriteTimeout = _config.TimeoutMs;
  118. byte[] payload = Encoding.UTF8.GetBytes(envelope);
  119. request.ContentLength = payload.Length;
  120. using (var stream = request.GetRequestStream())
  121. stream.Write(payload, 0, payload.Length);
  122. try
  123. {
  124. using (var response = (HttpWebResponse)request.GetResponse())
  125. using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
  126. {
  127. string soapResponse = reader.ReadToEnd();
  128. string result = ExtractSoapResult(soapResponse, methodName);
  129. var parsed = SfisResponse.Parse(result);
  130. OnLog?.Invoke("SFIS " + methodName + " => P_RET=" + parsed.ReturnCode);
  131. return parsed;
  132. }
  133. }
  134. catch (WebException ex)
  135. {
  136. string errorBody = ReadErrorBody(ex);
  137. OnLog?.Invoke("SFIS 调用失败: " + ex.Message);
  138. if (!string.IsNullOrWhiteSpace(errorBody))
  139. OnLog?.Invoke(errorBody);
  140. return new SfisResponse
  141. {
  142. ReturnCode = 0,
  143. Message = string.IsNullOrWhiteSpace(errorBody) ? ex.Message : errorBody,
  144. Raw = errorBody
  145. };
  146. }
  147. }
  148. }
  149. private void ValidateLiveConfig()
  150. {
  151. if (string.IsNullOrWhiteSpace(_config.ServiceUrl))
  152. throw new InvalidOperationException("SfisServiceUrl 未配置");
  153. if (string.IsNullOrWhiteSpace(_config.ProgramId))
  154. throw new InvalidOperationException("SfisProgramId 未配置");
  155. if (string.IsNullOrWhiteSpace(_config.Device))
  156. throw new InvalidOperationException("SfisDevice 未配置");
  157. }
  158. private static string ReadErrorBody(WebException ex)
  159. {
  160. if (ex.Response == null)
  161. return null;
  162. using (var reader = new StreamReader(ex.Response.GetResponseStream()))
  163. return reader.ReadToEnd();
  164. }
  165. private string BuildSoapEnvelope(string methodName, IDictionary<string, object> parameters)
  166. {
  167. var sb = new StringBuilder();
  168. sb.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
  169. sb.Append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">");
  170. sb.Append("<soap:Body>");
  171. sb.Append("<").Append(methodName).Append(" xmlns=\"").Append(XmlEscape(_config.SoapNamespace)).Append("\">");
  172. foreach (var pair in parameters)
  173. {
  174. sb.Append("<").Append(pair.Key).Append(">");
  175. sb.Append(XmlEscape(Convert.ToString(pair.Value ?? string.Empty)));
  176. sb.Append("</").Append(pair.Key).Append(">");
  177. }
  178. sb.Append("</").Append(methodName).Append(">");
  179. sb.Append("</soap:Body>");
  180. sb.Append("</soap:Envelope>");
  181. return sb.ToString();
  182. }
  183. private static string ExtractSoapResult(string soapResponse, string methodName)
  184. {
  185. if (string.IsNullOrWhiteSpace(soapResponse))
  186. return string.Empty;
  187. var doc = new XmlDocument();
  188. doc.LoadXml(soapResponse);
  189. string[] candidateNames = { methodName + "Result", methodName + "Response", "return" };
  190. foreach (string name in candidateNames)
  191. {
  192. XmlNodeList nodes = doc.GetElementsByTagName(name);
  193. if (nodes != null && nodes.Count > 0 && nodes[0] != null)
  194. return nodes[0].InnerText;
  195. }
  196. XmlNodeList bodyNodes = doc.GetElementsByTagName("soap:Body");
  197. if (bodyNodes == null || bodyNodes.Count == 0)
  198. bodyNodes = doc.GetElementsByTagName("Body");
  199. if (bodyNodes != null && bodyNodes.Count > 0 && bodyNodes[0] != null)
  200. return bodyNodes[0].InnerText?.Trim() ?? soapResponse;
  201. return soapResponse;
  202. }
  203. private SfisResponse InvokeDryRun(string methodName, IDictionary<string, object> parameters)
  204. {
  205. OnLog?.Invoke("[DryRun] SFIS 调用 " + methodName);
  206. switch (methodName)
  207. {
  208. case "WTSP_LOGINOUT":
  209. int status = Convert.ToInt32(parameters["status"]);
  210. if (status == 1)
  211. {
  212. IsLoggedIn = true;
  213. return SfisResponse.Parse("1" + SfisDelimiters.Field + "Welcome using Pegatron SFIS"
  214. + SfisDelimiters.Field + "DryRun Operator");
  215. }
  216. IsLoggedIn = false;
  217. return SfisResponse.Parse("1" + SfisDelimiters.Field + "Logout OK");
  218. case "WTSP_CHKROUTE":
  219. return SfisResponse.Parse("1" + SfisDelimiters.Field + "[#1][MODEL:DRYRUN]");
  220. case "WTSP_GETVERSION":
  221. return SfisResponse.Parse("1" + SfisDelimiters.Field + "DryRun Version");
  222. case "WTSP_RESULT":
  223. return SfisResponse.Parse("1" + SfisDelimiters.Field + "RESULT SAVED OK");
  224. case "WTSP_SSD_INPUTDATA":
  225. return SfisResponse.Parse("1" + SfisDelimiters.Field
  226. + "MO SAVED OK(DryRun);ISN OK!! PASS!-(TSP_SSD_INPUTDATA)");
  227. default:
  228. return SfisResponse.Parse("1" + SfisDelimiters.Field + methodName + " DryRun OK");
  229. }
  230. }
  231. private static string XmlEscape(string value)
  232. {
  233. if (string.IsNullOrEmpty(value))
  234. return string.Empty;
  235. return value.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;")
  236. .Replace("\"", "&quot;").Replace("'", "&apos;");
  237. }
  238. }
  239. }