/// <summary> /// WeixinException 日志 /// </summary> /// <param name="ex"></param> public static void WeixinExceptionLog(WeixinException ex) { if (!Config.IsDebug) { return; } LogBegin("[[WeixinException]]"); Log(ex.GetType().Name); Log("AccessTokenOrAppId:{0}", ex.AccessTokenOrAppId); Log("Message:{0}", ex.Message); Log("StackTrace:{0}", ex.StackTrace); if (ex.InnerException != null) { Log("InnerException:{0}", ex.InnerException.Message); Log("InnerException.StackTrace:{0}", ex.InnerException.StackTrace); } if (OnWeixinExceptionFunc != null) { try { OnWeixinExceptionFunc(ex); } catch { } } LogEnd(); }
/// <summary> /// WeixinException 日志 /// </summary> /// <param name="ex"></param> public static void WeixinExceptionLog(WeixinException ex) { if (!WxConfig.IsDebug) { return; } using (var traceItem = new TraceItem(LogTrace._logEndActon, "WeixinException")) { traceItem.Log(ex.GetType().Name); traceItem.Log("AccessTokenOrAppId:{0}", ex.AccessTokenOrAppId); traceItem.Log("Message:{0}", ex.Message); traceItem.Log("StackTrace:{0}", ex.StackTrace); if (ex.InnerException != null) { traceItem.Log("InnerException:{0}", ex.InnerException.Message); traceItem.Log("InnerException.StackTrace:{0}", ex.InnerException.StackTrace); } } if (OnWeixinExceptionFunc != null) { try { OnWeixinExceptionFunc(ex); } catch { } } }
public void ConfigOnWeixinExceptionFunc(WeixinException ex) { try { string desc = "发生错误" + ex.GetType().Name; string message = ex.Message; WeixinTrace.SendCustomLog(desc, desc); } catch (Exception e) { WeixinTrace.SendCustomLog("OnWeixinExceptionFunc过程错误", e.Message); } }
public void ThrowTest() { WeixinException unkonwnException = null; try { var response = MP.RequestMessageFactory.GetRequestEntity(xmlText); } catch (WeixinException ex) { unkonwnException = ex; } Assert.IsNotNull(unkonwnException); }
private WeixinMenuResponse(JObject response) { Response = response; var errcode = response.Value <int>("errcode"); HasError = (errcode != 0); if (!HasError) { } else { var errmsg = response.Value <string>("errmsg"); Error = new WeixinException(errmsg); } }
private WeixinMenuResponse(JsonDocument response) { Response = response; var errcode = response.RootElement.GetInt32("errcode"); HasError = (errcode != 0); if (!HasError) { } else { var errmsg = response.RootElement.GetString("errmsg"); Error = new WeixinException(errmsg); } }
/// <summary> /// 处理文字请求 /// </summary> /// <param name="requestMessage">请求消息</param> /// <returns></returns> public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { //说明:实际项目中这里的逻辑可以交给Service处理具体信息,参考OnLocationRequest方法或/Service/LocationSercice.cs #region 书中例子 //if (requestMessage.Content == "你好") //{ // var responseMessage = base.CreateResponseMessage<ResponseMessageNews>(); // var title = "Title"; // var description = "Description"; // var picUrl = "PicUrl"; // var url = "Url"; // responseMessage.Articles.Add(new Article() // { // Title = title, // Description = description, // PicUrl = picUrl, // Url = url // }); // return responseMessage; //} //else if (requestMessage.Content == "Senparc") //{ // //相似处理逻辑 //} //else //{ // //... //} #endregion #region 历史方法 //方法一(v0.1),此方法调用太过繁琐,已过时(但仍是所有方法的核心基础),建议使用方法二到四 //var responseMessage = // ResponseMessageBase.CreateFromRequestMessage(RequestMessage, ResponseMsgType.Text) as // ResponseMessageText; //方法二(v0.4) //var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(RequestMessage); //方法三(v0.4),扩展方法,需要using Senparc.Weixin.MP.Helpers; //var responseMessage = RequestMessage.CreateResponseMessage<ResponseMessageText>(); //方法四(v0.6+),仅适合在HandlerMessage内部使用,本质上是对方法三的封装 //注意:下面泛型ResponseMessageText即返回给客户端的类型,可以根据自己的需要填写ResponseMessageNews等不同类型。 #endregion var defaultResponseMessage = base.CreateResponseMessage <ResponseMessageText>(); var requestHandler = requestMessage.StartHandler() //关键字不区分大小写,按照顺序匹配成功后将不再运行下面的逻辑 .Keyword("约束", () => { defaultResponseMessage.Content = @"您正在进行微信内置浏览器约束判断测试。您可以: <a href=""https://sdk.weixin.senparc.com/FilterTest/"">点击这里</a>进行客户端约束测试(地址:https://sdk.weixin.senparc.com/FilterTest/),如果在微信外打开将直接返回文字。 或: <a href=""https://sdk.weixin.senparc.com/FilterTest/Redirect"">点击这里</a>进行客户端约束测试(地址:https://sdk.weixin.senparc.com/FilterTest/Redirect),如果在微信外打开将重定向一次URL。"; return(defaultResponseMessage); }). //匹配任一关键字 Keywords(new[] { "托管", "代理" }, () => { //开始用代理托管,把请求转到其他服务器上去,然后拿回结果 //甚至也可以将所有请求在DefaultResponseMessage()中托管到外部。 var dt1 = SystemTime.Now; //计时开始 var agentXml = RequestDocument.ToString(); #region 暂时转发到SDK线上Demo agentUrl = "https://sdk.weixin.senparc.com/weixin"; //agentToken = WebConfigurationManager.AppSettings["WeixinToken"];//Token //修改内容,防止死循环 var agentDoc = XDocument.Parse(agentXml); agentDoc.Root.Element("Content").SetValue("代理转发文字:" + requestMessage.Content); agentDoc.Root.Element("CreateTime").SetValue(DateTimeHelper.GetUnixDateTime(SystemTime.Now)); //修改时间,防止去重 agentDoc.Root.Element("MsgId").SetValue("123"); //防止去重 agentXml = agentDoc.ToString(); #endregion var responseXml = MessageAgent.RequestXml(this, agentUrl, agentToken, agentXml); //获取返回的XML //上面的方法也可以使用扩展方法:this.RequestResponseMessage(this,agentUrl, agentToken, RequestDocument.ToString()); /* 如果有WeiweihiKey,可以直接使用下面的这个MessageAgent.RequestWeiweihiXml()方法。 * WeiweihiKey专门用于对接www.weiweihi.com平台,获取方式见:https://www.weiweihi.com/ApiDocuments/Item/25#51 */ //var responseXml = MessageAgent.RequestWeiweihiXml(weiweihiKey, RequestDocument.ToString());//获取Weiweihi返回的XML var dt2 = SystemTime.Now; //计时结束 //转成实体。 /* 如果要写成一行,可以直接用: * responseMessage = MessageAgent.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString()); * 或 * */ var msg = string.Format("\r\n\r\n代理过程总耗时:{0}毫秒", (dt2 - dt1).Milliseconds); var agentResponseMessage = responseXml.CreateResponseMessage(this.MessageEntityEnlightener); if (agentResponseMessage is ResponseMessageText) { (agentResponseMessage as ResponseMessageText).Content += msg; } else if (agentResponseMessage is ResponseMessageNews) { (agentResponseMessage as ResponseMessageNews).Articles[0].Description += msg; } return(agentResponseMessage); //可能出现多种类型,直接在这里返回 }) .Keywords(new[] { "测试", "退出" }, () => { /* * 这是一个特殊的过程,此请求通常来自于微微嗨(http://www.weiweihi.com)的“盛派网络小助手”应用请求(https://www.weiweihi.com/User/App/Detail/1), * 用于演示微微嗨应用商店的处理过程,由于微微嗨的应用内部可以单独设置对话过期时间,所以这里通常不需要考虑对话状态,只要做最简单的响应。 */ if (defaultResponseMessage.Content == "测试") { //进入APP测试 defaultResponseMessage.Content = "您已经进入【盛派网络小助手】的测试程序,请发送任意信息进行测试。发送文字【退出】退出测试对话。10分钟内无任何交互将自动退出应用对话状态。"; } else { //退出APP测试 defaultResponseMessage.Content = "您已经退出【盛派网络小助手】的测试程序。"; } return(defaultResponseMessage); }) .Keyword("AsyncTest", () => { //异步并发测试(提供给单元测试使用) #if NET45 var begin = SystemTime.Now; int t1, t2, t3; System.Threading.ThreadPool.GetAvailableThreads(out t1, out t3); System.Threading.ThreadPool.GetMaxThreads(out t2, out t3); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(4)); var end = SystemTime.Now; var thread = System.Threading.Thread.CurrentThread; defaultResponseMessage.Content = string.Format("TId:{0}\tApp:{1}\tBegin:{2:mm:ss,ffff}\tEnd:{3:mm:ss,ffff}\tTPool:{4}", thread.ManagedThreadId, HttpContext.Current != null ? HttpContext.Current.ApplicationInstance.GetHashCode() : -1, begin, end, t2 - t1 ); #endif return(defaultResponseMessage); }) .Keyword("OPEN", () => { var openResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageNews>(); openResponseMessage.Articles.Add(new Article() { Title = "开放平台微信授权测试!", Description = @"点击进入Open授权页面。 授权之后,您的微信所收到的消息将转发到第三方(盛派网络小助手)的服务器上,并获得对应的回复。 测试完成后,您可以登陆公众号后台取消授权。", Url = "https://sdk.weixin.senparc.com/OpenOAuth/JumpToMpOAuth" }); return(openResponseMessage); }) .Keyword("错误", () => { var errorResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); //因为没有设置errorResponseMessage.Content,所以这小消息将无法正确返回。 return(errorResponseMessage); }) .Keyword("容错", () => { Thread.Sleep(4900); //故意延时1.5秒,让微信多次发送消息过来,观察返回结果 var faultTolerantResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); faultTolerantResponseMessage.Content = string.Format("测试容错,MsgId:{0},Ticks:{1}", requestMessage.MsgId, SystemTime.Now.Ticks); return(faultTolerantResponseMessage); }) .Keyword("TM", () => { var openId = requestMessage.FromUserName; var checkCode = Guid.NewGuid().ToString("n").Substring(0, 3); //为了防止openId泄露造成骚扰,这里启用验证码 TemplateMessageCollection[checkCode] = openId; defaultResponseMessage.Content = string.Format(@"新的验证码为:{0},请在网页上输入。网址:https://sdk.weixin.senparc.com/AsyncMethods", checkCode); return(defaultResponseMessage); }) .Keyword("OPENID", () => { var openId = requestMessage.FromUserName; //获取OpenId var userInfo = UserApi.Info(appId, openId, Language.zh_CN); defaultResponseMessage.Content = string.Format( "您的OpenID为:{0}\r\n昵称:{1}\r\n性别:{2}\r\n地区(国家/省/市):{3}/{4}/{5}\r\n关注时间:{6}\r\n关注状态:{7}", requestMessage.FromUserName, userInfo.nickname, (WeixinSex)userInfo.sex, userInfo.country, userInfo.province, userInfo.city, DateTimeHelper.GetDateTimeFromXml(userInfo.subscribe_time), userInfo.subscribe); return(defaultResponseMessage); }) .Keyword("EX", () => { var ex = new WeixinException("openid:" + requestMessage.FromUserName + ":这是一条测试异常信息"); //回调过程在global的ConfigWeixinTraceLog()方法中 defaultResponseMessage.Content = "请等待异步模板消息发送到此界面上(自动延时数秒)。\r\n当前时间:" + SystemTime.Now.ToString(); return(defaultResponseMessage); }) .Keyword("MUTE", () => //不回复任何消息 { //方案一: return(new SuccessResponseMessage()); //方案二: var muteResponseMessage = base.CreateResponseMessage <ResponseMessageNoResponse>(); return(muteResponseMessage); //方案三: base.TextResponseMessage = "success"; return(null); //方案四: return(null); //在 Action 中结合使用 return new FixWeixinBugWeixinResult(messageHandler); }) .Keyword("JSSDK", () => { defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/WeixinJsSdk"; return(defaultResponseMessage); }) //选择菜单,关键字:101(微信服务器端最终格式:id="s:101",content="满意") .SelectMenuKeyword("101", () => { defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!我们会一如既往为提高企业和开发者生产力而努力!"; return(defaultResponseMessage); }) //选择菜单,关键字:102(微信服务器端最终格式:id="s:102",content="一般") .SelectMenuKeyword("102", () => { defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!希望我们的服务能让您越来越满意!"; return(defaultResponseMessage); }) //选择菜单,关键字:103(微信服务器端最终格式:id="s:103",content="不满意") .SelectMenuKeyword("103", () => { defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!我们需要您的意见或建议,欢迎向我们反馈! <a href=\"https://github.com/JeffreySu/WeiXinMPSDK/issues/new\">点击这里</a>"; return(defaultResponseMessage); }) .SelectMenuKeywords(new[] { "110", "111" }, () => { defaultResponseMessage.Content = $"这里只是演示,可以同时支持多个选择菜单"; return(defaultResponseMessage); }) //Default不一定要在最后一个 .Default(() => { 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.ToString("HH:mm:ss"), historyMessage.MsgType.ToString(), (historyMessage is RequestMessageText) ? (historyMessage as RequestMessageText).Content : "[非文字类型]" ); } result.AppendLine("\r\n"); } result.AppendFormat("如果您在{0}分钟内连续发送消息,记录将被自动保留(当前设置:最多记录{1}条)。过期后记录将会自动清除。\r\n", GlobalMessageContext.ExpireMinutes, GlobalMessageContext.MaxRecordCount); result.AppendLine("\r\n"); result.AppendLine( "您还可以发送【位置】【图片】【语音】【视频】等类型的信息(注意是这几种类型,不是这几个文字),查看不同格式的回复。\r\nSDK官方地址:https://sdk.weixin.senparc.com"); defaultResponseMessage.Content = result.ToString(); return(defaultResponseMessage); }) //“一次订阅消息”接口测试 .Keyword("订阅", () => { defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/SubscribeMsg"; return(defaultResponseMessage); }) //正则表达式 .Regex(@"^\d+#\d+$", () => { defaultResponseMessage.Content = string.Format("您输入了:{0},符合正则表达式:^\\d+#\\d+$", requestMessage.Content); return(defaultResponseMessage); }); return(requestHandler.GetResponseMessage() as IResponseMessageBase); }
/// <summary> /// 微信MessageHandler事件处理,此代码的简化MessageHandler方法已由/CustomerMessageHandler/CustomerMessageHandler_Event.cs完成, /// 此方法不再更新 /// </summary> /// <param name="requestMessage"></param> /// <returns></returns> //public Senparc.Weixin.MP.Entities.ResponseMessageBase GetResponseMessage(RequestMessageEventBase requestMessage) //{ // ResponseMessageBase responseMessage = null; // switch (requestMessage.Event) // { // case Event.ENTER: // { // var strongResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>(); // strongResponseMessage.Content = "您刚才发送了ENTER事件请求。"; // responseMessage = strongResponseMessage; // break; // } // case Event.LOCATION: // throw new Exception("暂不可用"); // //break; // case Event.subscribe://订阅 // { // var strongResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>(); // //获取Senparc.Weixin.MP.dll版本信息 // var dllPath = Server.GetMapPath("~/bin/Release/netcoreapp1.1/Senparc.Weixin.MP.dll"); // var fileVersionInfo = FileVersionInfo.GetVersionInfo(dllPath); // var version = fileVersionInfo.FileVersion; // strongResponseMessage.Content = string.Format( // "欢迎关注【Senparc.Weixin.MP 微信公众平台SDK】,当前运行版本:v{0}。\r\n您还可以发送【位置】【图片】【语音】信息,查看不同格式的回复。\r\nSDK官方地址:http://sdk.weixin.senparc.com", // version); // responseMessage = strongResponseMessage; // break; // } // case Event.unsubscribe://退订 // { // //实际上用户无法收到非订阅账号的消息,所以这里可以随便写。 // //unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。 // var strongResponseMessage = requestMessage.CreateResponseMessage<ResponseMessageText>(); // strongResponseMessage.Content = "有空再来"; // responseMessage = strongResponseMessage; // break; // } // case Event.CLICK://菜单点击事件,根据自己需要修改 // //这里的CLICK在此DEMO中不会被执行到,因为已经重写了OnEvent_ClickRequest // break; // default: // throw new ArgumentOutOfRangeException(); // } // return responseMessage; //} public void ConfigOnWeixinExceptionFunc(WeixinException ex) { try { Task.Factory.StartNew(async() => { var appId = "wx758ea3c2d08895f9"; string openId = "";//收到通知的管理员OpenId var host = "A1 / AccessTokenOrAppId:" + (ex.AccessTokenOrAppId ?? "null"); string service = null; string message = ex.Message; var status = ex.GetType().Name; var remark = "\r\n这是一条通过OnWeixinExceptionFunc事件发送的异步模板消息"; string url = "https://github.com/JeffreySu/WeiXinMPSDK/blob/24aca11630bf833f6a4b6d36dce80c5b171281d3/src/Senparc.Weixin.MP.Sample/Senparc.Weixin.MP.Sample/Global.asax.cs#L246";//需要点击打开的URL var sendTemplateMessage = true; if (ex is ErrorJsonResultException) { var jsonEx = (ErrorJsonResultException)ex; service = jsonEx.Url; message = jsonEx.Message; //需要忽略的类型 var ignoreErrorCodes = new[] { ReturnCode.获取access_token时AppSecret错误或者access_token无效, ReturnCode.template_id不正确, ReturnCode.缺少access_token参数, ReturnCode.api功能未授权, ReturnCode.用户未授权该api, ReturnCode.参数错误invalid_parameter, ReturnCode.接口调用超过限制, ReturnCode.需要接收者关注, //43004 //其他更多可能的情况 }; if (ignoreErrorCodes.Contains(jsonEx.JsonResult.errcode)) { sendTemplateMessage = false;//防止无限递归,这种请款那个下不发送消息 } //TODO:防止更多的接口自身错误导致的无限递归。 } else { if (ex.Message.StartsWith("openid:")) { openId = ex.Message.Split(':')[1];//发送给指定OpenId } service = "WeixinException"; message = ex.Message; } if (sendTemplateMessage) { int sleepSeconds = 3; Thread.Sleep(sleepSeconds * 1000); var data = new TemplateMessage.WeixinTemplate_ExceptionAlert(string.Format("微信发生异常(延时{0}秒)", sleepSeconds), host, service, status, message, remark); //修改OpenId、启用以下代码后即可收到模板消息 if (!string.IsNullOrEmpty(openId)) { var result = await Senparc.Weixin.MP.AdvancedAPIs.TemplateApi.SendTemplateMessageAsync(appId, openId, data.TemplateId, url, data); } } }); } catch (Exception e) { Senparc.Weixin.WeixinTrace.SendCustomLog("OnWeixinExceptionFunc过程错误", e.Message); } }
/// <summary> /// 处理文字请求 /// </summary> /// <returns></returns> public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { //说明:实际项目中这里的逻辑可以交给Service处理具体信息 //参考OnLocationRequest方法或 /Service/LocationSercice.cs var defaultResponseMessage = base.CreateResponseMessage <ResponseMessageText>(); var requestHandler = requestMessage.StartHandler() //关键字不区分大小写,按照顺序匹配成功后将不再运行下面的逻辑 .Keyword("约束", () => { defaultResponseMessage.Content = @"您正在进行微信内置浏览器约束判断测试。 您可以:<a href=""http://sdk.weixin.senparc.com/FilterTest/"">点击这里</a> 进行客户端约束测试(地址:http://sdk.weixin.senparc.com/FilterTest/), 如果在微信外打开将直接返回文字。 或:<a href=""http://sdk.weixin.senparc.com/FilterTest/Redirect"">点击这里</a> 进行客户端约束测试(地址:http://sdk.weixin.senparc.com/FilterTest/Redirect), 如果在微信外打开将重定向一次URL。"; return(defaultResponseMessage); }). //匹配任一关键字 Keywords(new[] { "托管", "代理" }, () => { //开始用代理托管,把请求转到其他服务器上去,然后拿回结果 //甚至也可以将所有请求在DefaultResponseMessage()中托管到外部。 DateTime dt1 = DateTime.Now; //计时开始 var agentXml = RequestDocument.ToString(); #region 暂时转发到SDK线上Demo agentUrl = "http://sdk.weixin.senparc.com/weixin"; //agentToken = WebConfigurationManager.AppSettings["WeixinToken"];//Token //修改内容,防止死循环 var agentDoc = XDocument.Parse(agentXml); agentDoc.Root.Element("Content").SetValue("代理转发文字:" + requestMessage.Content); agentDoc.Root.Element("CreateTime").SetValue(DateTimeHelper.GetWeixinDateTime(DateTime.Now)); //修改时间,防止去重 agentDoc.Root.Element("MsgId").SetValue("123"); //防止去重 agentXml = agentDoc.ToString(); #endregion var responseXml = MessageAgent.RequestXml(this, agentUrl, agentToken, agentXml); //获取返回的XML //上面的方法也可以使用扩展方法:this.RequestResponseMessage(this,agentUrl, agentToken, RequestDocument.ToString()); /* 如果有WeiweihiKey,可以直接使用下面的这个MessageAgent.RequestWeiweihiXml()方法。 * WeiweihiKey专门用于对接www.weiweihi.com平台,获取方式见:https://www.weiweihi.com/ApiDocuments/Item/25#51 */ //var responseXml = MessageAgent.RequestWeiweihiXml(weiweihiKey, RequestDocument.ToString());//获取Weiweihi返回的XML DateTime dt2 = DateTime.Now; //计时结束 //转成实体。 /* 如果要写成一行,可以直接用: * responseMessage = MessageAgent.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString()); * 或 * */ var msg = string.Format("\r\n\r\n代理过程总耗时:{0}毫秒", (dt2 - dt1).Milliseconds); var agentResponseMessage = responseXml.CreateResponseMessage(); if (agentResponseMessage is ResponseMessageText) { (agentResponseMessage as ResponseMessageText).Content += msg; } else if (agentResponseMessage is ResponseMessageNews) { (agentResponseMessage as ResponseMessageNews).Articles[0].Description += msg; } return(agentResponseMessage); //可能出现多种类型,直接在这里返回 }) .Keywords(new[] { "退出" }, () => { defaultResponseMessage.Content = "您已经退出【威尔汽车租赁】的测试程序。"; return(defaultResponseMessage); }) .Keyword("OPEN", () => { var openResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageNews>(); openResponseMessage.Articles.Add(new Article() { Title = "开放平台微信授权测试", Description = @"点击进入Open授权页面。授权之后,您的微信所收到的消息将转发到第三方(威尔汽车租赁)的服务器上,并获得对应的回复。测试完成后,您可以登陆公众号后台取消授权。", Url = "http://sdk.weixin.senparc.com/OpenOAuth/JumpToMpOAuth" }); return(openResponseMessage); }) .Keyword("错误", () => { var errorResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); //因为没有设置errorResponseMessage.Content,所以这小消息将无法正确返回。 return(errorResponseMessage); }) .Keyword("容错", () => { Thread.Sleep(4900); //故意延时1.5秒,让微信多次发送消息过来,观察返回结果 var faultTolerantResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); faultTolerantResponseMessage.Content = string.Format("测试容错,MsgId:{0},Ticks:{1}", requestMessage.MsgId, DateTime.Now.Ticks); return(faultTolerantResponseMessage); }) .Keyword("TM", () => { var openId = requestMessage.FromUserName; var checkCode = Guid.NewGuid().ToString("n").Substring(0, 3); //为了防止openId泄露造成骚扰,这里启用验证码 TemplateMessageCollection[checkCode] = openId; defaultResponseMessage.Content = string.Format(@"新的验证码为:{0},请在网页上输入。网址:http://sdk.weixin.senparc.com/AsyncMethods", checkCode); return(defaultResponseMessage); }) .Keyword("OPENID", () => { var openId = requestMessage.FromUserName; //获取OpenId var userInfo = UserApi.Info(appId, openId, Language.zh_CN); defaultResponseMessage.Content = string.Format( "您的OpenID为:{0}\r\n昵称:{1}\r\n性别:{2}\r\n地区(国家/省/市):{3}/{4}/{5}\r\n关注时间:{6}\r\n关注状态:{7}", requestMessage.FromUserName, userInfo.nickname, (Sex)userInfo.sex, userInfo.country, userInfo.province, userInfo.city, DateTimeHelper.GetDateTimeFromXml(userInfo.subscribe_time), userInfo.subscribe); return(defaultResponseMessage); }) .Keyword("EX", () => { var ex = new WeixinException("openid:" + requestMessage.FromUserName + ":这是一条测试异常信息"); //回调过程在global的ConfigWeixinTraceLog()方法中 defaultResponseMessage.Content = "请等待异步模板消息发送到此界面上(自动延时数秒)。\r\n当前时间:" + DateTime.Now.ToString(); return(defaultResponseMessage); }) .Keyword("MUTE", () => //不回复任何消息 { //方案一: return(new SuccessResponseMessage()); //方案二: var muteResponseMessage = base.CreateResponseMessage <ResponseMessageNoResponse>(); return(muteResponseMessage); //方案三: base.TextResponseMessage = "success"; return(null); }) .Keyword("JSSDK", () => { defaultResponseMessage.Content = "点击打开:http://sdk.weixin.senparc.com/WeixinJsSdk"; return(defaultResponseMessage); }) //Default不一定要在最后一个 .Default(() => { 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.ToString("HH:mm:ss"), 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( "您还可以发送【位置】【图片】【语音】【视频】等类型的信息(注意是这几种类型,不是这几个文字),查看不同格式的回复。\r\nSDK官方地址:http://sdk.weixin.senparc.com"); defaultResponseMessage.Content = result.ToString(); return(defaultResponseMessage); }) //“一次订阅消息”接口测试 .Keyword("订阅", () => { defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/SubscribeMsg"; return(defaultResponseMessage); }) //正则表达式 .Regex(@"^\d+#\d+$", () => { defaultResponseMessage.Content = string.Format("您输入了:{0},符合正则表达式:^\\d+#\\d+$", requestMessage.Content); return(defaultResponseMessage); }); return(requestHandler.GetResponseMessage() as IResponseMessageBase); }
public async Task ConfigOnWeixinExceptionFunc(WeixinException ex) { Senparc.Weixin.WeixinTrace.SendCustomLog("进入 ConfigOnWeixinExceptionFunc() 方法", ex.Message); try { var appId = Config.SenparcWeixinSetting.WeixinAppId; string openId = "olPjZjsXuQPJoV0HlruZkNzKc91E";//收到通知的管理员OpenId var host = "A1 / AccessTokenOrAppId:" + (ex.AccessTokenOrAppId ?? "null"); string service = null; string message = ex.Message; var status = ex.GetType().Name; var remark = "\r\n这是一条通过OnWeixinExceptionFunc事件发送的异步模板消息"; string url = "https://github.com/JeffreySu/WeiXinMPSDK/blob/master/Samples/netcore3.0-mvc/Senparc.Weixin.Sample.NetCore3/Startup.cs#L410";//需要点击打开的URL var sendTemplateMessage = true; if (ex is ErrorJsonResultException) { var jsonEx = (ErrorJsonResultException)ex; service = $"{jsonEx.JsonResult?.errcode}:{jsonEx.JsonResult?.errmsg} - {jsonEx.Url?.Replace("https://api.weixin.qq.com/cgi-bin", "ApiUrl")}".Substring(0, 30); message = jsonEx.Message; //需要忽略的类型 var ignoreErrorCodes = new[] { ReturnCode.获取access_token时AppSecret错误或者access_token无效, ReturnCode.access_token超时, ReturnCode.template_id不正确, ReturnCode.调用接口的IP地址不在白名单中, //比较容易出现,需要注意! ReturnCode.缺少access_token参数, ReturnCode.回复时间超过限制, ReturnCode.api功能未授权, ReturnCode.用户未授权该api, ReturnCode.参数错误invalid_parameter, ReturnCode.接口调用超过限制, ReturnCode.需要接收者关注, //43004 ReturnCode.超出响应数量限制, //43004 - out of response count limit,一般只允许连续接收20条客服消息 ReturnCode.合法的APPID //其他更多可能的情况 }; if (ignoreErrorCodes.Contains(jsonEx.JsonResult.errcode)) { if (jsonEx.JsonResult.errcode == ReturnCode.调用接口的IP地址不在白名单中) { SenparcTrace.SendCustomLog("无法发送模板消息", "IP 未设置到白名单"); } sendTemplateMessage = false;//防止无限递归,这种请款那个下不发送消息 } //TODO:防止更多的接口自身错误导致的无限递归。 } else { if (ex.Message.StartsWith("openid:")) { openId = ex.Message.Split(':')[1];//发送给指定OpenId } service = "WeixinException"; message = ex.Message; } if (sendTemplateMessage) // DPBMARK MP { int sleepSeconds = 3; Thread.Sleep(sleepSeconds * 1000); var data = new WeixinTemplate_ExceptionAlert(string.Format("微信发生异常(延时{0}秒)", sleepSeconds), host, service, status, message, remark); //修改OpenId、启用以下代码后即可收到模板消息 if (!string.IsNullOrEmpty(openId)) { var result = Senparc.Weixin.MP.AdvancedAPIs.TemplateApi.SendTemplateMessageAsync(appId, openId, data.TemplateId, url, data); Task.WaitAll(new[] { result }); if (result.IsFaulted) { Senparc.Weixin.WeixinTrace.SendCustomLog("OnWeixinExceptionFunc过程模板消息发送异常", result.Exception?.Message + "\r\n" + result.Exception?.StackTrace); } } } // DPBMARK_END } catch (Exception e) { Senparc.Weixin.WeixinTrace.SendCustomLog("OnWeixinExceptionFunc过程错误", e.Message); } }
/// <summary> /// 获取页面提交的get和post参数 /// 注意:.NetCore环境必须传入HttpContext实例,不能传Null,这个接口调试特别困难,千万别出错! /// </summary> /// <param name="httpContext"></param> public ResponseHandler(HttpContext httpContext) { #if NET45 Parameters = new Hashtable(); this.HttpContext = httpContext ?? HttpContext.Current; NameValueCollection collection; //post data if (this.HttpContext.Request.HttpMethod == "POST") { collection = this.HttpContext.Request.Form; foreach (string k in collection) { string v = (string)collection[k]; this.SetParameter(k, v); } } //query string collection = this.HttpContext.Request.QueryString; foreach (string k in collection) { string v = (string)collection[k]; this.SetParameter(k, v); } if (this.HttpContext.Request.InputStream.Length > 0) { XmlDocument xmlDoc = new Senparc.CO2NET.ExtensionEntities.XmlDocument_XxeFixed(); xmlDoc.XmlResolver = null; xmlDoc.Load(this.HttpContext.Request.InputStream); XmlNode root = xmlDoc.SelectSingleNode("xml"); XmlNodeList xnl = root.ChildNodes; foreach (XmlNode xnf in xnl) { this.SetParameter(xnf.Name, xnf.InnerText); } } #else Parameters = new Hashtable(); //#if NETSTANDARD2_0 || NETSTANDARD2_1 // HttpContext = httpContext ?? throw new WeixinException(".net standard 2.0 环境必须传入HttpContext的实例"); //#else var serviceProvider = SenparcDI.GetServiceProvider(); HttpContext = httpContext ?? serviceProvider.GetService <IHttpContextAccessor>()?.HttpContext; //#endif //post data if (HttpContext.Request.Method.ToUpper() == "POST" && HttpContext.Request.HasFormContentType) { foreach (var k in HttpContext.Request.Form) { SetParameter(k.Key, k.Value[0]); } } //query string foreach (var k in HttpContext.Request.Query) { SetParameter(k.Key, k.Value[0]); } if (HttpContext.Request.ContentLength > 0) { var xmlDoc = new Senparc.CO2NET.ExtensionEntities.XmlDocument_XxeFixed(); xmlDoc.XmlResolver = null; //xmlDoc.Load(HttpContext.Request.Body); try { var requestStream = HttpContext.Request.GetRequestMemoryStream(); requestStream.Seek(0, System.IO.SeekOrigin.Begin); xmlDoc.Load(requestStream); //using (var reader = new System.IO.StreamReader(HttpContext.Request.Body)) //{ // xmlDoc.Load(reader); //} var root = xmlDoc.SelectSingleNode("xml"); foreach (XmlNode xnf in root.ChildNodes) { SetParameter(xnf.Name, xnf.InnerText); } } catch (Exception ex) { var weixinEx = new WeixinException("微信支付ResponseHandler错误", ex, true); Senparc.Weixin.WeixinTrace.WeixinExceptionLog(weixinEx); } } #endif }
/// <summary> /// 处理文字请求 /// </summary> /// <returns></returns> public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { //TODO:这里的逻辑可以交给Service处理具体信息,参考OnLocationRequest方法或/Service/LocationSercice.cs #region 书中例子 //if (requestMessage.Content == "你好") //{ // var responseMessage = base.CreateResponseMessage<ResponseMessageNews>(); // var title = "Title"; // var description = "Description"; // var picUrl = "PicUrl"; // var url = "Url"; // responseMessage.Articles.Add(new Article() // { // Title = title, // Description = description, // PicUrl = picUrl, // Url = url // }); // return responseMessage; //} //else if (requestMessage.Content == "Senparc") //{ // //相似处理逻辑 //} //else //{ // //... //} #endregion //方法一(v0.1),此方法调用太过繁琐,已过时(但仍是所有方法的核心基础),建议使用方法二到四 //var responseMessage = // ResponseMessageBase.CreateFromRequestMessage(RequestMessage, ResponseMsgType.Text) as // ResponseMessageText; //方法二(v0.4) //var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(RequestMessage); //方法三(v0.4),扩展方法,需要using Senparc.Weixin.MP.Helpers; //var responseMessage = RequestMessage.CreateResponseMessage<ResponseMessageText>(); //方法四(v0.6+),仅适合在HandlerMessage内部使用,本质上是对方法三的封装 //注意:下面泛型ResponseMessageText即返回给客户端的类型,可以根据自己的需要填写ResponseMessageNews等不同类型。 var responseMessage = base.CreateResponseMessage <ResponseMessageText>(); if (requestMessage.Content == null) { } else if (requestMessage.Content == "约束") { responseMessage.Content = @"您正在进行微信内置浏览器约束判断测试。您可以: <a href=""http://sdk.weixin.senparc.com/FilterTest/"">点击这里</a>进行客户端约束测试(地址:http://sdk.weixin.senparc.com/FilterTest/),如果在微信外打开将直接返回文字。 或: <a href=""http://sdk.weixin.senparc.com/FilterTest/Redirect"">点击这里</a>进行客户端约束测试(地址:http://sdk.weixin.senparc.com/FilterTest/Redirect),如果在微信外打开将重定向一次URL。"; } else if (requestMessage.Content == "托管" || requestMessage.Content == "代理") { //开始用代理托管,把请求转到其他服务器上去,然后拿回结果 //甚至也可以将所有请求在DefaultResponseMessage()中托管到外部。 DateTime dt1 = DateTime.Now; //计时开始 var agentXml = RequestDocument.ToString(); #region 暂时转发到SDK线上Demo agentUrl = "http://sdk.weixin.senparc.com/weixin"; agentToken = WebConfigurationManager.AppSettings["WeixinToken"];//Token //修改内容,防止死循环 var agentDoc = XDocument.Parse(agentXml); agentDoc.Root.Element("Content").SetValue("代理转发文字:" + requestMessage.Content); agentDoc.Root.Element("CreateTime").SetValue(DateTimeHelper.GetWeixinDateTime(DateTime.Now)); //修改时间,防止去重 agentDoc.Root.Element("MsgId").SetValue("123"); //防止去重 agentXml = agentDoc.ToString(); #endregion var responseXml = MessageAgent.RequestXml(this, agentUrl, agentToken, agentXml); //获取返回的XML //上面的方法也可以使用扩展方法:this.RequestResponseMessage(this,agentUrl, agentToken, RequestDocument.ToString()); /* 如果有WeiweihiKey,可以直接使用下面的这个MessageAgent.RequestWeiweihiXml()方法。 * WeiweihiKey专门用于对接www.weiweihi.com平台,获取方式见:https://www.weiweihi.com/ApiDocuments/Item/25#51 */ //var responseXml = MessageAgent.RequestWeiweihiXml(weiweihiKey, RequestDocument.ToString());//获取Weiweihi返回的XML DateTime dt2 = DateTime.Now; //计时结束 //转成实体。 /* 如果要写成一行,可以直接用: * responseMessage = MessageAgent.RequestResponseMessage(agentUrl, agentToken, RequestDocument.ToString()); * 或 * */ var msg = string.Format("\r\n\r\n代理过程总耗时:{0}毫秒", (dt2 - dt1).Milliseconds); var agentResponseMessage = responseXml.CreateResponseMessage(); if (agentResponseMessage is ResponseMessageText) { (agentResponseMessage as ResponseMessageText).Content += msg; } else if (agentResponseMessage is ResponseMessageNews) { (agentResponseMessage as ResponseMessageNews).Articles[0].Description += msg; } return(agentResponseMessage);//可能出现多种类型,直接在这里返回 } else if (requestMessage.Content == "测试" || requestMessage.Content == "退出") { /* * 这是一个特殊的过程,此请求通常来自于微微嗨(http://www.weiweihi.com)的“盛派网络小助手”应用请求(https://www.weiweihi.com/User/App/Detail/1), * 用于演示微微嗨应用商店的处理过程,由于微微嗨的应用内部可以单独设置对话过期时间,所以这里通常不需要考虑对话状态,只要做最简单的响应。 */ if (requestMessage.Content == "测试") { //进入APP测试 responseMessage.Content = "您已经进入【盛派网络小助手】的测试程序,请发送任意信息进行测试。发送文字【退出】退出测试对话。10分钟内无任何交互将自动退出应用对话状态。"; } else { //退出APP测试 responseMessage.Content = "您已经退出【盛派网络小助手】的测试程序。"; } } else if (requestMessage.Content == "AsyncTest") { //异步并发测试(提供给单元测试使用) DateTime begin = DateTime.Now; int t1, t2, t3; System.Threading.ThreadPool.GetAvailableThreads(out t1, out t3); System.Threading.ThreadPool.GetMaxThreads(out t2, out t3); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(4)); DateTime end = DateTime.Now; var thread = System.Threading.Thread.CurrentThread; responseMessage.Content = string.Format("TId:{0}\tApp:{1}\tBegin:{2:mm:ss,ffff}\tEnd:{3:mm:ss,ffff}\tTPool:{4}", thread.ManagedThreadId, HttpContext.Current != null ? HttpContext.Current.ApplicationInstance.GetHashCode() : -1, begin, end, t2 - t1 ); } else if (requestMessage.Content.ToUpper() == "OPEN") { var openResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageNews>(); openResponseMessage.Articles.Add(new Article() { Title = "开放平台微信授权测试", Description = @"点击进入Open授权页面。 授权之后,您的微信所收到的消息将转发到第三方(盛派网络小助手)的服务器上,并获得对应的回复。 测试完成后,您可以登陆公众号后台取消授权。", Url = "http://sdk.weixin.senparc.com/OpenOAuth/JumpToMpOAuth" }); return(openResponseMessage); } else if (requestMessage.Content == "错误") { var errorResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); //因为没有设置errorResponseMessage.Content,所以这小消息将无法正确返回。 return(errorResponseMessage); } else if (requestMessage.Content == "容错") { Thread.Sleep(1500);//故意延时1.5秒,让微信多次发送消息过来,观察返回结果 var faultTolerantResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); faultTolerantResponseMessage.Content = string.Format("测试容错,MsgId:{0},Ticks:{1}", requestMessage.MsgId, DateTime.Now.Ticks); return(faultTolerantResponseMessage); } else if (requestMessage.Content.ToUpper() == "TM")//异步模板消息设置 { var openId = requestMessage.FromUserName; var checkCode = Guid.NewGuid().ToString("n").Substring(0, 3);//为了防止openId泄露造成骚扰,这里启用验证码 TemplateMessageCollection[checkCode] = openId; responseMessage.Content = string.Format(@"新的验证码为:{0},请在网页上输入。网址:http://sdk.weixin.senparc.com/AsyncMethods", checkCode); } else if (requestMessage.Content.ToUpper() == "OPENID") //返回OpenId及用户信息 { var openId = requestMessage.FromUserName; //获取OpenId var userInfo = AdvancedAPIs.UserApi.Info(appId, openId, Language.zh_CN); responseMessage.Content = string.Format( "您的OpenID为:{0}\r\n昵称:{1}\r\n性别:{2}\r\n地区(国家/省/市):{3}/{4}/{5}\r\n关注时间:{6}\r\n关注状态:{7}", requestMessage.FromUserName, userInfo.nickname, (Sex)userInfo.sex, userInfo.country, userInfo.province, userInfo.city, DateTimeHelper.GetDateTimeFromXml(userInfo.subscribe_time), userInfo.subscribe); } else if (requestMessage.Content.ToUpper() == "EX") { var ex = new WeixinException("openid:" + requestMessage.FromUserName + ":这是一条测试异常信息");//回调过程在global的ConfigWeixinTraceLog()方法中 responseMessage.Content = "请等待异步模板消息发送到此界面上(自动延时数秒)。\r\n当前时间:" + DateTime.Now.ToString(); } else if (requestMessage.Content.ToUpper() == "MUTE") { return(new SuccessResponseMessage()); base.TextResponseMessage = "success"; responseMessage = null; } else { 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( "您还可以发送【位置】【图片】【语音】【视频】等类型的信息(注意是这几种类型,不是这几个文字),查看不同格式的回复。\r\nSDK官方地址:http://sdk.weixin.senparc.com"); responseMessage.Content = result.ToString(); } return(responseMessage); }
/// <summary> /// 处理文字请求 /// </summary> /// <param name="requestMessage">请求消息</param> /// <returns></returns> public override IResponseMessageBase OnTextRequest(RequestMessageText requestMessage) { //说明:实际项目中这里的逻辑可以交给Service处理具体信息,参考OnLocationRequest方法或/Service/LocationSercice.cs #region 书中例子 //if (requestMessage.Content == "你好") //{ // var responseMessage = base.CreateResponseMessage<ResponseMessageNews>(); // var title = "Title"; // var description = "Description"; // var picUrl = "PicUrl"; // var url = "Url"; // responseMessage.Articles.Add(new Article() // { // Title = title, // Description = description, // PicUrl = picUrl, // Url = url // }); // return responseMessage; //} //else if (requestMessage.Content == "Senparc") //{ // //相似处理逻辑 //} //else //{ // //... //} #endregion #region 历史方法 //方法一(v0.1),此方法调用太过繁琐,已过时(但仍是所有方法的核心基础),建议使用方法二到四 //var responseMessage = // ResponseMessageBase.CreateFromRequestMessage(RequestMessage, ResponseMsgType.Text) as // ResponseMessageText; //方法二(v0.4) //var responseMessage = ResponseMessageBase.CreateFromRequestMessage<ResponseMessageText>(RequestMessage); //方法三(v0.4),扩展方法,需要using Senparc.Weixin.MP.Helpers; //var responseMessage = RequestMessage.CreateResponseMessage<ResponseMessageText>(); //方法四(v0.6+),仅适合在HandlerMessage内部使用,本质上是对方法三的封装 //注意:下面泛型ResponseMessageText即返回给客户端的类型,可以根据自己的需要填写ResponseMessageNews等不同类型。 #endregion var defaultResponseMessage = base.CreateResponseMessage <ResponseMessageText>(); var requestHandler = requestMessage.StartHandler() //关键字不区分大小写,按照顺序匹配成功后将不再运行下面的逻辑 .Keyword("约束", () => { defaultResponseMessage.Content = @"您正在进行微信内置浏览器约束判断测试。您可以: <a href=""https://sdk.weixin.senparc.com/FilterTest/"">点击这里</a>进行客户端约束测试(地址:https://sdk.weixin.senparc.com/FilterTest/),如果在微信外打开将直接返回文字。 或: <a href=""https://sdk.weixin.senparc.com/FilterTest/Redirect"">点击这里</a>进行客户端约束测试(地址:https://sdk.weixin.senparc.com/FilterTest/Redirect),如果在微信外打开将重定向一次URL。"; return(defaultResponseMessage); }) //匹配任一关键字 .Keywords(new[] { "测试", "退出" }, () => { /* * 这是一个特殊的过程,此请求通常来自于微微嗨(http://www.weiweihi.com)的“盛派网络小助手”应用请求(https://www.weiweihi.com/User/App/Detail/1), * 用于演示微微嗨应用商店的处理过程,由于微微嗨的应用内部可以单独设置对话过期时间,所以这里通常不需要考虑对话状态,只要做最简单的响应。 */ if (requestMessage.Content == "测试") { //进入APP测试 defaultResponseMessage.Content = "您已经进入测试程序,请发送任意信息进行测试。发送文字【退出】退出测试对话。10分钟内无任何交互将自动退出应用对话状态。"; } else { //退出APP测试 defaultResponseMessage.Content = "您已经退出测试程序。"; } return(defaultResponseMessage); }) .Keyword("容错", () => { Thread.Sleep(4900); //故意延时1.5秒,让微信多次发送消息过来,观察返回结果 var faultTolerantResponseMessage = requestMessage.CreateResponseMessage <ResponseMessageText>(); faultTolerantResponseMessage.Content = string.Format("测试容错,MsgId:{0},Ticks:{1}", requestMessage.MsgId, SystemTime.Now.Ticks); return(faultTolerantResponseMessage); }) .Keyword("TM", () => { var openId = requestMessage.FromUserName; var checkCode = Guid.NewGuid().ToString("n").Substring(0, 3); //为了防止openId泄露造成骚扰,这里启用验证码 TemplateMessageCollection[checkCode] = openId; defaultResponseMessage.Content = string.Format(@"新的验证码为:{0},请在网页上输入。http://www.baidu.com", checkCode); return(defaultResponseMessage); }) .Keyword("OPENID", () => { var openId = requestMessage.FromUserName; //获取OpenId var userInfo = Senparc.Weixin.MP.AdvancedAPIs.UserApi.Info(appId, openId); defaultResponseMessage.Content = string.Format( "您的OpenID为:{0}\r\n昵称:{1}\r\n性别:{2}\r\n地区(国家/省/市):{3}/{4}/{5}\r\n关注时间:{6}\r\n关注状态:{7}", requestMessage.FromUserName, userInfo.nickname, (WeixinSex)userInfo.sex, userInfo.country, userInfo.province, userInfo.city, DateTimeHelper.GetDateTimeFromXml(userInfo.subscribe_time), userInfo.subscribe); return(defaultResponseMessage); }) .Keyword("EX", () => { var ex = new WeixinException("openid:" + requestMessage.FromUserName + ":这是一条测试异常信息"); //回调过程在global的ConfigWeixinTraceLog()方法中 defaultResponseMessage.Content = "请等待异步模板消息发送到此界面上(自动延时数秒)。\r\n当前时间:" + SystemTime.Now.ToString(); return(defaultResponseMessage); }) .Keyword("MUTE", () => //不回复任何消息 { //方案一: return(new SuccessResponseMessage()); //方案二: var muteResponseMessage = base.CreateResponseMessage <ResponseMessageNoResponse>(); return(muteResponseMessage); //方案三: base.TextResponseMessage = "success"; return(null); //方案四: return(null); //在 Action 中结合使用 return new FixWeixinBugWeixinResult(messageHandler); }) .Keyword("JSSDK", () => { defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/WeixinJsSdk"; return(defaultResponseMessage); }) ////选择菜单,关键字:101(微信服务器端最终格式:id="s:101",content="满意") //.SelectMenuKeyword("101", () => //{ // defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!我们会一如既往为提高企业和开发者生产力而努力!"; // return defaultResponseMessage; //}) ////选择菜单,关键字:102(微信服务器端最终格式:id="s:102",content="一般") //.SelectMenuKeyword("102", () => //{ // defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!希望我们的服务能让您越来越满意!"; // return defaultResponseMessage; //}) ////选择菜单,关键字:103(微信服务器端最终格式:id="s:103",content="不满意") //.SelectMenuKeyword("103", () => //{ // defaultResponseMessage.Content = $"感谢您的评价({requestMessage.Content})!我们需要您的意见或建议,欢迎向我们反馈! <a href=\"https://github.com/JeffreySu/WeiXinMPSDK/issues/new\">点击这里</a>"; // return defaultResponseMessage; //}) //.SelectMenuKeywords(new[] { "110", "111" }, () => //{ // defaultResponseMessage.Content = $"这里只是演示,可以同时支持多个选择菜单"; // return defaultResponseMessage; //}) //Default不一定要在最后一个 .Default(() => { 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.ToString("HH:mm:ss"), historyMessage.MsgType.ToString(), (historyMessage is RequestMessageText) ? (historyMessage as RequestMessageText).Content : "[非文字类型]" ); } result.AppendLine("\r\n"); } result.AppendFormat("如果您在{0}分钟内连续发送消息,记录将被自动保留(当前设置:最多记录{1}条)。过期后记录将会自动清除。\r\n", GlobalMessageContext.ExpireMinutes, GlobalMessageContext.MaxRecordCount); result.AppendLine("\r\n"); result.AppendLine( "您还可以发送【位置】【图片】【语音】【视频】等类型的信息(注意是这几种类型,不是这几个文字),查看不同格式的回复。\r\n"); defaultResponseMessage.Content = result.ToString(); return(defaultResponseMessage); }) //“一次订阅消息”接口测试 //.Keyword("订阅", () => //{ // defaultResponseMessage.Content = "点击打开:https://sdk.weixin.senparc.com/SubscribeMsg"; // return defaultResponseMessage; //}) //正则表达式 .Regex(@"^\d+#\d+$", () => { defaultResponseMessage.Content = string.Format("您输入了:{0},符合正则表达式:^\\d+#\\d+$", requestMessage.Content); return(defaultResponseMessage); }); return(requestHandler.GetResponseMessage() as IResponseMessageBase); }
public void ConfigOnWeixinExceptionFunc(WeixinException ex) { Senparc.Weixin.WeixinTrace.SendCustomLog("进入 ConfigOnWeixinExceptionFunc() 方法", ex.Message); try { Task.Factory.StartNew(async() => { var appId = Config.SenparcWeixinSetting.WeixinAppId; string openId = "";//收到通知的管理员OpenId var host = "A1 / AccessTokenOrAppId:" + (ex.AccessTokenOrAppId ?? "null"); string service = null; string message = ex.Message; var status = ex.GetType().Name; var remark = "\r\n这是一条通过OnWeixinExceptionFunc事件发送的异步模板消息"; string url = "https://github.com/JeffreySu/WeiXinMPSDK/blob/24aca11630bf833f6a4b6d36dce80c5b171281d3/src/Senparc.Weixin.MP.Sample/Senparc.Weixin.MP.Sample/Global.asax.cs#L246";//需要点击打开的URL var sendTemplateMessage = true; if (ex is ErrorJsonResultException) { var jsonEx = (ErrorJsonResultException)ex; service = jsonEx.Url; message = jsonEx.Message; //需要忽略的类型 var ignoreErrorCodes = new[] { ReturnCode.获取access_token时AppSecret错误或者access_token无效, ReturnCode.template_id不正确, ReturnCode.缺少access_token参数, ReturnCode.api功能未授权, ReturnCode.用户未授权该api, ReturnCode.参数错误invalid_parameter, ReturnCode.接口调用超过限制, ReturnCode.需要接收者关注, //43004 //其他更多可能的情况 }; if (ignoreErrorCodes.Contains(jsonEx.JsonResult.errcode)) { sendTemplateMessage = false;//防止无限递归,这种请款那个下不发送消息 } //TODO:防止更多的接口自身错误导致的无限递归。 } else { if (ex.Message.StartsWith("openid:")) { openId = ex.Message.Split(':')[1];//发送给指定OpenId } service = "WeixinException"; message = ex.Message; } }); } catch (Exception e) { Senparc.Weixin.WeixinTrace.SendCustomLog("OnWeixinExceptionFunc过程错误", e.Message); } }