微信公众号开发C#系列-七、消息管理-接收事件推送

一、概述

在微信用户和公众号产生交互的过程当中,用户的某些操做会使得微信服务器经过事件推送的形式通知到开发者在开发者中心处设置的服务器地址,从而开发者能够获取到该信息。其中,某些事件推送在发生后,是容许开发者回复用户的,某些则不容许git

咱们在上一篇微信公众号开发C#系列-六、消息管理-普通消息接受处理中讲到,微信的消息能够大致分为两种类型,一种是包括:文本,语音,图片等的普通消息,另外一种就是本篇要将的事件类型。包括:关注/取消关注事件,扫描带参数二维码事件,上报地理位置事件,自定义菜单相关事件等,本篇一一进行讲解。介于偏于内容过多易产生阅读疲劳,对于自定义菜单相关事件的处理咱们放在下一篇中讲解。github

这里的消息指的是传统的微信公众平台消息交互,微信用户向公众号发送消息后,公众号回复消息给微信用户。包括如下类型:数据库

  1. 关注/取消关注事件:subscribe/unsubscribe
  2. 扫描带参数二维码事件:scan
  3. 上报地理位置事件:location
  4. 自定义菜单事件
  5. 点击菜单拉取消息时的事件推送
  6. 点击菜单跳转连接时的事件推送

本篇主要介绍前三种。服务器

二、实现方式

使用Senparc.Weixin框架来快速处理各类接收事件推送,实现很是简单,自定义一个继承MessageHandler的类,重写这些类型的方法便可。注意:DefaultResponseMessage必须重写,用于返回没有处理过的消息类型(也能够用于默认消息,如帮助信息等);其中全部原OnXX的抽象方法已经都改成虚方法,能够没必要每一个都重写。若不重写,默认返回DefaultResponseMessage方法中的结果。微信

自定义消息处理类:网络

public partial class CustomMessageHandler : MessageHandler<MessageContext<IRequestMessageBase, IResponseMessageBase>>
{
    public CustomMessageHandler(Stream inputStream, int maxRecordCount = 0)
        : base(inputStream, null, maxRecordCount)
    {
        WeixinContext.ExpireMinutes = 3;
    }
    public override void OnExecuting()
    {
        //测试MessageContext.StorageData
        if (CurrentMessageContext.StorageData == null)
        {
            CurrentMessageContext.StorageData = 0;
        }
        base.OnExecuting();
    }
    public override void OnExecuted()
    {
        base.OnExecuted();
        CurrentMessageContext.StorageData = ((int)CurrentMessageContext.StorageData) + 1;
    }
}

定义好事件处理类后,分别重写上面提到几种接收事件推送的事件便可。
咱们能够经过重写MessageHandler里的这几种类型方法来处理咱们的业务,固然也能够只重写须要的部分类型,不须要的类型能够不重写,只须要定义一个统一的DefaultResponseMessage微信公众平台

public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
{
    //全部没有被处理的消息会默认返回这里的结果
    var responseMessage = this.CreateResponseMessage<ResponseMessageText>();
    responseMessage.Content = "这条消息来自DefaultResponseMessage。";
    return responseMessage;
}

三、消息的去重的重要性

上一篇咱们就已经提到过微信服务器在5秒内收不到响应会断掉链接,而且从新发起请求,总共重试三次。如此以来,咱们模拟有这样一个场景:当用户关注微信帐号时,获取当前用户信息,而后将信息写到数据库中,相似网站的注册。假设这个关注事件中,咱们须要处理比较复杂的业务逻辑。如送积分,写用户日志,分配用户组等等一系列的逻辑须要执行,或者网络环境比较复杂,没法保证5秒内响应当前用户的操做,那若是当操做还没有完成,微信服务器又给咱们的服务器推送了一条相同的关注事件,咱们将再次执行咱们的那些逻辑,这样就有可能致使数据库中出现重复的数据(有的童鞋就会说了,我在插入数据以前先判断当前是否已经存在了,若是存在了就不执行插入的操做。我想说的是,我当初也是这样想的,但真实的运行环境和咱们的调试环境仍是有差距的,直到发现数据库中有很多重复的用户信息时,我才发现消息去重的重要性。)。框架

消息的去重普通消息和事件消息是有区别的。普通消息使用msgid,而事件消息使用FromUserName + CreateTime。分布式

四、关注/取消关注事件

用户在关注与取消关注公众号时,微信会把这个事件推送到开发者填写的URL。方便开发者给用户下发欢迎消息或者作账号的解绑。ide

假如服务器没法保证在五秒内处理并回复,能够直接回复空串,微信服务器不会对此做任何处理,而且不会发起重试。

关注或取消事件推送XML数据包示例:

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

参数说明:

参数              描述
ToUserName      开发者微信号
FromUserName    发送方账号(一个OpenID)
CreateTime      消息建立时间 (整型)
MsgType         消息类型,event
Event           事件类型,subscribe(订阅)、unsubscribe(取消订阅)

4.1 关注事件

关注事件咱们只须要重写OnEvent_SubscribeRequest事件代码便可,以下咱们返回了一个文本消息,实现代码参考:

/// <summary>
/// 订阅(关注)事件
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnEvent_SubscribeRequest(RequestMessageEvent_Subscribe requestMessage)
{
    var responseMessage = CreateResponseMessage<ResponseMessageNews>();
    foreach (var model in messageList)
    {
        responseMessage.Articles.Add(new Article()
        {
            Title = "国思公众号",
            Description = "欢迎关注国思软件公众号,更多内容稳步官网,多谢!",
            PicUrl = "http://www.rdiframework.net/WeiXin.png",
            Url = "http://www.rdiframework.net/"
        });
    }
    return responseMessage;
}

关注事件执行后效果

在上面的关注事件中,用户关注公众号就会自动执行上面的事件代码,咱们就能够在事件代码中作相关的业务处理,如绑定用户分组、增长用户到本地等等。同时推送一条欢迎消息返回到用户手机上。

4.2 取消关注事件

取消关注事件与关注事件相似,主要是事件变成了unsubscribe(取消关注)。取消关注事件-unsubscribe的主要意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据,而且关注用户流失的状况。

取消关注事件咱们只须要重写OnEvent_UnsubscribeRequest事件代码便可,以下咱们返回了一个文本消息,实现代码参考:

/// <summary>
/// 退订/取消关注
/// 实际上用户没法收到非订阅帐号的消息,因此这里能够随便写。
/// unsubscribe事件的意义在于及时删除网站应用中已经记录的OpenID绑定,消除冗余数据。而且关注用户流失的状况。
/// </summary>
/// <returns></returns>
public override IResponseMessageBase OnEvent_UnsubscribeRequest(RequestMessageEvent_Unsubscribe requestMessage)
{
    int returnValue = RDIFrameworkService.Instance.WeixinBasicService.UserUnsubscribeByOpenId(Id,requestMessage.FromUserName);//退
    var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
    responseMessage.Content = "有空再来";
    return responseMessage;
}

上面的代码在用户取消公众号的关注时就会自动执行,能够看到咱们有一行代码针对用户取消关注时执行的业务逻辑,同时返回了一个文本消息。实际用户已经取消关注,返回的消息也返回不到用户手机上的。

五、扫描带参数二维码事件

用户扫描带场景值二维码时,可能推送如下两种事件:

  1. 若是用户还未关注公众号,则用户能够关注公众号,关注后微信会将带场景值关注事件推送给开发者。
  2. 若是用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者。

5.1 接口展现与实现方式

对于第一种上面已经讲了,这里就只说明下第二种。

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

参数说明:

参数              描述
ToUserName      开发者微信号
FromUserName    发送方账号(一个OpenID)
CreateTime      消息建立时间 (整型)
MsgType         消息类型,event
Event           事件类型,SCAN
EventKey        事件KEY值,是一个32位无符号整数,即建立二维码时的二维码scene_id
Ticket          二维码的ticket,可用来换取二维码图片

对于生成带参数的二维码咱们会在后面的文章中专门介绍,这儿咱们了解一个这个概念。为了知足用户渠道推广分析和用户账号绑定等场景的须要,公众平台提供了生成带参数二维码的接口。使用该接口能够得到多个带不一样场景值的二维码,用户扫描后,公众号能够接收到事件推送。具体官方技术文档可参考:生成带参数的二维码

目前有2种类型的二维码:

一、临时二维码,是有过时时间的,最长能够设置为在二维码生成后的30天(即2592000秒)后过时,但可以生成较多数量。临时二维码主要用于账号绑定等不要求二维码永久保存的业务场景

二、永久二维码,是无过时时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于账号绑定、用户来源统计等场景。

扫描带参数二维码事件只须要重写OnEvent_ScanRequest事件代码便可,以下咱们返回了一个文本消息,实现代码参考:

public override IResponseMessageBase OnEvent_ScanRequest(RequestMessageEvent_Scan requestMessage)
{
    //经过扫描关注
    var responseMessage = CreateResponseMessage<ResponseMessageText>();

    responseMessage.Content = responseMessage.Content ?? string.Format("欢迎关注国思软件,经过扫描二维码进入,场景值:{0}", requestMessage.EventKey);

    return responseMessage;
}

在上面的代码中用户扫描了带场景值的二维码进入公众号后咱们返回了一个提示的文本消息。这是很是有用的功能,经常使用途推广,能够根据不一样的二维码场景值分别作不一样的业务处理,如能够统计关注的每个粉丝从哪里来的,作到渠道推广分析,可是关注的都是同一个公众号。

5.2 生成带参数的二维码用途

微信公众号生成带参数的二维码有何用途?

  1. 能够区分粉丝来源,只须要生成不一样的带参数的二维码,把这些二维码分别投放到各个渠道,粉丝经过这些渠道二维码进来就能够区分粉丝来源,微号帮后台渠道粉丝列表中有粉丝数及明细;
  2. 粉丝经过扫描渠道二维码关注公众号,会打标签分组,好比粉丝扫商店A、B的二维码进来的, 在微信公众号后来的用户管理中可查看到商店A/B二维码名下的粉丝明细及分组状况;
  3. 能够生成多个不一样的渠道二维码配置不一样的营销活动,设置不一样的关注回复信息,让粉丝第一时间了解活动动机,是否有兴趣参与等等;
  4. 能够利用渠道二维码生成功能,能够实现微信收款前关注公众号,间接分析粉丝后续消费状况;
  5. 考核推广员完成任务的进度,如以推广名字生成多不个同的二维码,分配给不一样的推广员,每一个推广员吸引了多少粉丝关注公众号,微号帮后台均可以一一明细;
  6. 带参数的二维码也叫渠道二维码或者场景二维码,生存的数量有限,且是永久二维码。当数量用完后能够删除一些不用的二维码释放出来,二次利用。

经过扫描带场景值的二维码进入

六、上报地理位置事件

用户赞成上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,或在进入会话后每5秒上报一次地理位置,公众号能够在公众平台网站中修改以上设置。上报地理位置时,微信会将上报地理位置事件推送到开发者填写的URL。要获取用户地址位置,须要在微信公众平台开发者中心开启上报地理位置功能,开启以后会在用户首次进入公众号时,弹出是否容许上报地理位置选项,若是选择容许则在用户每次进入公众号会话的时候微信会以XML形式将用户的地理位置上报到你开发者中心填写的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>

参数说明:

参数              描述
ToUserName      开发者微信号
FromUserName    发送方账号(一个OpenID)
CreateTime      消息建立时间 (整型)
MsgType         消息类型,event
Event           事件类型,LOCATION
Latitude        地理位置纬度
Longitude       地理位置经度
Precision       地理位置精度

上报地理位置事件只须要重写OnEvent_LocationRequest事件代码便可,以下咱们返回了一个文本消息,实现代码参考:

public override IResponseMessageBase OnEvent_LocationRequest(RequestMessageEvent_Location requestMessage)
{
    //这里是微信客户端(经过微信服务器)自动发送过来的位置信息
    var responseMessage = CreateResponseMessage<ResponseMessageText>();
    responseMessage.Content = "这里写什么都无所谓,好比:上帝爱你!";
    return responseMessage;//这里也能够返回null(须要注意写日志时候null的问题)
}

上报地理位置用处很是多,能够用维度和经度获取城市代号,调用天气Api,也能够用来监测企业员工的位置进行微信考勤。在微信运营的时候,用户地理位置仍是咱们进行营销策划、广告活动投放、用户精准营销的重要依据。

参考文章

微信公众平台技术文档-官方

Senparc.Weixin SDK + 官网示例源代码

RDIFramework.NET — 基于.NET的快速信息化系统开发框架 — 系列目录

RDIFramework.NET ━ .NET快速信息化系统开发框架 ━ 工做流程组件介绍

RDIFramework.NET框架SOA解决方案(集Windows服务、WinForm形式与IIS形式发布)-分布式应用

RDIFramework.NET代码生成器全新V3.5版本发布-重大升级


一路走来数个年头,感谢RDIFramework.NET框架的支持者与使用者,你们能够经过下面的地址了解详情。

RDIFramework.NET官方网站:http://www.rdiframework.net/

RDIFramework.NET官方博客:http://blog.rdiframework.net/

同时须要说明的,之后的全部技术文章以官方网站为准,欢迎你们收藏!

RDIFramework.NET框架由专业团队长期打造、一直在更新、一直在升级,请放心使用!

欢迎关注RDIFramework.net框架官方公众微信(微信号:guosisoft),及时了解最新动态。

扫描二维码当即关注

微信号:guosisoft

相关文章
相关标签/搜索