using Microsoft.EntityFrameworkCore; using Nancy.Json; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using RB_MES_API.Context; using RB_MES_API.Controllers; using RB_MES_API.Controllers.Cloud; using RB_MES_API.Models; using RB_MES_API.Models.Cloud; using RB_MES_API.Models.Pangu; using RB_MES_APICore.Models.Pangu; using RB_MES_APICore.Models; using System.Data; using System.Net; using System.Reflection; using System.Text; namespace RB_MES_API.HostService { /// /// 定时推送服务 /// public class PushMesInterface : IPushMesInterface,IDisposable { private List _timer = new List(); private readonly RBContext _context; private readonly IConfiguration _config; private readonly IShareController _shareController; private readonly IKDCloudHttpClient _KdhttpClient; private readonly IKDSqlHelper _kdsqlhelper; /// /// /// /// 注入的数据库连接 /// 共享方法 /// 金蝶API /// /// public PushMesInterface(RBContext context, IConfiguration configuration, IShareController shareController , IKDCloudHttpClient httpClient, IKDSqlHelper kdsqlhelper) { _context = context; _config = configuration; _shareController = shareController; _KdhttpClient = httpClient; _kdsqlhelper = kdsqlhelper; } /// public void Dispose() { foreach (Timer timer in _timer) { timer?.Dispose(); } } private void DoWork(object state) { // 定时任务逻辑 try { List queryJsons = _shareController.GetAPIList().Result; var clouds = queryJsons.Where(s => s.GetFormID.FDocType == state.ToString()).ToList(); if (clouds.Count > 0) { new TaskFactory().StartNew(async () => { CloudBillQuery query = clouds.FirstOrDefault(); //启动新线程执行推送业务 Type type = this.GetType(); MethodInfo? methodInfo = type.GetMethod(query.GetFormID.FActionName); if (methodInfo != null) { object[] para = new object[] { query.GetFormID.FID, query.GetFormID.functions.FUrl }; methodInfo.Invoke(this, para); } }); } } catch (Exception ex) { LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork发生错误:{0}", ex.Message)); } } public async void DoTimerWorkAsyn() { await Task.Run(() => LoadLocalStaticRequest()); try { string v = LocalStaticRequest.GetSystemProfile(1, "AutoPushTask"); int at = 0; int.TryParse(v, out at); if (at > 0) { //只要FTimer > 0的接口都有一个属于自己的定时器! List systimeds = _shareController.GetAPIList().Result; if (systimeds.Count == 0) { return; } var sys = from a in systimeds select new { worktime = a.FTimer, name = a.FDocType }; foreach (var item in sys) { _timer.Add(new Timer(DoWork, item.name, TimeSpan.Zero, TimeSpan.FromMinutes(item.worktime))); } } } catch (Exception ex) { LogHelper.WriteLog(string.Format("TimedHostedService的StartAsync发生错误:{0}", ex.Message)); } return; } /// /// 优先加载系统必须的静态数据 /// private void LoadLocalStaticRequest() { try { //如果缓存中不存在,就从数据库里取出来再放进缓存 List sys = CacheHelper.GetCache>("sys"); if (sys == null) { //先初始化全局变量 sys = _context.r_SystemProfiles!.AsNoTracking().ToList(); if (sys.Any()) { CacheHelper.Set_AbsluteExpire("sys", sys); } } LocalStaticRequest.sysprofile = sys; //定时刷新 } catch (Exception ex) { //如果金蝶Cloud登录失败,就会发生异常,可能导致程序崩溃... string msg = ex.Message; LogHelper.WriteLog(string.Format("TimedHostedService的LoadHostFunctionAsync发生错误:{0}", msg)); } //将计量单位加入缓存 Thread uthread = new Thread(AddUnitCache); uthread.Start(); //无论是否推送,静态全局设置应该首先加载 string orgid = LocalStaticRequest.GetSystemProfile(2, "DefaultORGID"); string orgno = LocalStaticRequest.GetSystemProfile(2, "DefaultORG"); LocalStaticRequest.DefaultOrgID = string.IsNullOrEmpty(orgid) ? 1 : int.Parse(orgid); LocalStaticRequest.DefaultOrg = string.IsNullOrEmpty(orgno) ? "100" : orgno; } private void AddUnitCache() { try { List units = new List(); string messstr = string.Empty; string fileds = "FUNITID,FNumber,FName,FIsBaseUnit,FPrecision,FDocumentStatus,FForbidStatus,FConvertDenominator,FConvertNumerator,FRoundType"; //从云星空中把所有计量单位获取过来 BillQuery queryJson = new BillQuery() { FieldKeys = fileds, FormId = "BD_UNIT", FilterString = "FDOCUMENTSTATUS='C' AND FFORBIDSTATUS='A'" }; if (!LocalStaticRequest.Islogin) { if (!_KdhttpClient.LoginErp().Result) { return; } } //从云星空查询 string jsonstr = JsonConvert.SerializeObject(queryJson); List Parameters = new List(); Parameters.Add(jsonstr); string content = JsonConvert.SerializeObject(Parameters); string url = LocalStaticRequest.GetSystemProfile(4, "TokenUrl"); string myurl = url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc"; //string result = _KdhttpClient.AsyncRequest(); string result = _KdhttpClient.AsyncRequest(myurl, content); //如果访问正常 if (_KdhttpClient.CloudExecuteQueryStatus(result, ref messstr)) { //将获取到的结果转为List units = _shareController.GetNewObjForChild(fileds, result, ref messstr); CacheHelper.Set_AbsluteExpire("BD_UNIT", units); } } catch (Exception e) { LogHelper.WriteLog(string.Format("TimedHostedService的AddUnitCache发生错误:{0}", e.Message)); } } /// /// 将自定义SQL查询结果推送给MES /// /// /// public void GetSelfDBbaseAsync(int formtypeid, string url) { string result = GetCustomRequestTBAsync(formtypeid); List query = _shareController.GetAPIList().Result; if (query.Count == 0) return; string doctype = query.Find(s => s.FFormIDTypeID == formtypeid).GetFormID.FDocType; if (string.IsNullOrEmpty(result)) { return; } try { //可以将datatable直接转为JSON,但这里约定的格式用不上 //new JsonSerializer().Deserialize(new JsonTextReader(new StringReader(result))); JArray array = (JArray)JsonConvert.DeserializeObject(result); if (array == null || array.Count == 0) { return; } PanguPostBill mes = new PanguPostBill() { DocType = doctype, DataSet = _shareController.GetClassList(array) }; string json = JsonConvert.SerializeObject(mes); ////推送给MES //PanguBreakJson mesjson = PushMesData(json).Result; //if (mesjson.Status) //{ // LogHelper.WriteLog(string.Format("推送【{0}】成功:{1}", doctype, json), doctype); //} //else //{ // LogHelper.WriteLog(string.Format("TimedHostedService的GetSelfDBbaseAsync方法推送【{0}】失败:{1}\n原始数据:{2}", doctype, mesjson.Message, json), doctype); //} } catch (Exception ex) { LogHelper.WriteLog(string.Format("TimedHostedService推送【{0}】动态GetSelfDBbaseAsync方法出错:{1}", doctype, ex.Message), doctype); } } /// /// 查询Cloud表单。注意:基础资料表单查询有多用途,FFieldKeys中必须有Key。同理... /// /// /// public async void GetBDbase(int formtypeid, string url) //动态引用 { string reason = string.Empty; List queryJsons = await _shareController.GetAPIList(); if (queryJsons.Count == 0) { LogHelper.WriteLog("TimedHostedService的GetBDbase方法_shareController.GetAPIList()缓存过期"); return; } else { var formtype = queryJsons.Where(s => s.GetFormID.FID == formtypeid).FirstOrDefault()!.GetFormID; int fid = formtype.FFunctionID; string doctype = formtype.FDocType; var queryJson = from a in queryJsons.Where(s => s.GetFormID.FID == formtypeid) select new BillQuery { FieldKeys = a.FFieldKeys.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg), FormId = a.GetFormID.FDBName, FilterString = a.FFiledString.Replace("GETDATE", DateTime.Now.ToShortDateString()).Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg), Limit = a.FLimit, OrderString = a.FOrderString, StartRow = a.FStartRow, SubSystemId = a.FSubSystemID, TopRowCount = a.FTopRowCount }; if (queryJson.Any()) { try { if (!LocalStaticRequest.Islogin) { await _KdhttpClient.LoginErp(); } if (!LocalStaticRequest.Islogin) { reason = "KdhttpClient登录失败"; goto EBread; } string jsonstr = JsonConvert.SerializeObject(queryJson.FirstOrDefault()); List Parameters = new List() { jsonstr }; string content = JsonConvert.SerializeObject(Parameters); //string result = _KdhttpClient.AsyncRequest(); string result = _KdhttpClient.AsyncRequest(url, content); if (_KdhttpClient.CloudExecuteQueryStatus(result, ref reason)) //查询表单数据接口使用 { if (!string.IsNullOrEmpty(reason)) { goto EBread; } JArray jArray = (JArray)JsonConvert.DeserializeObject(result.ToString()!)!; //特别注意!!! //为dt添加数据 if (jArray != null && jArray.Count > 0) { string fileds = queryJson.FirstOrDefault()!.FieldKeys!; //根据字段对应关系分配字段 DataTable dt = _shareController.JsonConvertDatatable(fileds, result, ref reason); if (!string.IsNullOrEmpty(reason)) { goto EBread; } //DataTable dt = CreateFFieldKeys(fileds); //由于jArray没有字段名,只能先装填DataTable //LoadDatatable(jArray, ref dt); if (dt.Rows.Count > 0) { List> dic = GetClassList(fid, doctype, dt); if (dic.Any()) { //json = JsonConvert.SerializeObject(dic); PanguPostBill mes = new PanguPostBill() { DocType = doctype, DataSet = dic }; string json = JsonConvert.SerializeObject(mes); ////推送给MES //PanguBreakJson mesjson = await PushMesData(json); //if (mesjson.Status) //{ // reason = string.Format("推送【{0}】成功:{1}", doctype, json); //} //else //{ // reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】失败:{1}\r原始数据:{2}", doctype, mesjson.Message, json); //} } else { reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】失败:!GetClassList(fid, doctype, dt)Any():{1}}", doctype, result); } } } } else { //将message写入错误日志 reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】返回结果:{1}", doctype, result.ToString()); } } catch (Exception ex) { reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】过程中发生错误:{1}", doctype, ex.Message); } } EBread: if (!string.IsNullOrEmpty(reason)) { LogHelper.WriteLog(reason, doctype); } } } /// /// 向第三方系统推送数据 /// /// 推送的JSON文本 /// private async Task PushMesData(string inputdata) { PanguBreakJson breadJson = new PanguBreakJson() { Status = false }; string mesurl = _config.GetConnectionString("MesUrl"); mesurl += mesurl.Substring(mesurl.Length - 1, 1) == "/" ? "" : "/"; //如果最后一个字符不是"/"就添加上去 mesurl += "updateimsdata"; HttpWebRequest reqest = (HttpWebRequest)WebRequest.Create(mesurl); reqest.Timeout = 20 * 60 * 1000; reqest.Method = "POST"; reqest.ContentType = "application/json"; try { byte[] bytes = Encoding.UTF8.GetBytes(inputdata); reqest.ContentLength = bytes.Length; string result = string.Empty; reqest.GetRequestStream().Write(bytes, 0, bytes.Length); HttpWebResponse webResponse = (HttpWebResponse)await reqest.GetResponseAsync(); //读取返回数据 StreamReader streamReader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8); result = streamReader.ReadToEnd(); streamReader.Dispose(); webResponse.Dispose(); breadJson = JsonConvert.DeserializeObject(result); } catch (Exception ex) { breadJson.Message = ex.Message; } return breadJson; } /// /// 根据字段转换的目标名称,从table获取数据,生成新的键值对集合。 /// 适用于定时推送任务!或其他不需要存储的动态对象。与接口_shareController中同名方法有异曲同工之处 /// /// FFunctionID /// 目标表名 /// 需要转换的表,没有字段名 /// private List> GetClassList(int fid, string decname, DataTable table) { List> list = new List>(); //先检查是否需要作字段转换 List scc = _shareController.GetAPIList().Result; scc = scc.Where(s => s.FFunctionID == fid && s.FDesTableName.Equals(decname)).ToList(); if (scc.Any()) { foreach (DataRow row in table.Rows) { Dictionary keyValuePairs = new Dictionary(); foreach (SelectClumnConvert clumnConvert in scc) { string oldname = clumnConvert.FSourceName; if (table.Columns.Contains(oldname)) { string newname = clumnConvert.FDesName; keyValuePairs.Add(newname, row[oldname].ToString()!); } } list.Add(keyValuePairs); } } return list; } /// /// 来源于接口_ChiledSelect,但由于本地服务启动与依赖性注入底层冲突而不能直接调用接口 /// /// /// private string GetCustomRequestTBAsync(int formtypeid) { //throw new NotImplementedException(); string tbjson = string.Empty; try { List queryJsons = _shareController.GetAPIList().Result; var query = queryJsons.Where(s => s.FFormIDTypeID == formtypeid).FirstOrDefault(); //查询脚本 string sql = query.FFieldKeys.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()); if (string.IsNullOrEmpty(sql)) { return tbjson; } //这个方法无法携带参数,只能先写在查询语句里,然后替换之... string param = query.FFiledString.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg); if (!string.IsNullOrEmpty(param)) { string[] strings = param.Split(','); foreach (string s in strings) { string[] cs = s.Split('='); string key = cs[0]; string value = cs[1].Replace("GETDATE", DateTime.Now.ToShortDateString()).Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()); sql = sql.Replace(key, value); } } string doctype = query.GetFormID.FDocType; string costomsql = _config.GetValue("CustomRequestRemoteSql"); if (costomsql.ToUpper() == "Y") { string result = GetCustomReaderAsync(sql, "ExecuteDataSet"); //string errmess = string.Empty; try { if (string.IsNullOrWhiteSpace(result)) { return tbjson; } //先将返回数据格式化 JObject jobj = (JObject)JsonConvert.DeserializeObject(result); tbjson = JsonConvert.SerializeObject(jobj["Table"]); } catch (Exception ex) { LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0})本地查询{1}发生错误:{2}", formtypeid, doctype, ex.Message)); } } else { string mess = string.Empty; //实施本地化查询 DataSet dataSet = _kdsqlhelper.GetDataSet(CommandType.Text, sql, null, ref mess, true); if (mess != null || dataSet == null) { LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0})网络查询{1}发生错误:{2}", formtypeid, doctype, mess)); } else if (dataSet.Tables.Count != 0) { DataTable dataTable = dataSet.Tables[0]; tbjson = JsonConvert.SerializeObject(dataTable); } } } catch (Exception ex) { LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0})发生错误:{1}", formtypeid, ex.Message)); } return tbjson; } /// /// 来源于接口_ChiledSelect,但由于本地服务启动与依赖性注入底层冲突而不能直接调用接口 /// /// /// /// private string GetCustomReaderAsync(string sql, string servicesstubname) { string tbjson = string.Empty; try { //获取自定义查询的服务器端插件地址... string apiid = LocalStaticRequest.GetSystemProfile(1, "APIGrouID"); var sv = _context.r_CustomServices.Where(s => s.FApiGroupID == int.Parse(apiid) && s.FActionName == servicesstubname); if (!sv.Any()) { return tbjson; } CustomService customservice = sv.FirstOrDefault(); if (customservice == null) { return tbjson; } //查询前必须先登录... if (!LocalStaticRequest.Islogin) { _KdhttpClient.LoginErp(); } if (!LocalStaticRequest.Islogin) { return tbjson; } string url = LocalStaticRequest.GetSystemProfile(4, "TokenUrl"); url += url.Substring(url.Length - 1, 1) == "/" ? "" : "/"; //如果最后一个字符不是"/"就添加上去 url += customservice.FNamespace + "." + customservice.FClassName + "." + customservice.FActionName + "," + customservice.FAppComponents; List Parameters = new List { sql//服务中可添加参数SqlParam[],但要引用金蝶组件! }; string content = JsonConvert.SerializeObject(Parameters); tbjson = _KdhttpClient.AsyncRequest(url, content); } catch (Exception ex) { LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0},{1})发生错误:{1}", sql, servicesstubname, ex.Message)); } return tbjson; //throw new NotImplementedException(); } } }