.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}" }
二、编写通用类加载配置
usingSystem; usingSystem.Text; usingSystem.Security.Cryptography; usingMicrosoft.Extensions.Configuration; usingMicrosoft.Extensions.Configuration.Json; namespaceWXERP.Services { //////项目公有静态类 /// publicclassCommon { //////獲取根目錄 /// publicstaticstringAppRoot=>Environment.CurrentDirectory;//AppContext.BaseDirectory; //////獲取項目配置 /// publicstaticIConfigurationConfiguration{get;set;} //////加載項目配置 /// staticCommon() { Configuration=newConfigurationBuilder() .Add(newJsonConfigurationSource { Path="appsettings.json", ReloadOnChange=true//当appsettings.json被修改时重新加载 }) .Build(); } //////SHA1加密 /// ///需要加密的字符串 /// 返回40位大寫字符串 publicstaticstringSHA1(stringcontent) { try { SHA1sha1=newSHA1CryptoServiceProvider(); byte[]bytes_in=Encoding.UTF8.GetBytes(content); byte[]bytes_out=sha1.ComputeHash(bytes_in); sha1.Dispose(); stringresult=BitConverter.ToString(bytes_out); result=result.Replace("-",""); returnresult; } catch(Exceptionex) { thrownewException("ErrorinSHA1:"+ex.Message); } } } }
三、编写HttpHelper请求类
usingSystem; usingSystem.Text; usingSystem.Net.Http; usingSystem.Net.Http.Headers; usingSystem.Threading.Tasks; usingSystem.Collections.Generic; namespaceWXERP.Services { //////HTTP請求輔助類 /// publicclassHttpHelper { //////post同步請求 /// ///地址 /// 數據 /// application/xml、application/json、application/text、application/x-www-form-urlencoded /// 請求頭 /// publicstaticstringHttpPost(stringurl,stringpostData=null,stringcontentType=null,Dictionary headers=null) { usingHttpClientclient=newHttpClient(); if(headers!=null) { foreach(varheaderinheaders) client.DefaultRequestHeaders.Add(header.Key,header.Value); } postData??=""; usingHttpContenthttpContent=newStringContent(postData,Encoding.UTF8); if(contentType!=null) httpContent.Headers.ContentType=newMediaTypeHeaderValue(contentType); HttpResponseMessageresponse=client.PostAsync(url,httpContent).Result; returnresponse.Content.ReadAsStringAsync().Result; } /// ///post異步請求 /// ///地址 /// 數據 /// application/xml、application/json、application/text、application/x-www-form-urlencoded /// 請求超時時間 /// 請求頭 /// publicstaticasyncTask HttpPostAsync(stringurl,stringpostData=null,stringcontentType=null,inttimeOut=30,Dictionary headers=null) { usingHttpClientclient=newHttpClient(); client.Timeout=newTimeSpan(0,0,timeOut); if(headers!=null) { foreach(varheaderinheaders) client.DefaultRequestHeaders.Add(header.Key,header.Value); } postData??=""; usingHttpContenthttpContent=newStringContent(postData,Encoding.UTF8); if(contentType!=null) httpContent.Headers.ContentType=newMediaTypeHeaderValue(contentType); HttpResponseMessageresponse=awaitclient.PostAsync(url,httpContent); returnawaitresponse.Content.ReadAsStringAsync(); } /// ///get同步請求 /// ///地址 /// 請求頭 /// publicstaticstringHttpGet(stringurl,Dictionary headers=null) { usingHttpClientclient=newHttpClient(); if(headers!=null) { foreach(varheaderinheaders) client.DefaultRequestHeaders.Add(header.Key,header.Value); } HttpResponseMessageresponse=client.GetAsync(url).Result; returnresponse.Content.ReadAsStringAsync().Result; } /// ///get異步請求 /// ////// /// publicstaticasyncTask HttpGetAsync(stringurl,Dictionary headers=null) { usingHttpClientclient=newHttpClient(); if(headers!=null) { foreach(varheaderinheaders) client.DefaultRequestHeaders.Add(header.Key,header.Value); } HttpResponseMessageresponse=awaitclient.GetAsync(url); returnawaitresponse.Content.ReadAsStringAsync(); } } }
四、在sqlserver下存储并获取openid,这个主要是因为提交消息并不是在微信小程序端,如果是在微信小程序上发起订阅消息,可以忽略这个步骤
//创建数据库表 createtableTBSF_Conmmunicate_WXUser ( IDintidentity(1,1)primarykey, Staff_IDvarchar(10), OpenIdvarchar(50), SessionKeyvarchar(50), UnionIdvarchar(50), IsValidbit, ) //SqlHelper数据库辅助类来自于CommunicationOperateDBUtility,可以自己编写 usingSystem.Data; usingSystem.Text; usingCommunicationOperateDBUtility; namespaceWXERP.Services.CommunicationOperateDAL { //////微信信息 /// publicclassWXInforDeal { privateSqlHelpersqlHelper=null; //////初始化數據庫輔助對象 /// ///publicWXInforDeal(objectcon) { sqlHelper=newSqlHelper(con); } /// ///獲取微信登陸用戶信息 /// ///工號 /// publicDataSetGetLoginUserInfo(stringstaffIdList) { DataSetds=newDataSet(); StringBuilderstringBuilder=newStringBuilder(); stringBuilder.Append("SELECTdistinctOpenIdFROM"); stringBuilder.Append("TBSF_Conmmunicate_WXUserWHEREStaff_IDIN("); stringBuilder.Append(staffIdList); stringBuilder.Append(")"); stringstrSql=stringBuilder.ToString(); sqlHelper.DBRunSql(strSql,refds); returnds; } } }
五、编写订阅消息基类模型
usingSystem; usingSystem.Data; usingNewtonsoft.Json; usingSystem.Collections.Generic; usingWXERP.Services.CommunicationOperateDAL; namespaceWXERP.Models { //////訂閲消息請求模型 /// publicclassSubscribeMessageModel { //////初始化審核訂閲消息 /// ///數據庫事務 /// 下一個審核通知用戶工號 publicSubscribeMessageModel(objectdbTransOrCnn,stringnextAuditStaffId) { WXInforDealwxInfoDeal=newWXInforDeal(dbTransOrCnn); DataSetwxUserInfo=wxInfoDeal.GetLoginUserInfo(nextAuditStaffId); if(wxUserInfo!=null&&wxUserInfo.Tables.Count>0&&wxUserInfo.Tables[0].Rows.Count>0) { Touser=wxUserInfo.Tables[0].Rows[0]["OpenId"].ToString(); } } /// ///消息接收者的openid /// [JsonProperty("touser")] publicstringTouser{get;set;} //////消息模板ID /// [JsonProperty("template_id")] publicstringTemplateId{get;set;} //////點擊模板卡片后的跳轉頁面,僅限本小程序内的頁面,支持帶參數(示例index?foo=bar),該字段不填則不跳轉 /// [JsonProperty("page")] publicstringPage{get;set;} //////跳轉小程序類型:developer開發版、trial體驗版、formal正式版,默认为正式版 /// [JsonProperty("miniprogram_state")] publicstringMiniprogramState{get;set;} //////進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN /// [JsonProperty("lang")] publicstringLang{get;set;} //////模板内容 /// [JsonProperty("data")] publicDictionaryData{get;set;} } /// ///模板内容關鍵字 /// publicclassDataValue { //////訂閲消息參數值 /// [JsonProperty("value")] publicstringValue{get;set;} } //////小程序訂閲消息響應模型 /// publicclassSubscribeMsgResponseModel { //////錯誤代碼 /// publicintErrcode{get;set;} //////錯誤信息 /// publicstringErrmsg{get;set;} } //////小程序獲取token響應模型 /// publicclassAccessTokenResponseModel { //////小程序訪問token /// publicstringAccess_token{get;set;} //////Token過期時間,單位秒 /// publicintExpires_id{get;set;} //////Token創建時間 /// publicDateTimeCreate_time{get;set;} //////刷新以後的Token /// publicstringRefresh_token{get;set;} //////小程序用戶唯一標識,如果用戶未關注公衆號,訪問公衆號網頁也會產生 /// publicstringOpenid{get;set;} //////用戶授權的作用域,使用逗號分隔 /// publicstringScope{get;set;} } }
六、实现消息订阅基类,下面的SetTemplateData方法根据自己的情况设置需要推送消息的内容,如果以后有其他订阅消息模板,新增一个类实现SubscribeMessageModel
usingSystem; usingSystem.Collections.Generic; usingNewtonsoft.Json; usingBestSoft.Common.Resources; usingBSFWorkFlow.Common.GeneralUtility; usingWXERP.Models; namespaceWXERP.Services.SubscribeMessage { //////審核訂閲消息 /// publicclassAuditSubscribeMessage:SubscribeMessageModel { privatestringpage; privatestringlang; privateDictionarydata; /// ///設置小程序OpenId /// ///數據庫事務 /// 下一個審核通知用戶工號 publicAuditSubscribeMessage(objectdbTransOrCnn,stringnextAuditStaffId) :base(dbTransOrCnn,nextAuditStaffId) { } /// ///消息模板ID /// [JsonProperty("template_id")] publicnewstringTemplateId=>Common.Configuration["WX:Templates:Audit:TemplateId"]; //////設置小程序訂閲消息跳轉頁面 /// ////// publicvoidSetPageUrl(stringformId,stringtableId) { Page=string.Format(Common.Configuration["WX:Templates:Audit:PageUrl"], formId,tableId); } /// ///點擊模板卡片后的跳轉頁面 /// [JsonProperty("page")] publicnewstringPage { get { returnpage; } set { page=value; return; } } //////跳轉小程序類型 /// [JsonProperty("miniprogram_state")] publicnewstringMiniprogramState=>Common.Configuration["WX:Templates:Audit:MiniprogramState"]; //////進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN /// [JsonProperty("lang")] publicnewstringLang { get { lang=Common.Configuration["WX:Templates:Audit:Lang"]; if(!string.IsNullOrEmpty(MyHttpContext.Current.Request.Headers["bsLanKind"])) lang=MyHttpContext.Current.Request.Headers["bsLanKind"]; returnlang; } set { lang=value; return; } } //////設置審核訂閲消息數據 /// ///審核動作:通過、否決、作廢、退回 /// 審核狀態:1代表審核完畢 /// 審核標題 publicvoidSetTemplateData(WFAuditOperationoperation,WFAuditItemStatusitemAuditStatus,stringcurrentWorkflowName) { stringtip_msg=""; switch(operation) { caseWFAuditOperation.AuditPassAndAgree: if(itemAuditStatus==WFAuditItemStatus.SuccessfulToFinishAllAudits) tip_msg=GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_FinishAuditTip"),"您的單據已審核完成!"); else tip_msg=GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAgreeTip"),"您有一筆新單據待審核!"); break; caseWFAuditOperation.AuditPassButDegree: tip_msg=GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditDegreeTip"),"您提交的單據等待異議!"); break; caseWFAuditOperation.AuditAbort: tip_msg=GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAbortTip"),"您提交的單據已被作廢!"); break; caseWFAuditOperation.AuditBack: tip_msg=GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditBackTip"),"您提交的單據已被退回修正!"); break; } stringtitle=Common.Configuration["WX:Templates:Audit:Data:Title"]; stringcontent=Common.Configuration["WX:Templates:Audit:Data:Content"]; stringdate=Common.Configuration["WX:Templates:Audit:Data:Date"]; Dictionary data=newDictionary () { {title,newDataValue{Value=currentWorkflowName}}, {content,newDataValue{Value=tip_msg}}, {date,newDataValue{Value=DateTime.Now.ToShortDateString()}} }; Data=data; } /// ///審核訂閲消息數據 /// [JsonProperty("data")] publicnewDictionaryData { get { returndata; } set { data=value; return; } } } }
七、编写发送订阅消息,消息推送配置签名认证
usingSystem; usingSystem.Threading.Tasks; usingSystem.Collections.Generic; usingNewtonsoft.Json; usingWXERP.Models; namespaceWXERP.Services { //////系統消息上下文 /// publicclassMessageContext { //////獲取AccessToken的全局鎖 /// privatereadonlystaticobjectSyncLock=newobject(); privatestaticDictionarytokenCache=newDictionary (); /// ///發送訂閲消息 /// ///消息内容 /// 可能由於獲取的token錯誤 /// publicstaticboolSendSubscribeMsg(SubscribeMessageModelmsg,outstringerrMsg) { errMsg=""; try { stringtoken=GetAccessToken(); if(token.Length<20) { errMsg="Failedtosendsubscriptionmessage,Accesstokenerror!"; returnfalse; } stringurl=string.Format(Common.Configuration["WX:MessageSendUrl"],token); stringrequestJson=JsonConvert.SerializeObject(msg); stringresponseJson=HttpHelper.HttpPost(url,requestJson,"application/json",null); varmsgResponse=JsonConvert.DeserializeObject (responseJson); if(msgResponse.Errcode!=0) { errMsg=string.Format("Failedtosendsubscriptionmessage,{0}",msgResponse.Errmsg); returnfalse; } } catch(Exceptionexp) { thrownewException("SendSubscribeMsg:"+exp.Message); } returntrue; } /// ///獲取小程序訪問token /// ///privatestaticstringGetAccessToken() { lock(SyncLock) { stringappid=Common.Configuration["WX:AppId"]; stringappsecret=Common.Configuration["WX:AppSecret"]; stringaccessTokenUrl=string.Format(Common.Configuration["WX:AccessTokenUrl"],appid,appsecret); AccessTokenResponseModelresult=null; if(tokenCache.ContainsKey(appid)) result=tokenCache[appid]; if(result==null) { stringresponseJson=HttpHelper.HttpGet(accessTokenUrl,null); result=JsonConvert.DeserializeObject (responseJson); result.Create_time=DateTime.Now; tokenCache.Add(appid,result); } elseif(DateTime.Compare(result.Create_time.AddSeconds(result.Expires_id),DateTime.Now)<1) { stringresponseJson=HttpHelper.HttpGet(accessTokenUrl,null); result=JsonConvert.DeserializeObject (responseJson); result.Create_time=DateTime.Now; tokenCache[appid]=result; } returnresult.Access_token; } } /// ///驗證消息來自於微信服務器 /// ///微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce /// 時間戳 /// 隨機數 /// publicasyncTask CheckSignature(stringsignature,stringtimestamp,stringnonce) { stringtoken=Common.Configuration["WX:SignatureToken"]; string[]tmpArr={token,timestamp,nonce}; Array.Sort(tmpArr); stringtmpStr=string.Join("",tmpArr); tmpStr=Common.SHA1(tmpStr); if(!tmpStr.Equals(signature,StringComparison.OrdinalIgnoreCase)) returnfalse; awaitTask.CompletedTask; returntrue; } } }
八、编写消息推送配置签名认证控制器
usingMicrosoft.AspNetCore.Authorization; usingMicrosoft.AspNetCore.Http; usingMicrosoft.AspNetCore.Mvc; usingWXERP.Services; namespaceWXERP.Controllers { //////消息控制器 /// [Route("api/[controller]")] [ApiController] publicclassMessageController:ControllerBase { privatereadonlyMessageContext_context; //////初始化消息 /// publicMessageController() { _context=newMessageContext(); } ///微信消息 ///驗證消息來自於微信服務器 ///微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce /// 時間戳 /// 隨機數 /// 隨機字符串 /// [HttpGet("checkSignature")] [AllowAnonymous] publicasyncvoidCheckSignature(stringsignature,stringtimestamp,stringnonce,stringechostr) { boolresult=await_context.CheckSignature(signature,timestamp,nonce); if(result) { HttpContext.Response.ContentType="text/plain;charset=utf-8"; awaitHttpContext.Response.WriteAsync(echostr); } else { HttpContext.Response.StatusCode=409; HttpContext.Response.ContentType="text/plain;charset=utf-8"; awaitHttpContext.Response.WriteAsync("error"); } } } }
九、调用小程序订阅消息,需要自己实现其他逻辑
//@iFormSaveDAL.GetTran数据库链接事务,如果发送消息失败,应该回滚提交的表单数据 //@wFControl.NextAuditNotifyStaffIDStr下一个审核用户的工号 //@auditPageData.FormID表单编号 //@auditPageData.MainRecordID表单数据ID //@operationByCode一个枚举类型,前端传递的:审核通过、作废、退回等 //@wFControl.ItemAuditStatus一个枚举类型,如果全部审核完毕为1,否则为0 //@wFControl.CurrentWorkflowName当前流程的名称,例如:请假单审核 //@SaveAfterInfo全局字符变量,用于保存结果信息 AuditSubscribeMessageauditMsg=newAuditSubscribeMessage(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,outmessageStr)) { SaveAfterInfo=messageStr; returnfalse; } }
到此这篇关于.NETCORE3.1实现微信小程序发送订阅消息的文章就介绍到这了,更多相关.NETCORE小程序发送订阅内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!