/// <summary> /// 微信請求轉發控制器 /// </summary> [RoutePrefix("weixin")] public class WeixinController : ApiController { #region 建立微信菜單 /// <summary> /// 建立微信菜單 /// </summary> /// <returns></returns> [HttpPost] [Route("menu")] public string CreateMenu() { #region 菜單結構構建 ButtonGroup bg = new ButtonGroup(); string websiteUrl = WebConfigurationManager.AppSettings["WebsiteUrl"]; bg.button.Add(new SingleViewButton() { //url = MenuHelper.GetMenuUrl("Weixin/Index"), url = string.Format("{0}/{1}", websiteUrl, WebConfigurationManager.AppSettings["mainPage"]), name = "我要借款", }); bg.button.Add(new SingleViewButton() { url = string.Format("{0}/{1}", websiteUrl, "FrontendMobile/public/view/main.html#appeal"), name = "投訴建議", }); #endregion string result = string.Empty; try { CommonApi.CreateMenu(WeixinConfig.APPID, bg); result = "菜單生成成功,通常有24小時緩存時間,也能夠直接取消關注再關注直接查看效果"; } catch (WeixinException e) { result = e.Message; } return result; } /// <summary> /// 獲取微信菜單 /// </summary> /// <returns></returns> [HttpGet] [Route("menu")] public HttpResponseMessage GetMenu() { try { GetMenuResult result = CommonApi.GetMenu(WeixinConfig.APPID); return Request.CreateResponse(HttpStatusCode.OK, result); } catch (WeixinException e) { return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message); } } /// <summary> /// 刪除菜單方法 /// </summary> /// <returns></returns> [HttpDelete] [Route("menu")] public string DeleteMenu() { try { CommonApi.DeleteMenu(WeixinConfig.APPID); return "刪除成功,通常有24小時緩存時間,也能夠直接取消關注再關注直接查看效果"; } catch (WeixinException e) { return e.Message; } } #endregion #region 微信服務器消息接收及處理 /// <summary> /// 微信後臺驗證地址(使用Get),微信後臺的「接口配置信息」的Url填寫如:http://weixin.senparc.com/weixin /// </summary> [HttpGet] [Route("")] public HttpResponseMessage Get(string signature, string timestamp, string nonce, string echostr) { if (CheckSignature.Check(signature, timestamp, nonce, WeixinConfig.TOKEN)) { var result = new StringContent(echostr, UTF8Encoding.UTF8, "application/x-www-form-urlencoded"); var response = new HttpResponseMessage { Content = result }; return response; } return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "failed:" + signature + "," + CheckSignature.GetSignature(timestamp, nonce, WeixinConfig.TOKEN) + "。" + "若是你在瀏覽器中看到這句話,說明此地址能夠被做爲微信公衆帳號後臺的Url,請注意保持Token一致。"); } /// <summary> /// 用戶發送消息後,微信平臺自動Post一個請求到這裏,並等待響應XML。 /// PS:此方法爲簡化方法,效果與OldPost一致。 /// v0.8以後的版本能夠結合Senparc.Weixin.MP.MvcExtension擴展包,使用WeixinResult,見MiniPost方法。 /// </summary> [HttpPost] [Route("")] public HttpResponseMessage Post() { var requestQueryPairs = Request.GetQueryNameValuePairs().ToDictionary(k => k.Key, v => v.Value); if (requestQueryPairs.Count == 0 || !requestQueryPairs.ContainsKey("timestamp") || !requestQueryPairs.ContainsKey("signature") || !requestQueryPairs.ContainsKey("nonce") || !CheckSignature.Check(requestQueryPairs["signature"], requestQueryPairs["timestamp"], requestQueryPairs["nonce"], WeixinConfig.TOKEN)) { return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "未受權請求"); } PostModel postModel = new PostModel { Signature = requestQueryPairs["signature"], Timestamp = requestQueryPairs["timestamp"], Nonce = requestQueryPairs["nonce"] }; postModel.Token = WeixinConfig.TOKEN; postModel.EncodingAESKey = WeixinConfig.ENCODINGAESKEY;//根據本身後臺的設置保持一致 postModel.AppId = WeixinConfig.APPID;//根據本身後臺的設置保持一致 //v4.2.2以後的版本,能夠設置每一個人上下文消息儲存的最大數量,防止內存佔用過多,若是該參數小於等於0,則不限制 var maxRecordCount = 10; //自定義MessageHandler,對微信請求的詳細判斷操做都在這裏面。 var messageHandler = new CusMessageHandler(Request.Content.ReadAsStreamAsync().Result, postModel, maxRecordCount); try { #if DEBUG Log.Logger.Debug(messageHandler.RequestDocument.ToString()); if (messageHandler.UsingEcryptMessage) { Log.Logger.Debug(messageHandler.EcryptRequestDocument.ToString()); } #endif /* 若是須要添加消息去重功能,只需打開OmitRepeatedMessage功能,SDK會自動處理。 * 收到重複消息一般是由於微信服務器沒有及時收到響應,會持續發送2-5條不等的相同內容的RequestMessage*/ messageHandler.OmitRepeatedMessage = true; //執行微信處理過程 messageHandler.Execute(); #if DEBUG if (messageHandler.ResponseDocument != null) { Log.Logger.Debug(messageHandler.ResponseDocument.ToString()); } if (messageHandler.UsingEcryptMessage) { //記錄加密後的響應信息 Log.Logger.Debug(messageHandler.FinalResponseDocument.ToString()); } #endif var resMessage = Request.CreateResponse(HttpStatusCode.OK); resMessage.Content = new StringContent(messageHandler.ResponseDocument.ToString()); resMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); return resMessage; } catch (Exception ex) { Log.Logger.Error("處理微信請求出錯:", ex); return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "處理微信請求出錯"); } } #endregion #region JSSDK相關 /// <summary> /// 獲取JSSDK參數信息 /// </summary> /// <param name="url">獲取簽名所用的URL</param> /// <returns></returns> [HttpGet] [Route("JSSDK/{*url}")] public HttpResponseMessage GetJSSDK(string url) { if (!HttpContext.Current.SideInWeixinBroswer()) { return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "請經過微信端登陸"); } try { //獲取時間戳 var timestamp = JSSDKHelper.GetTimestamp(); //獲取隨機碼 var nonceStr = JSSDKHelper.GetNoncestr(); string ticket = AccessTokenContainer.TryGetJsApiTicket(WeixinConfig.APPID, WeixinConfig.APPSECRET); //獲取簽名 var signature = JSSDKHelper.GetSignature(ticket, nonceStr, timestamp, HttpUtility.UrlDecode(url)); return Request.CreateResponse(HttpStatusCode.OK, new { appId = WeixinConfig.APPID, timestamp = timestamp, nonceStr = nonceStr, signature = signature }); } catch (Exception e) { Log.Logger.Error("獲取JSSDK信息出錯:", e); return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "獲取JSSDK信息出錯"); } } #endregion /// <summary> /// 微信菜單導航 /// </summary> /// <param name="code"></param> /// <param name="state"></param> /// <returns></returns> [HttpGet] [Route("index")] public HttpResponseMessage Index(string code, string state) { var response = Request.CreateResponse(HttpStatusCode.Redirect); try { var result = OAuthApi.GetAccessToken(WeixinConfig.APPID, WeixinConfig.APPSECRET, code); response.Headers.Location = new Uri(string.Format("{0}?openId={1}", WebConfigurationManager.AppSettings["mainPage"], result.openid), UriKind.Relative); } catch (WeixinException e) { Log.Logger.Error("OAuth2受權失敗:", e); response.Headers.Location = new Uri(WebConfigurationManager.AppSettings["mainPage"], UriKind.Relative); } return response; } }