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


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

原文地址:https://www.cnblogs.com/Francis-YZR/p/4999394.html