XFApiService.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net.Http;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using Winsoft.GOV.XF.WebApi.WXCore.Models;
  9. using Newtonsoft.Json;
  10. using Winsoft.GOV.XF.WebApi.WXCore.Data;
  11. using Microsoft.Extensions.Logging;
  12. using System.Net;
  13. using Senparc.Weixin.Entities;
  14. using Microsoft.Extensions.Options;
  15. using Microsoft.Extensions.Configuration;
  16. using Newtonsoft.Json.Linq;
  17. namespace Winsoft.GOV.XF.WebApi.WXCore.Services
  18. {
  19. public class XFApiService : BaseService
  20. {
  21. public delegate void OnFails(string message);
  22. BundlesService _bundlesService;
  23. public XFApiService(BundlesService bundlesService, XFDbContext context, ILoggerFactory loggerFactory, IConfigurationRoot config) :base(context, loggerFactory, config)
  24. {
  25. _bundlesService = bundlesService;
  26. }
  27. public async Task<bool> PostAssets(Bundle b)
  28. {
  29. string end = "\r\n";
  30. string twoHyphens = "--";
  31. string boundary = "*****";
  32. byte[] endbyte = Encoding.UTF8.GetBytes(end);
  33. byte[] twoHyphensbyte = Encoding.UTF8.GetBytes(twoHyphens);
  34. byte[] boundarybyte = Encoding.UTF8.GetBytes(boundary);
  35. HttpClientHandler handler = new HttpClientHandler();
  36. HttpClient client = new HttpClient(handler);
  37. MemoryStream ms = new MemoryStream();
  38. int j = 0;
  39. for (int i = 0; i < b.Assets.Count(); i++)
  40. {
  41. Asset a = b.Assets.ElementAt(i);
  42. if (a.AssetType != AssetType.Image)
  43. continue;
  44. ms.Write(twoHyphensbyte, 0, twoHyphensbyte.Length);
  45. ms.Write(boundarybyte, 0, boundarybyte.Length);
  46. ms.Write(endbyte, 0, endbyte.Length);
  47. byte[] s = Encoding.UTF8.GetBytes(String.Format("Content-Disposition: form-data; name=\"file{0}\";filename=\"{1}\"\r\n", j, a.FileName));
  48. ms.Write(s, 0, s.Length);
  49. ms.Write(endbyte, 0, endbyte.Length);
  50. await ms.WriteAsync(a.FileBytes, 0, a.FileBytes.Length);
  51. ms.Write(endbyte, 0, endbyte.Length);
  52. j++;
  53. }
  54. ms.Write(twoHyphensbyte, 0, twoHyphensbyte.Length);
  55. ms.Write(boundarybyte, 0, boundarybyte.Length);
  56. ms.Write(twoHyphensbyte, 0, twoHyphensbyte.Length);
  57. ms.Write(endbyte, 0, endbyte.Length);
  58. HttpContent hc = new StreamContent(ms);
  59. hc.Headers.Add("APIKey", "MUA5NmU3OTIxOEPSOFTDQ1YTMzMDExMg");
  60. client.DefaultRequestHeaders.Add("Accept", "*/*");
  61. client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
  62. client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
  63. client.DefaultRequestHeaders.Add("Charset", "UTF-8");
  64. hc.Headers.Add("Content-Type", "Multipart/Form-Data; Boundary=" + boundary);
  65. var r = await client.PostAsync(_config["XFApi"] + "/letter/uploadFile;app_id=" + b.LetterId, hc);
  66. if (r.StatusCode != HttpStatusCode.OK)
  67. {
  68. Logger.LogError("省统一平台异常反馈:状态“{0}”", r.StatusCode);
  69. return false;
  70. }
  71. byte[] tmp = await r.Content.ReadAsByteArrayAsync();
  72. string rStr = Encoding.UTF8.GetString(tmp);
  73. Logger.LogInformation(rStr);
  74. JObject rObj = JsonConvert.DeserializeObject<JObject>(rStr);
  75. if (rObj == null)
  76. {
  77. Logger.LogError("数据提交省统一平台失败,原因:{0}", "数据为空");
  78. return false;
  79. }
  80. return true;
  81. }
  82. /// <summary>
  83. /// 提交信件
  84. /// </summary>
  85. /// <param name="b">信件内容</param>
  86. /// <param name="onFails">失败回调</param>
  87. /// <returns></returns>
  88. public async Task<bool> PostLetter(Bundle b, string absoluteUri, OnFails onFails)
  89. {
  90. string d = b.Describe;
  91. if (b.Assets.Count() > 0)
  92. //d += "(此信件内容含有其他多媒体信息,详细请复制网址到浏览器打开:" + _bundlesService.GenerateBaseURL(b, absoluteUri) + ")";
  93. d += "\r\n【扩展信息链接:" + _bundlesService.GenerateSampleBaseURL(b, absoluteUri) + "】";
  94. string s = "advice={0};type={1};name={2};phone={3};is_public={4};content={5};title={6};county_id={7};unit_id={8};sswz=8;ly=2; user_id={9}";
  95. s = String.Format(s, b.Advice, b.Type.ToString(), b.Name, b.Mobile, b.IsPublic.ToString(), d, b.Title, b.County_id, b.Unit_id, b.OpenID);
  96. XFApiResult rObj = await HttpPostAsync<XFApiResult>(_config["XFApi"] + "/letter/submitLetter;", s, onFails);
  97. if (rObj == null)
  98. return false;
  99. if (rObj.Data == null || !rObj.Data.Success)
  100. {
  101. Logger.LogError("数据提交省统一平台失败,原因:{0}", rObj.Message);
  102. onFails(string.Format("数据提交省统一平台失败,原因:{0}", rObj.Message));
  103. return false;
  104. }
  105. b.SearchCode = rObj.Data.Data;
  106. await _bundlesService.UpdateSearchCode(b);
  107. string s2;
  108. Bundle b2 = await GetBundleByQueryCode(b.SearchCode, e => s2 = e );
  109. if (b2 !=null)
  110. {
  111. b.LetterId = b2.LetterId;
  112. b.Status = b2.Status;
  113. b.Reply = b2.Reply;
  114. b.DealProcesses = b2.DealProcesses;
  115. b.ResultFromXF = b2.ResultFromXF;
  116. }
  117. return true;
  118. }
  119. /// <summary>
  120. /// 查询码是否有效
  121. /// </summary>
  122. /// <param name="queryCode">查询码</param>
  123. /// <param name="onFails">失败回调</param>
  124. /// <returns></returns>
  125. public async Task<bool> QueryCodeIsValid(string queryCode, OnFails onFails)
  126. {
  127. XFApiResult rObj = await HttpPostAsync<XFApiResult>(_config["XFApi"] + "/query/code;", "query_code=" + queryCode, onFails);
  128. if (rObj == null)
  129. return false;
  130. if (rObj.Data == null || !rObj.Data.Success)
  131. {
  132. Logger.LogError("数据提交省统一平台失败,原因:{0}", rObj.Message);
  133. onFails(string.Format("数据提交省统一平台失败,原因:{0}", rObj.Message));
  134. return false;
  135. }
  136. return true;
  137. }
  138. /// <summary>
  139. /// 查询信件详细信息
  140. /// </summary>
  141. /// <param name="queryCode">查询码</param>
  142. /// <param name="onFails">失败回调</param>
  143. /// <returns></returns>
  144. public async Task<Bundle> GetBundleByQueryCode(string queryCode, OnFails onFails)
  145. {
  146. JObject rObj = await HttpGetAsync<JObject>(_config["XFApi"] + "/query/letterDetail;", "query_code="+ queryCode, onFails);
  147. if (rObj == null)
  148. return null;
  149. if(String.IsNullOrWhiteSpace(rObj["data"]["letter"]["id"].ToString()))
  150. {
  151. Logger.LogError("省统一平台无该信件信息,查询码:{0}", queryCode);
  152. onFails(string.Format("查找不到该信件信息。"));
  153. return null;
  154. }
  155. Bundle bundle = new Bundle();
  156. bundle.LetterId = rObj["data"]["letter"]["id"].ToString();
  157. bundle.Status = rObj["data"]["letter"]["status"].ToString();
  158. bundle.Reply = rObj["data"]["letter"]["replyAdvice"].ToString();
  159. bundle.DealProcesses = rObj["data"]["dealProcesses"].ToString();
  160. bundle.ResultFromXF = rObj["data"].ToString();
  161. return bundle;
  162. }
  163. /// <summary>
  164. /// 是否可评价
  165. /// </summary>
  166. /// <param name="letter_id"></param>
  167. /// <param name="onFails"></param>
  168. /// <returns></returns>
  169. public async Task<XFApiIsEvaluateResultData> IsEvaluate(string letter_id, OnFails onFails)
  170. {
  171. XFApiIsEvaluateResult rObj = await HttpGetAsync<XFApiIsEvaluateResult>(_config["XFApi"] + "/query/isEvaluate;", "letter_id=" + letter_id, onFails);
  172. if (rObj == null)
  173. return null;
  174. if (rObj.Status == "10201")
  175. {
  176. Logger.LogError("查询信件是否可评价失败:{0}", letter_id);
  177. onFails(string.Format("查询信件是否可评价失败,原因:{0}", rObj.Message));
  178. return null;
  179. }
  180. return rObj.Data;
  181. }
  182. /// <summary>
  183. /// 评价
  184. /// </summary>
  185. /// <param name="e"></param>
  186. /// <param name="onFails"></param>
  187. /// <returns></returns>
  188. //http://<服务器IP>/query/submitEvaluate
  189. public async Task<bool> SubmitEvaluate(EvaluateModel e, OnFails onFails)
  190. {
  191. XFApiResult rObj = await HttpPostAsync<XFApiResult>(_config["XFApi"] + "/query/submitEvaluate;",
  192. String.Format(
  193. "cxm={0};xfbmmyd={1};zrdwmyd={2};type=1;xfbmpjsj={3};xfbmpjnr={4};zrdwpjsj={5};zrdwpjnr={6};",
  194. e.cxm, e.xfbmmyd, e.zrdwmyd, DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"), e.xfbmpjnr, DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"), e.zrdwpjnr), onFails);
  195. if (rObj == null)
  196. return false;
  197. if (rObj.Data == null)
  198. {
  199. Logger.LogError("数据提交省统一平台失败,原因:{0}", rObj.Message);
  200. onFails(string.Format("数据提交省统一平台失败,原因:{0}", rObj.Message));
  201. return false;
  202. }
  203. return rObj.Data.Success;
  204. }
  205. /// <summary>
  206. /// 查询满意度
  207. /// </summary>
  208. /// <param name="e"></param>
  209. /// <param name="onFails"></param>
  210. /// <returns></returns>
  211. //http://<服务器IP>/query/submitEvaluate
  212. public async Task<EvaluateModel> QueryEvaluate(string searchCode, OnFails onFails)
  213. {
  214. JObject rObj = await HttpGetAsync<JObject>(_config["XFApi"] + "/query/queryEvaluate;", String.Format("cxm={0}", searchCode), onFails);
  215. if (rObj == null)
  216. return null;
  217. if (rObj["status"].ToString() == "10201")
  218. {
  219. Logger.LogError("数据提交省统一平台失败,原因:{0}", rObj["message"].ToString());
  220. onFails(string.Format("数据提交省统一平台失败,原因:{0}", rObj["message"].ToString()));
  221. return null;
  222. }
  223. Logger.LogInformation(rObj.ToString());
  224. EvaluateModel em = new EvaluateModel();
  225. em.type = rObj["data"]["type"].ToString();
  226. em.xfbmmyd = rObj["data"]["xfbmmyd"].ToString();
  227. em.xfbmpjnr = rObj["data"]["xfbmpjnr"].ToString();
  228. em.xfbmpjsj = rObj["data"]["xfbmpjsj"].ToString();
  229. em.zrdwmyd = rObj["data"]["zrdwmyd"].ToString();
  230. em.zrdwpjnr = rObj["data"]["zrdwpjnr"].ToString();
  231. em.zrdwpjsj = rObj["data"]["zrdwpjsj"].ToString();
  232. return em;
  233. }
  234. /// <summary>
  235. /// POST 异步
  236. /// </summary>
  237. /// <param name="url"></param>
  238. /// <param name="postStream"></param>
  239. /// <param name="encoding"></param>
  240. /// <param name="timeOut"></param>
  241. /// <returns></returns>
  242. async Task<T> HttpPostAsync<T>(string url, string formData, OnFails onFails)
  243. {
  244. HttpClientHandler handler = new HttpClientHandler();
  245. HttpClient client = new HttpClient(handler);
  246. MemoryStream ms = new MemoryStream();
  247. HttpContent hc = new StreamContent(ms);
  248. hc.Headers.Add("APIKey", "MUA5NmU3OTIxOEPSOFTDQ1YTMzMDExMg");
  249. var r = await client.PostAsync(url + WebUtility.UrlEncode(formData), hc);
  250. if (r.StatusCode != HttpStatusCode.OK)
  251. {
  252. Logger.LogError("省统一平台异常反馈:状态“{0}”", r.StatusCode);
  253. onFails(string.Format("省统一平台异常反馈:状态“{0}”", r.StatusCode));
  254. return default(T);
  255. }
  256. byte[] tmp = await r.Content.ReadAsByteArrayAsync();
  257. string rStr = Encoding.UTF8.GetString(tmp);
  258. T rObj = JsonConvert.DeserializeObject<T>(rStr);
  259. if (rObj == null)
  260. {
  261. Logger.LogError("数据提交省统一平台失败,原因:{0}", "数据为空");
  262. onFails(string.Format("数据提交省统一平台失败,原因:{0}", "数据为空"));
  263. return default(T);
  264. }
  265. return rObj;
  266. }
  267. /// <summary>
  268. /// POST 异步
  269. /// </summary>
  270. /// <param name="url"></param>
  271. /// <param name="postStream"></param>
  272. /// <param name="encoding"></param>
  273. /// <param name="timeOut"></param>
  274. /// <returns></returns>
  275. async Task<T> HttpGetAsync<T>(string url, string formData, OnFails onFails)
  276. {
  277. HttpClient client = new HttpClient();
  278. client.DefaultRequestHeaders.Add("APIKey", "MUA5NmU3OTIxOEPSOFTDQ1YTMzMDExMg");
  279. var r = await client.GetAsync(url + WebUtility.UrlEncode(formData));
  280. if (r.StatusCode != HttpStatusCode.OK)
  281. {
  282. Logger.LogError("省统一平台异常反馈:状态“{0}”", r.StatusCode);
  283. onFails(string.Format("省统一平台异常反馈:状态“{0}”", r.StatusCode));
  284. return default(T);
  285. }
  286. byte[] tmp = await r.Content.ReadAsByteArrayAsync();
  287. string rStr = Encoding.UTF8.GetString(tmp);
  288. T rObj = JsonConvert.DeserializeObject<T>(rStr);
  289. if (rObj == null)
  290. {
  291. Logger.LogError("数据提交省统一平台失败,原因:{0}", "数据为空");
  292. onFails(string.Format("数据提交省统一平台失败,原因:{0}", "数据为空"));
  293. return default(T);
  294. }
  295. return rObj;
  296. }
  297. /// <summary>
  298. /// POST 同步
  299. /// </summary>
  300. /// <param name="url"></param>
  301. /// <param name="postStream"></param>
  302. /// <param name="encoding"></param>
  303. /// <param name="timeOut"></param>
  304. /// <returns></returns>
  305. string HttpPost(string url, Dictionary<string, string> formData = null, Encoding encoding = null, int timeOut = 10000)
  306. {
  307. HttpClientHandler handler = new HttpClientHandler();
  308. HttpClient client = new HttpClient(handler);
  309. MemoryStream ms = new MemoryStream();
  310. FillFormDataStream(formData, ms);//填充formData
  311. HttpContent hc = new StreamContent(ms);
  312. //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
  313. //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xhtml+xml"));
  314. //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml", 0.9));
  315. //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("image/webp"));
  316. //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*", 0.8));
  317. //hc.Headers.Add("UserAgent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36");
  318. //hc.Headers.Add("Timeout", timeOut.ToString());
  319. //hc.Headers.Add("KeepAlive", "true");
  320. var t = client.PostAsync(url, hc);
  321. t.Wait();
  322. var t2 = t.Result.Content.ReadAsByteArrayAsync();
  323. return encoding.GetString(t2.Result);
  324. }
  325. /// <summary>
  326. /// 组装QueryString的方法
  327. /// 参数之间用&连接,首位没有符号,如:a=1&b=2&c=3
  328. /// </summary>
  329. /// <param name="formData"></param>
  330. /// <returns></returns>
  331. string GetQueryString(Dictionary<string, string> formData)
  332. {
  333. if (formData == null || formData.Count == 0)
  334. {
  335. return "";
  336. }
  337. StringBuilder sb = new StringBuilder();
  338. var i = 0;
  339. foreach (var kv in formData)
  340. {
  341. i++;
  342. sb.AppendFormat("{0}={1}", kv.Key, kv.Value);
  343. if (i < formData.Count)
  344. {
  345. sb.Append("&");
  346. }
  347. }
  348. return sb.ToString();
  349. }
  350. /// <summary>
  351. /// 填充表单信息的Stream
  352. /// </summary>
  353. /// <param name="formData"></param>
  354. /// <param name="stream"></param>
  355. void FillFormDataStream(Dictionary<string, string> formData, Stream stream)
  356. {
  357. string dataString = GetQueryString(formData);
  358. var formDataBytes = formData == null ? new byte[0] : Encoding.UTF8.GetBytes(dataString);
  359. stream.Write(formDataBytes, 0, formDataBytes.Length);
  360. stream.Seek(0, SeekOrigin.Begin);//设置指针读取位置
  361. }
  362. }
  363. }