Exemplo n.º 1
0
        /// <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();
        }
Exemplo n.º 2
0
        /// <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
                {
                }
            }
        }
Exemplo n.º 3
0
 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);
     }
 }
Exemplo n.º 4
0
        public void ThrowTest()
        {
            WeixinException unkonwnException = null;

            try
            {
                var response = MP.RequestMessageFactory.GetRequestEntity(xmlText);
            }
            catch (WeixinException ex)
            {
                unkonwnException = ex;
            }

            Assert.IsNotNull(unkonwnException);
        }
Exemplo n.º 5
0
        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);
            }
        }
Exemplo n.º 7
0
        /// <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);
        }
Exemplo n.º 8
0
        /// <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);
        }
Exemplo n.º 10
0
        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);
            }
        }
Exemplo n.º 11
0
        /// <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
        }
Exemplo n.º 12
0
        /// <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);
        }
Exemplo n.º 13
0
        /// <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);
        }
Exemplo n.º 14
0
        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);
            }
        }