/// <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 = "投诉建议",});#endregionstring 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 DEBUGif (messageHandler.ResponseDocument != null){Log.Logger.Debug(messageHandler.ResponseDocument.ToString());}if (messageHandler.UsingEcryptMessage){//记录加密后的响应信息 Log.Logger.Debug(messageHandler.FinalResponseDocument.ToString());} #endifvar 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;}}