Heim  >  Artikel  >  WeChat-Applet  >  Einführung in die Methode zur Verwendung von C# zur Entwicklung öffentlicher WeChat-Konten für den Empfang von Event-Push und Nachrichtendeduplizierung

Einführung in die Methode zur Verwendung von C# zur Entwicklung öffentlicher WeChat-Konten für den Empfang von Event-Push und Nachrichtendeduplizierung

高洛峰
高洛峰Original
2017-03-19 18:00:561459Durchsuche

In diesem Artikel wird hauptsächlich die Methode zur Entwicklung öffentlicher WeChat-Konten für den Empfang von Event-Push und Nachrichtendeduplizierung vorgestellt. Er hat einen gewissen Referenzwert für die WeChat-Entwicklung benötigte Freunde können sich auf

beziehen. Dieser Artikel beschreibt die Methode zum Empfangen von Event-Push und Nachrichtendeduplizierung bei der Entwicklung öffentlicher C#-WeChat-Konten. Teilen Sie es als Referenz mit allen. Die spezifische Analyse lautet wie folgt:

Wenn der WeChat-Server innerhalb von 5 Sekunden keine Antwort erhält, trennt er die Verbindung und initiiert die Anfrage erneut, wobei es insgesamt dreimal erneut versucht wird. In diesem Fall tritt das Problem auf. Es gibt ein solches Szenario: Wenn ein Benutzer einem WeChat-Konto folgt, werden die aktuellen Benutzerinformationen abgerufen und diese Informationen dann in die Datenbank geschrieben. Ähnlich wie bei der Registrierung auf der PC-Website. Vielleicht ist die Geschäftslogik, mit der wir umgehen müssen, aufgrund dieser Bedenken relativ komplex. Beispielsweise das Versenden von Punkten, das Schreiben von Benutzerprotokollen und das Zuweisen von Benutzergruppen. Warten Sie ... Eine Reihe von Logik muss ausgeführt werden, oder die Netzwerkumgebung ist relativ komplex und es gibt keine Garantie dafür, dass der Vorgang des aktuellen Benutzers innerhalb von 5 Sekunden beantwortet wird. Wenn der Vorgang noch nicht abgeschlossen ist, wird der WeChat-Server verwendet schiebt das gleiche Aufmerksamkeitsereignis auf unseren Server. Wir werden unsere Logik erneut ausführen, was zu doppelten Daten in der Datenbank führen kann (einige Kinderschuhe sagen: Bevor ich die Daten einfüge, stelle ich zunächst fest, ob sie bereits vorhanden sind, und wenn sie vorhanden sind, Die Einfügung wird nicht durchgeführt. Ich habe das am Anfang gedacht, aber es gibt immer noch eine Lücke zwischen der realen Betriebsumgebung und unserer Debugging-Umgebung von doppelten Benutzerinformationen in der Datenbank, dass ich die Bedeutung der Nachrichtendeduplizierung entdeckt habe.


Es gibt einen Unterschied zwischen der Deduplizierung von Nachrichten und Ereignisnachrichten. Gewöhnliche Nachrichten verwenden msgid, während Ereignisnachrichten FromUserName + CreateTime verwenden. Meine Idee ist:

Erstellen Sie eine neue Klasse BaseMsg mit drei Attributen: FromUser, MsgFlag und CreateTime. Der Code lautet wie folgt:

Der Code lautet wie folgt:

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



Erstellen Sie eine statische Liste _queue zum Speichern der Nachrichtenliste Die Liste ist Listf822bda892e76d613fb5d807a4e9e7c8.
Bestimmen Sie vor der Verarbeitung des WeChat-Nachrichtentexts zunächst, ob die Liste instanziiert ist. Andernfalls stellen Sie fest, ob die Länge der Liste größer oder gleich 50 ist kann angepasst werden und wird für das gleichzeitige Nachrichtenvolumen von WeChat verwendet) ), wenn größer oder gleich 50, Nachrichten, die nicht innerhalb von 20 Sekunden geantwortet haben, aufbewahren (einmal alle 5 Sekunden wiederholen, insgesamt 3 Wiederholungen, also 15 Sekunden). , schreiben Sie hier sicherheitshalber 20 Sekunden).
Rufen Sie den Nachrichtentyp des aktuellen Nachrichtentexts ab und bestimmen Sie anhand von _queue, ob die aktuelle Nachricht angefordert wurde. Wenn es sich um ein Ereignis handelt, werden FromUser und Erstellungszeit gespeichert. Wenn es sich um eine normale Nachricht handelt, wird MsgFlag gespeichert. Das Folgende ist der Code:

Der Code lautet wie folgt:

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



Wenn die Nachricht bereits in der Warteschlange vorhanden ist, wird die aktuelle Nachricht nicht angezeigt direkt in eine Entität umgewandelt werden. Gibt null zurück. Beim Aufruf erfolgt keine Verarbeitung, wenn null zurückgegeben wird.

Beginnen wir mit den Veranstaltungsnachrichten. Fortsetzung des vorherigen Artikels. Alle Nachrichten erben BaseMessage und alle Ereignistypen enthalten eine Event-Eigenschaft. Zur Vereinfachung des Aufrufs lautet der

-Code der Nachricht wie folgt:

/// <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
}



Nach der Definition der Aufzählung ist es an der Zeit, die Nachrichtenentität zu definieren .

Ereignis verfolgen/entfolgen
Das XML-Datenpaket lautet wie folgt:

Der Code lautet wie folgt:

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



Entsprechende Entität:

Der Code lautet wie folgt:

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



Hier ist zu beachten, dass der Benutzer den QR-Code mit Parametern scannt Wenn der Benutzer der aktuellen öffentlichen Nummer nicht folgt und der Benutzer darauf achtet, werden der Parameter qrscene_ und das Ticket in den Nachrichtentext aufgenommen. Daher werden hier zwei Attribute definiert: EventKey und Ticket. Wenn Sie EventKey einen Wert zuweisen, ersetzen Sie qrscene_, denn was wir wirklich brauchen, sind die folgenden Parameter.

Scannen eines QR-Code-Ereignisses mit Parametern
Wenn ein Benutzer einen QR-Code mit Szenenwert scannt, können zwei Ereignisse übertragen werden:

Wenn der Benutzer dem offiziellen Konto nicht gefolgt ist, wird der Benutzer Sie können dem offiziellen Konto folgen. Nach dem Verfolgen wird WeChat die folgenden Ereignisse mit Szenenwerten an die Entwickler weiterleiten.
Wenn der Benutzer dem offiziellen Konto gefolgt ist, leitet WeChat das Scan-Ereignis mit Szenenwert an den Entwickler weiter. ,
Der erste Typ wurde oben besprochen und nur der zweite Typ wird hier erläutert.

Ereignis-Push, wenn der Benutzer gefolgt ist

Das XML-Paket lautet wie folgt:

Der Code lautet wie folgt:

<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>



Die entsprechenden Entitäten lauten wie folgt:

Der Code lautet wie folgt:

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



Geografische Standortereignisse melden
Wenn das offizielle Konto die Meldung von geografischen Standortereignissen aktiviert, wird der geografische Standort bei der Eingabe jedes Mal gemeldet, wenn er zum ersten Mal eine öffentliche Kontositzung betritt und nachdem der Benutzer der Meldung des geografischen Standorts zugestimmt hat Wird alle 5 Sekunden nach Eintritt in die Konversation gemeldet. Das offizielle Konto kann die Einstellungen im Hintergrund der öffentlichen Plattform ändern. Beim Melden des geografischen Standorts sendet WeChat das gemeldete geografische Standortereignis an die vom Entwickler eingegebene URL.

Das XML-Datenpaket lautet wie folgt:

Der Code lautet wie folgt:

<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>



Die entsprechende Entität lautet wie folgt:

Der Code lautet wie folgt:

/// <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);
            }
        }
}


Das obige ist der detaillierte Inhalt vonEinführung in die Methode zur Verwendung von C# zur Entwicklung öffentlicher WeChat-Konten für den Empfang von Event-Push und Nachrichtendeduplizierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn