.NET CORE3.1实现微信小程序发送订阅消息

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

"WX": {
  "AppId": "wx88822730803edd44",
  "AppSecret": "75b269042e8b5026e6ed14aa24ba9353",
  "Templates": {
  "Audit": {
    "TemplateId": "aBaIjTsPBluYtj2tzotzpowsDDBGLhXQkwrScupnQsM",
    "PageUrl": "/pages/index/formAudit?formId={0}&tableId={1}",
    "MiniprogramState": "developer",
    "Lang": "zh_TW",
    "Data": {
        "Title": "thing6",
        "Content": "thing19",
        "Date": "date9"
      }
    }
  },
  "SignatureToken": "aaaaaa",
  "MessageSendUrl": "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}",
  "AccessTokenUrl": "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"
}

二、编写通用类加载配置

using System;
using System.Text;
using System.Security.Cryptography;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;

namespace WXERP.Services
{
  /// <summary>
  /// 项目公有静态类
  /// </summary>
  public class Common
  {
    /// <summary>
    /// 獲取根目錄
    /// </summary>
    public static string AppRoot => Environment.CurrentDirectory;// AppContext.BaseDirectory;
    /// <summary>
    /// 獲取項目配置
    /// </summary>
    public static IConfiguration Configuration { get; set; }
    /// <summary>
    /// 加載項目配置
    /// </summary>
    static Common()
    {
      Configuration = new ConfigurationBuilder()
      .Add(new JsonConfigurationSource
      {
        Path = "appsettings.json",
        ReloadOnChange = true //当appsettings.json被修改时重新加载
      })
      .Build();
    }

    /// <summary>
    /// SHA1加密
    /// </summary>
    /// <param name="content">需要加密的字符串</param>
    /// <returns>返回40位大寫字符串</returns>
    public static string SHA1(string content)
    {
      try
      {
        SHA1 sha1 = new SHA1CryptoServiceProvider();
        byte[] bytes_in = Encoding.UTF8.GetBytes(content);
        byte[] bytes_out = sha1.ComputeHash(bytes_in);
        sha1.Dispose();
        string result = BitConverter.ToString(bytes_out);
        result = result.Replace("-", "");
        return result;
      }
      catch (Exception ex)
      {
        throw new Exception("Error in SHA1: " + ex.Message);
      }
    }

  }
}

三、编写HttpHelper请求类

using System;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace WXERP.Services
{
  /// <summary>
  /// HTTP請求輔助類
  /// </summary>
  public class HttpHelper
  {
    /// <summary>
    /// post同步請求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="postData">數據</param>
    /// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
    /// <param name="headers">請求頭</param>
    /// <returns></returns>
    public static string HttpPost(string url, string postData = null, string contentType = null, Dictionary<string, string> headers = null)
    {
      using HttpClient client = new HttpClient();

      if (headers != null)
      {
        foreach (var header in headers)
        client.DefaultRequestHeaders.Add(header.Key, header.Value);
      }

      postData ??= "";
      using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
      if (contentType != null)
      httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);

      HttpResponseMessage response = client.PostAsync(url, httpContent).Result;
      return response.Content.ReadAsStringAsync().Result;
    }

    /// <summary>
    /// post異步請求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="postData">數據</param>
    /// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
    /// <param name="timeOut">請求超時時間</param>
    /// <param name="headers">請求頭</param>
    /// <returns></returns>
    public static async Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null)
    {
      using HttpClient client = new HttpClient();
      client.Timeout = new TimeSpan(0, 0, timeOut);

      if (headers != null)
      {
        foreach (var header in headers)
        client.DefaultRequestHeaders.Add(header.Key, header.Value);
      }

      postData ??= "";
      using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
      if (contentType != null)
        httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);

      HttpResponseMessage response = await client.PostAsync(url, httpContent);
      return await response.Content.ReadAsStringAsync();
    }

    /// <summary>
    /// get同步請求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">請求頭</param>
    /// <returns></returns>
    public static string HttpGet(string url, Dictionary<string, string> headers = null)
    {
      using HttpClient client = new HttpClient();

      if (headers != null)
      {
        foreach (var header in headers)
        client.DefaultRequestHeaders.Add(header.Key, header.Value);
      }

      HttpResponseMessage response = client.GetAsync(url).Result;
      return response.Content.ReadAsStringAsync().Result;
    }

    /// <summary>
    /// get異步請求
    /// </summary>
    /// <param name="url"></param>
    /// <param name="headers"></param>
    /// <returns></returns>
    public static async Task<string> HttpGetAsync(string url, Dictionary<string, string> headers = null)
    {
      using HttpClient client = new HttpClient();

      if (headers != null)
      {
        foreach (var header in headers)
        client.DefaultRequestHeaders.Add(header.Key, header.Value);
      }

      HttpResponseMessage response = await client.GetAsync(url);
      return await response.Content.ReadAsStringAsync();
    }

  }
}

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

// 创建数据库表

create table TBSF_Conmmunicate_WXUser
(
  ID int identity(1,1) primary key,
  Staff_ID varchar(10),
  OpenId varchar(50),
  SessionKey varchar(50),
  UnionId varchar(50),
  IsValid bit,
)

// SqlHelper数据库辅助类来自于CommunicationOperateDBUtility,可以自己编写

using System.Data;
using System.Text;
using CommunicationOperateDBUtility;

namespace WXERP.Services.CommunicationOperateDAL
{
  /// <summary>
  /// 微信信息
  /// </summary>
  public class WXInforDeal
  {
    private SqlHelper sqlHelper = null;
    /// <summary>
    /// 初始化數據庫輔助對象
    /// </summary>
    /// <param name="con"></param>
    public WXInforDeal(object con)
    {
      sqlHelper = new SqlHelper(con);
    }
    /// <summary>
    /// 獲取微信登陸用戶信息
    /// </summary>
    /// <param name="staffIdList">工號</param>
    /// <returns></returns>
    public DataSet GetLoginUserInfo(string staffIdList)
    {
      DataSet ds = new DataSet();
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.Append(" SELECT distinct OpenId FROM ");
      stringBuilder.Append(" TBSF_Conmmunicate_WXUser WHERE Staff_ID IN (");
      stringBuilder.Append(staffIdList);
      stringBuilder.Append(")");
      string strSql = stringBuilder.ToString();
      sqlHelper.DBRunSql(strSql, ref ds);
      return ds;
    }
  }
}

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

using System;
using System.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using WXERP.Services.CommunicationOperateDAL;

namespace WXERP.Models
{
  /// <summary>
  /// 訂閲消息請求模型
  /// </summary>
  public class SubscribeMessageModel
  {
    /// <summary>
    /// 初始化審核訂閲消息
    /// </summary>
    /// <param name="dbTransOrCnn">數據庫事務</param>
    /// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
    public SubscribeMessageModel(object dbTransOrCnn, string nextAuditStaffId)
    {
      WXInforDeal wxInfoDeal = new WXInforDeal(dbTransOrCnn);
      DataSet wxUserInfo = wxInfoDeal.GetLoginUserInfo(nextAuditStaffId);
      if (wxUserInfo != null && wxUserInfo.Tables.Count > 0 && wxUserInfo.Tables[0].Rows.Count > 0)
      {
        Touser = wxUserInfo.Tables[0].Rows[0]["OpenId"].ToString();
      }
    }
    /// <summary>
    /// 消息接收者的openid
    /// </summary>
    [JsonProperty("touser")]
    public string Touser { get; set; }
    /// <summary>
    /// 消息模板ID
    /// </summary>
    [JsonProperty("template_id")]
    public string TemplateId { get; set; }
    /// <summary>
    /// 點擊模板卡片后的跳轉頁面,僅限本小程序内的頁面,支持帶參數(示例index?foo=bar),該字段不填則不跳轉
    /// </summary>
    [JsonProperty("page")]
    public string Page { get; set; }
    /// <summary>
    /// 跳轉小程序類型:developer開發版、trial體驗版、formal正式版,默认为正式版
    /// </summary>
    [JsonProperty("miniprogram_state")]
    public string MiniprogramState { get; set; }
    /// <summary>
    /// 進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN
    /// </summary>
    [JsonProperty("lang")]
    public string Lang { get; set; }
    /// <summary>
    /// 模板内容
    /// </summary>
    [JsonProperty("data")]
    public Dictionary<string, DataValue> Data { get; set; }
  }
  /// <summary>
  /// 模板内容關鍵字
  /// </summary>
  public class DataValue
  {
    /// <summary>
    /// 訂閲消息參數值
    /// </summary>
    [JsonProperty("value")]
    public string Value { get; set; }
  }

  /// <summary>
  /// 小程序訂閲消息響應模型
  /// </summary>
  public class SubscribeMsgResponseModel
  {
    /// <summary>
    /// 錯誤代碼
    /// </summary>
    public int Errcode { get; set; }
    /// <summary>
    /// 錯誤信息
    /// </summary>
    public string Errmsg { get; set; }
  }

  /// <summary>
  /// 小程序獲取token響應模型
  /// </summary>
  public class AccessTokenResponseModel
  {
    /// <summary>
    /// 小程序訪問token
    /// </summary>
    public string Access_token { get; set; }
    /// <summary>
    /// Token過期時間,單位秒
    /// </summary>
    public int Expires_id { get; set; }
    /// <summary>
    /// Token創建時間
    /// </summary>
    public DateTime Create_time { get; set; }
    /// <summary>
    /// 刷新以後的Token
    /// </summary>
    public string Refresh_token { get; set; }
    /// <summary>
    /// 小程序用戶唯一標識,如果用戶未關注公衆號,訪問公衆號網頁也會產生
      /// </summary>
    public string Openid { get; set; }
    /// <summary>
    /// 用戶授權的作用域,使用逗號分隔
    /// </summary>
    public string Scope { get; set; }
  }

}

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

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using BestSoft.Common.Resources;
using BSFWorkFlow.Common.GeneralUtility;
using WXERP.Models;

namespace WXERP.Services.SubscribeMessage
{
  /// <summary>
  /// 審核訂閲消息
  /// </summary>
  public class AuditSubscribeMessage : SubscribeMessageModel
  {
    private string page;
    private string lang;
    private Dictionary<string, DataValue> data;
    /// <summary>
    /// 設置小程序OpenId
    /// </summary>
    /// <param name="dbTransOrCnn">數據庫事務</param>
    /// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
    public AuditSubscribeMessage(object dbTransOrCnn, string nextAuditStaffId)
    : base(dbTransOrCnn, nextAuditStaffId)
    {

    }
    /// <summary>
    /// 消息模板ID
    /// </summary>
    [JsonProperty("template_id")]
    public new string TemplateId => Common.Configuration["WX:Templates:Audit:TemplateId"];

    /// <summary>
    /// 設置小程序訂閲消息跳轉頁面
    /// </summary>
    /// <param name="formId"></param>
    /// <param name="tableId"></param>
    public void SetPageUrl(string formId, string tableId)
    {
      Page = string.Format(Common.Configuration["WX:Templates:Audit:PageUrl"],
      formId, tableId);
    }
    /// <summary>
    /// 點擊模板卡片后的跳轉頁面
    /// </summary>
    [JsonProperty("page")]
    public new string Page
    {
      get
      {
        return page;
      }
      set
      {
        page = value;
        return;
      }
    }
    /// <summary>
    /// 跳轉小程序類型
    /// </summary>
    [JsonProperty("miniprogram_state")]
    public new string MiniprogramState => Common.Configuration["WX:Templates:Audit:MiniprogramState"];
    /// <summary>
    /// 進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN
    /// </summary>
    [JsonProperty("lang")]
    public new string Lang
    {
      get
      {
        lang = Common.Configuration["WX:Templates:Audit:Lang"];
        if (!string.IsNullOrEmpty(MyHttpContext.Current.Request.Headers["bsLanKind"]))
        lang = MyHttpContext.Current.Request.Headers["bsLanKind"];

        return lang;
      }
      set
      {
        lang = value;
        return;
      }
    }
    /// <summary>
    /// 設置審核訂閲消息數據
    /// </summary>
    /// <param name="operation">審核動作:通過、否決、作廢、退回</param>
    /// <param name="itemAuditStatus">審核狀態:1代表審核完畢</param>
    /// <param name="currentWorkflowName">審核標題</param>
    public void SetTemplateData(WFAuditOperation operation, WFAuditItemStatus itemAuditStatus, string currentWorkflowName)
    {
      string tip_msg = "";
      switch (operation)
      {
        case WFAuditOperation.AuditPassAndAgree:
          if (itemAuditStatus == WFAuditItemStatus.SuccessfulToFinishAllAudits)
            tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_FinishAuditTip"), "您的單據已審核完成!");
          else
            tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAgreeTip"), "您有一筆新單據待審核!");
        break;
        case WFAuditOperation.AuditPassButDegree:
          tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditDegreeTip"), "您提交的單據等待異議!");
        break;
        case WFAuditOperation.AuditAbort:
          tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAbortTip"), "您提交的單據已被作廢!");
        break;
        case WFAuditOperation.AuditBack:
          tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditBackTip"), "您提交的單據已被退回修正!");
        break;
      }

      string title = Common.Configuration["WX:Templates:Audit:Data:Title"];
      string content = Common.Configuration["WX:Templates:Audit:Data:Content"];
      string date = Common.Configuration["WX:Templates:Audit:Data:Date"];
      Dictionary<string, DataValue> data = new Dictionary<string, DataValue>()
      {
        {title, new DataValue{ Value= currentWorkflowName }},
        {content, new DataValue{ Value= tip_msg }},
        {date, new DataValue{ Value= DateTime.Now.ToShortDateString() }}
      };

      Data = data;
    }
    /// <summary>
    /// 審核訂閲消息數據
    /// </summary>
    [JsonProperty("data")]
    public new Dictionary<string, DataValue> Data
    {
      get
      {
        return data;
      }
      set
      {
        data = value;
        return;
      }
    }

  }
}

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

using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json;
using WXERP.Models;

namespace WXERP.Services
{
  /// <summary>
  /// 系統消息上下文
  /// </summary>
  public class MessageContext
  {
    /// <summary>
    /// 獲取AccessToken的全局鎖
    /// </summary>
    private readonly static object SyncLock = new object();

    private static Dictionary<string, AccessTokenResponseModel> tokenCache = new Dictionary<string, AccessTokenResponseModel>();

    /// <summary>
    /// 發送訂閲消息
    /// </summary>
    /// <param name="msg">消息内容</param>
    /// <param name="errMsg">可能由於獲取的token錯誤</param>
    /// <returns></returns>
    public static bool SendSubscribeMsg(SubscribeMessageModel msg, out string errMsg)
    {
      errMsg = "";
      try
      {
        string token = GetAccessToken();
        if (token.Length < 20)
        {
          errMsg = "Failed to send subscription message, Access token error!";
          return false;
        }
        string url = string.Format(Common.Configuration["WX:MessageSendUrl"], token);
        string requestJson = JsonConvert.SerializeObject(msg);
        string responseJson = HttpHelper.HttpPost(url, requestJson, "application/json", null);

        var msgResponse = JsonConvert.DeserializeObject<SubscribeMsgResponseModel>(responseJson);
        if (msgResponse.Errcode != 0)
        {
          errMsg = string.Format("Failed to send subscription message, {0}", msgResponse.Errmsg);
          return false;
        }
      }
      catch (Exception exp)
      {
        throw new Exception("SendSubscribeMsg: " + exp.Message);
      }
      return true;
    }

    /// <summary>
    /// 獲取小程序訪問token
    /// </summary>
    /// <returns></returns>
    private static string GetAccessToken()
    {
      lock (SyncLock)
      {
        string appid = Common.Configuration["WX:AppId"];
        string appsecret = Common.Configuration["WX:AppSecret"];
        string accessTokenUrl = string.Format(Common.Configuration["WX:AccessTokenUrl"], appid, appsecret);

        AccessTokenResponseModel result = null;
        if (tokenCache.ContainsKey(appid))
          result = tokenCache[appid];

        if (result == null)
        {
          string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
          result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
          result.Create_time = DateTime.Now;
          tokenCache.Add(appid, result);
        }
        else if (DateTime.Compare(result.Create_time.AddSeconds(result.Expires_id), DateTime.Now) < 1)
        {
          string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
          result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
          result.Create_time = DateTime.Now;
          tokenCache[appid] = result;
        }
        return result.Access_token;
      }
    }

    /// <summary>
    /// 驗證消息來自於微信服務器
    /// </summary>
    /// <param name="signature">微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param>
    /// <param name="timestamp">時間戳</param>
    /// <param name="nonce">隨機數</param>
    /// <returns></returns>
    public async Task<bool> CheckSignature(string signature, string timestamp, string nonce)
    {
      string token = Common.Configuration["WX:SignatureToken"];
      string[] tmpArr = { token, timestamp, nonce };
      Array.Sort(tmpArr);
      string tmpStr = string.Join("", tmpArr);
      tmpStr = Common.SHA1(tmpStr);

      if (!tmpStr.Equals(signature, StringComparison.OrdinalIgnoreCase))
        return false;

      await Task.CompletedTask;
      return true;
    }

  }
}

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

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WXERP.Services;

namespace WXERP.Controllers
{
  /// <summary>
  /// 消息控制器
  /// </summary>
  [Route("api/[controller]")]
  [ApiController]
  public class MessageController : ControllerBase
  {
    private readonly MessageContext _context;
    /// <summary>
    /// 初始化消息
    /// </summary>
    public MessageController()
    {
      _context = new MessageContext();
    }

    /// <summary>微信消息</summary>
    /// <remarks>驗證消息來自於微信服務器</remarks>
    /// <param name="signature">微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param>
    /// <param name="timestamp">時間戳</param>
    /// <param name="nonce">隨機數</param>
    /// <param name="echostr">隨機字符串</param>
    /// <returns></returns>
    [HttpGet("checkSignature")]
    [AllowAnonymous]
    public async void CheckSignature(string signature,string timestamp,string nonce,string echostr)
    {
      bool result = await _context.CheckSignature(signature, timestamp, nonce);
      if (result)
      {
        HttpContext.Response.ContentType = "text/plain; charset=utf-8";
        await HttpContext.Response.WriteAsync(echostr);
      }
      else
      {
        HttpContext.Response.StatusCode = 409;
        HttpContext.Response.ContentType = "text/plain; charset=utf-8";
        await HttpContext.Response.WriteAsync("error");
      }
    }

  }
}

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

//@iFormSaveDAL.GetTran 数据库链接事务,如果发送消息失败,应该回滚提交的表单数据
//@wFControl.NextAuditNotifyStaffIDStr 下一个审核用户的工号
//@auditPageData.FormID 表单编号
//@auditPageData.MainRecordID 表单数据ID
//@operationByCode 一个枚举类型,前端传递的:审核通过、作废、退回等
//@wFControl.ItemAuditStatus 一个枚举类型,如果全部审核完毕为1,否则为0
//@wFControl.CurrentWorkflowName 当前流程的名称,例如:请假单审核
//@SaveAfterInfo 全局字符变量,用于保存结果信息

AuditSubscribeMessage auditMsg = new AuditSubscribeMessage(iFormSaveDAL.GetTran, wFControl.NextAuditNotifyStaffIDStr);
auditMsg.SetPageUrl(auditPageData.FormID, auditPageData.MainRecordID);
auditMsg.SetTemplateData(operationByCode, wFControl.ItemAuditStatus, wFControl.CurrentWorkflowName);
if (!string.IsNullOrEmpty(auditMsg.Touser))
{
  if (!MessageContext.SendSubscribeMsg(auditMsg, out messageStr))
  {
    SaveAfterInfo = messageStr;
    return false;
  }
}

到此这篇关于.NET CORE3.1实现微信小程序发送订阅消息的文章就介绍到这了,更多相关.NET CORE 小程序发送订阅内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • .net core如何使用Redis发布订阅

    Redis是一个性能非常强劲的内存数据库,它一般是作为缓存来使用,但是他不仅仅可以用来作为缓存,比如著名的分布式框架dubbo就可以用Redis来做服务注册中心.接下来介绍一下.net core 使用Redis的发布/订阅功能. Redis 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的通道. 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 -- client2 .

  • ASP.NET Core实现单体程序的事件发布/订阅详解

    背景 事件发布/订阅是一种非常强大的模式,它可以帮助业务组件间实现完全解耦,不同的业务组件只依赖事件,只关注哪些事件是需要自己处理的,而不用关注谁来处理自己发布事件,事件追溯(Event Sourcing)也是基于事件发布/订阅的.在微服务架构中,事件发布/订阅有非常多的应用场景.今天我给大家分享一个基于ASP.NET Core的单体程序使用事件发布/订阅的例子,针对分布式项目的事件发布/订阅比较复杂,难点是事务处理,后续我会另写一篇博文来演示. 案例说明 当前我们有一个基于ASP.NET Co

  • Asp.net core利用MediatR进程内发布/订阅详解

    1.背景 最近,一个工作了一个月的同事离职了,所做的东西怼了过来.一看代码,惨不忍睹,一个方法六七百行,啥也不说了吧,实在没法儿说.介绍下业务场景吧,一个公共操作A,业务中各个地方都会做A操作,正常人正常思维应该是把A操作提取出来封装,其他地方调用,可这哥们儿偏偏不这么干,代码到处复制.仔细分析了整个业务之后,发现是一个典型的事件/消息驱动型,或者叫发布/订阅型的业务逻辑.鉴于系统是单体的,所以想到利用进程内发布/订阅的解决方案.记得很久之前,做WPF时候,用过Prism的EventAggreg

  • .NET CORE3.1实现微信小程序发送订阅消息

    一.appsettings.json定义小程序配置信息 "WX": { "AppId": "wx88822730803edd44", "AppSecret": "75b269042e8b5026e6ed14aa24ba9353", "Templates": { "Audit": { "TemplateId": "aBaIjTsPBluYt

  • 微信小程序发送订阅消息的方法(php 为例)

    1.订阅消息 其实如果用过模板消息的话,改用订阅消息挺简单的,看一下官方文档稍加摸索就能使用. 但是对于那些第一次用的萌新来说,可能会遇到各种各样的坑,所以我会具体的说一下实现的过程,有经验的可以直接翻到文章底部查看 Demo. 虽然如此,但是更详细的参数描述还是需要去看官方文档,传送门: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html 2.准备工作 首先

  • C#开发之微信小程序发送模板消息功能

    步骤一:获取模板ID 有两个方法可以获取模版ID 通过模版消息管理接口获取模版ID 在微信公众平台手动配置获取模版ID 步骤二:页面的 <form/> 组件,属性report-submit为true时,可以声明为需发模板消息,此时点击按钮提交表单可以获取formId,用于发送模板消息.或者当用户完成支付行为,可以获取prepay_id用于发送模板消息. 步骤三:调用接口下发模板消息 今天重要的说第三步怎么实现,前面的步骤比较简单就略过. ----------------------------

  • 微信小程序(订阅消息)功能

    小程序模板消息即将被废弃掉,于是有了新接口wx.requestSubscribeMessage 订阅消息文档 步骤: 1.获取用户openid .access_token 2.获取模板 ID 3.获取下发权限(api) 4.发送订阅消息 (api) 模板id 小程序代码: 获取下发权限: // login.js requestMsg(){ return new Promise((resolve, reject) => { wx.requestSubscribeMessage({ tmplIds:

  • 基于PHP实现微信小程序客服消息功能

    项目说明: 本项目是一个简单微信小程序客服消息类,实现客服消息相关功能.官方给的php示例有误,这里就不再吐槽了. 本示例是采用开发者服务器,没有采用云调用的形式. 官方文档: 客服消息指南 客服消息服务端 适用场景 客户消息流程图 使用步骤 1.开启客服消息 https://mp.weixin.qq.com/wxam... 登录-开发-开发设置-消息推送 []( https://raw.githubusercontent... 点击"启动" []( https://raw.githu

  • php实现QQ小程序发送模板消息功能

    QQ小程序群里有伙伴要发送模板消息的代码,所以今天给大家分享QQ小程序模板消息发布,绝对一步一步带着大家走,每个细节都讲到. 今天先用php简单写一下,有空了再写java的. 首先创建一个空项目: 因为QQ小程序没有编译器,先用微信小程序创建. 然后新建一个页面,直接上html代码: <form bindsubmit="form_submit" report-submit="true"> <button formType="submit&

  • 微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能【附源码下载】

    本文实例讲述了微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能.分享给大家供大家参考,具体如下: 1.效果展示 2.关键代码 ① index.wxml <form bindsubmit="formBindsubmit" bindreset="formReset"> <view style="display:flex;"> <label>用户名:</label> <input

  • 微信小程序实现滚动消息通知

    本文实例为大家分享了微信小程序实现滚动消息的具体代码,供大家参考,具体内容如下 效果图: index.wxml <!--index.wxml--> <swiper class="swiper_container" vertical="true" autoplay="true" circular="true" interval="1000"> <block wx:for=&quo

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

    微信小程序注册完整实例,发送短信验证码,带60秒倒计时功能,无需服务器端.效果图: 代码: index.wxml <!--index.wxml--> <view class="container"> <view class='row'> <input placeholder='请输入姓名' bindinput='bindNameInput'/> </view> <view class='row'> <inpu

  • 微信小程序开发实现消息推送

    微信小程序的消息推送简单的说就是发送一条微信通知给用户,用户点开消息可以查看消息内容,可以链接进入到小程序的指定页面. 微信小程序消息推送需要用户触发动作才能发送消息,比如用户提交订单.支付成功.一次只能发一条,当然可以通过某种方法发送多条,小的就不在这里赘述了.下面就介绍一下如何推送消息. 一.准备工作 首先,在微信公众平台开通消息推送功能,并添加消息模板.可以从模板库选择模板也可以创建一个模板,模板添加之后,模板ID我们接下来要用的. 发送模板消息需要用到accesstoken.formId

随机推荐