using Google.Protobuf.WellKnownTypes; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Http; using System.Text; using System.Threading; using System.Xml.Linq; namespace Appointment.Entity { public class AizhuhotelHelper { private static readonly log4net.ILog _logger = log4net.LogManager.GetLogger(typeof(AizhuhotelHelper)); // ---- 获取公众号 Access_token private class LoveInnGetAccessTokenRes { /// /// 200-成功,400-出错, /// public int Code { get; set; } /// /// 返回信息:正确、错误都提示 /// public string Message { get; set; } /// /// 信息 /// public GetAccessTokenRes Data { get; set; } } private class GetAccessTokenRes { public string Access_token { get; set; } public int? Expires_in { get; set; } public string Errcode { get; set; } public string Errmsg { get; set; } } /// /// 通过爱住接口获取Accesstoken /// /// public static ApiResult AizhuhotelGetAccesstoken() { var url = "https://pay.aizhuhotel.com/dlwx/api/WD/LoveInnGetAccessToken"; string AppId = BaseConfig.App(new string[] { "WeChatService", "AppId" }); if (string.IsNullOrWhiteSpace(AppId)) return ApiResult.Failed("配置文件中未获取有效的消息推送AppId"); string AppName = BaseConfig.App(new string[] { "WeChatService", "AppName" }); if (string.IsNullOrWhiteSpace(AppName)) return ApiResult.Failed("配置文件中未获取有效的消息推送AppName"); string AppSecret = BaseConfig.App(new string[] { "WeChatService", "AppSecret" }); if (string.IsNullOrWhiteSpace(AppSecret)) return ApiResult.Failed("配置文件中未获取有效的消息推送AppSecret"); var json = JsonConvert.SerializeObject(new { AppId, AppName, AppSecret }); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Proxy = null; request.Method = "POST"; request.ContentType = "application/json"; // request.Timeout = 10000; using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream())) { dataStream.Write(json); dataStream.Close(); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if (response == null) { return ApiResult.Failed("远程服务器没有响应!"); } string encoding = response.ContentEncoding; if (encoding == null || encoding.Length < 1) { encoding = "UTF-8"; //默认编码 } StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); string retString = reader.ReadToEnd(); var res = JsonConvert.DeserializeObject(retString); if (res.Code != 200) return ApiResult.Failed(res.Message); if (res.Data == null) return ApiResult.Failed("未获取到有效信息"); return ApiResult.Success(string.Empty, res.Data.Access_token); } catch (Exception ex) { _logger.Debug(ex.ToString()); return ApiResult.Failed("http请求异常,异常信息:" + ex.Message); } } // ---- 通过微信服务器获取access_token private static WxAccessTokenData accessCacheToken = null; public class WxAccessTokenData { /// /// 获取到的access_token /// public string Access_token { get; set; } /// /// 获取时间 /// public DateTime GetDate { get; set; } } /// /// 微信授权返回结果 /// public class WxAuthorizationCodeRep { /// /// 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 /// public string Access_token { get; set; } /// /// access_token接口调用凭证超时时间,单位(秒) /// 错误时不返回 /// public int? Expires_in { get; set; } /// /// 用户刷新access_token /// public string Refresh_token { get; set; } /// /// 用户唯一标识 /// public string Openid { get; set; } /// /// 用户授权的作用域,使用逗号(,)分隔 /// public string Scope { get; set; } /// /// 错误码:返回码 /// 正确时不返回 /// public int? Errcode { get; set; } /// /// 错误信息 /// public string Errmsg { get; set; } } /// /// 获取服务号AccessToken /// /// 强制刷新 /// public static ApiResult GetAccessToken(bool forceUpdate = false) { try { string AppId = BaseConfig.App(new string[] { "WeChatService", "AppId" }); if (string.IsNullOrWhiteSpace(AppId)) return ApiResult.Failed("配置文件中未获取有效的服务号AppId"); string AppSecret = BaseConfig.App(new string[] { "WeChatService", "AppSecret" }); if (string.IsNullOrWhiteSpace(AppSecret)) return ApiResult.Failed("配置文件中未获取有效的服务号AppSecret"); DateTime now = DateTime.Now; if (forceUpdate == false && accessCacheToken != null && now.AddSeconds(-1 * 55 * 2) < accessCacheToken.GetDate) { return ApiResult.Success(string.Empty, accessCacheToken.Access_token); } var url = $"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={AppId}&secret={AppSecret}"; using (var http = new HttpClient(new HttpClientHandler())) { var res = http.GetAsync(url).Result; if (res.StatusCode != HttpStatusCode.OK) { _logger.Error("获取公众号access_token失败,微信服务接口响应" + res.StatusCode.ToString()); return ApiResult.Failed("获取公众号access_token失败,微信服务接口响应" + res.StatusCode.ToString()); } var reContent = res.Content.ReadAsStringAsync().Result; if (!string.IsNullOrWhiteSpace(reContent)) { var reToken = JsonConvert.DeserializeObject(reContent); if (!string.IsNullOrEmpty(reToken.Access_token)) { accessCacheToken = new WxAccessTokenData() { Access_token = reToken.Access_token, GetDate = now }; return ApiResult.Success(string.Empty, reToken.Access_token); } else { _logger.Error(reContent); } } return ApiResult.Failed(string.Empty); } } catch (Exception ex) { _logger.Error(ex.Message); return ApiResult.Failed(ex.Message); } } // ---- 获取用户Openid private class WxServiceRes { public string Access_token { get; set; } public int? Expires_in { get; set; } public string Refresh_token { get; set; } public string Openid { get; set; } public string Errcode { get; set; } public string Errmsg { get; set; } } public static ApiResult GetWxSericeOpenId(string code) { if (string.IsNullOrWhiteSpace(code)) return ApiResult.Failed("未获取到有效的code"); string AppId = BaseConfig.App(new string[] { "WeChatService", "AppId" }); if (string.IsNullOrWhiteSpace(AppId)) return ApiResult.Failed("配置文件中未获取有效的消息推送AppId"); string AppSecret = BaseConfig.App(new string[] { "WeChatService", "AppSecret" }); if (string.IsNullOrWhiteSpace(AppSecret)) return ApiResult.Failed("配置文件中未获取有效的消息推送AppSecret"); string url = $"https://api.weixin.qq.com/sns/oauth2/access_token?appid={AppId}&secret={AppSecret}&code={code}&grant_type=authorization_code"; using (var http = new HttpClient(new HttpClientHandler())) { var response = http.GetAsync(url).Result; if (response.StatusCode != HttpStatusCode.OK) return ApiResult.Failed("微信接口无响应"); string res = response.Content.ReadAsStringAsync().Result; if (!string.IsNullOrWhiteSpace(res)) { var wxServiceRes = JsonConvert.DeserializeObject(res); if (!string.IsNullOrWhiteSpace(wxServiceRes.Openid)) { return ApiResult.Success(string.Empty, wxServiceRes.Openid); } else { _logger.Error(res); return ApiResult.Failed(wxServiceRes.Errcode); } } return ApiResult.Failed("返回空"); } } // ---- 发送消息模板 public static ApiResult SendTemplateMsg(string touser, string template_id, string url, string first, string remark, params object[] args) { try { string error = string.Empty; for (int i = 0; i < 3; i++) { error = string.Empty; var msg = WechatHelper.BuildTemlMsg(touser, template_id, url, first, remark, args); string accessTokenMode = BaseConfig.App(new string[] { "AccessTokenMode" }); if (string.IsNullOrWhiteSpace(accessTokenMode)) { _logger.Error("配置文件中未获取有效的AccessTokenMode"); return ApiResult.Failed("配置文件中未获取有效的AccessTokenMode"); } ApiResult tokenResult = null; if (i == 0) { tokenResult = accessTokenMode == "1" ? AizhuhotelGetAccesstoken() : GetAccessToken(); } else { tokenResult = accessTokenMode == "1" ? AizhuhotelGetAccesstoken() : GetAccessToken(true); } if (!tokenResult.IsSuccess) { error = "配置文件中未获取有效的AccessTokenMode"; _logger.Error(error); continue; } var postUrl = $"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={tokenResult.Info}"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl); request.Proxy = null; request.Method = "POST"; request.ContentType = "application/json"; // request.Timeout = 10000; using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream())) { dataStream.Write(msg); dataStream.Close(); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if (response == null) { error = "远程服务器没有响应!"; _logger.Error(error); continue; } string encoding = response.ContentEncoding; if (encoding == null || encoding.Length < 1) { encoding = "UTF-8"; //默认编码 } StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); string retString = reader.ReadToEnd(); if (!string.IsNullOrWhiteSpace(retString)) { var sendTemplateMsgRes = JsonConvert.DeserializeObject(retString); if (sendTemplateMsgRes.Errmsg.ToLower() == "ok") { return ApiResult.Success(string.Empty); } else { error = $"接收者openid:{touser},错误代码{sendTemplateMsgRes.Errcode}"; _logger.Error(error); continue; } } } return ApiResult.Failed(msg: "", info: error); } catch (Exception ex) { _logger.Debug(ex.ToString()); return ApiResult.Failed(msg: "", info: ex.Message); } } /// /// 发送模板消息返回结果 /// private class SendTemplateMsgRes { /// /// 返回代码,0-发送成功 /// public int Errcode { get; set; } /// /// 返回消息:"ok"-成功 /// public string Errmsg { get; set; } /// /// 发送成功返回编号:失败不返回 /// public long? Msgid { get; set; } } public static void SendTemplateMsg(List tousers, string template_id, string url, string first, string remark, params object[] args) { if (tousers == null || tousers.Count == 0) return; string accessTokenMode = BaseConfig.App(new string[] { "AccessTokenMode" }); if (string.IsNullOrWhiteSpace(accessTokenMode)) { _logger.Error("配置文件中未获取有效的AccessTokenMode"); return; } ApiResult tokenResult = accessTokenMode == "1" ? AizhuhotelGetAccesstoken() : GetAccessToken(); if (!tokenResult.IsSuccess) { _logger.Error(tokenResult.Msg); return; } List msgList = new List(); foreach (var touser in tousers) { msgList.Add(WechatHelper.BuildTemlMsg(touser, template_id, url, first, remark, args)); } int send = 0; _logger.Info($"发送推送消息,模板:{template_id}, 接收者openId:{string.Join(",", msgList)} 。"); StringBuilder msg = new StringBuilder(); foreach (var itemMsg in msgList) { for (int i = 0; i < 3; i++) { if (i > 0) { Thread.Sleep(100); tokenResult = accessTokenMode == "1" ? AizhuhotelGetAccesstoken() : GetAccessToken(true); if (!tokenResult.IsSuccess) { _logger.Error(tokenResult.Msg); continue; } } var postUrl = $"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={tokenResult.Info}"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl); request.Proxy = null; request.Method = "POST"; request.ContentType = "application/json"; // request.Timeout = 10000; using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream())) { dataStream.Write(itemMsg); dataStream.Close(); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if (response == null) { _logger.Error("微信接口远程服务器没有响应"); continue; } string encoding = response.ContentEncoding; if (encoding == null || encoding.Length < 1) { encoding = "UTF-8"; //默认编码 } StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); string retString = reader.ReadToEnd(); _logger.Info("-->" + itemMsg + " response-->" + retString); if (!string.IsNullOrWhiteSpace(retString)) { var sendTemplateMsgRes = JsonConvert.DeserializeObject(retString); if (sendTemplateMsgRes.Errmsg.ToLower() == "ok") { send += 1; break; } else { if (msg.Length == 0) msg.AppendFormat("消息推送失败:消息模板{0}", template_id); msg.AppendFormat("接收者openid:{0},错误代码{1}", itemMsg, sendTemplateMsgRes.Errcode); continue; } } } Thread.Sleep(100); } if (msg.Length > 0) _logger.Error(msg.ToString()); } public static ApiResult SendTempMsg(string msg) { try { string accessTokenMode = BaseConfig.App(new string[] { "AccessTokenMode" }); if (string.IsNullOrWhiteSpace(accessTokenMode)) { _logger.Error("配置文件中未获取有效的AccessTokenMode"); return ApiResult.Failed("配置文件中未获取有效的AccessTokenMode"); } // 获取 AccessToken string access_token = string.Empty; for (int i = 0; i < 3; i++) { ApiResult tokenResult = null; if (i == 0) { tokenResult = accessTokenMode == "1" ? AizhuhotelGetAccesstoken() : GetAccessToken(); } else { tokenResult = accessTokenMode == "1" ? AizhuhotelGetAccesstoken() : GetAccessToken(true); } if (tokenResult.IsSuccess && !string.IsNullOrEmpty(tokenResult.Info)) { access_token = tokenResult.Info; break; } Thread.Sleep(500); } if (string.IsNullOrWhiteSpace(access_token)) return ApiResult.Failed("未获取有效的AccessToken"); // 推送消息 var postUrl = $"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={access_token}"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl); request.Proxy = null; request.Method = "POST"; request.ContentType = "application/json"; using (StreamWriter dataStream = new StreamWriter(request.GetRequestStream())) { dataStream.Write(msg); dataStream.Close(); } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string encoding = response.ContentEncoding; if (encoding == null || encoding.Length < 1) { encoding = "UTF-8"; //默认编码 } StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); string retString = reader.ReadToEnd(); _logger.Info("-->" + msg + " response-->" + retString); if (!string.IsNullOrWhiteSpace(retString)) { var sendTemplateMsgRes = JsonConvert.DeserializeObject(retString); if (sendTemplateMsgRes.Errmsg.ToLower() == "ok") { return ApiResult.Success(string.Empty); } } return ApiResult.Failed(msg: "", info: retString); } catch (Exception ex) { _logger.Debug(ex.ToString()); return ApiResult.Failed(msg: "", info: ex.Message); } } } }