/// <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; } }