一、說明
在微信用戶和公衆號產生交互的過程中,用戶的某些操作會使得微信服務器通過事件推送的形式通知到開發者在開發者中心處設置的服務器地址,從而開發者可以獲取到該信息。
二、新建partial 類
partial即爲定義部分類的關鍵字。部分類主要用於當一個類中的內容較多時將相似類中的內容拆分到不同的類中,並且部分類的名稱必須相同。
CustomMessageHandler.cs加關鍵詞partial
Handler下新建CustomMessageHandler_Events部分類用來接收事件推送
修改類名爲CustomMessageHandler並添加關鍵詞partial使得CustomMessageHandler_Events爲CustomMessageHandler的部分類,這樣推送事件和普通消息事件就分開了,職責清晰,便於維護。
namespace WeiXinApi.Application.Handler
{
public partial class CustomMessageHandler
{
}
}
同樣的我們新建MessageService_Events部分類
namespace WeiXinApi.Application.Services
{
public partial interface IMessageService
{
}
}
namespace WeiXinApi.Application.Services
{
public partial class MessageService
{
}
}
IMessageService和IMessageService也要加partial關鍵字
三、關注/取消關注事件
IMessageService_Events定義接口
/// <summary>
/// 訂閱
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
Task<IResponseMessageBase> OnEvent_SubscribeRequestAsync(RequestMessageEvent_Subscribe requestMessage);
/// <summary>
/// 取消訂閱
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
Task<IResponseMessageBase> OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage);
MessageService_Events實現接口
public async Task<IResponseMessageBase> OnEvent_SubscribeRequestAsync(RequestMessageEvent_Subscribe requestMessage)
{
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
var receives = await DbContext.Db.Queryable<MessageReceive>().ToListAsync();
//如果關鍵字搜不到,列出關鍵字
var result = new StringBuilder();
result.AppendFormat("歡迎訂閱,可以試試下面的關鍵字\r\n\r\n");
for (int i = 0; i < receives.Count; i++)
{
result.AppendFormat($"{i + 1}:{receives[i].KeyWords}\r\n");
}
responseMessage.Content = result.ToString();
return responseMessage;
}
/// <summary>
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public async Task<IResponseMessageBase> OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage)
{
//實際上用戶無法收到非訂閱賬號的消息,所以這裏可以隨便寫。
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
responseMessage.Content = $"再見!";
Console.WriteLine($"{requestMessage.FromUserName}取消了訂閱");
return responseMessage;
}
CustomMessageHandler_Events裏重寫訂閱和取消訂閱事件
/// <summary>
/// 訂閱或關注事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override async Task<IResponseMessageBase> OnEvent_SubscribeRequestAsync(RequestMessageEvent_Subscribe requestMessage)
{
var result = await _messageService.OnEvent_SubscribeRequestAsync(requestMessage);
return result;
}
/// <summary>
/// 退訂
/// unsubscribe事件的意義在於及時刪除網站應用中已經記錄的OpenID綁定,消除冗餘數據。並且關注用戶流失的情況。
/// </summary>
/// <returns></returns>
public override async Task<IResponseMessageBase> OnEvent_UnsubscribeRequestAsync(RequestMessageEvent_Unsubscribe requestMessage)
{
var result = await _messageService.OnEvent_UnsubscribeRequest(requestMessage);
return result;
}
發佈到服務器,測試下效果,成功接收到事件
四、掃描帶參數二維碼事件
IMessageService_Events定義接口
/// <summary>
/// 掃描帶參數二維碼事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
Task<IResponseMessageBase> OnEvent_ScanRequestAsync(RequestMessageEvent_Scan requestMessage);
MessageService_Events實現接口
public async Task<IResponseMessageBase> OnEvent_ScanRequestAsync(RequestMessageEvent_Scan requestMessage)
{
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
var result = "掃描帶二維碼事件";
var sceneId = requestMessage.EventKey.ObjToInt();
var receive = await DbContext.Db.Queryable<QrCode>().Where(it => it.SceneId == sceneId).FirstAsync();//從數據庫拿數據
Console.WriteLine($"是否有數據:{receive != null}");
if (receive != null)
{
switch (receive.ReceiveInfo.ReceiveType)
{
case ReceiveType.文字:
result += $"{receive.ReceiveInfo.ReceiveString}";
break;
}
}
responseMessage.Content = result;
return responseMessage;
}
CustomMessageHandler_Events重寫掃描二維碼事件
/// <summary>
/// 掃描帶參數二維碼事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override async Task<IResponseMessageBase> OnEvent_ScanRequestAsync(RequestMessageEvent_Scan requestMessage)
{
var result = await _messageService.OnEvent_ScanRequestAsync(requestMessage);
return result;
}
先用api接口創建一個二維碼,然後發佈到服務器,記得sqlite文件爲始終複製,可以正常顯示
先取消關注再掃碼,發現只回復了“掃描帶二維碼事件”這幾個字,發現原來在沒有關注的情況下會將eventkey推送到訂閱事件
因爲關注事件和掃碼二維碼事件都會去數據庫查數據,所以將共用的方法提取出來,編寫方法GetScanRequest
/// <summary>
/// 獲取掃描事件結果
/// </summary>
/// <param name="eventKey"></param>
/// <returns></returns>
private async Task<string> GetScanRequest(string eventKey)
{
Console.WriteLine($"eventKey:{eventKey}");
var result = "掃描帶二維碼事件!";
var sceneId = eventKey.ObjToInt();
var receive = await DbContext.Db.Queryable<QrCode>().Where(it => it.SceneId == sceneId).FirstAsync();//從數據庫拿數據
Console.WriteLine($"是否有數據:{receive != null}");
if (receive != null)
{
switch (receive.ReceiveInfo.ReceiveType)
{
case ReceiveType.文字:
result += $"{receive.ReceiveInfo.ReceiveString}";
break;
}
}
return result;
}
修改OnEvent_SubscribeRequestAsync方法
public async Task<IResponseMessageBase> OnEvent_SubscribeRequestAsync(RequestMessageEvent_Subscribe requestMessage)
{
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
if (!string.IsNullOrWhiteSpace(requestMessage.EventKey) && requestMessage.EventKey.StartsWith("qrscene_"))//掃二維碼事件
{
responseMessage.Content = await GetScanRequest(requestMessage.EventKey.Split("_")[1]);
}
else
{
var receives = await DbContext.Db.Queryable<MessageReceive>().ToListAsync();
//如果關鍵字搜不到,列出關鍵字
var result = new StringBuilder();
result.AppendFormat("歡迎訂閱,可以試試下面的關鍵字\r\n\r\n");
for (int i = 0; i < receives.Count; i++)
{
result.AppendFormat($"{i + 1}:{receives[i].KeyWords}\r\n");
}
responseMessage.Content = result.ToString();
}
return responseMessage;
}
OnEvent_ScanRequestAsync也改下
public async Task<IResponseMessageBase> OnEvent_ScanRequestAsync(RequestMessageEvent_Scan requestMessage)
{
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
responseMessage.Content = await GetScanRequest(requestMessage.EventKey);
return responseMessage;
}
發佈到服務器,取消關注再掃描,成功顯示數據
五、上報地理位置事件
IMessageService_Events定義接口
/// <summary>
/// 位置事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
Task<IResponseMessageBase> OnEvent_LocationRequestAsync(RequestMessageEvent_Location requestMessage);
MessageService_Events實現接口
public async Task<IResponseMessageBase> OnEvent_LocationRequestAsync(RequestMessageEvent_Location requestMessage)
{
//這裏是微信客戶端(通過微信服務器)自動發送過來的位置信息
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
var result = $"Latitude:{requestMessage.Latitude},Longitude:{requestMessage.Longitude}";
Console.WriteLine(result);
responseMessage.Content = result;//這裏寫什麼都無所謂
return responseMessage;
}
CustomMessageHandler_Events重寫位置事件
/// <summary>
/// 位置事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override async Task<IResponseMessageBase> OnEvent_LocationRequestAsync(RequestMessageEvent_Location requestMessage)
{
var result = await _messageService.OnEvent_LocationRequestAsync(requestMessage);
return result;
}
開通位置權限
測試一下,正常打印日誌
六、自定義菜單事件
6.1、創建菜單
參考自定義菜單章節
6.2、點擊事件
IMessageService_Events定義接口
/// <summary>
/// 點擊事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
Task<IResponseMessageBase> OnEvent_ClickRequestAsync(RequestMessageEvent_Click requestMessage);
MessageService_Events實現接口
public async Task<IResponseMessageBase> OnEvent_ClickRequestAsync(RequestMessageEvent_Click requestMessage)
{
Console.WriteLine("進入點擊事件");
IResponseMessageBase reponseMessage = null;
switch (requestMessage.EventKey)
{
case "V1001_TODAY_MUSIC":
{
var filePath = "~/wwwroot/Images/music.jpeg";//記得調成始終複製
var uploadResult = await MediaApi.UploadTemporaryMediaAsync(appId, UploadMediaFileType.thumb,
ServerUtility.ContentRootMapPath(filePath));
//PS:縮略圖官方沒有特別提示文件大小限制,實際測試哪怕114K也會返回文件過大的錯誤,因此儘量控制在小一點
//設置音樂信息
var strongResponseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageMusic>(requestMessage);
reponseMessage = strongResponseMessage;
strongResponseMessage.Music.Title = "天籟之音";
strongResponseMessage.Music.Description = "真的是天籟之音";
strongResponseMessage.Music.MusicUrl = "https://sdk.weixin.senparc.com/Content/music1.mp3";
strongResponseMessage.Music.HQMusicUrl = "https://sdk.weixin.senparc.com/Content/music1.mp3";
strongResponseMessage.Music.ThumbMediaId = uploadResult.thumb_media_id;
}
break;
default:
{
var strongResponseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
strongResponseMessage.Content = "您點擊了按鈕,EventKey:" + requestMessage.EventKey;
reponseMessage = strongResponseMessage;
}
break;
}
return reponseMessage;
}
CustomMessageHandler_Events重寫點擊事件
/// <summary>
/// 點擊事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override async Task<IResponseMessageBase> OnEvent_ClickRequestAsync(RequestMessageEvent_Click requestMessage)
{
var result = await _messageService.OnEvent_ClickRequestAsync(requestMessage);
return result;
}
發佈到服務器,測試下,沒毛病,這裏縮略圖不知道爲啥沒顯示,不管了,後面再看看啥問題。
七、點擊菜單跳轉鏈接時的事件推送
IMessageService_Events定義接口
/// <summary>
/// 打開網頁事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
Task<IResponseMessageBase> OnEvent_ViewRequestAsync(RequestMessageEvent_View requestMessage);
MessageService_Events實現接口
public async Task<IResponseMessageBase> OnEvent_ViewRequestAsync(RequestMessageEvent_View requestMessage)
{
Console.WriteLine("進入鏈接跳轉事件");
//說明:這條消息只作爲接收,下面的responseMessage到達不了客戶端,類似OnEvent_UnsubscribeRequest
var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(requestMessage);
responseMessage.Content = "您點擊了view按鈕,將打開網頁:" + requestMessage.EventKey;
return responseMessage;
}
CustomMessageHandler_Events重寫打開網頁事件
/// <summary>
/// 打開網頁事件
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override async Task<IResponseMessageBase> OnEvent_ViewRequestAsync(RequestMessageEvent_View requestMessage)
{
var result = await _messageService.OnEvent_ViewRequestAsync(requestMessage);
return result;
}
發佈到服務器,測試下,沒毛病。
八、本章Gitee地址鏈接
https://gitee.com/huguodong520/weixinapi/tree/%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81/