>위챗 애플릿 >위챗 개발 >이벤트 푸시 및 메시지 중복 제거를 수신하기 위한 WeChat 공개 계정을 개발하기 위해 C#을 사용하는 방법 소개

이벤트 푸시 및 메시지 중복 제거를 수신하기 위한 WeChat 공개 계정을 개발하기 위해 C#을 사용하는 방법 소개

高洛峰
高洛峰원래의
2017-03-19 18:00:561482검색

이 글에서는 주로 C#을 사용하여 이벤트 푸시 및 메시지 중복 제거를 수신하는 WeChat 공개 계정을 개발하는 방법을 소개합니다. 이벤트 푸시 및 메시지 중복 제거의 사용 기술은 WeChat 개발에 대한 특정 참조 가치가 있습니다. 필요한 친구들은

을 참고하세요. 이 글에서는 C# 위챗 공개계정 개발에서 이벤트 푸시 수신 및 메시지 중복제거 방법에 대해 설명합니다. 참고할 수 있도록 모든 사람과 공유하세요. 구체적인 분석은 다음과 같습니다.

위챗 서버가 5초 이내에 응답을 받지 못하면 연결을 끊고 요청을 다시 시작하여 총 3번을 재시도합니다. 이 경우 문제가 발생합니다. 다음과 같은 시나리오가 있습니다. 사용자가 WeChat 계정을 팔로우하면 현재 사용자 정보를 얻은 다음 해당 정보가 데이터베이스에 기록됩니다. PC 홈페이지 회원가입과 유사합니다. 아마도 이러한 우려 때문에 우리가 처리해야 하는 비즈니스 로직은 상대적으로 복잡합니다. 포인트 보내기, 사용자 로그 작성, 사용자 그룹 할당 등이 있습니다. 잠깐... 일련의 로직을 실행해야 하거나, 네트워크 환경이 상대적으로 복잡하고 현재 사용자의 작업이 5초 이내에 응답할 것이라는 보장이 없습니다. 그러면 작업이 아직 완료되지 않으면 WeChat 서버가 작동합니다. 동일한 어텐션 이벤트를 서버에 푸시합니다. 로직을 다시 실행하면 데이터베이스에 데이터가 중복될 수 있습니다(일부 어린이 신발에서는 데이터를 삽입하기 전에 먼저 해당 데이터가 존재하는지 확인하고 존재하는 경우 삽입 작업은 수행되지 않습니다. 제가 말씀드리고 싶은 것은 처음에는 그렇게 생각했지만 실제 운영 환경과 우리의 디버깅 환경 사이에는 여전히 격차가 있다는 것입니다. 메시지 중복 제거의 중요성을 발견한 데이터베이스의 중복된 사용자 정보.)


일반 메시지와 이벤트 메시지의 중복 제거에는 차이가 있습니다. 일반 메시지는 msgid를 사용하고, 이벤트 메시지는 FromUserName + CreateTime을 사용합니다. 내 생각은 다음과 같습니다.

FromUser, MsgFlag 및 CreateTime의 세 가지 속성을 사용하여 새로운 BaseMsg 클래스를 만듭니다. 코드는 다음과 같습니다.

코드는 다음과 같습니다.

public class BaseMsg
{
        /// <summary>
        /// 发送者标识
        /// </summary>
        public string FromUser { get; set; }
        /// <summary>
        /// 消息表示。普通消息时,为msgid,事件消息时,为事件的创建时间
        /// </summary>
        public string MsgFlag { get; set; }
        /// <summary>
        /// 添加到队列的时间
        /// </summary>
        public DateTime CreateTime { get; set; }
}



메시지 목록을 저장하기 위한 정적 list_queue를 만듭니다. 목록 유형은 다음과 같습니다. Listf822bda892e76d613fb5d807a4e9e7c8.
WeChat 메시지 본문을 처리하기 전에 먼저 목록이 인스턴스화되었는지 확인하세요. 그렇지 않으면 목록 길이가 50보다 크거나 같은지 확인하세요. 위챗의 동시 메시지량에 사용됩니다.) 50보다 크거나 같을 경우 20초 이내에 응답하지 않은 메시지는 보관됩니다. (5초마다 한 번씩 재시도, 총 3번의 재시도, 15초) , 안전을 위해 여기에 20초가 기록됩니다.
현재 메시지 본문의 메시지 유형을 가져오고 _queue를 기반으로 현재 메시지가 요청되었는지 확인합니다. 이벤트인 경우 FromUser와 생성시간이 저장됩니다. 정상적인 메시지라면 MsgFlag가 저장됩니다. 코드는 다음과 같습니다.

코드는 다음과 같습니다.

if (_queue == null)
{
 _queue = new List<BaseMsg>();
}
else if(_queue.Count>=50)
{
 _queue = _queue.Where(q => { return q.CreateTime.AddSeconds(20) > DateTime.Now; }).ToList();//保留20秒内未响应的消息
}
XElement xdoc = XElement.Parse(xml);
var msgtype = xdoc.Element("MsgType").Value.ToUpper();
var FromUserName = xdoc.Element("FromUserName").Value;
var MsgId = xdoc.Element("MsgId").Value;
var CreateTime = xdoc.Element("CreateTime").Value;
MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype);
if (type!=MsgType.EVENT)
{
 if (_queue.FirstOrDefault(m => { return m.MsgFlag == MsgId; }) == null)
 {
     _queue.Add(new BaseMsg
     {
  CreateTime = DateTime.Now,
  FromUser = FromUserName,
  MsgFlag = MsgId
     });
 }
 else
 {
     return null;
 }
       
}
else
{
 if (_queue.FirstOrDefault(m => { return m.MsgFlag == CreateTime; }) == null)
 {
     _queue.Add(new BaseMsg
     {
  CreateTime = DateTime.Now,
  FromUser = FromUserName,
  MsgFlag = CreateTime
     });
 }
 else
 {
     return null;
 }
}



큐에 메시지가 이미 존재할 경우 현재 메시지는 변환되지 않습니다. 엔터티에 넣으면 null이 직접 반환됩니다. 호출 시 null이 반환되면 처리가 수행되지 않습니다.

먼저 이벤트 소식부터 전해드리겠습니다. 이전 기사에 이어 계속됩니다. 모든 메시지는 BaseMessage를 상속하며 모든 이벤트 유형에는 Event 속성이 포함됩니다. 호출의 편의를 위해 메시지

코드는 다음과 같습니다.

/// <summary>
/// 事件类型枚举
/// </summary>
public enum Event
{
        /// <summary>
        /// 非事件类型
        /// </summary>
        NOEVENT,
        /// <summary>
        /// 订阅
        /// </summary>
        SUBSCRIBE,
        /// <summary>
        /// 取消订阅
        /// </summary>
        UNSUBSCRIBE,
        /// <summary>
        /// 扫描带参数的二维码
        /// </summary>
        SCAN,
        /// <summary>
        /// 地理位置
        /// </summary>
        LOCATION,
        /// <summary>
        /// 单击按钮
        /// </summary>
        CLICK,
        /// <summary>
        /// 链接按钮
        /// </summary>
        VIEW,
        /// <summary>
        /// 扫码推事件
        /// </summary>
        SCANCODE_PUSH,
        /// <summary>
        /// 扫码推事件且弹出“消息接收中”提示框
        /// </summary>
        SCANCODE_WAITMSG,
        /// <summary>
        /// 弹出系统拍照发图
        /// </summary>
        PIC_SYSPHOTO,
        /// <summary>
        /// 弹出拍照或者相册发图
        /// </summary>
        PIC_PHOTO_OR_ALBUM,
        /// <summary>
        /// 弹出微信相册发图器
        /// </summary>
        PIC_WEIXIN,
        /// <summary>
        /// 弹出地理位置选择器
        /// </summary>
        LOCATION_SELECT,
        /// <summary>
        /// 模板消息推送
        /// </summary>
        TEMPLATESENDJOBFINISH
}



열거형을 정의한 후 메시지 엔터티를 정의할 차례입니다.

이벤트 팔로우/언팔로우
xml 데이터 패키지는 다음과 같습니다.

코드는 다음과 같습니다.

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
</xml>



해당 개체 :

코드는 다음과 같습니다.

/// <summary>
/// 订阅/取消订阅事件
/// </summary>
public class SubEventMessage : EventMessage
{
        private string _eventkey;
        /// <summary>
        /// 事件KEY值,qrscene_为前缀,后面为二维码的参数值(已去掉前缀,可以直接使用)
        /// </summary>
        public string EventKey
        {
            get { return _eventkey; }
            set { _eventkey = value.Replace("qrscene_", ""); }
        }
        /// <summary>
        /// 二维码的ticket,可用来换取二维码图片
        /// </summary>
        public string Ticket { get; set; }
}



여기서 주목해야 할 점은 사용자가 매개변수가 포함된 QR 코드를 스캔할 때, 현재 공식 계정을 팔로우하지 않는 경우 사용자는 메시지 본문에 qrscene_ 매개변수와 티켓이 포함되므로 여기에 EventKey와 Ticket이라는 두 가지 속성이 정의됩니다. EventKey에 값을 할당할 때 qrscene_을 교체하세요. 실제로 필요한 것은 다음 매개변수이기 때문입니다.

매개변수가 포함된 QR 코드 이벤트 스캔
사용자가 장면 값이 포함된 QR 코드를 스캔하면 두 가지 이벤트가 푸시될 수 있습니다.

사용자가 공식 계정을 팔로우하지 않은 경우 사용자는 공개 계정을 팔로우하면 WeChat은 장면 값과 함께 다음 이벤트를 개발자에게 푸시합니다.
사용자가 공식 계정을 팔로우한 경우 WeChat은 장면 값과 함께 스캔 이벤트를 개발자에게 푸시합니다. ,
위에서 첫 번째 유형에 대해 설명했고, 여기서는 두 번째 유형에 대해서만 설명하겠습니다.

사용자가 팔로우했을 때 이벤트 푸시

xml 패키지는 다음과 같습니다.

코드는 다음과 같습니다.

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[SCAN]]></Event>
<EventKey><![CDATA[SCENE_VALUE]]></EventKey>
<Ticket><![CDATA[TICKET]]></Ticket>
</xml>



해당 엔터티는 다음과 같습니다.

코드는 다음과 같습니다.

/// <summary>
/// 扫描带参数的二维码实体
/// </summary>
public class ScanEventMessage : EventMessage
{
 
        /// <summary>
        /// 事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
        /// </summary>
        public string EventKey { get; set; }
        /// <summary>
        /// 二维码的ticket,可用来换取二维码图片
        /// </summary>
        public string Ticket { get; set; }
}



지리적 위치 이벤트 보고
공식 계정이 활성화될 때 지리적 위치 보고 기능은 공식 계정에 들어갈 때마다 대화 중 사용자가 지리적 위치 보고에 동의한 후 입장 시 지리적 위치가 보고되거나, 대화에 들어간 후 5초마다 지리적 위치가 보고됩니다. . 공식 계정은 공식 플랫폼 백그라운드에서 설정을 수정할 수 있습니다. 지리적 위치를 보고할 때 WeChat은 보고된 지리적 위치 이벤트를 개발자가 입력한 URL로 푸시합니다.

xml 데이터 패키지는 다음과 같습니다.

코드는 다음과 같습니다.

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[LOCATION]]></Event>
<Latitude>23.137466</Latitude>
<Longitude>113.352425</Longitude>
<Precision>119.385040</Precision>
</xml>



해당 엔터티는 다음과 같습니다.

코드는 다음과 같습니다.

/// <summary>
/// 上报地理位置实体
/// </summary>
public class LocationEventMessage : EventMessage
{
 
        /// <summary>
        /// 地理位置纬度
        /// </summary>
        public string Latitude { get; set; }
        /// <summary>
        /// 地理位置经度
        /// </summary>
        public string Longitude { get; set; }
       /// <summary>
        /// 地理位置精度
       /// </summary>
        public string Precision { get; set; }
}


 
自定义菜单事件常用的事件有:click,view,scancode_puth,scancode_waitmsg,location_select。另外还有三种发图的事件,由于并不常用,笔者也没想到使用场景,再次就不一一讲述了,有兴趣的可以自己研究下,或者和我进行交流。
 
click事件推送的xml数据包:

代码如下:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[EVENTKEY]]></EventKey>
</xml>


 
view事件推送的xml数据包和click的格式是一样的,所以定义一个类就可以了,如下:

 代码如下:

/// <summary>
/// 普通菜单事件,包括click和view
/// </summary>
public class NormalMenuEventMessage : EventMessage
{
 
        /// <summary>
        /// 事件KEY值,设置的跳转URL
        /// </summary>
        public string EventKey { get; set; }
}

 
scancode事件的xml数据包如下:

代码如下:

<xml><ToUserName><![CDATA[ToUserName]]></ToUserName>
<FromUserName><![CDATA[FromUserName]]></FromUserName>
<CreateTime>1419265698</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[scancode_push]]></Event>
<EventKey><![CDATA[EventKey]]></EventKey>
<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
<ScanResult><![CDATA[http://weixin.qq.com/r/JEy5oRLE0U_urVbC9xk2]]></ScanResult>
</ScanCodeInfo>
</xml>

对应的实体如下:

 代码如下:

/// <summary>
/// 菜单扫描事件
/// </summary>
public class ScanMenuEventMessage : EventMessage
{
 
        /// <summary>
        /// 事件KEY值
        /// </summary>
        public string EventKey { get; set; }
        /// <summary>
        /// 扫码类型。qrcode是二维码,其他的是条码
        /// </summary>
        public string ScanType { get; set; }
        /// <summary>
        /// 扫描结果
        /// </summary>
        public string ScanResult { get; set; }
}


 
至此,当前常用的事件类型消息都已定义完毕,结合上一篇所讲的,将xml数据包转换成对象的完整代码如下:

代码如下:

public class MessageFactory
{
        private static List<BaseMsg> _queue; 
        public static BaseMessage CreateMessage(string xml)
        {
            if (_queue == null)
            {
                _queue = new List<BaseMsg>();
            }
            else if(_queue.Count>=50)
            {
                _queue = _queue.Where(q => { return q.CreateTime.AddSeconds(20) > DateTime.Now; }).ToList();//保留20秒内未响应的消息
            }
            XElement xdoc = XElement.Parse(xml);
            var msgtype = xdoc.Element("MsgType").Value.ToUpper();
            var FromUserName = xdoc.Element("FromUserName").Value;
            var MsgId = xdoc.Element("MsgId").Value;
            var CreateTime = xdoc.Element("CreateTime").Value;
            MsgType type = (MsgType)Enum.Parse(typeof(MsgType), msgtype);
            if (type!=MsgType.EVENT)
            {
                if (_queue.FirstOrDefault(m => { return m.MsgFlag == MsgId; }) == null)
                {
                    _queue.Add(new BaseMsg
                    {
                        CreateTime = DateTime.Now,
                        FromUser = FromUserName,
                        MsgFlag = MsgId
                    });
                }
                else
                {
                    return null;
                }
               
            }
            else
            {
                if (_queue.FirstOrDefault(m => { return m.MsgFlag == CreateTime; }) == null)
                {
                    _queue.Add(new BaseMsg
                    {
                        CreateTime = DateTime.Now,
                        FromUser = FromUserName,
                        MsgFlag = CreateTime
                    });
                }
                else
                {
                    return null;
                }
            }
            switch (type)
            {
                case MsgType.TEXT: return Utils.ConvertObj<TextMessage>(xml);
                case MsgType.IMAGE: return Utils.ConvertObj<ImgMessage>(xml);
                case MsgType.VIDEO: return Utils.ConvertObj<VideoMessage>(xml);
                case MsgType.VOICE: return Utils.ConvertObj<VoiceMessage>(xml);
                case MsgType.LINK:
                    return Utils.ConvertObj<LinkMessage>(xml);
                case MsgType.LOCATION:
                    return Utils.ConvertObj<LocationMessage>(xml);
                case MsgType.EVENT://事件类型
                {
                    var eventtype = (Event)Enum.Parse(typeof(Event), xdoc.Element("Event").Value.ToUpper());
                    switch (eventtype)
                    {
                        case Event.CLICK:
                            return Utils.ConvertObj<NormalMenuEventMessage>(xml);
                        case Event.VIEW: return Utils.ConvertObj<NormalMenuEventMessage>(xml);
                        case Event.LOCATION: return Utils.ConvertObj<LocationEventMessage>(xml);
                        case Event.LOCATION_SELECT: return Utils.ConvertObj<LocationMenuEventMessage>(xml);
                        case Event.SCAN: return Utils.ConvertObj<ScanEventMessage>(xml);
                        case Event.SUBSCRIBE: return Utils.ConvertObj<SubEventMessage>(xml);
                        case Event.UNSUBSCRIBE: return Utils.ConvertObj<SubEventMessage>(xml);
                        case Event.SCANCODE_WAITMSG: return Utils.ConvertObj<ScanMenuEventMessage>(xml);
                        default:
                            return Utils.ConvertObj<EventMessage>(xml);
                    }
                } break;
                default:
                    return Utils.ConvertObj<BaseMessage>(xml);
            }
        }
}


위 내용은 이벤트 푸시 및 메시지 중복 제거를 수신하기 위한 WeChat 공개 계정을 개발하기 위해 C#을 사용하는 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.