若是說用Asp.Net開發微信後臺是非主流,那麼Asp.Net Web API的微信後臺絕對是不走尋常路。php
須要說明的是,本人認爲Asp.Net Web API在開發不少不一樣的請求方法的Restful服務的時候是利器,可在開發微信後臺的時候,由於微信調用咱們這個後臺的時候來來去去就一個方法,因此Web API有點殺雞用牛刀的感受。數據庫
並且因爲Web API實際上是微軟封裝了大量的類庫,因此會致使後臺至關臃腫。因此,不建議Asp.Net Web API開發微信後臺。api
若是好奇心太強實在想試一下,能夠參看如下內容。服務器
首先登錄微信公衆平臺,在左側欄底下點擊開發者中心填寫服務器配置。微信
目前僅支持80端口,因此發佈的時候須要在iis配置清楚。微信開發
建立一個Web API項目,而後添加controller,命名爲:WechatController。app
在WechatController類下添加如下一個方法:微信公衆平臺
[HttpGet] //標明HttpGet註解屬性明確聲明這個方法僅僅接受Get請求 [ActionName("getMsg")] //ActionName註解屬性覆蓋了方法名,這個方法名將會映射到「/api/wechat/getmsg」(若是沒有修改默認的路由規則的話) public HttpResponseMessage WetChatVerify(HttpRequestMessage content) //HttpRequestMessage 和HttpResponseMessage,分別用於封裝Requset和Response { string echostr = (from kvp in content.GetQueryNameValuePairs() where kvp.Key == "echostr" select kvp.Value).FirstOrDefault(); string signature = (from kvp in content.GetQueryNameValuePairs() where kvp.Key == "signature" select kvp.Value).FirstOrDefault(); string timestamp = (from kvp in content.GetQueryNameValuePairs() where kvp.Key == "timestamp" select kvp.Value).FirstOrDefault(); string nonce = (from kvp in content.GetQueryNameValuePairs() where kvp.Key == "nonce" select kvp.Value).FirstOrDefault(); string returnStr=""; if (string.IsNullOrEmpty(echostr) | string.IsNullOrEmpty(signature) | string.IsNullOrEmpty(timestamp) | string.IsNullOrEmpty(nonce)) { returnStr="error"; } if (CheckSignature(signature, timestamp, nonce)) { log.Info("驗證成功,返回:" + echostr); returnStr=echostr; } HttpResponseMessage result = new HttpResponseMessage(); result.Content = new StringContent(returnStr); return result; }
CheckSignature的代碼以下:框架
/// <summary> /// 驗證微信簽名 /// </summary> private bool CheckSignature(string signature, string timestamp, string nonce) { String[] ArrTmp = { Common.Common.Token, timestamp, nonce }; Array.Sort(ArrTmp); String tmpStr = String.Join("", ArrTmp); tmpStr = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1").ToLower(); if (tmpStr == signature) { return true; } else { return false; } }
微信將會發送一個請求到後臺,這個請求根據你在其開發平臺填寫的信息,類型能夠是以下:curl
http://【server】/api/wechat/getMsg?signature=【signature】&echostr=【echostr】×tamp=【timestamp】&nonce=【nonce】
只要按照CheckSignature的步驟將Token以及獲取到的timestamp,nonce串聯並用sha1加密,若是所得結果跟signature一致,就原樣返回echostr,如此微信開發平臺就會認爲服務器配置成功了。
咱們知道Web API的返回類型很靈活,能夠返回string類型也能夠int類型,固然也能夠複雜一點採用上面的HttpResponseMessage類型,不過若是返回的是string類型,就有兩個問題:
一、echostr不能原樣返回,會自動給你加上雙引號,因此微信開發平臺會一直說驗證失敗,取巧一點的話,由於如今的echostr都是數字,能夠返回整形;
二、返回的文字信息若是須要換行,直接返回string類型的話,「\n」就不會看成是換行符處理而回直接在消息中顯示出來。這關乎下面的一些內容了……
驗證成功以後,再寫另一個方法來接收並處理信息。
[HttpPost] [ActionName("getMsg")] public HttpResponseMessage HandleMsgFromWeChat(HttpRequestMessage request) { List<KeyValuePair<string, string>> query = Request.GetQueryNameValuePairs().ToList(); string xmlContent = request.Content.ReadAsStringAsync().Result;
string response = string.Empty; WeChatMessage msg = WeChatHelper.GetWxMessage(xmlContent); if (msg.MsgType.Trim() == "text")//用戶發送一些文字信息 { response = 「oh my lady gaga」; } if (msg.MsgType.Trim() == "event")//點擊菜單或者新增/取消關注 { switch (msg.EventName.Trim().ToLower()) { case "click": //點擊菜單 response = "haha"; break; case "subscribe": //用戶新增關注(能夠返回一些歡迎信息之類) response = 「wawa」; break; case "unsubscribe": //用戶取消關注(通常不須要去返回什麼信息) default: break; } } HttpResponseMessage result = new HttpResponseMessage(); result.Content = new StringContent(response); return result; }
//自定義一個微信消息實體類 public class WeChatMessage { public string FromUserName { get; set; } public string ToUserName { get; set; } public string MsgType { get; set; } public string EventName { get; set; } public string EventKey { get; set; } public string Content { get; set; } } //發送圖文消息的列表項 public class ArticleItem { public string title { get; set; } public string description { get; set; } public string picurl { get; set; } public string url { get; set; } } public class WeChatHelper { /// <summary> /// 獲取微信信息。 /// </summary> /// <returns></returns> public static WeChatMessage GetWxMessage(string xmlStr) { WeChatMessage wx = new WeChatMessage(); XmlDocument xml = new XmlDocument(); xml.LoadXml(xmlStr); wx.ToUserName = xml.SelectSingleNode("xml").SelectSingleNode("ToUserName").InnerText; wx.FromUserName = xml.SelectSingleNode("xml").SelectSingleNode("FromUserName").InnerText; wx.MsgType = xml.SelectSingleNode("xml").SelectSingleNode("MsgType").InnerText; if (wx.MsgType.Trim() == "text") { wx.Content = xml.SelectSingleNode("xml").SelectSingleNode("Content").InnerText; } if (wx.MsgType.Trim() == "event") { wx.EventName = xml.SelectSingleNode("xml").SelectSingleNode("Event").InnerText; wx.EventKey = xml.SelectSingleNode("xml").SelectSingleNode("EventKey").InnerText; } return wx; } /// <summary> /// 發送文字消息 /// </summary> public static string SendTextMessage(string fromUserName,string toUserName,string content) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("<xml><ToUserName><![CDATA[{0}]]></ToUserName>", fromUserName); sb.AppendFormat("<FromUserName><![CDATA[{0}]]></FromUserName>", toUserName); sb.AppendFormat("<CreateTime>{0}</CreateTime>", DateTime.Now); sb.Append("<MsgType><![CDATA[text]]></MsgType>"); sb.AppendFormat("<Content><![CDATA[{0}]]></Content>", content); sb.Append("<FuncFlag>0</FuncFlag></xml>"); return sb.ToString(); } /// <summary> /// 發送圖文列表信息,若是列表爲空,會轉爲發送「沒有搜索到內容」的文字信息 /// </summary> public static string SendImageListMessage(string fromUserName, string toUserName, List<ArticleItem> itemList) { if (itemList == null || itemList.Count == 0) { return SendTextMessage(fromUserName, toUserName, "沒有搜索到相關內容"); } StringBuilder sb = new StringBuilder(); sb.Append("<xml>"); sb.AppendFormat("<ToUserName><![CDATA[{0}]]></ToUserName>", fromUserName); sb.AppendFormat("<FromUserName><![CDATA[{0}]]></FromUserName>", toUserName); sb.AppendFormat("<CreateTime>{0}</CreateTime>", DateTime.Now); sb.Append("<MsgType><![CDATA[news]]></MsgType>"); sb.AppendFormat("<ArticleCount>{0}</ArticleCount>", itemList.Count); sb.Append("<Articles>"); foreach (ArticleItem item in itemList) { sb.Append("<item>"); sb.AppendFormat("<Title><![CDATA[{0}]]></Title> ", item.title); sb.AppendFormat("<Description><![CDATA[{0}]]></Description>", item.description); sb.AppendFormat("<PicUrl><![CDATA[{0}]]></PicUrl>", item.picurl); sb.AppendFormat("<Url><![CDATA[{0}]]></Url>", item.url); sb.Append("</item>"); } sb.Append("</Articles>"); sb.Append("</xml>"); return sb.ToString(); } //http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token public static string GetAccessToken() { string accessToken = string.Empty; //http請求方式: GET //https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET string query=string.Format("grant_type=client_credential&appid={0}&secret={1}",Common.AppID,Common.AppSecret); string result = WebApiRequest.GetRequest("https://api.weixin.qq.com", "/cgi-bin/token", query); //result返回說明 //正常狀況下,微信會返回下述JSON數據包給公衆號: //{"access_token":"ACCESS_TOKEN","expires_in":7200} //參數 說明 //access_token 獲取到的憑證 //expires_in 憑證有效時間,單位:秒 //錯誤時微信會返回錯誤碼等信息,JSON數據包示例以下(該示例爲AppID無效錯誤): //{"errcode":40013,"errmsg":"invalid appid"} JObject jOb = JObject.Parse(result); if (jOb["access_token"] != null) { accessToken = jOb["access_token"].ToString(); ; } return accessToken; } }
以上就搭建了一個簡易的微信後臺框架了。跟微信相關的內容大概也差很少了。想擴展內容、增長數據庫支持等等,按照往常C#程序開發那樣子作就行了。