.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,Dictionaryheaders=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
///請求超時時間
///請求頭
///
publicstaticasyncTaskHttpPostAsync(stringurl,stringpostData=null,stringcontentType=null,inttimeOut=30,Dictionaryheaders=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,Dictionaryheaders=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異步請求
///
///
///
///
publicstaticasyncTaskHttpGetAsync(stringurl,Dictionaryheaders=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"];
Dictionarydata=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
///時間戳
///隨機數
///
publicasyncTaskCheckSignature(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小程序发送订阅内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!