本文講述使用Senparc.Weixin框架來快速處理各類接收的普通消息。這裏的消息指的是傳統的微信公衆平臺消息交互,微信用戶向公衆號發送消息後,公衆號回覆消息給微信用戶。包括如下7種類型:html
1 文本消息
2 圖片消息
3 語音消息
4 視頻消息
5 小視頻消息
6 地理位置消息
7 連接消息c#
實現很是簡單,自定義一個繼承MessageHandler的類,重寫這7種類型的方法便可。注意:DefaultResponseMessage必須重寫,用於返回沒有處理過的消息類型(也能夠用於默認消息,如幫助信息等);其中全部原OnXX的抽象方法已經都改成虛方法,能夠沒必要每一個都重寫。若不重寫,默認返回DefaultResponseMessage方法中的結果。瀏覽器
下面詳細介紹實現步驟:服務器
private readonly string Token = ConfigurationManager.AppSettings["token"];//與微信公衆帳號後臺的Token設置保持一致,區分大小寫。
protected void Page_Load(object sender, EventArgs e)
{
string signature = Request["signature"];
string timestamp = Request["timestamp"];
string nonce = Request["nonce"];
string echostr = Request["echostr"];
if (Request.HttpMethod == "GET")
{
//get method - 僅在微信後臺填寫URL驗證時觸發
if (CheckSignature.Check(signature, timestamp, nonce, Token))
{
WriteContent(echostr); //返回隨機字符串則表示驗證經過
}
else
{
WriteContent("failed:" + signature + "," + CheckSignature.GetSignature(timestamp, nonce, Token) + "。" +
"若是你在瀏覽器中看到這句話,說明此地址能夠被做爲微信公衆帳號後臺的Url,請注意保持Token一致。");
}
Response.End();
}
else
{
//post method - 當有用戶想公衆帳號發送消息時觸發
if (!CheckSignature.Check(signature, timestamp, nonce, Token))
{
WriteContent("參數錯誤!");
return;
}
//設置每一個人上下文消息儲存的最大數量,防止內存佔用過多,若是該參數小於等於0,則不限制
var maxRecordCount = 10;
//自定義MessageHandler,對微信請求的詳細判斷操做都在這裏面。
var messageHandler = new CustomMessageHandler(Request.InputStream, maxRecordCount);
try
{
//測試時可開啓此記錄,幫助跟蹤數據,使用前請確保App_Data文件夾存在,且有讀寫權限。
messageHandler.RequestDocument.Save(
Server.MapPath("~/App_Data/" + DateTime.Now.Ticks + "_Request_" +
messageHandler.RequestMessage.FromUserName + ".txt"));
//執行微信處理過程
messageHandler.Execute();
//測試時可開啓,幫助跟蹤數據
messageHandler.ResponseDocument.Save(
Server.MapPath("~/App_Data/" + DateTime.Now.Ticks + "_Response_" +
messageHandler.ResponseMessage.ToUserName + ".txt"));
WriteContent(messageHandler.ResponseDocument.ToString());
return;
}
catch (Exception ex)
{
//將程序運行中發生的錯誤記錄到App_Data文件夾
using (TextWriter tw = new StreamWriter(Server.MapPath("~/App_Data/Error_" + DateTime.Now.Ticks + ".txt")))
{
tw.WriteLine(ex.Message);
tw.WriteLine(ex.InnerException.Message);
if (messageHandler.ResponseDocument != null)
{
tw.WriteLine(messageHandler.ResponseDocument.ToString());
}
tw.Flush();
tw.Close();
}
WriteContent("");
}
finally
{
Response.End();
}
}
}
private void WriteContent(string str)
{
Response.Output.Write(str);
}
1)當Get請求時,調用 CheckSignature.Check(signature, timestamp, nonce, Token) 方法驗證url接入, 詳情參考 用c#開發微信(1)服務號的服務器配置和企業號的回調模式 - url接入 (源碼下載)微信
2) 當有Post請求過來時,調用自定義MessageHandler類,對微信請求的詳細判斷操做都在這裏面。app
var messageHandler = new CustomMessageHandler(Request.InputStream, maxRecordCount);微信公衆平臺
messageHandler.Execute();框架
定義CustomMessageHandler繼承MessageHandler<MessageContext<IRequestMessageBase, IResponseMessageBase>>ide
public partial class CustomMessageHandler : MessageHandler<MessageContext<IRequestMessageBase, IResponseMessageBase>>
{
public CustomMessageHandler(Stream inputStream, int maxRecordCount = 0)
: base(inputStream, null, maxRecordCount)
{
WeixinContext.ExpireMinutes = 3;
}
public override void OnExecuting()
{
//測試MessageContext.StorageData
if (CurrentMessageContext.StorageData == null)
{
CurrentMessageContext.StorageData = 0;
}
base.OnExecuting();
}
public override void OnExecuted()
{
base.OnExecuted();
CurrentMessageContext.StorageData = ((int)CurrentMessageContext.StorageData) + 1;
}
}
咱們能夠經過重寫MessageHandler裏的這7種類型方法來處理咱們的業務,固然也能夠只重寫須要的部分類型,不須要的類型能夠不重寫,只須要定義一個統一的DefaultResponseMessagepost
public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
{
//全部沒有被處理的消息會默認返回這裏的結果
var responseMessage = this.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "這條消息來自DefaultResponseMessage。";
return responseMessage;
}
下面分別就這7種類型,各寫一個例子:
/// <summary>
/// 處理文字請求
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage)
{
//注意:下面泛型ResponseMessageText即返回給客戶端的類型,能夠根據本身的須要填寫ResponseMessageNews等不一樣類型。
var responseMessage = CreateResponseMessage<ResponseMessageText>();
var result = new StringBuilder();
result.AppendFormat("您剛纔發送了文字信息:{0}\r\n\r\n", requestMessage.Content);
if (CurrentMessageContext.RequestMessages.Count > 1)
{
result.AppendFormat("您剛纔還發送了以下消息({0}/{1}):\r\n", CurrentMessageContext.RequestMessages.Count, CurrentMessageContext.StorageData);
for (int i = CurrentMessageContext.RequestMessages.Count - 2; i >= 0; i--)
{
var historyMessage = CurrentMessageContext.RequestMessages[i];
result.AppendFormat("{0} 【{1}】{2}\r\n",
historyMessage.CreateTime.ToShortTimeString(),
historyMessage.MsgType.ToString(),
(historyMessage is RequestMessageText)
? (historyMessage as RequestMessageText).Content
: "[非文字類型]"
);
}
result.AppendLine("\r\n");
}
result.AppendFormat("若是您在{0}分鐘內連續發送消息,記錄將被自動保留(當前設置:最多記錄{1}條)。過時後記錄將會自動清除。\r\n", WeixinContext.ExpireMinutes, WeixinContext.MaxRecordCount);
result.AppendLine("\r\n");
result.AppendLine("您還能夠發送【位置】【圖片】【語音】【視頻】等類型的信息(注意是這幾種類型,不是這幾個文字),查看不一樣格式的回覆。");
responseMessage.Content = result.ToString();
return responseMessage;
}
/// <summary>
/// 處理圖片請求
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnImageRequest(RequestMessageImage requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageNews>();
responseMessage.Articles.Add(new Article()
{
Title = "您剛纔發送了圖片信息",
Description = "您發送的圖片將會顯示在邊上",
PicUrl = requestMessage.PicUrl,
Url = "http://www.hp.com"
});
responseMessage.Articles.Add(new Article()
{
Title = "第二條",
Description = "第二條帶鏈接的內容",
PicUrl = requestMessage.PicUrl,
Url = "http://www.hp.com"
});
return responseMessage;
}
/// <summary>
/// 處理語音請求
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnVoiceRequest(RequestMessageVoice requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageMusic>();
responseMessage.Music.MusicUrl = "http://www.qxuninfo.com/music.mp3";
responseMessage.Music.Title = "這裏是一條音樂消息";
responseMessage.Music.Description = "時間都去哪兒了";
return responseMessage;
}
/// <summary>
/// 處理視頻請求
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnVideoRequest(RequestMessageVideo requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "您發送了一條視頻信息,ID:" + requestMessage.MediaId;
return responseMessage;
}
/// <summary>
/// 處理小視頻請求
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnShortVideoRequest(RequestMessageShortVideo requestMessage)
{
var responseMessage = this.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "您剛纔發送的是小視頻";
return responseMessage;
}
/// <summary>
/// 處理位置請求
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnLocationRequest(RequestMessageLocation requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = string.Format("您剛纔發送了地理位置信息。Location_X:{0},Location_Y:{1},Scale:{2},標籤:{3}",
requestMessage.Location_X, requestMessage.Location_Y,
requestMessage.Scale, requestMessage.Label);
return responseMessage;
}
/// <summary>
/// 處理連接消息請求
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnLinkRequest(RequestMessageLink requestMessage)
{
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = string.Format(@"您發送了一條鏈接信息:
Title:{0}
Description:{1}
Url:{2}", requestMessage.Title, requestMessage.Description, requestMessage.Url);
return responseMessage;
}
從上面的例子中能夠看出,回覆的消息類型能夠多種多樣,不必定要跟請求的消息類型同樣。
最後整個程序結構以下:
源碼下載: http://yunpan.cn/cwsftnRtzK599 訪問密碼 4247
一樣的,使用源碼前,要先把配置文件裏的參數修改爲本身的公衆號。
部份類型效果截圖:
官方文檔: 接收普通消息