一个还算简单的微信消息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 voidFormatPropertiesFromMsg(){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 {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(),// 具体事件处理委托// 也可以使用上例的 ProcessTestMsgProcessFunc = 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不能为空,微信某些特殊事件无法满足

 高级模式,使用的是子类继承模式,每个子类都可以实现同一消息类型下不同定制委托
  其适用的场景: 多租户平台下针对每种消息类型,不同的平台等级都有不同的特殊定制实现,
以及所有特殊的消息事件

 2.几种模式的优先级:

    基础模式(使用WxMsgHandler时) => 高级模式 => 进阶模式
 举例:如果你同时在高级模式和进阶模式下定义了一个消息类型为"test"的处理实现,系统默认使用高级模式下的实现。如果你的控制类直接继承了 WxMsgBaseHandler 则 不会进入基础模式

 3. 对象属性的赋值问题

 如果你自定义了接收消息实体的对象,需要重写FormatPropertiesFromMsg方法,详见 进阶模式下 2.a 的实现。
 对应响应的消息,不需要在执行委托里给 ToUserName,FromUserName,CreateTime 赋值,系统自动处理。

 4. 使用反射的地方

 为了尽可能减少系统底层给带来的性能影响,所以在系统中基本没有使用反射和序列化,有两个地方需要注意一下:

 1. 需要在 FormatPropertiesFromMsg 中给自己的属性赋值,系统尽可能的提供了this索引来简化赋值的方式。

 2. 自定义Processor(继承WxMsgProcessor<TRecMsg>或者子类)时,RecInsCreater属性如果不赋值,
 则系统底层在 创建对应的实例时,通过泛型的 new() 机制实现,属于反射。

 六. 终极大招
 前面基本都能满足所有的定制需求了,但是如果可能...你还想要更大的定制自由度,那么我这里也尽力的满足你。在生命周期扩展中其实还有一个方法,这个方法是总的执行方法,其他的生命周期事件也都是在这里触发:
 ResultMo<WxMsgContext> Execute(string recMsgXml)

 如果你希望自己定义一套完整的生命周期,OK,重写这里即可。系统将帮你完成验签,消息对象赋值,加密等边缘操作只需要记住一件事情,如果你重写了这里,上述的几种模式和其他生命周期事件将无效。

相关文章: 

  • 限时团购,6.9折:《微信开发深度解析:公众号、小程序高效开发秘籍》推荐序

  • OSS.Social微信项目标准库介绍

  • 微信和支付宝支付模式详解及实现(.Net标准库)

原文地址:http://www.cnblogs.com/osscoder/p/7467537.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323835.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汇编语言(二十八)之统计单词

输入一行字符串&#xff0c;统计单词SUN出现的个数 程序运行&#xff1a; 代码&#xff1a; datas segmentENG_max_length db 0ffhENG_length db 0ENG db 100h dup(?)eng_len dw 0SUN db SUNsun_len dw $-SUNcount dw 0…

这可能就是写代码的乐趣吧,你,也一定会爱上写代码的!

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”现在是&#xff1a;2021年10月23日22:02:41。于我来说&#xff0c;最感兴趣的莫过于上课和写代码了。最近一下在做一个项目&#xff0c;可能是前期数据库设计的不是很好&#xff0c;导…

汇编语言(二十九)之数值的二进制和十进制

给定一个数&#xff0c;输出该数的二进制和十进制数 程序运行&#xff1a; 代码&#xff1a; datas segmentVAL1 dw 156datas endsstacks segment stackdb 100h dup(?)stacks endscodes segmentassume cs:codes,ds:datas,ss:stacks BANDO proc far start:push dsmov ax,0…

ASP.NET Core MVC – Tag Helper 组件

ASP.NET Core Tag Helpers系列目录&#xff0c;这是第五篇&#xff0c;共五篇&#xff1a; ASP.NET Core MVC – Tag Helpers 介绍ASP.NET Core MVC – Caching Tag HelpersASP.NET Core MVC – Form Tag HelpersASP.NET Core MVC – 自定义 Tag HelpersASP.NET Core MVC – T…

vue+elementui中,el-select多选下拉列表中,如何同时获取:value和:label的值?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 项目场景&#xff1a; 正如题目所说&#xff0c;今天在项目过程中遇到了个需求&#xff0c;因为需要在前台展示运动员的名称&#xff0c;但是运动员的编号在别的地方还需要使用&#xff…

C#使用Xamarin开发可移植移动应用进阶篇(9.混淆代码,防止反编译)

嗯,既然是客户端应用,自然而然就需要一些防止源码泄漏的手段.通过C#编写的APP,完全是可以直接解压APK,然后得到里面的DLL然后进行反编译的.. 如下图: 嗯..这样就会造成代码泄漏.. 下面就介绍一下,如何使用VS自带的Dotfuscator来进行混淆代码. 1.安装Dotfuscator 打开VS2017…

想绝交,就借钱!

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”今天谈论的话题只有两个字&#xff0c;就是“钱”之前在原来单位工作的时候&#xff0c;老板就给我说&#xff0c;我弟弟的工资让我帮忙管着&#xff0c;不然到用的时候拿不出来&#…

luoguSP1805,POJ2559-Largest Rectangle in a Histogram【单调栈】

正题 POJ题目链接:http://poj.org/problem?id2559 luogu评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidSP1805 大意 有n个高度不同&#xff0c;宽度为1的长方形排列在一起。找到一个长方形使其面积最大 解题思路 我们先考虑单调递增的情况 …

Orleans解决并发之痛(一):单线程

程序在运行过程中有时会莫名其妙出现代码的某些约束或者执行结果和理想状况不一样&#xff0c;正常逻辑怎么会出现这样的情况&#xff1f;到底发生了什么&#xff1f;好像见了鬼&#xff01;瞬间好无助。 谁来救救我 大多数出现正常逻辑很难解释的时候&#xff0c;我们可能会想…

你们考试,我们都有点紧张呢…

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”考试计划都好久好久了&#xff0c;一直没有时间&#xff0c;终于在今天考了一次。去监考的时候王老师还说&#xff0c;我都有点紧张呢&#xff0c;我说我也是&#xff0c;哈哈哈~上午几…

汇编语言(三十一)之数字字符串加密与解密

输入一串数字&#xff0c;然后进行加密解密输出 程序运行&#xff1a; 代码&#xff1a; datas segmentline_max_len db 0ffh line db 0, 100h dup(?)linesecret db 0, 100h dup(?)linedesecret db 0, 100h dup(?)secret …

ASP.NET Core 运行原理解剖[1]:Hosting

SP.NET Core 是新一代的 ASP.NET&#xff0c;第一次出现时代号为 ASP.NET vNext&#xff0c;后来命名为ASP.NET 5&#xff0c;随着它的完善与成熟&#xff0c;最终命名为 ASP.NET Core&#xff0c;表明它不是 ASP.NET 的升级&#xff0c;而是一个重新设计的Web开发框架。而它一…

公众号文章

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 常用的几个sql整理 1.按照日期统计今天的客流信息。 SELECT * FROM base_disanfang WHERE DATE_FORMAT(create_time,%Y-%m-%d) DATE_FORMAT(NOW(),%Y-%m-%d) 其中base_disanfang为表名…

2017(深圳) .NET技术分享交流会 第二期,将有网络直播

2017 .NET技术分享交流会第一期已在5月13日成功举办&#xff0c;但是有同学反馈哪个地方有点偏&#xff0c;又过去了3个月&#xff0c;这期间一直没找到合适的地方举办活动&#xff0c;一直在南山科技园寻找经济适合的场地&#xff0c;终于找到一个安静&#xff0c;风景好的深圳…

整理几个常用的sql和其他代码

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”常用的几个sql整理1.按照日期统计今天的客流信息。SELECT * FROM base_disanfang WHERE DATE_FORMAT(create_time,%Y-%m-%d) DATE_FORMAT(NOW(),%Y-%m-%d)其中base_disanfang为表名&…

汇编语言(三十三)之四进制转十进制

输入四进制的数&#xff0c;转为十进制输出 程序运行&#xff1a; 代码&#xff1a; datas segmentN_string_max_length db 0ffhN_string db 0, 100h dup(?)N dw 0,0 sum dd 0 input db inp…

Orleans解决并发之痛(二):Grain状态

Grains是Orleans应用程序的构建块&#xff0c;它们是彼此孤立的原子单位&#xff0c;分布的&#xff0c;持久的&#xff0c; 一个典型的Grain是有状态和行为的一个单实例&#xff0c;每个Grain实例的在单线程内执行&#xff0c;Grain之间共享数据通过消息传递&#xff0c;Grain…

汇编语言(三十四)之输出中文

输出中文 程序运行&#xff1a; 代码&#xff1a; daones segmentfull_name db 0,1,2,3,4,5 full_name_length dw $-full_name start_char db 0 change_char_count dw 6color db 1 x dw 40 y …

vue使用element ui实现下拉列表分页的功能!!!

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”前几天做了个功能&#xff0c;需求是使用利用element ui如何给下拉列表分页&#xff0c;经过网上查找&#xff0c;自己摸索&#xff0c;已经完成&#xff0c;今天来记录一下吧。实现的…

ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍

在上一章ASP.NET Core 运行原理解剖[1]:Hosting中&#xff0c;我们介绍了 ASP.NET Core 的启动过程&#xff0c;主要是对 WebHost 源码的探索。而本文则是对上文的一个补充&#xff0c;更加偏向于实战&#xff0c;详细的介绍一下我们在实际开发中需要对 Hosting 做一些配置时经…