1.搭建回撥伺服器
可參考:https://www.cnblogs.com/zspwf/p/16381643.html進行搭建
2.編寫程式碼
2.1介面定義
應用可以傳送模板卡片訊息,傳送之後可再通過介面更新可回撥的使用者任務卡片訊息的替換文案資訊(僅原卡片為 按鈕互動型、投票選擇型、多項選擇型的卡片以及填寫了action_menu欄位的文字通知型、圖文展示型可以呼叫本介面更新)。
請注意,當應用呼叫傳送模版卡片訊息後,介面會返回一個response_code,通過response_code使用者可以呼叫本介面一次。後續如果有使用者點選任務卡片,回撥介面也會帶上response_code,開發者通過該code也可以呼叫本介面一次,注意response_code的有效期是24小時,超過24小時後將無法使用。
請求方式:POST(HTTPS)
請求地址: https://qyapi.weixin.qq.com/cgi-bin/message/update_template_card?access_token=ACCESS_TOKEN
引數說明:
2.2 appsettings配置
根據實際情況填寫、
corpid 企業ID
corpsecret 應用金鑰,
CallBackToken 企業微信後臺,開發者設定的Token,
EncodingAESKey企業微信後臺,開發者設定的EncodingAESKey。
"Wx": { "Baseurl": "https://qyapi.weixin.qq.com/cgi-bin/", "PushUrl": "message/send?access_token={0}", "PushCardUrl": "message/update_template_card?access_token={0}", "PushTokenUrl": "gettoken?corpid=&corpsecret=", "CallBackToken": "", "EncodingAESKey": "", "corpid": "" }
2.3 Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddHttpClient("WxClient", config => { config.BaseAddress = new Uri(Configuration["Wx:baseurl"]); config.DefaultRequestHeaders.Add("Accept", "application/json"); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { GlobalContext.httpClientFactory = app.ApplicationServices.GetService<IHttpClientFactory>(); }
2.4 GlobalContext.cs
提供了Token,推送等方法。
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net.Http; using System.Text; namespace Wx { public class GlobalContext { public static IHttpClientFactory httpClientFactory { get; set; } /// <summary> /// Wx 過期時間 /// </summary> public static DateTime TimeOutDate { get; set; } /// <summary> /// Wx Token /// </summary> public static string Token { get; set; } /// <summary> /// 獲取Token /// </summary> /// <returns>Item1 Token;Item2 是否成功</returns> public static Tuple<string, bool> GetPushToken() { //判斷Token是否存在 以及Token是否在有效期內 if (string.IsNullOrEmpty(Token) || TimeOutDate > DateTime.Now) { //構造請求連結 var requestBuild = AppSetting.Configuration["Wx:PushTokenUrl"]; using (var wxClient = httpClientFactory.CreateClient("WxClient")) { var httpResponse = wxClient.GetAsync(requestBuild).Result; var dynamic = JsonConvert.DeserializeObject<GetTokenResult>( httpResponse.Content.ReadAsStringAsync().Result ); if (dynamic.errcode == 0) { Token = dynamic.access_token; //過期5分鐘前重新整理Token var expires_in = Convert.ToDouble(dynamic.expires_in - 5 * 60); TimeOutDate = DateTime.Now.AddSeconds(expires_in); return Tuple.Create(Token, true); } else { return Tuple.Create($"獲取Token失敗,錯誤:{ dynamic.errmsg}", false); } } } else { return Tuple.Create(Token, true); } } /// <summary> /// 推送MES /// </summary> /// <returns>Item1 Token;Item2 是否成功</returns> public static string WxPush(string content) { //構造請求連結 var requestBuild = AppSetting.Configuration["Wx:PushUrl"]; var (token, issuccess) = GetPushToken(); if (!issuccess) throw new Exception(token); requestBuild = string.Format(requestBuild, token); //建立HttpClient using (var wxClient = httpClientFactory.CreateClient("WxClient")) { byte[] data = Encoding.UTF8.GetBytes(content); var bytearray = new ByteArrayContent(data); var httpResponse = wxClient.PostAsync(requestBuild, bytearray).Result; var dynamic = JsonConvert.DeserializeObject<dynamic>( httpResponse.Content.ReadAsStringAsync().Result ); bytearray.Dispose(); if (dynamic.errcode == 0) return "推送成功!"; if (dynamic.errcode == 82001) throw new Exception("推送失敗,原因:未配置員工手機號或者員工手機號不在應用可見範圍!"); else throw new Exception($"推送失敗,原因:{JsonConvert.SerializeObject(dynamic) }"); } } /// <summary> /// 獲取傳送內容 /// </summary> /// <param name="userId"></param> /// <param name="Msg"></param> /// <returns></returns> public static string GetTextContent(string userId, string msg, int agentid) { var objText = new { content = msg }; string text = JsonConvert.SerializeObject(objText); var obj = new { touser = userId, toparty = "", totag = "", msgtype = "text", agentid = agentid, text = objText, safe = 0, enable_id_trans = 0, enable_duplicate_check = 0, duplicate_check_interval = 1800 }; string strJson = JsonConvert.SerializeObject(obj); return strJson; } /// <summary> /// 更新微信推送訊息內容 /// </summary> /// <param name="userId"></param> /// <param name="responsecode"></param> /// <param name="replacename"></param> /// <param name="agentid"></param> /// <returns></returns> public static string UpdateTextCardContent(string[] userId, string responsecode, string replacename, int agentid) { var obj = new { userids = userId, atall = 0, agentid = agentid, response_code = responsecode, button = new { replace_name = replacename } }; string strJson = JsonConvert.SerializeObject(obj); return strJson; } /// <summary> /// 更新卡片訊息 /// </summary> /// <returns>Item1 Token;Item2 是否成功</returns> public static string UpdateCard(string content) { //構造請求連結 var requestBuild = AppSetting.Configuration["Wx:PushCardUrl"]; var (token, issuccess) = GetPushToken(); if (!issuccess) throw new Exception(token); requestBuild = string.Format(requestBuild, token); //建立HttpClient using (var wxClient = httpClientFactory.CreateClient("WxClient")) { byte[] data = Encoding.UTF8.GetBytes(content); var bytearray = new ByteArrayContent(data); var httpResponse = wxClient.PostAsync(requestBuild, bytearray).Result; var dynamic = JsonConvert.DeserializeObject<dynamic>( httpResponse.Content.ReadAsStringAsync().Result ); bytearray.Dispose(); if (dynamic.errcode == 0) return "推送成功!"; if (dynamic.errcode == 82001) throw new Exception("推送失敗,原因:未配置員工手機號或者員工手機號不在應用可見範圍!"); else throw new Exception($"推送失敗,原因:{JsonConvert.SerializeObject(dynamic) }"); } } } }
2.5 回撥中編寫內容
下圖中是按鈕互動性的按鈕,點選確認會觸發回撥伺服器的方法,在回撥服務中根據返回的FromUserName和ResponseCode呼叫更新模板方法,把按鈕改為已推送。
下面程式碼為回撥服務中的Post方法,在1中搭建回撥伺服器中的方法。業務邏輯,失主請求獲取聯絡方式,拾取人點選確認,推送聯絡方式至失主企業微信。將確認更新成已傳送。可根據自己的實際業務替換內容,其中UpdateCard方法為更新模板已推送方法。
[HttpPost, Route("callback/interAspect")] public ContentResult AcceptMessage(string msg_signature,string timestamp,string nonce) { //獲取被動響應包 string encrypt = ""; using (StreamReader sr = new StreamReader(Request.Body, Encoding.UTF8)) { encrypt = sr.ReadToEndAsync().Result; } //驗證 WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(AppSetting.Configuration["Wx:CallBackToken"] , AppSetting.Configuration["Wx:EncodingAESKey"] , AppSetting.Configuration["Wx:corpid"]); string sMsg = ""; // 解析之後的明文 int ret = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, encrypt, ref sMsg); if (ret != 0) { throw new Exception(); } // ret==0表示解密成功,sMsg表示解密之後的明文xml串 XmlDocument doc = new XmlDocument(); doc.LoadXml(sMsg); XmlNode root = doc.FirstChild; string userName = root["FromUserName"].InnerText; string eventKey = root["EventKey"].InnerText; string responseCode = root["ResponseCode"].InnerText; //業務邏輯 eventKey是我儲存的請求人推送UserID。 var content = GlobalContext.GetTextContent(eventKey, $"我的聯絡方式:" + userName, 1); var message = GlobalContext.WxPush(content); if (message == "推送成功!") { try { var responseContent = GlobalContext.UpdateTextCardContent(new string[] { userName }, responseCode, "已推送", 1); var updateMessage = GlobalContext.UpdateCard(responseContent); if (updateMessage == "推送成功!") { return Content("成功"); } else {throw new Exception(); } } catch(Exception ex) {throw new Exception(); } } else { throw new Exception(); } }
3.測試
4.連結
更新模板卡片:https://developer.work.weixin.qq.com/document/path/94888