一、appsettings.json定义小程序配置信息

  1. "WX": {
  2.   "AppId": "wx88822730803edd44",
  3.   "AppSecret": "75b269042e8b5026e6ed14aa24ba9353",
  4.   "Templates": {
  5.   "Audit": {
  6.     "TemplateId": "aBaIjTsPBluYtj2tzotzpowsDDBGLhXQkwrScupnQsM",
  7.     "PageUrl": "/pages/index/formAudit?formId={0}&tableId={1}",
  8.     "MiniprogramState": "developer",
  9.     "Lang": "zh_TW",
  10.     "Data": {
  11.         "Title": "thing6",
  12.         "Content": "thing19",
  13.         "Date": "date9"
  14.       }
  15.     }
  16.   },
  17.   "SignatureToken": "aaaaaa",
  18.   "MessageSendUrl": "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}",
  19.   "AccessTokenUrl": "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"
  20. }

二、编写通用类加载配置

  1. using System;
  2. using System.Text;
  3. using System.Security.Cryptography;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.Extensions.Configuration.Json;
  6.  
  7. namespace WXERP.Services
  8. {
  9. /// <summary>
  10. /// 项目公有静态类
  11. /// </summary>
  12. public class Common
  13. {
  14. /// <summary>
  15. /// 獲取根目錄
  16. /// </summary>
  17. public static string AppRoot => Environment.CurrentDirectory;// AppContext.BaseDirectory;
  18. /// <summary>
  19. /// 獲取項目配置
  20. /// </summary>
  21. public static IConfiguration Configuration { get; set; }
  22. /// <summary>
  23. /// 加載項目配置
  24. /// </summary>
  25. static Common()
  26. {
  27.   Configuration = new ConfigurationBuilder()
  28.   .Add(new JsonConfigurationSource
  29.   {
  30.     Path = "appsettings.json",
  31.     ReloadOnChange = true //当appsettings.json被修改时重新加载
  32.   })
  33.   .Build();
  34. }
  35.  
  36. /// <summary>
  37. /// SHA1加密
  38. /// </summary>
  39. /// <param name="content">需要加密的字符串</param>
  40. /// <returns>返回40位大寫字符串</returns>
  41. public static string SHA1(string content)
  42. {
  43.   try
  44.   {
  45.     SHA1 sha1 = new SHA1CryptoServiceProvider();
  46.     byte[] bytes_in = Encoding.UTF8.GetBytes(content);
  47.     byte[] bytes_out = sha1.ComputeHash(bytes_in);
  48.     sha1.Dispose();
  49.     string result = BitConverter.ToString(bytes_out);
  50.     result = result.Replace("-", "");
  51.     return result;
  52.   }
  53.   catch (Exception ex)
  54.   {
  55.     throw new Exception("Error in SHA1: " + ex.Message);
  56.   }
  57. }
  58.  
  59. }
  60. }

三、编写HttpHelper请求类

  1. using System;
  2. using System.Text;
  3. using System.Net.Http;
  4. using System.Net.Http.Headers;
  5. using System.Threading.Tasks;
  6. using System.Collections.Generic;
  7.  
  8. namespace WXERP.Services
  9. {
  10. /// <summary>
  11. /// HTTP請求輔助類
  12. /// </summary>
  13. public class HttpHelper
  14. {
  15. /// <summary>
  16. /// post同步請求
  17. /// </summary>
  18. /// <param name="url">地址</param>
  19. /// <param name="postData">數據</param>
  20. /// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
  21. /// <param name="headers">請求頭</param>
  22. /// <returns></returns>
  23. public static string HttpPost(string url, string postData = null, string contentType = null, Dictionary<string, string> headers = null)
  24. {
  25.   using HttpClient client = new HttpClient();
  26.  
  27.   if (headers != null)
  28.   {
  29.     foreach (var header in headers)
  30.     client.DefaultRequestHeaders.Add(header.Key, header.Value);
  31.   }
  32.  
  33.   postData ??= "";
  34.   using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
  35.   if (contentType != null)
  36.   httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
  37.  
  38.   HttpResponseMessage response = client.PostAsync(url, httpContent).Result;
  39.   return response.Content.ReadAsStringAsync().Result;
  40. }
  41.  
  42. /// <summary>
  43. /// post異步請求
  44. /// </summary>
  45. /// <param name="url">地址</param>
  46. /// <param name="postData">數據</param>
  47. /// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
  48. /// <param name="timeOut">請求超時時間</param>
  49. /// <param name="headers">請求頭</param>
  50. /// <returns></returns>
  51. public static async Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null)
  52. {
  53.   using HttpClient client = new HttpClient();
  54.   client.Timeout = new TimeSpan(0, 0, timeOut);
  55.  
  56.   if (headers != null)
  57.   {
  58.     foreach (var header in headers)
  59.     client.DefaultRequestHeaders.Add(header.Key, header.Value);
  60.   }
  61.  
  62.   postData ??= "";
  63.   using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
  64.   if (contentType != null)
  65.   httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
  66.  
  67.   HttpResponseMessage response = await client.PostAsync(url, httpContent);
  68.   return await response.Content.ReadAsStringAsync();
  69. }
  70.  
  71. /// <summary>
  72. /// get同步請求
  73. /// </summary>
  74. /// <param name="url">地址</param>
  75. /// <param name="headers">請求頭</param>
  76. /// <returns></returns>
  77. public static string HttpGet(string url, Dictionary<string, string> headers = null)
  78. {
  79.   using HttpClient client = new HttpClient();
  80.  
  81.   if (headers != null)
  82.   {
  83.   foreach (var header in headers)
  84.   client.DefaultRequestHeaders.Add(header.Key, header.Value);
  85.   }
  86.  
  87.   HttpResponseMessage response = client.GetAsync(url).Result;
  88.   return response.Content.ReadAsStringAsync().Result;
  89. }
  90.  
  91. /// <summary>
  92. /// get異步請求
  93. /// </summary>
  94. /// <param name="url"></param>
  95. /// <param name="headers"></param>
  96. /// <returns></returns>
  97. public static async Task<string> HttpGetAsync(string url, Dictionary<string, string> headers = null)
  98. {
  99.   using HttpClient client = new HttpClient();
  100.  
  101.   if (headers != null)
  102.   {
  103.     foreach (var header in headers)
  104.     client.DefaultRequestHeaders.Add(header.Key, header.Value);
  105.   }
  106.  
  107.   HttpResponseMessage response = await client.GetAsync(url);
  108.   return await response.Content.ReadAsStringAsync();
  109. }
  110.  
  111. }
  112. }

四、在sqlserver下存储并获取openid,这个主要是因为提交消息并不是在微信小程序端,如果是在微信小程序上发起订阅消息,可以忽略这个步骤

  1. // 创建数据库表
  2.  
  3. create table TBSF_Conmmunicate_WXUser
  4. (
  5.   ID int identity(1,1) primary key,
  6.   Staff_ID varchar(10),
  7.   OpenId varchar(50),
  8.   SessionKey varchar(50),
  9.   UnionId varchar(50),
  10.   IsValid bit,
  11. )
  12.  
  13. // SqlHelper数据库辅助类来自于CommunicationOperateDBUtility,可以自己编写
  14.  
  15. using System.Data;
  16. using System.Text;
  17. using CommunicationOperateDBUtility;
  18.  
  19. namespace WXERP.Services.CommunicationOperateDAL
  20. {
  21. /// <summary>
  22. /// 微信信息
  23. /// </summary>
  24. public class WXInforDeal
  25. {
  26.   private SqlHelper sqlHelper = null;
  27.   /// <summary>
  28.   /// 初始化數據庫輔助對象
  29.   /// </summary>
  30.   /// <param name="con"></param>
  31.   public WXInforDeal(object con)
  32.   {
  33.     sqlHelper = new SqlHelper(con);
  34.   }
  35.   /// <summary>
  36.   /// 獲取微信登陸用戶信息
  37.   /// </summary>
  38.   /// <param name="staffIdList">工號</param>
  39.   /// <returns></returns>
  40.   public DataSet GetLoginUserInfo(string staffIdList)
  41.   {
  42.     DataSet ds = new DataSet();
  43.     StringBuilder stringBuilder = new StringBuilder();
  44.     stringBuilder.Append(" SELECT distinct OpenId FROM ");
  45.     stringBuilder.Append(" TBSF_Conmmunicate_WXUser WHERE Staff_ID IN (");
  46.     stringBuilder.Append(staffIdList);
  47.     stringBuilder.Append(")");
  48.     string strSql = stringBuilder.ToString();
  49.     sqlHelper.DBRunSql(strSql, ref ds);
  50.     return ds;
  51.   }
  52. }
  53. }

五、编写订阅消息基类模型

  1. using System;
  2. using System.Data;
  3. using Newtonsoft.Json;
  4. using System.Collections.Generic;
  5. using WXERP.Services.CommunicationOperateDAL;
  6.  
  7. namespace WXERP.Models
  8. {
  9. /// <summary>
  10. /// 訂閲消息請求模型
  11. /// </summary>
  12. public class SubscribeMessageModel
  13. {
  14.   /// <summary>
  15.   /// 初始化審核訂閲消息
  16.   /// </summary>
  17.   /// <param name="dbTransOrCnn">數據庫事務</param>
  18.   /// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
  19.   public SubscribeMessageModel(object dbTransOrCnn, string nextAuditStaffId)
  20.   {
  21.     WXInforDeal wxInfoDeal = new WXInforDeal(dbTransOrCnn);
  22.     DataSet wxUserInfo = wxInfoDeal.GetLoginUserInfo(nextAuditStaffId);
  23.     if (wxUserInfo != null && wxUserInfo.Tables.Count > 0 && wxUserInfo.Tables[0].Rows.Count > 0)
  24.     {
  25.       Touser = wxUserInfo.Tables[0].Rows[0]["OpenId"].ToString();
  26.     }
  27.   }
  28.   /// <summary>
  29.   /// 消息接收者的openid
  30.   /// </summary>
  31.   [JsonProperty("touser")]
  32.   public string Touser { get; set; }
  33.   /// <summary>
  34.   /// 消息模板ID
  35.   /// </summary>
  36.   [JsonProperty("template_id")]
  37.   public string TemplateId { get; set; }
  38.   /// <summary>
  39.   /// 點擊模板卡片后的跳轉頁面,僅限本小程序内的頁面,支持帶參數(示例index?foo=bar),該字段不填則不跳轉
  40.   /// </summary>
  41.   [JsonProperty("page")]
  42.   public string Page { get; set; }
  43.   /// <summary>
  44.   /// 跳轉小程序類型:developer開發版、trial體驗版、formal正式版,默认为正式版
  45.   /// </summary>
  46.   [JsonProperty("miniprogram_state")]
  47.   public string MiniprogramState { get; set; }
  48.   /// <summary>
  49.   /// 進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN
  50.   /// </summary>
  51.   [JsonProperty("lang")]
  52.   public string Lang { get; set; }
  53.   /// <summary>
  54.   /// 模板内容
  55.   /// </summary>
  56.   [JsonProperty("data")]
  57.   public Dictionary<string, DataValue> Data { get; set; }
  58. }
  59. /// <summary>
  60. /// 模板内容關鍵字
  61. /// </summary>
  62. public class DataValue
  63. {
  64.   /// <summary>
  65.   /// 訂閲消息參數值
  66.   /// </summary>
  67.   [JsonProperty("value")]
  68.   public string Value { get; set; }
  69. }
  70.  
  71. /// <summary>
  72. /// 小程序訂閲消息響應模型
  73. /// </summary>
  74. public class SubscribeMsgResponseModel
  75. {
  76.   /// <summary>
  77.   /// 錯誤代碼
  78.   /// </summary>
  79.   public int Errcode { get; set; }
  80.   /// <summary>
  81.   /// 錯誤信息
  82.   /// </summary>
  83.   public string Errmsg { get; set; }
  84. }
  85.  
  86. /// <summary>
  87. /// 小程序獲取token響應模型
  88. /// </summary>
  89. public class AccessTokenResponseModel
  90. {
  91.   /// <summary>
  92.   /// 小程序訪問token
  93.   /// </summary>
  94.   public string Access_token { get; set; }
  95.   /// <summary>
  96.   /// Token過期時間,單位秒
  97.   /// </summary>
  98.   public int Expires_id { get; set; }
  99.   /// <summary>
  100.   /// Token創建時間
  101.   /// </summary>
  102.   public DateTime Create_time { get; set; }
  103.   /// <summary>
  104.   /// 刷新以後的Token
  105.   /// </summary>
  106.   public string Refresh_token { get; set; }
  107.   /// <summary>
  108.   /// 小程序用戶唯一標識,如果用戶未關注公衆號,訪問公衆號網頁也會產生
  109.   /// </summary>
  110.   public string Openid { get; set; }
  111.   /// <summary>
  112.   /// 用戶授權的作用域,使用逗號分隔
  113.   /// </summary>
  114.   public string Scope { get; set; }
  115. }
  116.  
  117. }

六、实现消息订阅基类,下面的SetTemplateData方法根据自己的情况设置需要推送消息的内容,如果以后有其他订阅消息模板,新增一个类实现SubscribeMessageModel

  1. using System;
  2. using System.Collections.Generic;
  3. using Newtonsoft.Json;
  4. using BestSoft.Common.Resources;
  5. using BSFWorkFlow.Common.GeneralUtility;
  6. using WXERP.Models;
  7.  
  8. namespace WXERP.Services.SubscribeMessage
  9. {
  10. /// <summary>
  11. /// 審核訂閲消息
  12. /// </summary>
  13. public class AuditSubscribeMessage : SubscribeMessageModel
  14. {
  15.   private string page;
  16.   private string lang;
  17.   private Dictionary<string, DataValue> data;
  18.   /// <summary>
  19.   /// 設置小程序OpenId
  20.   /// </summary>
  21.   /// <param name="dbTransOrCnn">數據庫事務</param>
  22.   /// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
  23.   public AuditSubscribeMessage(object dbTransOrCnn, string nextAuditStaffId)
  24.   : base(dbTransOrCnn, nextAuditStaffId)
  25.   {
  26.  
  27.   }
  28.   /// <summary>
  29.   /// 消息模板ID
  30.   /// </summary>
  31.   [JsonProperty("template_id")]
  32.   public new string TemplateId => Common.Configuration["WX:Templates:Audit:TemplateId"];
  33.  
  34.   /// <summary>
  35.   /// 設置小程序訂閲消息跳轉頁面
  36.   /// </summary>
  37.   /// <param name="formId"></param>
  38.   /// <param name="tableId"></param>
  39.   public void SetPageUrl(string formId, string tableId)
  40.   {
  41.     Page = string.Format(Common.Configuration["WX:Templates:Audit:PageUrl"],
  42.     formId, tableId);
  43.   }
  44.   /// <summary>
  45.   /// 點擊模板卡片后的跳轉頁面
  46.   /// </summary>
  47.   [JsonProperty("page")]
  48.   public new string Page
  49.   {
  50.     get
  51.     {
  52.     return page;
  53.     }
  54.     set
  55.     {
  56.       page = value;
  57.       return;
  58.     }
  59.   }
  60.   /// <summary>
  61.   /// 跳轉小程序類型
  62.   /// </summary>
  63.   [JsonProperty("miniprogram_state")]
  64.   public new string MiniprogramState => Common.Configuration["WX:Templates:Audit:MiniprogramState"];
  65.   /// <summary>
  66.   /// 進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN
  67.   /// </summary>
  68.   [JsonProperty("lang")]
  69.   public new string Lang
  70.   {
  71.     get
  72.     {
  73.       lang = Common.Configuration["WX:Templates:Audit:Lang"];
  74.       if (!string.IsNullOrEmpty(MyHttpContext.Current.Request.Headers["bsLanKind"]))
  75.       lang = MyHttpContext.Current.Request.Headers["bsLanKind"];
  76.  
  77.       return lang;
  78.     }
  79.     set
  80.     {
  81.       lang = value;
  82.       return;
  83.     }
  84.   }
  85.   /// <summary>
  86.   /// 設置審核訂閲消息數據
  87.   /// </summary>
  88.   /// <param name="operation">審核動作:通過、否決、作廢、退回</param>
  89.   /// <param name="itemAuditStatus">審核狀態:1代表審核完畢</param>
  90.   /// <param name="currentWorkflowName">審核標題</param>
  91.   public void SetTemplateData(WFAuditOperation operation, WFAuditItemStatus itemAuditStatus, string currentWorkflowName)
  92.   {
  93.     string tip_msg = "";
  94.     switch (operation)
  95.     {
  96.       case WFAuditOperation.AuditPassAndAgree:
  97.         if (itemAuditStatus == WFAuditItemStatus.SuccessfulToFinishAllAudits)
  98.           tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_FinishAuditTip"), "您的單據已審核完成!");
  99.         else
  100.           tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAgreeTip"), "您有一筆新單據待審核!");
  101.       break;
  102.       case WFAuditOperation.AuditPassButDegree:
  103.         tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditDegreeTip"), "您提交的單據等待異議!");
  104.       break;
  105.       case WFAuditOperation.AuditAbort:
  106.         tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAbortTip"), "您提交的單據已被作廢!");
  107.       break;
  108.       case WFAuditOperation.AuditBack:
  109.         tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditBackTip"), "您提交的單據已被退回修正!");
  110.       break;
  111.     }
  112.  
  113.     string title = Common.Configuration["WX:Templates:Audit:Data:Title"];
  114.     string content = Common.Configuration["WX:Templates:Audit:Data:Content"];
  115.     string date = Common.Configuration["WX:Templates:Audit:Data:Date"];
  116.     Dictionary<string, DataValue> data = new Dictionary<string, DataValue>()
  117.     {
  118.       {title, new DataValue{ Value= currentWorkflowName }},
  119.       {content, new DataValue{ Value= tip_msg }},
  120.       {date, new DataValue{ Value= DateTime.Now.ToShortDateString() }}
  121.     };
  122.  
  123.     Data = data;
  124.   }
  125.   /// <summary>
  126.   /// 審核訂閲消息數據
  127.   /// </summary>
  128.   [JsonProperty("data")]
  129.   public new Dictionary<string, DataValue> Data
  130.   {
  131.     get
  132.     {
  133.       return data;
  134.     }
  135.     set
  136.     {
  137.       data = value;
  138.       return;
  139.     }
  140.   }
  141.  
  142. }
  143. }

七、编写发送订阅消息,消息推送配置签名认证

  1. using System;
  2. using System.Threading.Tasks;
  3. using System.Collections.Generic;
  4. using Newtonsoft.Json;
  5. using WXERP.Models;
  6.  
  7. namespace WXERP.Services
  8. {
  9. /// <summary>
  10. /// 系統消息上下文
  11. /// </summary>
  12. public class MessageContext
  13. {
  14.   /// <summary>
  15.   /// 獲取AccessToken的全局鎖
  16.   /// </summary>
  17.   private readonly static object SyncLock = new object();
  18.  
  19.   private static Dictionary<string, AccessTokenResponseModel> tokenCache = new Dictionary<string, AccessTokenResponseModel>();
  20.  
  21.   /// <summary>
  22.   /// 發送訂閲消息
  23.   /// </summary>
  24.   /// <param name="msg">消息内容</param>
  25.   /// <param name="errMsg">可能由於獲取的token錯誤</param>
  26.   /// <returns></returns>
  27.   public static bool SendSubscribeMsg(SubscribeMessageModel msg, out string errMsg)
  28.   {
  29.     errMsg = "";
  30.     try
  31.     {
  32.       string token = GetAccessToken();
  33.       if (token.Length < 20)
  34.       {
  35.         errMsg = "Failed to send subscription message, Access token error!";
  36.         return false;
  37.       }
  38.       string url = string.Format(Common.Configuration["WX:MessageSendUrl"], token);
  39.       string requestJson = JsonConvert.SerializeObject(msg);
  40.       string responseJson = HttpHelper.HttpPost(url, requestJson, "application/json", null);
  41.  
  42.       var msgResponse = JsonConvert.DeserializeObject<SubscribeMsgResponseModel>(responseJson);
  43.       if (msgResponse.Errcode != 0)
  44.       {
  45.         errMsg = string.Format("Failed to send subscription message, {0}", msgResponse.Errmsg);
  46.         return false;
  47.       }
  48.     }
  49.     catch (Exception exp)
  50.     {
  51.       throw new Exception("SendSubscribeMsg: " + exp.Message);
  52.     }
  53.     return true;
  54.   }
  55.  
  56.   /// <summary>
  57.   /// 獲取小程序訪問token
  58.   /// </summary>
  59.   /// <returns></returns>
  60.   private static string GetAccessToken()
  61.   {
  62.     lock (SyncLock)
  63.     {
  64.       string appid = Common.Configuration["WX:AppId"];
  65.       string appsecret = Common.Configuration["WX:AppSecret"];
  66.       string accessTokenUrl = string.Format(Common.Configuration["WX:AccessTokenUrl"], appid, appsecret);
  67.  
  68.       AccessTokenResponseModel result = null;
  69.       if (tokenCache.ContainsKey(appid))
  70.       result = tokenCache[appid];
  71.  
  72.       if (result == null)
  73.       {
  74.         string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
  75.         result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
  76.         result.Create_time = DateTime.Now;
  77.         tokenCache.Add(appid, result);
  78.       }
  79.       else if (DateTime.Compare(result.Create_time.AddSeconds(result.Expires_id), DateTime.Now) < 1)
  80.       {
  81.         string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
  82.         result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
  83.         result.Create_time = DateTime.Now;
  84.         tokenCache[appid] = result;
  85.       }
  86.       return result.Access_token;
  87.     }
  88.   }
  89.  
  90.   /// <summary>
  91.   /// 驗證消息來自於微信服務器
  92.   /// </summary>
  93.   /// <param name="signature">微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param>
  94.   /// <param name="timestamp">時間戳</param>
  95.   /// <param name="nonce">隨機數</param>
  96.   /// <returns></returns>
  97.   public async Task<bool> CheckSignature(string signature, string timestamp, string nonce)
  98.   {
  99.     string token = Common.Configuration["WX:SignatureToken"];
  100.     string[] tmpArr = { token, timestamp, nonce };
  101.     Array.Sort(tmpArr);
  102.     string tmpStr = string.Join("", tmpArr);
  103.     tmpStr = Common.SHA1(tmpStr);
  104.  
  105.     if (!tmpStr.Equals(signature, StringComparison.OrdinalIgnoreCase))
  106.       return false;
  107.  
  108.     await Task.CompletedTask;
  109.     return true;
  110.   }
  111.  
  112. }
  113. }

八、编写消息推送配置签名认证控制器

  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using WXERP.Services;
  5.  
  6. namespace WXERP.Controllers
  7. {
  8.   /// <summary>
  9.   /// 消息控制器
  10.   /// </summary>
  11.   [Route("api/[controller]")]
  12.   [ApiController]
  13.   public class MessageController : ControllerBase
  14.   {
  15.     private readonly MessageContext _context;
  16.     /// <summary>
  17.     /// 初始化消息
  18.     /// </summary>
  19.     public MessageController()
  20.     {
  21.       _context = new MessageContext();
  22.     }
  23.  
  24.   /// <summary>微信消息</summary>
  25.   /// <remarks>驗證消息來自於微信服務器</remarks>
  26.   /// <param name="signature">微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param>
  27.   /// <param name="timestamp">時間戳</param>
  28.   /// <param name="nonce">隨機數</param>
  29.   /// <param name="echostr">隨機字符串</param>
  30.   /// <returns></returns>
  31.   [HttpGet("checkSignature")]
  32.   [AllowAnonymous]
  33.   public async void CheckSignature(string signature,string timestamp,string nonce,string echostr)
  34.   {
  35.     bool result = await _context.CheckSignature(signature, timestamp, nonce);
  36.     if (result)
  37.     {
  38.       HttpContext.Response.ContentType = "text/plain; charset=utf-8";
  39.       await HttpContext.Response.WriteAsync(echostr);
  40.     }
  41.     else
  42.     {
  43.       HttpContext.Response.StatusCode = 409;
  44.       HttpContext.Response.ContentType = "text/plain; charset=utf-8";
  45.       await HttpContext.Response.WriteAsync("error");
  46.   }
  47. }
  48.  
  49. }
  50. }

九、调用小程序订阅消息,需要自己实现其他逻辑

  1. //@iFormSaveDAL.GetTran 数据库链接事务,如果发送消息失败,应该回滚提交的表单数据
  2. //@wFControl.NextAuditNotifyStaffIDStr 下一个审核用户的工号
  3. //@auditPageData.FormID 表单编号
  4. //@auditPageData.MainRecordID 表单数据ID
  5. //@operationByCode 一个枚举类型,前端传递的:审核通过、作废、退回等
  6. //@wFControl.ItemAuditStatus 一个枚举类型,如果全部审核完毕为1,否则为0
  7. //@wFControl.CurrentWorkflowName 当前流程的名称,例如:请假单审核
  8. //@SaveAfterInfo 全局字符变量,用于保存结果信息
  9.  
  10. AuditSubscribeMessage auditMsg = new AuditSubscribeMessage(iFormSaveDAL.GetTran, wFControl.NextAuditNotifyStaffIDStr);
  11. auditMsg.SetPageUrl(auditPageData.FormID, auditPageData.MainRecordID);
  12. auditMsg.SetTemplateData(operationByCode, wFControl.ItemAuditStatus, wFControl.CurrentWorkflowName);
  13. if (!string.IsNullOrEmpty(auditMsg.Touser))
  14. {
  15.   if (!MessageContext.SendSubscribeMsg(auditMsg, out messageStr))
  16.   {
  17.     SaveAfterInfo = messageStr;
  18.     return false;
  19.   }
  20. }

有不懂或需要改正的欢迎留言!

.netcore 3.1 C# 微信小程序发送订阅消息的更多相关文章

  1. 微信小程序发送订阅消息(之前是模板消息)

    之前的模板消息已经废弃,现在改为订阅消息,订阅消息发布前,需要用户确认后才能接收订阅消息. 小程序端 index.wxml <button bindtap="send"> ...

  2. 微信小程序发送模板消息

    微信小程序发送模板消息 标签(空格分隔): php 看小程序文档 [模板消息文档总览]:https://developers.weixin.qq.com/miniprogram/dev/framewo ...

  3. 微信小程序 发送模版消息

    微信小程序开发之发送模板消息 1,小程序wxml页面form表单添加 report-submit="true" <form bindsubmit="sub" ...

  4. 微信小程序 发送模板消息的功能实现

    背景 - 小程序开发的过程中,绝大多数会满足微信支付 - 那么,作为友好交互的体现,自然就会考虑到支付后的消息通知咯 - 所以,我的小程序项目也要求完成这个效果,so.分享一下自己的实现步骤,以方便道 ...

  5. 微信小程序-发送模板消息

    1 添加一个小程序的消息模板,获取到模板id,存储到数据库中,方便以后修改调用 2. https://developers.weixin.qq.com/miniprogram/dev/api-back ...

  6. 微信小程序-发送模板消息(C#)

    步骤一:获取模板ID 有两个方法可以获取模版ID 通过模版消息管理接口获取模版ID 在微信公众平台手动配置获取模版ID 步骤二:页面的 <form/> 组件,属性report-submit ...

  7. Q:微信小程序一次性订阅消息(前台收集)

    说明:官方文档(https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.ht ...

  8. 微信小程序发送短信验证码完整实例

    微信小程序注册完整实例,发送短信验证码,带60秒倒计时功能,无需服务器端.效果图: 代码: index.wxml <!--index.wxml--> <view class=&quo ...

  9. 微信小程序发送ajax

    微信小程序通过 wx.request发送ajax请求 1. GET wx.request({ url: app.globalData.pubSiteUrl + 'user-information/ge ...

随机推荐

  1. Sqlalchemy 事件监听与初始化

    sqlalchemy不仅仅能自动创建数据库,更提供了其他更强大的功能,今天要介绍的就是sqlalchemy中的事件监听,并将其应用到数据库的初始化中. 需求:当插入设置password字段时,自动加密 ...

  2. Python2.7.8 setuptools 下载及安装方法

    Python2.7.8  setuptools 下载及安装方法 电脑配置:联想笔记本电脑 windows8系统 Python版本:2.7.8 本文章撰写时间:2014.12.11 作者:陈东陈 阅读说 ...

  3. 微信商户H5支付申请不通过被驳回解法,拒绝提示:网站有不实内容或不安全信息

    H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付.主要用于触屏版的手机浏览器请求微信支付的场景.可以方便从外部浏览器唤起 ...

  4. 洛谷 P4343 [SHOI2015]自动刷题机

    思路 二分答案 显然的二分答案,但是因为二分判定条件 \(\text{wa}\) 了好几遍-- 可以发现,\(n\) 越大,\(k\) 就越小,所以答案是有单调性的,因此可以用两个二分,一次求最大值, ...

  5. 理解Word2Vec

    一.简介 Word2vec 是 Word Embedding 的方法之一,属于NLP 领域.它是将词转化为「可计算」「结构化」的向量的过程.它是 2013 年由谷歌的 Mikolov 提出了一套新的词 ...

  6. 【HttpRunner v3.x】笔记—8.用例引用、变量传递

    看到这里,对于httprunner已经有了一个大概的了解,现在想对于一些比较重要或者常用的功能,进行一些实践操作. 毕竟那谁说过,"纸上得来终觉浅,绝知此事要躬行." 上一篇提到了 ...

  7. MySQL 数据库 查 续

    MySQL 增删查改 必知必会 4.1.13 使用 like 关键字进行模糊查询 -- 说明:模糊查询,使用查询关键字like,like意思是类似于,像...的意思 -- 模糊查询,支持两种字符匹配符 ...

  8. centos7 RPM MySQL5.5

    一.安装MYSQL 把下载好的rpm版的mysql上传到centos7中,目前公司中最爱用的是5.5版本和5.7版本,推荐用5.5. 先安装服务端 rpm -ivh MySQL-server-5.5. ...

  9. Oracle重做日志和日志挖掘

    重做日志-Redo log 首先给出参考资料: 1.Oracle官网-Managing the Redo Log 为什么需要redo log 内存中数据修改后,不必立即更新到磁盘---效率 由日志完成 ...

  10. Python学习—Anaconda详细 下载、安装与使用,以及如何创建虚拟环境,不仅仅只有安装步骤哦

    上一期我们介绍了Python.Pycharm.Anaconda三者之间的关系以及使用,这一期主要详细介绍如何在Windows上下载和安装工具Anaconda,然后使用其自带的conda管理不同项目的虚 ...