zoukankan      html  css  js  c++  java
  • 啊Ran讲微信开发(.net) :订阅号+自定义服务器(消息,关注事件)

         经过上一篇的介绍,我们应该大致对微信平台下 的公众号开发有个了解,其实也就那么一回事,现在我们首先来说说微信开发的"消息",然后再点一下微信中的"关注".

          微信公众平台的消息是以XML数据格式进行封装和传递的,那么简单来说,消息分为两种咯,就是用户发送的消息以及公众号回复的消息.

          以最简单的文本消息为列,消息格式如下:

      <xml>
           <ToUserName><![CDATA[{0}]]></ToUserName>
           <FromUserName><![CDATA[{1}]]></FromUserName>
           <CreateTime>{2}</CreateTime>
    <MsgType><![CDATA[{1}]]></MsgType>

    <Content><![CDATA[{4}]]></Content>
    <MsgId>{5}</MsgId>
    </xml>

           

            /// <summary>
            /// 发送方帐号
            /// </summary>
            public string FromUserName { get; set; }
            /// <summary>
            /// 接收方账号
            /// </summary>
            public string ToUserName { get; set; }
            /// <summary>
            /// 消息类型
            /// </summary>
            public string MsgType { get; protected set; }
            /// <summary>
            /// 创建时间
            /// </summary>
            public string CreateTime { get; set; }
            /// <summary>
            /// 内容
            /// </summary>
            public string Content { get; set; }
            /// <summary>
            /// 消息ID
            /// </summary>
            public string MsgId { get; set; }

    用户发送消息数据实体:

          文本消息,图片消息,语言消息,视频消息,地理位置消息,链接消息,事件消息.

          其中,事件消息:关注/取消关注事件,扫描二维码事件,上报地理位置事件,自定义菜单事件.

    公众号回复得消息数据实体也是相对应的.

    在实际开发中,我们程序首先得到的是微信服务器转发过来的请求,我们需要对Request进行解析然后得到XML字符串,代码如下:

            /// <summary>
            /// 读取请求对象的内容
            /// 只能读一次
            /// </summary>
            /// <param name="request">HttpRequest对象</param>
            /// <returns>XML</returns>
            public static string ReadRequest(HttpRequest request) 
            {
                string reqStr = string.Empty;
                using (Stream s = request.InputStream)
                {
                    using (StreamReader reader = new StreamReader(s, Encoding.UTF8))
                    {
                        reqStr = reader.ReadToEnd();
                    }
                }
    
                return reqStr;
            }

    我们需要将XML数据报转化为对应的C#数据实体,以及将实体封装为XML数据报回复,.net framewokr提供了一套xml数据的完整操作.在system.xml命名空间下,以文本消息为例,如下:

            /// <summary>
            /// 从xml数据加载文本消息
            /// </summary>
            /// <param name="xml"></param>
            public static TextMessage LoadFromXml(string xml)
            {
                TextMessage tm = null;
                if (!string.IsNullOrEmpty(xml))
                {
                    XElement element = XElement.Parse(xml);
                    if (element != null)
                    {
                        tm = new TextMessage();
                        tm.FromUserName = element.Element(FROM_USERNAME).Value;
                        tm.ToUserName = element.Element(TO_USERNAME).Value;
                        tm.CreateTime = element.Element(CREATE_TIME).Value;
                        tm.Content = element.Element(CONTENT).Value;
                        tm.MsgId = element.Element(MSG_ID).Value;
                        
                    }
                }
    
                return tm;
            }

    接下来我们就可以知道用户发送了一个什么样的消息类型给服务器(MsgType),这样,我们需要定义不同消息类型的处理类,比如TextHandler:

            /// <summary>
            /// 处理请求
            /// </summary>
            /// <returns></returns>
            public string HandleRequest()
            {
                string response = string.Empty;
                TextMessage tm = TextMessage.LoadFromXml(RequestXml);
                string content = tm.Content.Trim();
                if (string.IsNullOrEmpty(content))
                {
                    response = "消息不能为空";
                }
                if(content.Contains("你好"))
                {
                      response = "hello,I am YZR"
                }
                tm.Content = response;
                //进行发送者、接收者转换
                string temp = tm.ToUserName;
                tm.ToUserName = tm.FromUserName;
                tm.FromUserName = temp;
                response = tm.GenerateContent();
                return response;
            }

    GenerateContent()返回一定格式的XML字符串:

            /// <summary>
            /// 生成内容
            /// </summary>
            /// <returns></returns>
            public override string GenerateContent()
            {
                this.CreateTime = Common.GetNowTime();
                return string.Format(this.Template,this.ToUserName,this.FromUserName,this.CreateTime,this.MsgType,this.Content,this.MsgId);//模板template
            }
    
            /// <summary>
            /// 加载模板
            /// </summary>
            private static void LoadTemplate()
            {
                m_Template = @"<xml>
                                    <ToUserName><![CDATA[{0}]]></ToUserName>
                                    <FromUserName><![CDATA[{1}]]></FromUserName>
                                    <CreateTime>{2}</CreateTime>
                                    <MsgType><![CDATA[{3}]]></MsgType>
                                    <Content><![CDATA[{4}]]></Content>
                                    <MsgId>{5}</MsgId>
                                </xml>";
            }

    最后将XML返回回去完成回复操作:

                //由微信服务接收请求,具体处理请求
                WeiXinService wxService = new WeiXinService(context.Request);
                string responseMsg = wxService.Response();
                context.Response.Clear();
                context.Response.Charset = "UTF-8";
                context.Response.Write(responseMsg);
                context.Response.End();

    那么现在对于微信的"关注"事件,应该也是一件很容易的事情了.首先通过以get方式URL接入,之后用户发起"关注"事件消息传送,我们需要先得到Request中的XML字符串数据(解析Request得到XML之后进行判断消息的MsgType),再对关注事件作出服务器的响应回去客户端,将数据封装成XML在Response中输出即可.

            /// <summary>
            /// 处理请求
            /// </summary>
            /// <param name="context"></param>
            public void ProcessRequest(HttpContext context)
            {
                //由微信服务接收请求,具体处理请求
                WeiXinService wxService = new WeiXinService(context.Request);
                string responseMsg = wxService.Response();
                context.Response.Clear();
                context.Response.Charset = "UTF-8";
                context.Response.Write(responseMsg);
                context.Response.End();
            }
            /// <summary>
            /// 处理请求,产生响应
            /// </summary>
            /// <returns></returns>
            public string Response()
            {
                string method = Request.HttpMethod.ToUpper();
                //验证签名
                if (method == "GET")
                {
                    if (CheckSignature())
                    {
                        return Request.QueryString[ECHOSTR];//随机字符串
                    }
                    else
                    {
                        return "error";
                    }
                }
    
                //处理消息
                if (method == "POST")
                {
                    return ResponseMsg();
                }
                else
                {
                    return "无法处理";
                }
            }
            /// <summary>
            /// 处理请求
            /// </summary>
            /// <returns></returns>
            private string ResponseMsg()
            {
                string requestXml = Common.ReadRequest(this.Request);//得到Request的XML字符串信息
                IHandler handler = HandlerFactory.CreateHandler(requestXml);//处理器
                if (handler != null)
                {
                    return handler.HandleRequest();//处理器处理请求
                }
    
                return string.Empty;
            }
            /// <summary>
            /// 创建处理器 
            /// </summary>
            /// <param name="requestXml">请求的xml</param>
            /// <returns>IHandler对象</returns>
            public static IHandler CreateHandler(string requestXml)
            {
                IHandler handler = null;
                if (!string.IsNullOrEmpty(requestXml))
                {
                    //解析数据
                    XmlDocument doc = new System.Xml.XmlDocument();
                    doc.LoadXml(requestXml);
                    XmlNode node = doc.SelectSingleNode("/xml/MsgType");
                    if (node != null)
                    {
                        XmlCDataSection section = node.FirstChild as XmlCDataSection;
                        if (section != null)
                        {
                            string msgType = section.Value;
    
                            switch (msgType)
                            {
                                case "text":
                                    handler = new TextHandler(requestXml);    //文本处理
                                    break;
                                case "event":
                                    handler = new EventHandler(requestXml);   //事件处理
                                    break;
                            }
                        }
                    }
                }
    
                return handler;
            }
            /// <summary>
            /// 处理请求
            /// </summary>
            /// <returns></returns>
            public string HandleRequest()
            {
                string response = string.Empty;
                EventMessage em = EventMessage.LoadFromXml(RequestXml);
                if (em.Event.Equals("subscribe",StringComparison.OrdinalIgnoreCase))
                {
                    //回复欢迎消息
                    TextMessage tm = new TextMessage();
                    tm.ToUserName = em.FromUserName;
                    tm.FromUserName = em.ToUserName;
                    tm.CreateTime = Common.GetNowTime();
                    tm.Content = "欢迎您关注";
                    response = tm.GenerateContent();
                }
    
                return response;
            }

    最后补充一下EventMessage:

    class EventMessage : Message
        {
            private const string EVENT = "Event";
            private const string EVENT_KEY = "EventKey";
            /// <summary>
            /// 模板
            /// </summary>
            private static string mTemplate;
            /// <summary>
            /// 模板
            /// </summary>
            public override string Template
            {
                get 
                {
                    if (string.IsNullOrEmpty(mTemplate))
                    { 
                         mTemplate = @"<xml>
                                    <ToUserName><![CDATA[{0}]]></ToUserName>
                                    <FromUserName><![CDATA[{1}]]></FromUserName>
                                    <CreateTime>{2}</CreateTime>
                                    <MsgType><![CDATA[event]]></MsgType>
                                    <Event><![CDATA[{3}]]></Event>
                                    <EventKey>{4}</EventKey>
                                </xml>";
                    }
    
                    return mTemplate;
                }
            }
            /// <summary>
            /// 事件类型
            /// </summary>
            public string Event { get; set; }
            /// <summary>
            /// 事件KEY值,与自定义菜单接口中KEY值对应
            /// </summary>
            public string EventKey { get; set; }
            /// <summary>
            /// 构造函数
            /// </summary>
            public EventMessage()
            {
                this.MsgType = "event";
            }
            /// <summary>
            /// 从xml数据加载文本消息
            /// </summary>
            /// <param name="xml"></param>
            public static EventMessage LoadFromXml(string xml)
            {
                EventMessage em = null;
                if (!string.IsNullOrEmpty(xml))
                {
                    XElement element = XElement.Parse(xml);
                    if (element != null)
                    {
                        em = new EventMessage();
                        em.FromUserName = element.Element(Common.FROM_USERNAME).Value;
                        em.ToUserName = element.Element(Common.TO_USERNAME).Value;
                        em.CreateTime = element.Element(Common.CREATE_TIME).Value;
                        em.Event =element.Element(EVENT).Value;
                        em.EventKey = element.Element(EVENT_KEY).Value;
                    }
                }
    
                return em;
            }
        }


    下一次,我们来看一看,自定义菜单的实现.

  • 相关阅读:
    VMware Workstation 16.0 key (仅支持 intel 架构)
    使用思科ASA对指定端口、IP进行抓包
    轮子的意义
    dubbo学习(三)泛化
    dubbo学习(二)链接
    dubbo学习(一)线程池
    mips交叉编译:SQLite3
    生成证书脚本
    ssh连接不上 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
    gmssl ocsp 验证证书
  • 原文地址:https://www.cnblogs.com/Francis-YZR/p/4999394.html
Copyright © 2011-2022 走看看