As mentioned in the previous post, messages can be divided into two types: text, voice, image, and other common messages, the other is the event type to be described in this article. Including: pay attention to unconcerned events, scan events with parameter QR codes, report geographical location events, and customize menu-related events. This article will be explained one by one. As mentioned in the previous post, messages can be divided into two types: text, voice, image, and other common messages, the other is the event type to be described in this article. Including: Follow/cancel follow events, scan QR code events with parameters, report geographical location events, and customize menu-related events. This article will be explained one by one.
As mentioned in the previous article,If the server fails to receive the response within five seconds, the connection will be disconnected and the server will initiate a new request. a total of three retries will be made.In this case, the problem arises. In this scenario, when a user pays attention to the account, the user obtains the current user information and writes the information to the database. Similar to pc-side website registration. It may be because the business logic we need to handle in this event is complicated. Such as credit delivery, user log writing, and User Group allocation. Wait ...... A series of logic needs to be executed, or the network environment is complex, so it cannot be guaranteed to respond to the current user's operation within five seconds. if the operation is not completed, the server pushes the same attention event to our server, and we will execute our logic again, in this way, duplicate data may appear in the database. (some children's shoes will say that before inserting data, I will first determine whether the data already exists, if yes, the insert operation will not be executed. What I want to say is that I thought the same way at the beginning, but there is still a gap between the real running environment and our debugging environment until we find that there are many duplicate user information in the database, I discovered the importance of message deduplication .).
There is a difference between deduplication of messages and event messages. Common messages use msgid, and event messages use FromUserName + CreateTime. My thinking is:
The new class BaseMsg has three attributes: FromUser, MsgFlag, and CreateTime. The code is as follows:
Public class BaseMsg {////// Sender ID ///Public string FromUser {get; set ;}////// Message representation. When a common message is sent, it is msgid. When an event message is sent, it is the event creation time ///Public string MsgFlag {get; set ;}////// Time when the queue is added ///Public DateTime CreateTime {get; set ;}}
Create a static list_queue to store the message List. the List type is List. .
Before processing a message body, first determine whether the list is instantiated. if the list is not instantiated, it is instantiated. otherwise, determine whether the list length is greater than or equal to 50 (this can be customized, is the number of concurrent messages). If the value is greater than or equal to 50, messages that have not responded within 20 seconds are retried once in 5 seconds. a total of three retries are retried, that is, 15 seconds, for the sake of insurance, this is 20 seconds ).
Obtain the message type of the current message body and determine whether the current message has been requested based on _ queue. If it is an event, the FromUser and creation time are saved. If it is a common message, save MsgFlag. The following code is used:
If (_ queue = null) {_ queue = new List
();} Else if (_ queue. count> = 50) {_ queue = _ queue. where (q => {return q. createTime. addSeconds (20)> DateTime. now ;}). toList (); // retain unresponded messages within 20 seconds} 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 = (Msg Type) 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 ;}}
When a message already exists in the queue, the current message is not converted into an entity and null is directly returned. when the message is called, no processing is performed when null is returned.
The following describes the event message. Later. All messages inherit from BaseMessage, and all Event types contain the attribute of an Event. For convenient calling, the message type is defined as Enumeration. the code is as follows:
////// Event type enumeration ///Public enum Event {////// Non-event type ///NOEVENT ,////// Subscribe ///SUBSCRIBE ,////// Cancel the subscription ///UNSUBSCRIBE ,////// Scan the QR code with parameters ///SCAN ,////// Geographic location ///LOCATION ,////// Click the button ///CLICK ,////// Link button ///VIEW ,////// Scan the QR code to push events ///SCANCODE_PUSH ,////// Scan the QR code and the prompt box "receiving messages" is displayed ///SCANCODE_WAITMSG ,////// Pop up the system photo layout ///PIC_SYSPHOTO ,////// A photo or album is displayed ///PIC_PHOTO_OR_ALBUM ,////// Pop up the album poster ///PIC_WEIXIN ,////// Pop-up location selector ///LOCATION_SELECT ,////// Template message push ///TEMPLATESENDJOBFINISH}
After the enumeration is defined, the message entity is defined.
Follow/cancel follow events
Xml data packets are as follows:
toUser
FromUser
123456789
event
subscribe
Corresponding entity:
////// Subscribe/unsubscribe to events ///Public class SubEventMessage: EventMessage {private string _ eventkey ;////// Event KEY value. qrscene _ is the prefix, followed by the parameter value of the QR code (the prefix has been removed and can be directly used )///Public string EventKey {get {return _ eventkey;} set {_ eventkey = value. Replace ("qrscene _","");}}////// Ticket of the QR code, which can be used in exchange for the QR code image ///Public string Ticket {get; set ;}}
It should be noted that when a user scans a QR code with parameters, if the user does not pay attention to the current public number, the user will add the qrscene _ parameter and Ticket in the message body, therefore, two attributes are defined: EventKey and Ticket. When assigning values to EventKey, replace qrscene _, because what we really need is the following parameters.
Scan QR code events with parameters
When a user scans a QR code with a scene value, two events may be pushed:
If the user has not followed the public account, the user can follow the public account, after which the event with the scene value will be pushed to the developer.
If the user has followed the public account, the event with the scene value will be pushed to the developer. ,
The first one has been mentioned above. here we will only describe the second one.
Event push when the user is concerned
The xml package is as follows:
toUser
FromUser
123456789
event
SCAN
SCENE_VALUE
TICKET
The corresponding entities are as follows:
////// Scan the two-dimensional code entity with parameters ///Public class ScanEventMessage: EventMessage {////// Event KEY value, which is a 32-bit unsigned integer, that is, the two-dimensional code scene_id when the QR code is created ///Public string EventKey {get; set ;}////// Ticket of the QR code, which can be used in exchange for the QR code image ///Public string Ticket {get; set ;}}
Report location events
When the report location function is enabled for a public account, the user agrees to report the location each time the public account is in the session, or, the location is reported every five seconds after the call is returned. the public account can be changed on the background of the public platform. When a location event is reported, the event is pushed to the url entered by the developer.
Xml data packets are as follows:
toUser
fromUser
123456789
event
LOCATION
23.137466
113.352425
119.385040
The corresponding entities are as follows:
////// Report the geographic location entity ///Public class LocationEventMessage: EventMessage {////// Geographic location and latitude ///Public string Latitude {get; set ;}////// Geographic longitude ///Public string longpolling {get; set ;}////// Geographic location accuracy ///Public string Precision {get; set ;}}
Commonly used custom menu events include click, view, scancode_puth, scancode_waitmsg, and location_select. There are also three types of image sending events. because they are not commonly used, I did not expect to use the scenarios. I will not talk about them one by one again. if you are interested, you can study them yourself or communicate with me.
Xml data packets pushed by the click event:
toUser
FromUser
123456789
event
CLICK
EVENTKEY
The xml data packet pushed by the view event is in the same format as the click event, so you can define a class as follows:
////// Common menu events, including click and view ///Public class NormalMenuEventMessage: EventMessage {////// Event KEY value, jump URL set ///Public string EventKey {get; set ;}}
The xml data packet of the scancode event is as follows:
ToUserName
FromUserName
1419265698
event
scancode_push
EventKey
qrcode
http://weixin.qq.com/r/JEy5oRLE0U_urVbC9xk2
The corresponding entities are as follows:
////// Menu scan event ///Public class ScanMenuEventMessage: EventMessage {////// Event KEY value ///Public string EventKey {get; set ;}////// Scan type. Qrcode is a QR code, and the other is a bar code ///Public string ScanType {get; set ;}////// Scan result ///Public string ScanResult {get; set ;}}
Now, all commonly used event-type messages have been defined. combined with the previous article, the complete code for converting xml data packets into objects is as follows:
Public class MessageFactory {private static List
_ Queue; public static BaseMessage CreateMessage (string xml) {if (_ queue = null) {_ queue = new List
();} Else if (_ queue. count> = 50) {_ queue = _ queue. where (q => {return q. createTime. addSeconds (20)> DateTime. now ;}). toList (); // retain unresponded messages within 20 seconds} 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 = (Msg Type) 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
(Xml); case MsgType. IMAGE: return Utils. ConvertObj (xml); case MsgType. VIDEO: return Utils. ConvertObj
(Xml); case MsgType. VOICE: return Utils. ConvertObj
(Xml); case MsgType. LINK: return Utils. ConvertObj
(Xml); case MsgType. LOCATION: return Utils. ConvertObj
(Xml); case MsgType. EVENT: // Event type {var eventtype = (EVENT) Enum. parse (typeof (Event), xdoc. element ("Event "). value. toUpper (); switch (eventtype) {case Event. CLICK: return Utils. convertObj
(Xml); case Event. VIEW: return Utils. ConvertObj
(Xml); case Event. LOCATION: return Utils. ConvertObj
(Xml); case Event. LOCATION_SELECT: return Utils. ConvertObj
(Xml); case Event. SCAN: return Utils. ConvertObj
(Xml); case Event. SUBSCRIBE: return Utils. ConvertObj
(Xml); case Event. UNSUBSCRIBE: return Utils. ConvertObj
(Xml); case Event. SCANCODE_WAITMSG: return Utils. ConvertObj
(Xml); default: return Utils. ConvertObj
(Xml) ;}} break; default: return Utils. ConvertObj
(Xml );}}}