GroupMessageApi.cs 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219
  1. #region Apache License Version 2.0
  2. /*----------------------------------------------------------------
  3. Copyright 2019 Jeffrey Su & Suzhou Senparc Network Technology Co.,Ltd.
  4. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
  5. except in compliance with the License. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software distributed under the
  8. License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  9. either express or implied. See the License for the specific language governing permissions
  10. and limitations under the License.
  11. Detail: https://github.com/JeffreySu/WeiXinMPSDK/blob/master/license.md
  12. ----------------------------------------------------------------*/
  13. #endregion Apache License Version 2.0
  14. /*----------------------------------------------------------------
  15. Copyright (C) 2019 Senparc
  16. 文件名:GroupMessageAPI.cs
  17. 文件功能描述:高级群发接口
  18. 创建标识:Senparc - 20150211
  19. 修改标识:Senparc - 20150303
  20. 修改描述:整理接口
  21. 修改标识:Senparc - 20150312
  22. 修改描述:开放代理请求超时时间
  23. 修改标识:Senparc - 20160718
  24. 修改描述:增加其接口的异步方法
  25. 修改标识:Senparc - 20170402
  26. 修改描述:v14.3.140 1、添加BaseGroupMessageDataByGroupId.send_ignore_reprint属性
  27. 2、优化代码
  28. 修改标识:Senparc - 20170707
  29. 修改描述:v14.5.1 完善异步方法async/await
  30. 修改标识:Senparc - 2017224
  31. 修改描述:v14.8.12 完成群发接口添加clientmsgid属性
  32. 修改标识:Senparc - 20180319
  33. 修改描述:v14.10.8 GroupMessageApi.SendGroupMessageByFilter() 方法修复判断错误
  34. 修改标识:Senparc - 20180507
  35. 修改描述:v14.12.4 删除群发接口 GroupMessageApi.DeleteSendMessage() 添加article_idx参数
  36. 修改标识:Senparc - 20180928
  37. 修改描述:增加GetSendSpeed,SetSendSpeed
  38. ----------------------------------------------------------------*/
  39. /*
  40. API地址:http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html
  41. */
  42. using System;
  43. using System.Threading.Tasks;
  44. using Senparc.Weixin.Entities;
  45. using Senparc.CO2NET.Extensions;
  46. using Senparc.Weixin.MP.AdvancedAPIs.GroupMessage;
  47. using Senparc.NeuChar;
  48. using Senparc.Weixin.CommonAPIs;
  49. namespace Senparc.Weixin.MP.AdvancedAPIs
  50. {
  51. /// <summary>
  52. /// 高级群发接口
  53. /// </summary>
  54. public static class GroupMessageApi
  55. {
  56. //官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1481187827_i0l21
  57. #region 同步方法
  58. #region 根据分组或标签群发
  59. /// <summary>
  60. /// 根据分组或标签进行群发【订阅号与服务号认证后均可用】
  61. ///
  62. /// 请注意:
  63. /// 1、该接口暂时仅提供给已微信认证的服务号
  64. /// 2、虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,请小心测试
  65. /// 3、无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败。
  66. /// 4、群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  67. ///
  68. /// </summary>
  69. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  70. /// <param name="groupId">群发到的分组的group_id,参见用户管理中用户分组接口,若is_to_all值为true,可不填写group_id;如果groupId和tagId同时填写,优先使用groupId;groupId和tagId最多只能使用一个</param>
  71. /// <param name="tagId">群发到的标签的tag_id,若is_to_all值为true,可不填写tag_id;如果groupId和tagId同时填写,优先使用groupId;groupId和tagId最多只能使用一个</param>
  72. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  73. /// <param name="type"></param>
  74. /// <param name="isToAll">用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户,选择false可根据group_id发送给指定群组的用户</param>
  75. /// <param name="sendIgnoreReprint">待群发的文章被判定为转载时,是否继续群发</param>
  76. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  77. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  78. /// <returns></returns>
  79. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByFilter", true)]
  80. private static SendResult SendGroupMessageByFilter(string accessTokenOrAppId, string groupId, string tagId, string value, GroupMessageType type, bool isToAll = false, bool sendIgnoreReprint = false, string clientmsgid = null, int timeOut = Config.TIME_OUT)
  81. {
  82. return ApiHandlerWapper.TryCommonApi(accessToken =>
  83. {
  84. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/sendall?access_token={0}";
  85. BaseGroupMessageDataByFilter baseData = null;
  86. BaseGroupMessageByFilter filter = null;
  87. if (!groupId.IsNullOrEmpty())
  88. {
  89. filter = new GroupMessageByGroupId()
  90. {
  91. group_id = groupId,
  92. is_to_all = isToAll,
  93. };
  94. }
  95. else
  96. {
  97. filter = new GroupMessageByTagId()
  98. {
  99. tag_id = tagId,
  100. is_to_all = isToAll,
  101. };
  102. }
  103. switch (type)
  104. {
  105. case GroupMessageType.image:
  106. baseData = new GroupMessageByFilter_ImageData()
  107. {
  108. filter = filter,
  109. image = new GroupMessageByGroupId_MediaId()
  110. {
  111. media_id = value
  112. },
  113. msgtype = "image"
  114. };
  115. break;
  116. case GroupMessageType.voice:
  117. baseData = new GroupMessageByFilter_VoiceData()
  118. {
  119. filter = filter,
  120. voice = new GroupMessageByGroupId_MediaId()
  121. {
  122. media_id = value
  123. },
  124. msgtype = "voice"
  125. };
  126. break;
  127. case GroupMessageType.mpnews:
  128. baseData = new GroupMessageByFilter_MpNewsData()
  129. {
  130. filter = filter,
  131. mpnews = new GroupMessageByGroupId_MediaId()
  132. {
  133. media_id = value
  134. },
  135. msgtype = "mpnews"
  136. };
  137. break;
  138. case GroupMessageType.video:
  139. baseData = new GroupMessageByFilter_MpVideoData()
  140. {
  141. filter = filter,
  142. mpvideo = new GroupMessageByGroupId_MediaId()
  143. {
  144. media_id = value
  145. },
  146. msgtype = "mpvideo"
  147. };
  148. break;
  149. case GroupMessageType.wxcard:
  150. baseData = new GroupMessageByFilter_WxCardData()
  151. {
  152. filter = filter,
  153. wxcard = new GroupMessageByGroupId_WxCard()
  154. {
  155. card_id = value
  156. },
  157. msgtype = "wxcard"
  158. };
  159. break;
  160. case GroupMessageType.text:
  161. baseData = new GroupMessageByFilter_TextData()
  162. {
  163. filter = filter,
  164. text = new GroupMessageByGroupId_Content()
  165. {
  166. content = value
  167. },
  168. msgtype = "text"
  169. };
  170. break;
  171. default:
  172. throw new Exception("参数错误。");
  173. //break;
  174. }
  175. baseData.send_ignore_reprint = sendIgnoreReprint ? 0 : 1;//待群发的文章被判定为转载时,是否继续群发
  176. baseData.clientmsgid = clientmsgid;
  177. return CommonJsonSend.Send<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  178. }, accessTokenOrAppId);
  179. }
  180. /// <summary>
  181. /// 根据[分组]进行群发【订阅号与服务号认证后均可用】
  182. ///
  183. /// 请注意:
  184. /// 1、该接口暂时仅提供给已微信认证的服务号
  185. /// 2、虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,请小心测试
  186. /// 3、无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败。
  187. /// 4、群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  188. ///
  189. /// </summary>
  190. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  191. /// <param name="groupId">群发到的分组的group_id,参见用户管理中用户分组接口,若is_to_all值为true,可不填写group_id;如果groupId和tagId同时填写,优先使用groupId;groupId和tagId最多只能使用一个</param>
  192. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  193. /// <param name="type"></param>
  194. /// <param name="isToAll">用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户,选择false可根据group_id发送给指定群组的用户</param>
  195. /// <param name="sendIgnoreReprint">待群发的文章被判定为转载时,是否继续群发</param>
  196. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  197. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  198. /// <returns></returns>
  199. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByGroupId", true)]
  200. public static SendResult SendGroupMessageByGroupId(string accessTokenOrAppId, string groupId, string value, GroupMessageType type, bool isToAll = false, bool sendIgnoreReprint = false, string clientmsgid = null,
  201. int timeOut = Config.TIME_OUT)
  202. {
  203. return SendGroupMessageByFilter(accessTokenOrAppId, groupId, null, value, type, isToAll, sendIgnoreReprint, clientmsgid,
  204. timeOut);
  205. }
  206. /// <summary>
  207. /// 根据[标签]进行群发【订阅号与服务号认证后均可用】
  208. ///
  209. /// 请注意:
  210. /// 1、该接口暂时仅提供给已微信认证的服务号
  211. /// 2、虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,请小心测试
  212. /// 3、无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败。
  213. /// 4、群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  214. ///
  215. /// </summary>
  216. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  217. /// <param name="tagId">群发到的标签的tag_id,若is_to_all值为true,可不填写tag_id</param>
  218. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  219. /// <param name="type"></param>
  220. /// <param name="isToAll">用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户,选择false可根据group_id发送给指定群组的用户</param>
  221. /// <param name="sendIgnoreReprint">待群发的文章被判定为转载时,是否继续群发</param>
  222. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  223. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  224. /// <returns></returns>
  225. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByTagId", true)]
  226. public static SendResult SendGroupMessageByTagId(string accessTokenOrAppId, string tagId, string value, GroupMessageType type, bool isToAll = false, bool sendIgnoreReprint = false, string clientmsgid = null,
  227. int timeOut = Config.TIME_OUT)
  228. {
  229. return SendGroupMessageByFilter(accessTokenOrAppId, null, tagId, value, type, isToAll, sendIgnoreReprint, clientmsgid,
  230. timeOut);
  231. }
  232. #endregion
  233. /// <summary>
  234. /// 根据OpenId进行群发【订阅号不可用,服务号认证后可用】
  235. /// </summary>
  236. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  237. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  238. /// <param name="type"></param>
  239. /// <param name="openIds">openId字符串数组</param>
  240. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  241. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  242. /// <returns></returns>
  243. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByOpenId", true)]
  244. public static SendResult SendGroupMessageByOpenId(string accessTokenOrAppId, GroupMessageType type, string value, string clientmsgid = null, int timeOut = Config.TIME_OUT, params string[] openIds)
  245. {
  246. return ApiHandlerWapper.TryCommonApi(accessToken =>
  247. {
  248. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/send?access_token={0}";
  249. BaseGroupMessageDataByOpenId baseData = null;
  250. switch (type)
  251. {
  252. case GroupMessageType.image:
  253. baseData = new GroupMessageByOpenId_ImageData()
  254. {
  255. touser = openIds,
  256. image = new GroupMessageByOpenId_MediaId()
  257. {
  258. media_id = value
  259. },
  260. msgtype = "image"
  261. };
  262. break;
  263. case GroupMessageType.voice:
  264. baseData = new GroupMessageByOpenId_VoiceData()
  265. {
  266. touser = openIds,
  267. voice = new GroupMessageByOpenId_MediaId()
  268. {
  269. media_id = value
  270. },
  271. msgtype = "voice"
  272. };
  273. break;
  274. case GroupMessageType.mpnews:
  275. baseData = new GroupMessageByOpenId_MpNewsData()
  276. {
  277. touser = openIds,
  278. mpnews = new GroupMessageByOpenId_MediaId()
  279. {
  280. media_id = value
  281. },
  282. msgtype = "mpnews"
  283. };
  284. break;
  285. case GroupMessageType.wxcard:
  286. baseData = new GroupMessageByOpenId_WxCardData()
  287. {
  288. touser = openIds,
  289. wxcard = new GroupMessageByOpenId_WxCard()
  290. {
  291. card_id = value
  292. },
  293. msgtype = "wxcard"
  294. };
  295. break;
  296. case GroupMessageType.video:
  297. throw new Exception("发送视频信息请使用SendVideoGroupMessageByOpenId方法。");
  298. break;
  299. case GroupMessageType.text:
  300. baseData = new GroupMessageByOpenId_TextData()
  301. {
  302. touser = openIds,
  303. text = new GroupMessageByOpenId_Content()
  304. {
  305. content = value
  306. },
  307. msgtype = "text"
  308. };
  309. break;
  310. default:
  311. throw new Exception("参数错误。");
  312. break;
  313. }
  314. baseData.clientmsgid = clientmsgid;
  315. return CommonJsonSend.Send<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  316. }, accessTokenOrAppId);
  317. }
  318. /// <summary>
  319. /// 根据OpenID列表群发视频消息【订阅号不可用,服务号认证后可用】
  320. /// 注意:群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  321. /// </summary>
  322. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  323. /// <param name="title"></param>
  324. /// <param name="mediaId"></param>
  325. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  326. /// <param name="openIds">openId字符串数组</param>
  327. /// <param name="description"></param>
  328. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  329. /// <returns></returns>
  330. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendVideoGroupMessageByOpenId", true)]
  331. public static SendResult SendVideoGroupMessageByOpenId(string accessTokenOrAppId, string title, string description, string mediaId, string clientmsgid = null, int timeOut = Config.TIME_OUT, params string[] openIds)
  332. {
  333. return ApiHandlerWapper.TryCommonApi(accessToken =>
  334. {
  335. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/send?access_token={0}";
  336. BaseGroupMessageDataByOpenId baseData = new GroupMessageByOpenId_MpVideoData()
  337. {
  338. touser = openIds,
  339. video = new GroupMessageByOpenId_Video()
  340. {
  341. title = title,
  342. description = description,
  343. media_id = mediaId
  344. },
  345. msgtype = "mpvideo"
  346. };
  347. baseData.clientmsgid = clientmsgid;
  348. return CommonJsonSend.Send<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  349. }, accessTokenOrAppId);
  350. }
  351. /// <summary>
  352. /// 删除群发消息
  353. /// </summary>
  354. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  355. /// <param name="msgId">发送出去的消息ID</param>
  356. /// <param name="articleIdx">(非必填)要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章</param>
  357. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  358. /// <returns></returns>
  359. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.DeleteSendMessage", true)]
  360. public static WxJsonResult DeleteSendMessage(string accessTokenOrAppId, string msgId, int? articleIdx, int timeOut = Config.TIME_OUT)
  361. {
  362. return ApiHandlerWapper.TryCommonApi(accessToken =>
  363. {
  364. //官方API地址为https://api.weixin.qq.com//cgi-bin/message/mass/delete?access_token={0},应该是多了一个/
  365. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/delete?access_token={0}";
  366. var data = new
  367. {
  368. msg_id = msgId,
  369. article_idx = articleIdx
  370. };
  371. return CommonJsonSend.Send<WxJsonResult>(accessToken, urlFormat, data, timeOut: timeOut);
  372. }, accessTokenOrAppId);
  373. }
  374. /// <summary>
  375. /// 预览接口【订阅号与服务号认证后均可用】
  376. /// 注意:openId与wxName两者任选其一,同时传入以wxName优先
  377. /// </summary>
  378. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  379. /// <param name="value">群发媒体消息时为media_id,群发文本信息为content</param>
  380. /// <param name="type"></param>
  381. /// <param name="openId">接收消息用户对应该公众号的openid</param>
  382. /// <param name="wxName">接收消息用户的微信号</param>
  383. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  384. /// <returns></returns>
  385. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessagePreview", true)]
  386. public static SendResult SendGroupMessagePreview(string accessTokenOrAppId, GroupMessageType type, string value, string openId, string wxName = null, int timeOut = Config.TIME_OUT)
  387. {
  388. return ApiHandlerWapper.TryCommonApi(accessToken =>
  389. {
  390. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/preview?access_token={0}";
  391. BaseGroupMessageDataPreview baseData = null;
  392. switch (type)
  393. {
  394. case GroupMessageType.image:
  395. baseData = new GroupMessagePreview_ImageData()
  396. {
  397. touser = openId,
  398. towxname = wxName,
  399. image = new GroupMessagePreview_MediaId()
  400. {
  401. media_id = value
  402. },
  403. msgtype = "image"
  404. };
  405. break;
  406. case GroupMessageType.voice:
  407. baseData = new GroupMessagePreview_VoiceData()
  408. {
  409. touser = openId,
  410. towxname = wxName,
  411. voice = new GroupMessagePreview_MediaId()
  412. {
  413. media_id = value
  414. },
  415. msgtype = "voice"
  416. };
  417. break;
  418. case GroupMessageType.mpnews:
  419. baseData = new GroupMessagePreview_MpNewsData()
  420. {
  421. touser = openId,
  422. towxname = wxName,
  423. mpnews = new GroupMessagePreview_MediaId()
  424. {
  425. media_id = value
  426. },
  427. msgtype = "mpnews"
  428. };
  429. break;
  430. case GroupMessageType.video:
  431. baseData = new GroupMessagePreview_MpVideoData()
  432. {
  433. touser = openId,
  434. towxname = wxName,
  435. mpvideo = new GroupMessagePreview_MediaId()
  436. {
  437. media_id = value
  438. },
  439. msgtype = "mpvideo"
  440. };
  441. break;
  442. case GroupMessageType.text:
  443. baseData = new GroupMessagePreview_TextData()
  444. {
  445. touser = openId,
  446. towxname = wxName,
  447. text = new GroupMessagePreview_Content()
  448. {
  449. content = value
  450. },
  451. msgtype = "text"
  452. };
  453. break;
  454. case GroupMessageType.wxcard:
  455. throw new Exception("发送卡券息请使用WxCardGroupMessagePreview方法。");
  456. default:
  457. throw new Exception("参数错误。");
  458. }
  459. return CommonJsonSend.Send<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  460. }, accessTokenOrAppId);
  461. }
  462. /// <summary>
  463. /// 预览卡券接口
  464. /// </summary>
  465. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  466. /// <param name="cardId"></param>
  467. /// <param name="code"></param>
  468. /// <param name="openId"></param>
  469. /// <param name="wxName"></param>
  470. /// <param name="timestamp"></param>
  471. /// <param name="signature"></param>
  472. /// <param name="timeOut"></param>
  473. /// <returns></returns>
  474. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.WxCardGroupMessagePreview", true)]
  475. public static SendResult WxCardGroupMessagePreview(string accessTokenOrAppId, string cardId, string code,
  476. string openId, string wxName, string timestamp, string signature, int timeOut = Config.TIME_OUT)
  477. {
  478. return ApiHandlerWapper.TryCommonApi(accessToken =>
  479. {
  480. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/preview?access_token={0}";
  481. BaseGroupMessageDataPreview baseData = new GroupMessagePreview_WxCardData()
  482. {
  483. touser = openId,
  484. towxname = wxName,
  485. wxcard = new GroupMessagePreview_WxCard()
  486. {
  487. card_id = cardId,
  488. card_ext = string.Format("\"code\":\"{0}\",\"openid\":\"{1}\",\"timestamp\":\"{2}\",\"signature\":\"{3}\"", code, openId, timestamp, signature)
  489. },
  490. msgtype = "wxcard"
  491. };
  492. return CommonJsonSend.Send<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  493. }, accessTokenOrAppId);
  494. }
  495. /// <summary>
  496. /// 查询群发消息发送状态【订阅号与服务号认证后均可用】
  497. /// </summary>
  498. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  499. /// <param name="msgId">群发消息后返回的消息id</param>
  500. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  501. /// <returns></returns>
  502. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.GetGroupMessageResult", true)]
  503. public static GetSendResult GetGroupMessageResult(string accessTokenOrAppId, string msgId, int timeOut = Config.TIME_OUT)
  504. {
  505. return ApiHandlerWapper.TryCommonApi(accessToken =>
  506. {
  507. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/get?access_token={0}";
  508. var data = new
  509. {
  510. msg_id = msgId
  511. };
  512. return CommonJsonSend.Send<GetSendResult>(accessToken, urlFormat, data, timeOut: timeOut);
  513. }, accessTokenOrAppId);
  514. }
  515. /// <summary>
  516. /// 获取视频群发用的MediaId
  517. /// </summary>
  518. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  519. /// <param name="mediaId"></param>
  520. /// <param name="title"></param>
  521. /// <param name="description"></param>
  522. /// <param name="timeOut"></param>
  523. /// <returns></returns>
  524. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.GetVideoMediaIdResult", true)]
  525. public static VideoMediaIdResult GetVideoMediaIdResult(string accessTokenOrAppId, string mediaId, string title,
  526. string description, int timeOut = Config.TIME_OUT)
  527. {
  528. return ApiHandlerWapper.TryCommonApi(accessToken =>
  529. {
  530. string url = string.Format("https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token={0}", accessToken.AsUrlData());
  531. var data = new
  532. {
  533. media_id = mediaId,
  534. title = title,
  535. description = description
  536. };
  537. return CommonJsonSend.Send<VideoMediaIdResult>(null, url, data, CommonJsonSendType.POST, timeOut, true);
  538. }, accessTokenOrAppId);
  539. }
  540. /// <summary>
  541. /// 获取群发速度
  542. /// </summary>
  543. /// <param name="accessTokenOrAppId"></param>
  544. /// <param name="timeOut"></param>
  545. /// <returns></returns>
  546. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.GetSendSpeed", true)]
  547. public static GetSpeedResult GetSendSpeed(string accessTokenOrAppId, int timeOut = Config.TIME_OUT)
  548. {
  549. return ApiHandlerWapper.TryCommonApi(accessToken =>
  550. {
  551. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/speed/get?access_token={0}";
  552. return CommonJsonSend.Send<GetSpeedResult>(null, urlFormat, null, CommonJsonSendType.POST, timeOut, true);
  553. }, accessTokenOrAppId);
  554. }
  555. /// <summary>
  556. /// 设置群发速度
  557. /// </summary>
  558. /// <param name="accessTokenOrAppId"></param>
  559. /// <param name="speed">群发速度的级别</param>
  560. /// <param name="timeOut"></param>
  561. /// <returns></returns>
  562. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SetSendSpeed", true)]
  563. public static WxJsonResult SetSendSpeed(string accessTokenOrAppId, int speed, int timeOut = Config.TIME_OUT)
  564. {
  565. return ApiHandlerWapper.TryCommonApi(accessToken =>
  566. {
  567. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/speed/set?access_token={0}";
  568. var data = new
  569. {
  570. speed = speed
  571. };
  572. return CommonJsonSend.Send<WxJsonResult>(null, urlFormat, data, CommonJsonSendType.POST, timeOut, true);
  573. }, accessTokenOrAppId);
  574. }
  575. #endregion
  576. #if !NET35 && !NET40
  577. #region 异步方法
  578. #region 根据分组或标签群发
  579. /// <summary>
  580. /// 【异步方法】根据分组进行群发【订阅号与服务号认证后均可用】
  581. ///
  582. /// 请注意:
  583. /// 1、该接口暂时仅提供给已微信认证的服务号
  584. /// 2、虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,请小心测试
  585. /// 3、无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败。
  586. /// 4、群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  587. ///
  588. /// </summary>
  589. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  590. /// <param name="groupId">群发到的分组的group_id,参见用户管理中用户分组接口,若is_to_all值为true,可不填写group_id;如果groupId和tagId同时填写,优先使用groupId;groupId和tagId最多只能使用一个</param>
  591. /// <param name="tagId">群发到的标签的tag_id,若is_to_all值为true,可不填写tag_id;如果groupId和tagId同时填写,优先使用groupId;groupId和tagId最多只能使用一个</param>
  592. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  593. /// <param name="type"></param>
  594. /// <param name="isToAll">用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户,选择false可根据group_id发送给指定群组的用户</param>
  595. /// <param name="sendIgnoreReprint">待群发的文章被判定为转载时,是否继续群发</param>
  596. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  597. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  598. /// <returns></returns>
  599. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByFilterAsync", true)]
  600. private static async Task<SendResult> SendGroupMessageByFilterAsync(string accessTokenOrAppId, string groupId, string tagId, string value, GroupMessageType type, bool isToAll = false, bool sendIgnoreReprint = false, string clientmsgid = null, int timeOut = Config.TIME_OUT)
  601. {
  602. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  603. {
  604. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/sendall?access_token={0}";
  605. BaseGroupMessageDataByFilter baseData = null;
  606. BaseGroupMessageByFilter filter = null;
  607. if (!groupId.IsNullOrEmpty())
  608. {
  609. filter = new GroupMessageByGroupId()
  610. {
  611. group_id = groupId,
  612. is_to_all = isToAll,
  613. };
  614. }
  615. else
  616. {
  617. filter = new GroupMessageByTagId()
  618. {
  619. tag_id = tagId,
  620. is_to_all = isToAll,
  621. };
  622. }
  623. switch (type)
  624. {
  625. case GroupMessageType.image:
  626. baseData = new GroupMessageByFilter_ImageData()
  627. {
  628. filter = filter,
  629. image = new GroupMessageByGroupId_MediaId()
  630. {
  631. media_id = value
  632. },
  633. msgtype = "image"
  634. };
  635. break;
  636. case GroupMessageType.voice:
  637. baseData = new GroupMessageByFilter_VoiceData()
  638. {
  639. filter = filter,
  640. voice = new GroupMessageByGroupId_MediaId()
  641. {
  642. media_id = value
  643. },
  644. msgtype = "voice"
  645. };
  646. break;
  647. case GroupMessageType.mpnews:
  648. baseData = new GroupMessageByFilter_MpNewsData()
  649. {
  650. filter = filter,
  651. mpnews = new GroupMessageByGroupId_MediaId()
  652. {
  653. media_id = value
  654. },
  655. msgtype = "mpnews"
  656. };
  657. break;
  658. case GroupMessageType.video:
  659. baseData = new GroupMessageByFilter_MpVideoData()
  660. {
  661. filter = filter,
  662. mpvideo = new GroupMessageByGroupId_MediaId()
  663. {
  664. media_id = value
  665. },
  666. msgtype = "mpvideo"
  667. };
  668. break;
  669. case GroupMessageType.wxcard:
  670. baseData = new GroupMessageByFilter_WxCardData()
  671. {
  672. filter = filter,
  673. wxcard = new GroupMessageByGroupId_WxCard()
  674. {
  675. card_id = value
  676. },
  677. msgtype = "wxcard"
  678. };
  679. break;
  680. case GroupMessageType.text:
  681. baseData = new GroupMessageByFilter_TextData()
  682. {
  683. filter = filter,
  684. text = new GroupMessageByGroupId_Content()
  685. {
  686. content = value
  687. },
  688. msgtype = "text"
  689. };
  690. break;
  691. default:
  692. throw new Exception("参数错误。");
  693. //break;
  694. }
  695. baseData.send_ignore_reprint = sendIgnoreReprint ? 0 : 1;//待群发的文章被判定为转载时,是否继续群发
  696. baseData.clientmsgid = clientmsgid;
  697. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  698. }, accessTokenOrAppId);
  699. }
  700. /// <summary>
  701. /// 【异步方法】根据[分组]进行群发【订阅号与服务号认证后均可用】
  702. ///
  703. /// 请注意:
  704. /// 1、该接口暂时仅提供给已微信认证的服务号
  705. /// 2、虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,请小心测试
  706. /// 3、无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败。
  707. /// 4、群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  708. ///
  709. /// </summary>
  710. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  711. /// <param name="groupId">群发到的分组的group_id,参见用户管理中用户分组接口,若is_to_all值为true,可不填写group_id;如果groupId和tagId同时填写,优先使用groupId;groupId和tagId最多只能使用一个</param>
  712. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  713. /// <param name="type"></param>
  714. /// <param name="isToAll">用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户,选择false可根据group_id发送给指定群组的用户</param>
  715. /// <param name="sendIgnoreReprint">待群发的文章被判定为转载时,是否继续群发</param>
  716. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  717. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  718. /// <returns></returns>
  719. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByGroupIdAsync", true)]
  720. public static async Task<SendResult> SendGroupMessageByGroupIdAsync(string accessTokenOrAppId, string groupId, string value, GroupMessageType type, bool isToAll = false, bool sendIgnoreReprint = false, string clientmsgid = null,
  721. int timeOut = Config.TIME_OUT)
  722. {
  723. return await SendGroupMessageByFilterAsync(accessTokenOrAppId, groupId, null, value, type, isToAll, sendIgnoreReprint, clientmsgid,
  724. timeOut);
  725. }
  726. /// <summary>
  727. /// 【异步方法】根据[标签]进行群发【订阅号与服务号认证后均可用】
  728. ///
  729. /// 请注意:
  730. /// 1、该接口暂时仅提供给已微信认证的服务号
  731. /// 2、虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,请小心测试
  732. /// 3、无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败。
  733. /// 4、群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  734. ///
  735. /// </summary>
  736. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  737. /// <param name="tagId">群发到的标签的tag_id,若is_to_all值为true,可不填写tag_id</param>
  738. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  739. /// <param name="type"></param>
  740. /// <param name="isToAll">用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户,选择false可根据group_id发送给指定群组的用户</param>
  741. /// <param name="sendIgnoreReprint">待群发的文章被判定为转载时,是否继续群发</param>
  742. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  743. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  744. /// <returns></returns>
  745. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByTagIdAsync", true)]
  746. public static async Task<SendResult> SendGroupMessageByTagIdAsync(string accessTokenOrAppId, string tagId, string value, GroupMessageType type, bool isToAll = false, bool sendIgnoreReprint = false, string clientmsgid = null,
  747. int timeOut = Config.TIME_OUT)
  748. {
  749. return await SendGroupMessageByFilterAsync(accessTokenOrAppId, null, tagId, value, type, isToAll, sendIgnoreReprint, clientmsgid,
  750. timeOut);
  751. }
  752. #endregion
  753. /// <summary>
  754. /// 【异步方法】根据OpenId进行群发【订阅号不可用,服务号认证后可用】
  755. /// </summary>
  756. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  757. /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
  758. /// <param name="type"></param>
  759. /// <param name="openIds">openId字符串数组</param>
  760. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  761. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  762. /// <returns></returns>
  763. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessageByOpenIdAsync", true)]
  764. public static async Task<SendResult> SendGroupMessageByOpenIdAsync(string accessTokenOrAppId, GroupMessageType type, string value, string clientmsgid = null, int timeOut = Config.TIME_OUT, params string[] openIds)
  765. {
  766. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  767. {
  768. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/send?access_token={0}";
  769. BaseGroupMessageDataByOpenId baseData = null;
  770. switch (type)
  771. {
  772. case GroupMessageType.image:
  773. baseData = new GroupMessageByOpenId_ImageData()
  774. {
  775. touser = openIds,
  776. image = new GroupMessageByOpenId_MediaId()
  777. {
  778. media_id = value
  779. },
  780. msgtype = "image"
  781. };
  782. break;
  783. case GroupMessageType.voice:
  784. baseData = new GroupMessageByOpenId_VoiceData()
  785. {
  786. touser = openIds,
  787. voice = new GroupMessageByOpenId_MediaId()
  788. {
  789. media_id = value
  790. },
  791. msgtype = "voice"
  792. };
  793. break;
  794. case GroupMessageType.mpnews:
  795. baseData = new GroupMessageByOpenId_MpNewsData()
  796. {
  797. touser = openIds,
  798. mpnews = new GroupMessageByOpenId_MediaId()
  799. {
  800. media_id = value
  801. },
  802. msgtype = "mpnews"
  803. };
  804. break;
  805. case GroupMessageType.wxcard:
  806. baseData = new GroupMessageByOpenId_WxCardData()
  807. {
  808. touser = openIds,
  809. wxcard = new GroupMessageByOpenId_WxCard()
  810. {
  811. card_id = value
  812. },
  813. msgtype = "wxcard"
  814. };
  815. break;
  816. case GroupMessageType.video:
  817. throw new Exception("发送视频信息请使用SendVideoGroupMessageByOpenId方法。");
  818. //break;
  819. case GroupMessageType.text:
  820. baseData = new GroupMessageByOpenId_TextData()
  821. {
  822. touser = openIds,
  823. text = new GroupMessageByOpenId_Content()
  824. {
  825. content = value
  826. },
  827. msgtype = "text"
  828. };
  829. break;
  830. default:
  831. throw new Exception("参数错误。");
  832. //break;
  833. }
  834. baseData.clientmsgid = clientmsgid;
  835. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  836. }, accessTokenOrAppId);
  837. }
  838. /// <summary>
  839. /// 【异步方法】根据OpenID列表群发视频消息【订阅号不可用,服务号认证后可用】
  840. /// 注意:群发视频时需要先调用GetVideoMediaIdResult接口获取专用的MediaId然后进行群发
  841. /// </summary>
  842. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  843. /// <param name="title"></param>
  844. /// <param name="mediaId"></param>
  845. /// <param name="clientmsgid">开发者侧群发msgid,长度限制64字节,如不填,则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
  846. /// <param name="openIds">openId字符串数组</param>
  847. /// <param name="description"></param>
  848. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  849. /// <returns></returns>
  850. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendVideoGroupMessageByOpenIdAsync", true)]
  851. public static async Task<SendResult> SendVideoGroupMessageByOpenIdAsync(string accessTokenOrAppId, string title, string description, string mediaId, string clientmsgid = null, int timeOut = Config.TIME_OUT, params string[] openIds)
  852. {
  853. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  854. {
  855. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/send?access_token={0}";
  856. BaseGroupMessageDataByOpenId baseData = new GroupMessageByOpenId_MpVideoData()
  857. {
  858. touser = openIds,
  859. video = new GroupMessageByOpenId_Video()
  860. {
  861. title = title,
  862. description = description,
  863. media_id = mediaId
  864. },
  865. msgtype = "mpvideo"
  866. };
  867. baseData.clientmsgid = clientmsgid;
  868. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  869. }, accessTokenOrAppId);
  870. }
  871. /// <summary>
  872. /// 【异步方法】删除群发消息
  873. /// </summary>
  874. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  875. /// <param name="msgId">发送出去的消息ID</param>
  876. /// <param name="articleIdx">(非必填)要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章</param>
  877. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  878. /// <returns></returns>
  879. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.DeleteSendMessageAsync", true)]
  880. public static async Task<WxJsonResult> DeleteSendMessageAsync(string accessTokenOrAppId, string msgId, int? articleIdx, int timeOut = Config.TIME_OUT)
  881. {
  882. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  883. {
  884. //官方API地址为https://api.weixin.qq.com//cgi-bin/message/mass/delete?access_token={0},应该是多了一个/
  885. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/delete?access_token={0}";
  886. var data = new
  887. {
  888. msg_id = msgId,
  889. article_idx = articleIdx
  890. };
  891. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<WxJsonResult>(accessToken, urlFormat, data, timeOut: timeOut);
  892. }, accessTokenOrAppId);
  893. }
  894. /// <summary>
  895. /// 【异步方法】预览接口【订阅号与服务号认证后均可用】
  896. /// 注意:openId与wxName两者任选其一,同时传入以wxName优先
  897. /// </summary>
  898. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  899. /// <param name="value">群发媒体消息时为media_id,群发文本信息为content</param>
  900. /// <param name="type"></param>
  901. /// <param name="openId">接收消息用户对应该公众号的openid</param>
  902. /// <param name="wxName">接收消息用户的微信号</param>
  903. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  904. /// <returns></returns>
  905. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SendGroupMessagePreviewAsync", true)]
  906. public static async Task<SendResult> SendGroupMessagePreviewAsync(string accessTokenOrAppId, GroupMessageType type, string value, string openId, string wxName = null, int timeOut = Config.TIME_OUT)
  907. {
  908. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  909. {
  910. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/preview?access_token={0}";
  911. BaseGroupMessageDataPreview baseData = null;
  912. switch (type)
  913. {
  914. case GroupMessageType.image:
  915. baseData = new GroupMessagePreview_ImageData()
  916. {
  917. touser = openId,
  918. towxname = wxName,
  919. image = new GroupMessagePreview_MediaId()
  920. {
  921. media_id = value
  922. },
  923. msgtype = "image"
  924. };
  925. break;
  926. case GroupMessageType.voice:
  927. baseData = new GroupMessagePreview_VoiceData()
  928. {
  929. touser = openId,
  930. towxname = wxName,
  931. voice = new GroupMessagePreview_MediaId()
  932. {
  933. media_id = value
  934. },
  935. msgtype = "voice"
  936. };
  937. break;
  938. case GroupMessageType.mpnews:
  939. baseData = new GroupMessagePreview_MpNewsData()
  940. {
  941. touser = openId,
  942. towxname = wxName,
  943. mpnews = new GroupMessagePreview_MediaId()
  944. {
  945. media_id = value
  946. },
  947. msgtype = "mpnews"
  948. };
  949. break;
  950. case GroupMessageType.video:
  951. baseData = new GroupMessagePreview_MpVideoData()
  952. {
  953. touser = openId,
  954. towxname = wxName,
  955. mpvideo = new GroupMessagePreview_MediaId()
  956. {
  957. media_id = value
  958. },
  959. msgtype = "mpvideo"
  960. };
  961. break;
  962. case GroupMessageType.text:
  963. baseData = new GroupMessagePreview_TextData()
  964. {
  965. touser = openId,
  966. towxname = wxName,
  967. text = new GroupMessagePreview_Content()
  968. {
  969. content = value
  970. },
  971. msgtype = "text"
  972. };
  973. break;
  974. case GroupMessageType.wxcard:
  975. throw new Exception("发送卡券息请使用WxCardGroupMessagePreview方法。");
  976. default:
  977. throw new Exception("参数错误。");
  978. }
  979. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  980. }, accessTokenOrAppId);
  981. }
  982. /// <summary>
  983. /// 【异步方法】预览卡券接口
  984. /// </summary>
  985. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  986. /// <param name="cardId"></param>
  987. /// <param name="code"></param>
  988. /// <param name="openId"></param>
  989. /// <param name="wxName"></param>
  990. /// <param name="timestamp"></param>
  991. /// <param name="signature"></param>
  992. /// <param name="timeOut"></param>
  993. /// <returns></returns>
  994. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.WxCardGroupMessagePreviewAsync", true)]
  995. public static async Task<SendResult> WxCardGroupMessagePreviewAsync(string accessTokenOrAppId, string cardId, string code,
  996. string openId, string wxName, string timestamp, string signature, int timeOut = Config.TIME_OUT)
  997. {
  998. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  999. {
  1000. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/preview?access_token={0}";
  1001. BaseGroupMessageDataPreview baseData = new GroupMessagePreview_WxCardData()
  1002. {
  1003. touser = openId,
  1004. towxname = wxName,
  1005. wxcard = new GroupMessagePreview_WxCard()
  1006. {
  1007. card_id = cardId,
  1008. card_ext = string.Format("\"code\":\"{0}\",\"openid\":\"{1}\",\"timestamp\":\"{2}\",\"signature\":\"{3}\"", code, openId, timestamp, signature)
  1009. },
  1010. msgtype = "wxcard"
  1011. };
  1012. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<SendResult>(accessToken, urlFormat, baseData, timeOut: timeOut);
  1013. }, accessTokenOrAppId);
  1014. }
  1015. /// <summary>
  1016. /// 【异步方法】查询群发消息发送状态【订阅号与服务号认证后均可用】
  1017. /// </summary>
  1018. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  1019. /// <param name="msgId">群发消息后返回的消息id</param>
  1020. /// <param name="timeOut">代理请求超时时间(毫秒)</param>
  1021. /// <returns></returns>
  1022. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.GetGroupMessageResultAsync", true)]
  1023. public static async Task<GetSendResult> GetGroupMessageResultAsync(string accessTokenOrAppId, string msgId, int timeOut = Config.TIME_OUT)
  1024. {
  1025. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  1026. {
  1027. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/get?access_token={0}";
  1028. var data = new
  1029. {
  1030. msg_id = msgId
  1031. };
  1032. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<GetSendResult>(accessToken, urlFormat, data, timeOut: timeOut);
  1033. }, accessTokenOrAppId);
  1034. }
  1035. /// <summary>
  1036. /// 【异步方法】获取视频群发用的MediaId
  1037. /// </summary>
  1038. /// <param name="accessTokenOrAppId">AccessToken或AppId(推荐使用AppId,需要先注册)</param>
  1039. /// <param name="mediaId"></param>
  1040. /// <param name="title"></param>
  1041. /// <param name="description"></param>
  1042. /// <param name="timeOut"></param>
  1043. /// <returns></returns>
  1044. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.GetVideoMediaIdResultAsync", true)]
  1045. public static async Task<VideoMediaIdResult> GetVideoMediaIdResultAsync(string accessTokenOrAppId, string mediaId, string title,
  1046. string description, int timeOut = Config.TIME_OUT)
  1047. {
  1048. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  1049. {
  1050. string url = string.Format("https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token={0}", accessToken.AsUrlData());
  1051. var data = new
  1052. {
  1053. media_id = mediaId,
  1054. title = title,
  1055. description = description
  1056. };
  1057. return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync<VideoMediaIdResult>(null, url, data, CommonJsonSendType.POST, timeOut, true);
  1058. }, accessTokenOrAppId);
  1059. }
  1060. /// <summary>
  1061. /// 【异步方法】获取群发速度
  1062. /// </summary>
  1063. /// <param name="accessTokenOrAppId"></param>
  1064. /// <param name="timeOut"></param>
  1065. /// <returns></returns>
  1066. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.GetSendSpeedAsync", true)]
  1067. public static async Task<GetSpeedResult> GetSendSpeedAsync(string accessTokenOrAppId, int timeOut = Config.TIME_OUT)
  1068. {
  1069. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  1070. {
  1071. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/speed/get?access_token={0}";
  1072. return await Weixin.CommonAPIs.CommonJsonSend.SendAsync<GetSpeedResult>(null, urlFormat, null, CommonJsonSendType.POST, timeOut, true);
  1073. }, accessTokenOrAppId);
  1074. }
  1075. /// <summary>
  1076. /// 【异步方法】设置群发速度
  1077. /// </summary>
  1078. /// <param name="accessTokenOrAppId"></param>
  1079. /// <param name="speed">群发速度的级别</param>
  1080. /// <param name="timeOut"></param>
  1081. /// <returns></returns>
  1082. [ApiBind(NeuChar.PlatformType.WeChat_OfficialAccount, "GroupMessageApi.SetSendSpeedAsync", true)]
  1083. public static async Task<WxJsonResult> SetSendSpeedAsync(string accessTokenOrAppId, int speed, int timeOut = Config.TIME_OUT)
  1084. {
  1085. return await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
  1086. {
  1087. string urlFormat = Config.ApiMpHost + "/cgi-bin/message/mass/speed/set?access_token={0}";
  1088. var data = new
  1089. {
  1090. speed = speed
  1091. };
  1092. return await Weixin.CommonAPIs.CommonJsonSend.SendAsync<WxJsonResult>(null, urlFormat, data, CommonJsonSendType.POST, timeOut, true);
  1093. }, accessTokenOrAppId);
  1094. }
  1095. #endregion
  1096. #endif
  1097. }
  1098. }