一个还算简单的微信消息SDK(基于.Net Standard 2.0)
虽然微信公众号出现了好久,不过在SDK这件事情上感觉并没有多少人把它当成一个有技术含量的事情来做,很多SDK做的事情就是一个代码的堆叠,当然也可能写的好的并没有开源出来。所以在某个翻遍Github而无所获的下午我写了一个基础的基于事件的微信消息类,今年初我把它放到了github和开源中国上并逐步完善,这篇文章就是简单介绍OSS开源系列下的微信消息模块SDK的使用方式,主要围绕以下几个方面分解:
一. 全局介绍
二. 配置管理
三. 框架使用
1. 框架组成元素
2. 框架支持的模式
四. 生命周期扩展
五. 常见问题
六. 终极定制
一. 全局介绍
整个SDK的核心框架代码部分不超过300行,支持多租户平台模式,以及对各类特殊微信消息的扩展性。代码在 OSS.SnsSdk下的OSS.SnsSdk.Msg.Wx,【开源中国】和【Github】都可以搜到。
Nuget安装命令:Install-Package OSS.SnsSdk.Msg.Wx
调用方式:
二. 配置管理
(示例详见:WxMsgController.cs)
1. 通过构造函数传入,适合单一的应用,这种情况下的配置信息生存周期和当前config实例同步
2. 通过 SetContext方式 注入,适合多租户,平台的方式使用,这个时候配置的生存周期只在当前请求的整个上下文中有效。
三. 框架使用
首先,框架组成元素(可以直接跳到使用模式,再回过头来看):
1. 实体对象,也就是消息体对象,主要分为:
a. 接收消息(继承自 WxBaseRecMsg 的普通消息 和 继承自 WxBaseRecEventMsg 的事件消息系统默认实现了 六种普通消息和五种事件消息对象,在后边的使用模式中介绍如何扩展其他对象类型
b. 回复消息(继承自 WxBaseReplyMsg ,主要是响应给微信接口的实体(当前支持六种 + WxNoneReplyMsg)
除非特殊情况,否则返回消息基本就是这几种类型。当前可用回复消息:
WxTextReplyMsg-回复文本消息,WxImageReplyMsg-回复图片消息,
WxVoiceReplyMsg-回复语音消息,WxVideoReplyMsg-回复视频消息,
WxMusicReplyMsg-回复音频消息,WxNewsReplyMsg-回复图文消息
WxNoneReplyMsg 表示不需要给对方响应,系统会返回给微信端success 。使用中可以使用 WxNoneReplyMsg.None 默认值。
c. 消息上下文(WxMsgContext 对象
含有 RecMsg 和 ReplyMsg 两个属性,也就是上边的接收消息和回复消息,方便在生命周期中控制
2. Handler,消息处理控制类,实现整个消息处理的生命周期和执行调度
当前系统有 WxMsgBaseHandler 和 WxMsgHandler 两个,前者作为基类,实现了生命周期的控制和调度。 后者则实现了系统基础消息的事件定义(六个普通消息事件 和 五个Event消息事件)
3. Procesor(WxMsgProcessor<TRecMsg>),消息的具体执行者.
这个只有在高级定制模式下才会需要用户自定义
其次,框架支持的模式
1. 基础模式
系统 WxMsgHandler.cs 默认实现常见的六种普通消息和五种事件消息,只需要重写(overwrite)对应的以 Process 开头的方法即可。每个方法的参数对应的都是详细的消息类型。以文本类型消息举例:
protected override WxBaseReplyMsg ProcessTextMsg(WxTextRecMsg msg)
{
return WxNoneReplyMsg.None;
} 那么可以重写的包含以下方法: // 处理文本消息
ProcessTextMsg(WxTextRecMsg msg) // 处理图像消息
ProcessImageMsg(WxImageRecMsg msg) // 处理语音消息
ProcessVoiceMsg(WxVoiceRecMsg msg) // 处理视频/小视频消息
ProcessVideoMsg(WxVideoRecMsg msg) // 处理地理位置消息
ProcessLocationMsg(WxLocationRecMsg msg) // 处理链接消息
ProcessLinkMsg(WxLinkRecMsg msg) // 处理关注/取消关注事件
ProcessSubscribeEventMsg(WxSubscribeRecEventMsg msg) // 处理扫描带参数二维码事件
ProcessScanEventMsg(WxSubscribeRecEventMsg msg) // 处理上报地理位置事件
ProcessLocationEventMsg(WxLocationRecEventMsg msg) // 处理点击菜单拉取消息时的事件推送
ProcessClickEventMsg(WxClickRecEventMsg msg) // 处理点击菜单跳转链接时的事件推送
ProcessViewEventMsg(WxViewRecEventMsg msg)
2. 进阶模式
对于不在基础实现类型的消息,系统提供注入消息处理委托的模式来处理消息,以一个 test_msg 消息类型注入示例
a. 定义消息实体:
public class WxTestRecMsg : WxBaseRecMsg
{
public string Test { get; set; }
// 重写实体实体内部属性赋值
protected override void
FormatPropertiesFromMsg()
{
Test = this["Test"];
}
}
b. 定义处理委托:
private static WxTextReplyMsg ProcessTestMsg(WxTestRecMsg msg)
{
return new WxTextReplyMsg()
{ Content = " test_msg 类型消息返回 " };
}
c. 注入(内含:RegisteEventProcessor方法):
WxMsgProcessorProvider.RegisteProcessor<WxTextRecMsg>("test_msg", ProcessTestMsg);
恭喜,你已经完成了新的消息类型处理注入。
3. 高级模式
自定义Processor,基础模式和进阶模式中都在内部实现了Processor的调度,这里依然使用上边示例:
a. 定义实体(这里继续使用 WxTestRecMsg)
b. 定义CustomeHandler, 重写获取Processor方法
public class CustomeHandler:WxmsgHandler
{
protected override WxMsgProcessor GetCustomProcessor(string msgType,string eventName,
IDictionary<string, string> msgInfo)
{
if (msgType=="test_msg")
{
return new WxMsgProcessor<WxTestRecMsg>()
{
// 此委托属性满足对性能有要求的同学
// 如果不填则系统默认会通过泛型的 new t() 创建
RecInsCreater=() => new WxTestRecMsg(), // 具体事件处理委托
// 也可以使用上例的 ProcessTestMsg
ProcessFunc = msg => WxNoneReplyMsg.None
};
}
return null;
}
}
恭喜,你又完成了高级模式下的定制。
四. 生命周期扩展
上边讲解了几种模式主要实现方式,那么在实际的使用过程中你会遇到消息的重复判断,对特定消息的转发等。在系统处理的不同阶段,我定义了几个主要的处理事件,来满足对消息处理时的全局和局部控制,分别对应在WxMsgBaseHandler的以Execute开头的虚方法:
1. Executing(WxMsgContext context),开始执行事件,作为范围为全部消息类型。所有的消息类型都会经过这个事件,然后执行具体消息类型对应的委托,此时 msgContext 中的 ReplyMsg,如果给context中的 ReplyMsg 属性赋值,则 后边定义的对应的具体消息委托放弃执行。
在这个事件中我们可以过滤重复消息,用户授权验证等
2. ExecuteUnknowProcessor(WxBaseRecMsg msg) ,未知消息类型事件,作用范围为所有未发现对应处理委托的消息类型。在执行具体的事件时,如果当前消息类型未能找到对应的处理委托,则会唤起这个方法,需要注意的是,即使你使用的是 WxMsgHandler ,如果没有重写其 实现,或者返回了为空, 也会触发此方法
可以通过这个方法中添加未知类型消息日志等
3. ExecuteEnd(WxMsgContext msgContext), 执行结束时调用的方法,作为范围为全部消息类型。具体消息处理委托执行结束,回复微信响应之前。此时 msgContext 中的 ReplyMsg 不为空,如果前面执行方法中返回null,在执行此方法之前,会默认赋值 WxNoneReplyMsg.None
可以在这里添加全局日志,None类型的消息转发客服等。
五. 常见问题
1. 各模式的适用场景及区别
基础模式,此模式已经由系统内部实现,只需要重写委托方法即可,简单方便,基本适用大部分的场景
进阶模式,只需要消息类型,和消息处理委托 在程序入口处注册即可,简单灵活。
其适用场景:基本满足一般的所有定制需求,但消息体的MsgType不能为空,微信某些特殊事件无法满足
高级模式,使用的是子类继承模式,每个子类都可以实现同一消息类型下不同定制委托
其适用的场景: 多租户平台下针对每种消息类型,不同的平台等级都有不同的特殊定制实现,以及所有特殊的消息事件
几种模式的优先级:基础模式(使用WxMsgHandler时) => 高级模式 => 进阶模式
举例:如果你同时在高级模式和进阶模式下定义了一个消息类型为"test"的处理实现,系统默认使用高级模式下的实现。如果你的控制类直接继承了 WxMsgBaseHandler 则 不会进入基础模式
2. 对象属性的赋值问题
如果你自定义了接收消息实体的对象,需要重写FormatPropertiesFromMsg方法,详见 进阶模式下 2.a 的实现。
对应响应的消息,不需要在执行委托里给 ToUserName,FromUserName,CreateTime 赋值,系统自动处理。
3. 使用反射的地方
为了尽可能减少系统底层给带来的性能影响,所以在系统中基本没有使用反射和序列化,有两个地方需要注意一下:
1. 需要在 FormatPropertiesFromMsg 中给自己的属性赋值,系统尽可能的提供了this索引来简化赋值的方式。
2. 自定义Processor(继承WxMsgProcessor<TRecMsg>或者子类)时,RecInsCreater属性如果不赋值,
则系统底层在 创建对应的实例时,通过泛型的 new() 机制实现,属于反射。
六. 终极定制
前面基本都能满足所有的定制需求了,但是如果可能...你还想要更大的定制自由度,那么我这里也尽力的满足你。在生命周期扩展中其实还有一个方法,这个方法是总的执行方法,其他的生命周期事件也都是在这里触发:
ResultMo<WxMsgContext> Execute(string recMsgXml)
如果你希望自己定义一套完整的生命周期,OK,重写这里即可。系统将帮你完成验签,消息对象赋值,加密等边缘操作,只需要记住一件事情,如果你重写了这里,上述的几种模式和其他生命周期事件将无效。
=============================
如果你还有其他问题,欢迎关注公众号(OSSCoder)
一个还算简单的微信消息SDK(基于.Net Standard 2.0)的更多相关文章
- 解决微信官方SDK给出1.4.0等版本没有预览文件(previewFile)等接口
使用苹果手机测试 调用微信的js-sdk在系统中实现上传.预览附件的功能.在自己的手机测试通过后,直接丢给QA测试了 本以为相安无事了,没想到QA用安卓手机测的时候居然不得,使用的是下载下来的jwei ...
- 微信小程序基于最新版1.0开发者工具分享-小试牛刀(视频)+发布流程
第一章:小程序初级入门教程 小试牛刀[含视频] 视频地址:https://v.qq.com/x/page/i0554akzobq.html 这一章节中,我们尝试着写一个最简单的例子,包含 2 个静态页 ...
- 开源一个基于dotnet standard的轻量级的ORM框架-Light.Data
还在dotnet framework 2.0的时代,当时还没有EF,而NHibernate之类的又太复杂,并且自己也有一些特殊需求,如查询结果直接入表.水平分表和新增数据默认值等,就试着折腾个轻量点O ...
- 使用 CocoaPods 给微信集成 SDK 打印收发消息
使用 CocoaPods 给微信集成 SDK 打印收发消息 推荐序 本文介绍的是一套逆向工具,可以在非越狱手机上给任意应用增加插件.在文末的示例中,作者拿微信举例,展示出在微信中打印收发消息的功能. ...
- 线程安全使用(四) [.NET] 简单接入微信公众号开发:实现自动回复 [C#]C#中字符串的操作 自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化 自已动手做高性能消息队列 自行实现高性能MVC WebAPI 面试题随笔 字符串反转
线程安全使用(四) 这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来. 这里主要讲解下CancellationT ...
- 手把手教你用redis实现一个简单的mq消息队列(java)
众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...
- Unity接入微信支付SDK 2022年版安卓篇
最近1年转了UE开发,博客更新的比较少,技术栈宽了不少,以后有空尽量多更新,也方便总结记忆 Unity接入微信支付整个过程坑比较多,网上之前的教程要么比较老,要么比较零碎,只能东拼西凑摸索,跑通后还是 ...
- 微信消息体签名及加解密功能详细解析以及.net实现
原文:微信消息体签名及加解密功能详细解析以及.net实现 前言 微信消息体签名及加密功能已上线,明文传输确实存在安全风险,鉴于微信的用户范围使用之广泛,必定会成为众矢之的.所以大家还是尽快接入安全模式 ...
- ValueInjecter----最好用的OOM(以微信消息转对象举例)
使用数据实体的好处我这里就不多说了,但大家享受这些好处的时候,难免也对那些琐碎的赋值代码感到厌烦,基于此,我认为掌握一个oom的使用,还是很有必要的. 这种类型的工具有很多,比如automapper, ...
随机推荐
- Spring定时器实现(二)
Spring结合quarzt可以实现更复杂的定时器,现做简单介绍相关配置: <?xml version="1.0" encoding="UTF-8"?&g ...
- DL4NLP——词表示模型(二)基于神经网络的模型:NPLM;word2vec(CBOW/Skip-gram)
本文简述了以下内容: 神经概率语言模型NPLM,训练语言模型并同时得到词表示 word2vec:CBOW / Skip-gram,直接以得到词表示为目标的模型 (一)原始CBOW(Continuous ...
- 《HelloGitHub》第 16 期
<HelloGitHub>第 16 期 兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程. ...
- MySQL学习笔记(四):存储引擎的选择
一:几种常用存储引擎汇总表 二:如何选择 一句话:除非需要InnoDB 不具备的特性,并且没有其他办法替代,否则都应该优先考虑InnoDB:或者,不需要InnoDB的特性,并且其他的引擎更加合适当前情 ...
- AC自动机总结及板子(不带指针)
蒟蒻最近想学个AC自动机简直被网上的板子搞疯了,随便点开一个都是带指针的,然而平时用到指针的时候并不多,看到这些代码也完全是看不懂的状态.只好在大概理解后自己脑补(yy)了一下AC自动机的代码,居然还 ...
- Mysql的JDBC
Java程序可以通过JDBC链接数据库,通过JDBC可以方便的访问数据库,不必为特定的数据库编写专门的程序. 需要先配置mysql-connector-java-5.0.8-bin.jar 使用JDB ...
- phpMyAdmin安装部署
phpMyAdmin 是一个用PHP编写的软件工具,可以通过web方式控制和操作MySQL数据库.通过phpMyAdmin 可以完全对数据库进行操作,例如建立.复制和删除数据等等.如果使用合适的工具, ...
- Uva140 Bandwidth 全排列+生成测试法+剪枝
参考过仰望高端玩家的小清新的代码... 思路:1.按字典序对输入的字符串抽取字符,id[字母]=编号,id[编号]=字母,形成双射 2.邻接表用两个vector存储,存储相邻关系 ...
- LFLiveKit架构简介
LFLiveSession LFLiveSession 是整个sdk的核心,提供对外部的主要接口.主要功能有:管理推流开关.管理音视频录制及渲染.管理录制渲染后的音视频编码.管理编码后的数据上传.管理 ...
- CentOS Linux 系统 英文 改中文
CentOS Linux 系统 英文 改中文 首先,使用root用户登录Linux系统,然后进入打开终端(桌面上右键第四个选项,应该是),然后进入到etc/sysconfig目录下