微信企业号开发:接收消息和事件

来源:互联网 发布:91视频解析网站源码 编辑:程序博客网 时间:2024/04/30 11:47

接收到的消息和事件,其实都是微信post到我们配置的URL的消息。接收普通消息就是用户给公众号发送的消息,事件是由于用户的特定操作,微信post给我们的消息。被动响应消息是我们收到微信post过来的普通消息或者是事件时,企业号通过Response.Write这种方式回复的消息。


核心代码:

把微信post过来的数据先解密,转为能处理的XML,再把XML转为对象

 #region 将POST过来的数据转化成实体对象        /// <summary>        /// 将微信POST过来的数据转化成实体对象        /// </summary>        /// <param name="token"></param>        /// <returns></returns>        public static ReceiveMessageBase ConvertMsgToObject(string msgBody = "")        {                                 if (string.IsNullOrWhiteSpace(msgBody))            {                Stream s = System.Web.HttpContext.Current.Request.InputStream;                byte[] b = new byte[s.Length];                s.Read(b, 0, (int)s.Length);                msgBody = Encoding.UTF8.GetString(b);            }            string CorpToken = AppIdInfo.GetToken();            string corpId = AppIdInfo.GetCorpId();            string encodingAESKey = AppIdInfo.GetEncodingAESKey();            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(CorpToken, encodingAESKey, corpId);            string msg_signature = HttpContext.Current.Request.QueryString["msg_signature"];            string timestamp = HttpContext.Current.Request.QueryString["timestamp"];            string nonce = HttpContext.Current.Request.QueryString["nonce"];            string sMsg = "";  // 解析之后的明文            int flag = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, msgBody, ref sMsg);            if (flag == 0)            {                msgBody = sMsg;                LogInfo.Info("解密后的消息为" + sMsg);            }            else            {                LogInfo.Error("解密消息失败!flag=" + flag);            }                       if (string.IsNullOrWhiteSpace(msgBody))            {                return null;            }            XmlDocument doc = null;            MsgType msgType = MsgType.UnKnown;            EventType eventType = EventType.UnKnown;            ReceiveMessageBase msg = new ReceiveMessageBase();            msg.MsgType = msgType;            msg.MessageBody = msgBody;            XmlNode node = null;            XmlNode tmpNode = null;            try            {                doc = new XmlDocument();                doc.LoadXml(msgBody);//解密后才是需要处理的XML数据,读取XML字符串                XmlElement rootElement = doc.DocumentElement;                XmlNode msgTypeNode = rootElement.SelectSingleNode("MsgType");//获取字符串中的消息类型                node = rootElement.SelectSingleNode("FromUserName");                if (node != null)                {                    msg.FromUserName = node.InnerText;                }                node = rootElement.SelectSingleNode("AgentID");                if (node != null)                {                    msg.AgentID = Convert.ToInt32(node.InnerText);                }                node = rootElement.SelectSingleNode("ToUserName");                if (node != null)                {                    msg.ToUserName = node.InnerText;                }                node = rootElement.SelectSingleNode("CreateTime");                if (node != null)                {                    msg.CreateTime = Convert.ToInt64(node.InnerText);                }                #region 获取具体的消息对象                string strMsgType = msgTypeNode.InnerText;                string msgId = string.Empty;                string content = string.Empty;                tmpNode = rootElement.SelectSingleNode("MsgId");                if (tmpNode != null)                {                    msgId = tmpNode.InnerText.Trim();                }                string strMsgType2 = strMsgType.Trim().ToLower();                switch (strMsgType2)                {                    case "text"://接收普通消息 text消息                        msgType = MsgType.Text;                        tmpNode = rootElement.SelectSingleNode("Content");                        if (tmpNode != null)                        {                            content = tmpNode.InnerText.Trim();                        }                        TextReceiveMessage txtMsg = new TextReceiveMessage(msg)                        {                                                       MsgType = msgType,                                                    MsgId = Convert.ToInt64(msgId),                            Content = content                        };                        txtMsg.AfterRead();                        return txtMsg;                    case "image"://接收普通消息 image消息                        msgType = MsgType.Image;                        ImageReceiveMessage imgMsg = new ImageReceiveMessage(msg)                        {                                                       MsgId = Convert.ToInt64(msgId),                            MsgType = msgType,                                                      MediaId = rootElement.SelectSingleNode("MediaId").InnerText,                            PicUrl = rootElement.SelectSingleNode("PicUrl").InnerText                        };                        imgMsg.AfterRead();                        return imgMsg;                    case "voice"://接收普通消息 voice消息                        msgType = MsgType.Voice;                        XmlNode node1 = rootElement.SelectSingleNode("Recognition");                        if (node1 != null)                        {                            msgType = MsgType.VoiceResult;                        }                        VoiceReceiveMessage voiceMsg = new VoiceReceiveMessage(msg)                        {                                                       MsgId = Convert.ToInt64(msgId),                            MsgType = msgType,                            Recognition = node1 == null ? string.Empty : node1.InnerText.Trim(),                            Format = rootElement.SelectSingleNode("Format").InnerText,                            MediaId = rootElement.SelectSingleNode("MediaId").InnerText                        };                        voiceMsg.AfterRead();                        return voiceMsg;                    case "video"://接收普通消息 video消息                        msgType = MsgType.Video;                        VideoReceiveMessage videoMsg = new VideoReceiveMessage(msg)                        {                                                      MediaId = rootElement.SelectSingleNode("MediaId").InnerText,                                                      MsgId = Convert.ToInt64(msgId),                            MsgType = msgType,                                                      ThumbMediaId = rootElement.SelectSingleNode("ThumbMediaId").InnerText                        };                        videoMsg.AfterRead();                        return videoMsg;                    case "location"://接收普通消息 location消息                        msgType = MsgType.Location;                        LocationReceiveMessage locationMsg = new LocationReceiveMessage(msg)                        {                                                                              MsgId = Convert.ToInt64(msgId),                            MsgType = msgType,                                                   Label = rootElement.SelectSingleNode("Label").InnerText,                            Location_X = rootElement.SelectSingleNode("Location_X").InnerText,                            Location_Y = rootElement.SelectSingleNode("Location_Y ").InnerText,                            Scale = rootElement.SelectSingleNode("Scale").InnerText                        };                        locationMsg.AfterRead();                        return locationMsg;                    case "event":// 接收事件                        msgType = MsgType.Event;                        eventType = EventType.UnKnown;                        msg.MsgType = msgType;                        XmlNode eventNode = rootElement.SelectSingleNode("Event");                        if (eventNode != null)                        {                            string eventtype = eventNode.InnerText.Trim().ToLower();                            switch (eventtype)                            {                                case "subscribe": //接收事件 成员关注                                    eventType = EventType.Subscribe;                                                                       SubscribeEventMessage subEvt = new SubscribeEventMessage(msg)                                    {                                                                              EventType = EventType.Subscribe,                                                                              MsgType = msgType,                                                                          };                                    subEvt.AfterRead();                                    return subEvt;                                case "unsubscribe": //接收事件 取消关注事件                                    eventType = EventType.UnSubscribe;                                    UnSubscribeEventMessage unSubEvt = new UnSubscribeEventMessage(msg)                                    {                                                                              EventType = eventType,                                                                           MsgType = msgType,                                                                         };                                    unSubEvt.AfterRead();                                    return unSubEvt;                                case "location"://接收事件 上报地理位置事件                                    eventType = EventType.Location;                                    UploadLocationEventMessage locationEvt = new UploadLocationEventMessage(msg)                                    {                                                                               EventType = eventType,                                                                              Latitude = rootElement.SelectSingleNode("Latitude").InnerText,                                        Longitude = rootElement.SelectSingleNode("Longitude").InnerText,                                                                             MsgType = msgType,                                        Precision = rootElement.SelectSingleNode("Precision").InnerText,                                                                         };                                    locationEvt.AfterRead();                                    return locationEvt;                                case "click": //接收事件 上报菜单事件 点击菜单拉取消息的事件推送                                    eventType = EventType.Click;                                    MenuEventMessage menuEvt = new MenuEventMessage(msg)                                    {                                                                            EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                        EventType = eventType,                                                                            MsgType = msgType,                                                                         };                                    menuEvt.AfterRead();                                    return menuEvt;                                case "view": //接收事件 上报菜单事件 点击菜单跳转链接的事件推送                                    eventType = EventType.VIEW;                                    MenuEventVIEWEventMessage menuVIEWEvt = new MenuEventVIEWEventMessage(msg)                                    {                                                                              EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                        EventType = eventType,                                                                             MsgType = msgType,                                                                       };                                    menuVIEWEvt.AfterRead();                                    return menuVIEWEvt;                                case "scancode_push"://接收事件 上报菜单事件 扫码推事件的事件推送                                    eventType = EventType.scancode_push;                                    ScanCodePushEventMessage scanCodePushEventMessage = new ScanCodePushEventMessage(msg)                                    {                                                                             EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                        EventType = eventType,                                                                             MsgType = msgType,                                                                            ScanCodeInfo = new ScanCodeInfo(rootElement.SelectSingleNode("ScanCodeInfo"))                                    };                                    scanCodePushEventMessage.AfterRead();                                    return scanCodePushEventMessage;                                case "scancode_waitmsg"://接收事件 上报菜单事件 扫码推事件且弹出“消息接收中”提示框的事件推送                                    eventType = EventType.scancode_waitmsg;                                    ScanCodeWaitMsgEventMessage scanCodeWaitMsgEventMessage = new ScanCodeWaitMsgEventMessage(msg)                                    {                                                                              EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                        EventType = eventType,                                                                              MsgType = msgType,                                                                              ScanCodeInfo = new ScanCodeInfo(rootElement.SelectSingleNode("ScanCodeInfo"))                                    };                                    scanCodeWaitMsgEventMessage.AfterRead();                                    return scanCodeWaitMsgEventMessage;                                case "pic_sysphoto"://接收事件 上报菜单事件 弹出系统拍照发图的事件推送                                    eventType = EventType.pic_sysphoto;                                    PicSysPhotoEventMessage picSysPhotoEventMessage = new PicSysPhotoEventMessage(msg)                                    {                                                                            EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                                                              MsgType = msgType,                                                                              SendPicsInfo = new SendPicsInfo(rootElement.SelectSingleNode("SendPicsInfo"))                                    };                                    picSysPhotoEventMessage.AfterRead();                                    return picSysPhotoEventMessage;                                case "pic_photo_or_album"://接收事件 上报菜单事件 弹出拍照或者相册发图的事件推送                                    eventType = EventType.pic_photo_or_album;                                    PicPhotoOrAlbumEventMessage picPhotoOrAlbumEventMessage = new PicPhotoOrAlbumEventMessage(msg)                                    {                                                                             EventType = eventType,                                        EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                                                          MsgType = msgType,                                                                              SendPicsInfo = new SendPicsInfo(rootElement.SelectSingleNode("SendPicsInfo"))                                    };                                    picPhotoOrAlbumEventMessage.AfterRead();                                    return picPhotoOrAlbumEventMessage;                                case "pic_weixin"://接收事件 上报菜单事件 弹出微信相册发图器的事件推送                                    eventType = EventType.pic_weixin;                                    PicWeiXinEventMessage picWeiXinEventMessage = new PicWeiXinEventMessage(msg)                                    {                                                                            EventType = eventType,                                        EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                                                              MsgType = msgType,                                                                              SendPicsInfo = new SendPicsInfo(rootElement.SelectSingleNode("SendPicsInfo"))                                    };                                    picWeiXinEventMessage.AfterRead();                                    return picWeiXinEventMessage;                                case "location_select"://接收事件 上报菜单事件 弹出地理位置选择器的事件推送                                    eventType = EventType.location_select;                                    LocationSelectEventMessage locationSelectEventMessage = new LocationSelectEventMessage(msg)                                    {                                                                            EventType = eventType,                                        EventKey = rootElement.SelectSingleNode("EventKey").InnerText,                                                                             MsgType = msgType,                                                                              SendLocationInfo = new SendLocationInfo(rootElement.SelectSingleNode("SendLocationInfo"))                                                                          };                                    locationSelectEventMessage.AfterRead();                                    return locationSelectEventMessage;                                case "enter_agent": //接收事件 成员进入应用的事件推送                                    eventType = EventType.enter_agent;                                    EnterAgentEventMessage EnterAgentEventMessage = new EnterAgentEventMessage(msg)                                    {                                          MsgType = msgType,                                                                        };                                    EnterAgentEventMessage.AfterRead();                                    return EnterAgentEventMessage;                                default:                                    LogInfo.Error("事件类型" + eventtype + "未处理");                                    break;                            }                        }                        break;                    default:                        LogInfo.Error("消息类型" + strMsgType2 + "未处理");                        break;                }                msg.MsgType = msgType;                #endregion            }            catch (Exception ex)            {                LogInfo.Error("处理消息异常:" + msgBody, ex);            }            finally            {                if (doc != null)                {                    doc = null;                }            }            msg.MsgType = msgType;            return msg;        }

发送被动响应文本消息:

  /// <summary>        /// 发送被动响应文本消息,需要先加密在发送        /// </summary>        /// <param name="fromUserName">发送方</param>        /// <param name="toUserName">接收方</param>        /// <param name="content">文本内容</param>        public static void SendTextReplyMessage(string fromUserName, string toUserName, string content)        {            TextReplyMessage msg = new TextReplyMessage()            {                CreateTime = Tools.ConvertDateTimeInt(DateTime.Now),                FromUserName = fromUserName,                ToUserName = toUserName,                Content = content            };          /*  LogInfo.Info("发送信息2sMsg=" + content);//也可以使用微信的接口发送消息            TextMsg data = new TextMsg(content);            data.agentid = "7";            data.safe = "0";            // data.toparty = "@all";            //   data.totag = "@all";            data.touser = toUserName;            BLLMsg.SendMessage(data);*/                           string CorpToken = AppIdInfo.GetToken();            string corpId = AppIdInfo.GetCorpId();            string encodingAESKey = AppIdInfo.GetEncodingAESKey();            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(CorpToken, encodingAESKey, corpId);            string msg_signature = HttpContext.Current.Request.QueryString["msg_signature"];            string timestamp = HttpContext.Current.Request.QueryString["timestamp"];            string nonce = HttpContext.Current.Request.QueryString["nonce"];            string encryptResponse = "";//加密后的文字            string sMsg = msg.ToXmlString();//加密前的文字            int isok = wxcpt.EncryptMsg(sMsg, timestamp, nonce, ref encryptResponse);//            LogInfo.Info("发送信息sMsg=" + sMsg);         //   LogInfo.Info("发送信息encryptResponse=" + encryptResponse);            if (isok == 0 && !string.IsNullOrEmpty(encryptResponse))            {                HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;                HttpContext.Current.Response.Write(encryptResponse);//被动相应消息不需要调用微信接口            }            else {                LogInfo.Info("发送信息失败isok=" + isok);            }           }

注释掉的代码就是主动发送消息,具体可参考微信企业号开发:主动发送消息

使用注释掉的代码也可以给用户发送消息,但这种方式不叫被动响应消息



被动响应消息实体

 /// <summary>    /// 被动响应消息类    /// </summary>    public abstract class ReplyMessage    {        public string ToUserName { get; set; }        public string FromUserName { get; set; }        public long CreateTime { get; set; }        /// <summary>        /// 将对象转化为Xml消息        /// </summary>        /// <returns></returns>        public abstract  string ToXmlString();    }    /// <summary>    /// 被动响应文本消息    /// </summary>    public class TextReplyMessage : ReplyMessage    {        /// <summary>        /// 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)         /// </summary>        public string Content { get; set; }        /// <summary>        /// 将对象转化为Xml消息        /// </summary>        /// <returns></returns>        public override string ToXmlString()        {            string s = "<xml><ToUserName><![CDATA[{0}]]></ToUserName><FromUserName><![CDATA[{1}]]></FromUserName><CreateTime>{2}</CreateTime><MsgType><![CDATA[{3}]]></MsgType><Content><![CDATA[{4}]]></Content></xml>";            s = string.Format(s,                ToUserName ?? string.Empty,                FromUserName ?? string.Empty,                CreateTime.ToString(),                "text",                Content ?? string.Empty                );            return s;        }    }

配置的URL网页的代码:

public class TestWeixin : IHttpHandler {      public void ProcessRequest (HttpContext context) {              if (context.Request.HttpMethod.ToLower() == "post")        {            try            {                System.IO.Stream s = context.Request.InputStream;                byte[] b = new byte[s.Length];                s.Read(b, 0, (int)s.Length);                string postStr = System.Text.Encoding.UTF8.GetString(b);                if (!string.IsNullOrEmpty(postStr))                {                    Execute(postStr);                }            }catch(Exception e)            {                new AppException("收到信息异常" + e.Message);            }            }        else //开启应用的回调模式调用 ,代码省略        {                    }    }    private void Execute(string postStr)    {       ReceiveMessageBase basemsg = ConvertMsgToObject(postStr);        if (basemsg.MsgType ==.MsgType.Text)        {          TextReceiveMessage txtMsg = basemsg as TextReceiveMessage;            if (txtMsg != null)            {                SendTextReplyMessage(txtMsg.ToUserName, txtMsg.FromUserName, "收到文本消息:" + txtMsg.Content);//发送被动消息            }        }                 }        public bool IsReusable {        get {            return false;        }    }

开启应用的回调模式调用使用的代码参考微信企业号开发:启用回调模式


这样修改之后呢,用户给企业号发送文本消息时,企业号就可以把用户发送的消息主动回复给用户。

效果如下:


其他的类型的普通消息,也都相似。

但我个人发现,收到事件时,发送被动响应消息,似乎不保证用户能收到,似乎有很大的概率收不到,不知道是我人的原因,还是微信的原因。但奇怪的是,事件都能收到,发送被动响应消息,很大的概率收不到。

其实收到普通的消息时,也可以通过主动发送消息,也就是调用微信的相关接口,也可以达到回复用户的目的,这个我测试过,但比发送被动响应消息慢,也能实现和上边类似的效果。

1 0
原创粉丝点击