WeixinExecutor.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. using System.Web;
  2. using LYFZ.Weixin.SDK;
  3. using System.Text;
  4. using System.Text.RegularExpressions;
  5. using LYFZ.Weixin.SDK.Helpers;
  6. using LYFZ.Weixin.SDK.Entities;
  7. using System.Collections.Generic;
  8. //using LYFZ.Web.Services;
  9. namespace LYFZ.WXLibrary
  10. {
  11. public class WeixinExecutor : IWeixinExecutor
  12. {
  13. public WeixinExecutor()
  14. {
  15. }
  16. /// <summary>
  17. /// 说明:带TODO字眼的代码段,需要开发者自行按照自己的业务逻辑实现
  18. /// </summary>
  19. /// <param name="message"></param>
  20. /// <returns>已经打包成xml的用于回复用户的消息包</returns>
  21. public string Execute(WeixinMessage message)
  22. {
  23. var result = "";
  24. var domain = System.Configuration.ConfigurationManager.AppSettings["Domain"];//请更改成你的域名
  25. var openId = message.Body.FromUserName.Value;
  26. var myUserName = message.Body.ToUserName.Value;
  27. //这里需要调用TokenHelper获取Token的,省略了。
  28. switch (message.Type)
  29. {
  30. case WeixinMessageType.Text://文字消息
  31. string userMessage = message.Body.Content.Value;
  32. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, "欢迎使用,您输入了:" + userMessage);
  33. break;
  34. case WeixinMessageType.Image://图片消息
  35. string imageUrl = message.Body.PicUrl.Value;//图片地址
  36. string mediaId = message.Body.MediaId.Value;//mediaId
  37. result = ReplayPassiveMessageAPI.ReplayImage(openId, myUserName, mediaId);
  38. break;
  39. case WeixinMessageType.Video://视频消息
  40. #region 视频消息
  41. {
  42. var media_id = message.Body.MediaId.Value.ToString();
  43. var thumb_media_id = message.Body.ThumbMediaId.Value.ToString();
  44. var msgId = message.Body.MsgId.Value.ToString();
  45. //TODO
  46. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("视频消息:openid:{0},media_id:{1},thumb_media_id:{2},msgId:{3}", openId, media_id, thumb_media_id, msgId));
  47. }
  48. #endregion
  49. break;
  50. case WeixinMessageType.Voice://语音消息
  51. #region 语音消息
  52. {
  53. var media_id = message.Body.MediaId.Value.ToString();
  54. var format = message.Body.Format.Value.ToString();
  55. var msgId = message.Body.MsgId.Value.ToString();
  56. //TODO
  57. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("语音消息:openid:{0},media_id:{1},format:{2},msgId:{3}", openId, media_id, format, msgId));
  58. }
  59. #endregion
  60. break;
  61. case WeixinMessageType.Location://地理位置消息
  62. #region 地理位置消息
  63. {
  64. var location_X = message.Body.Location_X.Value.ToString();
  65. var location_Y = message.Body.Location_Y.Value.ToString();
  66. var scale = message.Body.Scale.Value.ToString();
  67. var Label = message.Body.Label.Value.ToString();
  68. //TODO
  69. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("地理位置消息: openid:{0},Location_X:{1},Location_Y:{2},Scale:{3},label:{4}", openId, location_X, location_Y, scale, Label));
  70. }
  71. #endregion
  72. break;
  73. case WeixinMessageType.Link://链接消息
  74. #region 链接消息
  75. {
  76. var title = message.Body.Title.Value.ToString();
  77. var description = message.Body.Description.Value.ToString();
  78. var url = message.Body.Url.Value.ToString();
  79. var msgId = message.Body.MsgId.Value.ToString();
  80. //TODO
  81. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("openid:{0},title:{1},description:{2},url:{3},msgId:{4}", openId, title, description, url, msgId));
  82. }
  83. #endregion
  84. break;
  85. case WeixinMessageType.Event:
  86. string eventType = message.Body.Event.Value.ToLower();
  87. string eventKey = string.Empty;
  88. try
  89. {
  90. eventKey = message.Body.EventKey.Value;
  91. }
  92. catch { }
  93. switch (eventType)
  94. {
  95. case "subscribe"://用户未关注时,进行关注后的事件推送
  96. #region 首次关注
  97. var token = WeixinConfig.TokenHelper.GetToken();
  98. //TODO: 获取用户基本信息后,将用户信息存储在本地。
  99. //var weixinInfo = UserAdminAPI.GetInfo(token, openId);//注意:订阅号没有此权限
  100. if (!string.IsNullOrEmpty(eventKey))
  101. {
  102. var qrscene = eventKey.Replace("qrscene_", "");//此为场景二维码的场景值
  103. result = ReplayPassiveMessageAPI.RepayNews(openId, myUserName,
  104. new WeixinNews
  105. {
  106. title = "欢迎订阅,场景值:" + qrscene,
  107. description = "欢迎订阅,场景值:" + qrscene,
  108. picurl = string.Format("{0}/ad.jpg", domain),
  109. url = domain
  110. });
  111. }
  112. else
  113. {
  114. result = ReplayPassiveMessageAPI.RepayNews(openId, myUserName,
  115. new WeixinNews
  116. {
  117. title = "欢迎订阅",
  118. description = "欢迎订阅,点击此消息查看在线demo",
  119. picurl = string.Format("{0}/ad.jpg", domain),
  120. url = domain
  121. });
  122. }
  123. #endregion
  124. break;
  125. case "unsubscribe"://取消关注
  126. #region 取消关注
  127. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, "欢迎再来");
  128. #endregion
  129. break;
  130. case "scan":// 用户已关注时的事件推送
  131. #region 已关注扫码事件
  132. if (!string.IsNullOrEmpty(eventKey))
  133. {
  134. var qrscene = eventKey.Replace("qrscene_", "");//此为场景二维码的场景值
  135. result = ReplayPassiveMessageAPI.RepayNews(openId, myUserName,
  136. new WeixinNews
  137. {
  138. title = "欢迎使用,场景值:" + qrscene,
  139. description = "欢迎使用,场景值:" + qrscene,
  140. picurl = string.Format("{0}/ad.jpg", domain),
  141. url = domain
  142. });
  143. }
  144. else
  145. {
  146. result = ReplayPassiveMessageAPI.RepayNews(openId, myUserName,
  147. new WeixinNews
  148. {
  149. title = "欢迎使用",
  150. description = "欢迎订阅,点击此消息查看在线demo",
  151. picurl = string.Format("{0}/ad.jpg", domain),
  152. url = domain
  153. });
  154. }
  155. #endregion
  156. break;
  157. case "masssendjobfinish"://事件推送群发结果,
  158. #region 事件推送群发结果
  159. {
  160. var msgId = message.Body.MsgID.Value;
  161. var msgStatus = message.Body.Status.Value;//“send success”或“send fail”或“err(num)”
  162. //send success时,也有可能因用户拒收公众号的消息、系统错误等原因造成少量用户接收失败。
  163. //err(num)是审核失败的具体原因,可能的情况如下:err(10001)涉嫌广告, err(20001)涉嫌政治, err(20004)涉嫌社会, err(20002)涉嫌色情, err(20006)涉嫌违法犯罪,
  164. //err(20008)涉嫌欺诈, err(20013)涉嫌版权, err(22000)涉嫌互推(互相宣传), err(21000)涉嫌其他
  165. var totalCount = message.Body.TotalCount.Value;//group_id下粉丝数;或者openid_list中的粉丝数
  166. var filterCount = message.Body.FilterCount.Value;//过滤(过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,FilterCount = SentCount + ErrorCount
  167. var sentCount = message.Body.SentCount.Value;//发送成功的粉丝数
  168. var errorCount = message.Body.FilterCount.Value;//发送失败的粉丝数
  169. //TODO:开发者自己的处理逻辑,这里用log4net记录日志
  170. CommonHandleClass.WriteLog(string.Format("mass send job finishe,msgId:{0},msgStatus:{1},totalCount:{2},filterCount:{3},sentCount:{4},errorCount:{5}", msgId, msgStatus, totalCount, filterCount, sentCount, errorCount));
  171. }
  172. #endregion
  173. break;
  174. case "templatesendjobfinish"://模版消息结果,
  175. #region 模版消息结果
  176. {
  177. var msgId = message.Body.MsgID.Value;
  178. var msgStatus = message.Body.Status.Value;//发送状态为成功: success; 用户拒绝接收:failed:user block; 发送状态为发送失败(非用户拒绝):failed: system failed
  179. //TODO:开发者自己的处理逻辑,这里用log4net记录日志
  180. CommonHandleClass.WriteLog(string.Format("template send job finish,msgId:{0},msgStatus:{1}", msgId, msgStatus));
  181. }
  182. #endregion
  183. break;
  184. case "location"://上报地理位置事件
  185. #region 上报地理位置事件
  186. var lat = message.Body.Latitude.Value.ToString();
  187. var lng = message.Body.Longitude.Value.ToString();
  188. var pcn = message.Body.Precision.Value.ToString();
  189. //TODO:在此处将经纬度记录在数据库,这里用log4net记录日志
  190. CommonHandleClass.WriteLog(string.Format("openid:{0} ,location,lat:{1},lng:{2},pcn:{3}", openId, lat, lng, pcn));
  191. #endregion
  192. break;
  193. case "voice"://语音消息
  194. #region 语音消息
  195. //A:已开通语音识别权限的公众号
  196. var userVoice = message.Body.Recognition.Value;//用户语音消息文字
  197. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, "您说:" + userVoice);
  198. //B:未开通语音识别权限的公众号
  199. var userVoiceMediaId = message.Body.MediaId.Value;//media_id
  200. //TODO:调用自定义的语音识别程序识别用户语义
  201. #endregion
  202. break;
  203. case "image"://图片消息
  204. #region 图片消息
  205. var userImage = message.Body.PicUrl.Value;//用户语音消息文字
  206. result = ReplayPassiveMessageAPI.RepayNews(openId, myUserName, new WeixinNews
  207. {
  208. title = "您刚才发送了图片消息",
  209. picurl = string.Format("{0}/Images/ad.jpg", domain),
  210. description = "点击查看图片",
  211. url = userImage
  212. });
  213. #endregion
  214. break;
  215. case "click"://自定义菜单事件
  216. #region 自定义菜单事件
  217. {
  218. switch (eventKey)
  219. {
  220. case "myaccount"://CLICK类型事件举例
  221. #region 我的账户
  222. result = ReplayPassiveMessageAPI.RepayNews(openId, myUserName, new List<WeixinNews>()
  223. {
  224. new WeixinNews{
  225. title="我的帐户",
  226. url=string.Format("{0}/user?openId={1}",domain,openId),
  227. description="点击查看帐户详情",
  228. picurl=string.Format("{0}/Images/ad.jpg",domain)
  229. },
  230. });
  231. #endregion
  232. break;
  233. case "www.weixinsdk.net"://VIEW类型事件举例,注意:点击菜单弹出子菜单,不会产生上报。
  234. //TODO:后台处理逻辑
  235. break;
  236. default:
  237. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, "没有响应菜单事件");
  238. break;
  239. }
  240. }
  241. #endregion
  242. break;
  243. case "view"://点击菜单跳转链接时的事件推送
  244. #region 点击菜单跳转链接时的事件推送
  245. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("您将跳转至:{0}", eventKey));
  246. #endregion
  247. break;
  248. case "scancode_push"://扫码推事件的事件推送
  249. {
  250. var scanType = message.Body.ScanCodeInfo.ScanType.Value;//扫描类型,一般是qrcode
  251. var scanResult = message.Body.ScanCodeInfo.ScanResult.Value;//扫描结果,即二维码对应的字符串信息
  252. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("您扫描了二维码,scanType:{0},scanResult:{1},EventKey:{2}", scanType, scanResult, eventKey));
  253. }
  254. break;
  255. case "scancode_waitmsg"://扫码推事件且弹出“消息接收中”提示框的事件推送
  256. {
  257. var scanType = message.Body.ScanCodeInfo.ScanType.Value;//扫描类型,一般是qrcode
  258. var scanResult = message.Body.ScanCodeInfo.ScanResult.Value;//扫描结果,即二维码对应的字符串信息
  259. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("您扫描了二维码,scanType:{0},scanResult:{1},EventKey:{2}", scanType, scanResult, eventKey));
  260. }
  261. break;
  262. case "pic_sysphoto"://弹出系统拍照发图的事件推送
  263. {
  264. var count = message.Body.SendPicsInfo.Count;//发送的图片数量
  265. var picList = message.Body.PicList;//发送的图片信息
  266. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("弹出系统拍照发图,count:{0},EventKey:{1}", count, eventKey));
  267. }
  268. break;
  269. case "pic_photo_or_album"://弹出拍照或者相册发图的事件推送
  270. {
  271. var count = message.Body.SendPicsInfo.Count.Value;//发送的图片数量
  272. var picList = message.Body.PicList.Value;//发送的图片信息
  273. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("弹出拍照或者相册发图,count:{0},EventKey:{1}", count, eventKey));
  274. }
  275. break;
  276. case "pic_weixin"://弹出微信相册发图器的事件推送
  277. {
  278. var count = message.Body.SendPicsInfo.Count.Value;//发送的图片数量
  279. var picList = message.Body.PicList.Value;//发送的图片信息
  280. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("弹出微信相册发图器,count:{0},EventKey:{1}", count, eventKey));
  281. }
  282. break;
  283. case "location_select"://弹出地理位置选择器的事件推送
  284. {
  285. var location_X = message.Body.SendLocationInfo.Location_X.Value;//X坐标信息
  286. var location_Y = message.Body.SendLocationInfo.Location_Y.Value;//Y坐标信息
  287. var scale = message.Body.SendLocationInfo.Scale.Value;//精度,可理解为精度或者比例尺、越精细的话 scale越高
  288. var label = message.Body.SendLocationInfo.Label.Value;//地理位置的字符串信息
  289. var poiname = message.Body.SendLocationInfo.Poiname.Value;//朋友圈POI的名字,可能为空
  290. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("弹出地理位置选择器,location_X:{0},location_Y:{1},scale:{2},label:{3},poiname:{4},eventKey:{5}", location_X, location_Y, scale, label, poiname, eventKey));
  291. }
  292. break;
  293. case "card_pass_check"://生成的卡券通过审核时,微信会把这个事件推送到开发者填写的URL。
  294. {
  295. var cardid = message.Body.CardId.Value;//CardId
  296. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("您的卡券已经通过审核"));
  297. }
  298. break;
  299. case "card_not_pass_check"://生成的卡券未通过审核时,微信会把这个事件推送到开发者填写的URL。
  300. {
  301. var cardid = message.Body.CardId.Value;//CardId
  302. }
  303. break;
  304. case "user_get_card"://用户在领取卡券时,微信会把这个事件推送到开发者填写的URL。
  305. {
  306. var cardid = message.Body.CardId.Value;//CardId
  307. var isGiveByFriend = message.Body.IsGiveByFriend.Value;//是否为转赠,1代表是,0代表否。
  308. var fromUserName = message.Body.FromUserName.Value;//领券方帐号(一个OpenID)
  309. var friendUserName = message.Body.FriendUserName.Value;//赠送方账号(一个OpenID),"IsGiveByFriend”为1时填写该参数。
  310. var userCardCode = message.Body.UserCardCode.Value;//code序列号。自定义code及非自定义code的卡券被领取后都支持事件推送。
  311. var outerId = message.Body.OuterId.Value;//领取场景值,用于领取渠道数据统计。可在生成二维码接口及添加JSAPI接口中自定义该字段的整型值。
  312. }
  313. break;
  314. case "user_del_card"://用户在删除卡券时,微信会把这个事件推送到开发者填写的URL
  315. {
  316. var cardid = message.Body.CardId.Value;//CardId
  317. var userCardCode = message.Body.UserCardCode.Value;//商户自定义code值。非自定code推送为空
  318. }
  319. break;
  320. case "merchant_order"://微信小店:订单付款通知:在用户在微信中付款成功后,微信服务器会将订单付款通知推送到开发者在公众平台网站中设置的回调URL(在开发模式中设置)中,如未设置回调URL,则获取不到该事件推送。
  321. {
  322. var orderId = message.Body.OrderId.Value;//CardId
  323. var orderStatus = message.Body.OrderStatus.Value;//OrderStatus
  324. var productId = message.Body.ProductId.Value;//ProductId
  325. var skuInfo = message.Body.SkuInfo.Value;//SkuInfo
  326. }
  327. break;
  328. }
  329. break;
  330. default:
  331. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("未处理消息类型:{0}", message.Type));
  332. break;
  333. }
  334. return result;
  335. }
  336. /// <summary>
  337. /// 说明:带TODO字眼的代码段,需要开发者自行按照自己的业务逻辑实现
  338. /// </summary>
  339. /// <param name="message"></param>
  340. /// <returns>已经打包成xml的用于回复用户的消息包</returns>
  341. public string ServiceExecute(WeixinMessage message)
  342. {
  343. var result = "ERP 未处理的请求关键信息";
  344. var openId = message.Body.FromUserName.Value;
  345. var myUserName = message.Body.ToUserName.Value;
  346. //这里需要调用TokenHelper获取Token的,省略了。
  347. // LYFZ.WXLibrary.CommonHandleClass.WriteLog("message.Type:" + message.Type.ToString());
  348. switch (message.Type)
  349. {
  350. case WeixinMessageType.Text://文字消息
  351. string userMessage = message.Body.Content.Value;
  352. if (userMessage.IndexOf("#") > 0)
  353. {
  354. result = userMessage.Split('#')[0];
  355. }
  356. else {
  357. result = userMessage;
  358. }
  359. break;
  360. case WeixinMessageType.Voice:
  361. #region 语音消息
  362. {
  363. var media_id = message.Body.MediaId.Value.ToString();
  364. var format = message.Body.Format.Value.ToString();
  365. var msgId = message.Body.MsgId.Value.ToString();
  366. var Recognition = message.Body.Recognition.Value.ToString();
  367. result = Recognition.ToString().Trim().Replace("!", "").Replace("!", "").Replace(".", "").Replace("。", "");
  368. // LYFZ.WXLibrary.CommonHandleClass.WriteLog("用户语音消息文字:" + Recognition + " result:" + result);
  369. //TODO
  370. // result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("语音消息:openid:{0},media_id:{1},format:{2},msgId:{3}", openId, media_id, format, msgId));
  371. }
  372. #endregion
  373. break;
  374. case WeixinMessageType.Event:
  375. string eventType = message.Body.Event.Value.ToLower();
  376. string eventKey = string.Empty;
  377. try
  378. {
  379. eventKey = message.Body.EventKey.Value;
  380. }
  381. catch { }
  382. //LYFZ.WXLibrary.CommonHandleClass.WriteLog("eventType:" + eventType);
  383. switch (eventType)
  384. {
  385. case "subscribe"://用户未关注时,进行关注后的事件推送
  386. #region 首次关注
  387. // var token = WeixinConfig.TokenHelper.GetToken();
  388. //TODO: 获取用户基本信息后,将用户信息存储在本地。
  389. //var weixinInfo = UserAdminAPI.GetInfo(token, openId);//注意:订阅号没有此权限
  390. #endregion
  391. break;
  392. case "unsubscribe"://取消关注
  393. #region 取消关注
  394. // result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, "欢迎再来");
  395. #endregion
  396. break;
  397. case "scan":// 用户已关注时的事件推送
  398. break;
  399. case "masssendjobfinish"://事件推送群发结果,
  400. break;
  401. case "templatesendjobfinish"://模版消息结果,
  402. #region 模版消息结果
  403. {
  404. var msgId = message.Body.MsgID.Value;
  405. var msgStatus = message.Body.Status.Value;//发送状态为成功: success; 用户拒绝接收:failed:user block; 发送状态为发送失败(非用户拒绝):failed: system failed
  406. //TODO:开发者自己的处理逻辑,这里用log4net记录日志
  407. // CommonHandleClass.WriteLog(string.Format("template send job finish,msgId:{0},msgStatus:{1}", msgId, msgStatus));
  408. result = "templatesendjobfinish";
  409. }
  410. #endregion
  411. break;
  412. case "voice"://语音消息
  413. #region 语音消息
  414. //A:已开通语音识别权限的公众号
  415. // var userVoice = message.Body.Recognition.Value;//用户语音消息文字
  416. //B:未开通语音识别权限的公众号
  417. // var userVoiceMediaId = message.Body.MediaId.Value;//media_id
  418. //TODO:调用自定义的语音识别程序识别用户语义
  419. var userVoice = message.Body.Recognition.Value;//用户语音消息文字
  420. var userVoiceMediaId = message.Body.MediaId.Value;//media_id
  421. if (userVoice.ToString().Trim().Length > 0)
  422. {
  423. result = userVoice.ToString().Trim().Replace("!", "").Replace("!", "").Replace(".", "").Replace("。", "");
  424. // LYFZ.WXLibrary.CommonHandleClass.WriteLog("用户语音消息文字:" + result);
  425. }
  426. // result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, "您说:" + userVoice);
  427. //B:未开通语音识别权限的公众号
  428. // var userVoiceMediaId = message.Body.MediaId.Value;//media_id
  429. //TODO:调用自定义的语音识别程序识别用户语义
  430. #endregion
  431. break;
  432. case "click"://自定义菜单事件
  433. result = eventKey;
  434. break;
  435. }
  436. break;
  437. default:
  438. result = ReplayPassiveMessageAPI.RepayText(openId, myUserName, string.Format("未处理消息类型:{0}", message.Type));
  439. break;
  440. }
  441. return result;
  442. }
  443. }
  444. }