[开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)

简介:   目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具。   测试工具在线DEMO:http://weixin.

  目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具。

  测试工具在线DEMO:http://weixin.senparc.com/SimulateTool

  Senparc.Weixin.MP是一个开源的微信SDK项目,地址:https://github.com/JeffreySu/WeiXinMPSDK (其中https://github.com/JeffreySu/WeiXinMPSDK/tree/master/Senparc.Weixin.MP.Sample 包含了本文所讲的所有源代码)

  也可以通过Nuget直接安装到项目中:https://www.nuget.org/packages/Senparc.Weixin.MP

  Senparc.Weixin.MP教程索引:http://www.cnblogs.com/szw/archive/2013/05/14/weixin-course-index.html

 

  下面大致解释一下源代码及工作原理:

一、界面

  

  界面分为4大区域:接口设置、发送参数、发送内容和接收内容

  其中接口设置用于提供类似微信公众账号后台的Url和Token的对接参数设置,指定目标服务器。

  在发送参数中,根据选择不同的消息类型,下面的参数选项会对应变化。

  发送内容显示的是提交参数之后,模拟发送到目标服务器的XML,这里摆脱了之前一些需要手动输入XML的麻烦。

  根据发送内容,在接收内容框中,显示目标服务器返回的实际内容。

二、服务器端代码

  由于使用了Senparc.Weixin.MP SDK,所有的XML生成、代理操作、XML流等操作都变得非常简单,一共只用了100多行代码就实现了XML生成及模拟发送、接收等2大块功能,这里为了让大家看得更明白,将所有代码都尽量平铺直叙,实际还可以有很多缩减或重用的地方(文件位于源代码/Senparc.Weixin.MP.Sample/Senparc.Weixin.MP.Sample/Controllers/SimulateToolController.cs):

using System;
using System.IO;
using System.Web.Mvc;
using System.Xml.Linq;
using Senparc.Weixin.MP.Agent;
using Senparc.Weixin.MP.Entities;
using Senparc.Weixin.MP.Helpers;

namespace Senparc.Weixin.MP.Sample.Controllers
{
    public class SimulateToolController : BaseController
    {
        /// <summary>
        /// 获取请求XML
        /// </summary>
        /// <returns></returns>
        private XDocument GetrequestMessaageDoc(string url, string token, RequestMsgType requestType, Event? eventType)
        {
            RequestMessageBase requestMessaage = null;
            switch (requestType)
            {
                case RequestMsgType.Text:
                    requestMessaage = new RequestMessageText()
                    {
                        Content = Request.Form["Content"],
                    };
                    break;
                case RequestMsgType.Location:
                    requestMessaage = new RequestMessageLocation()
                    {
                        Label = Request.Form["Label"],
                        Location_X = double.Parse(Request.Form["Location_X"]),
                        Location_Y = double.Parse(Request.Form["Location_Y"]),
                        Scale = int.Parse(Request.Form["Scale"])
                    };
                    break;
                case RequestMsgType.Image:
                    requestMessaage = new RequestMessageImage()
                    {
                        PicUrl = Request.Form["PicUrl"],
                    };
                    break;
                case RequestMsgType.Voice:
                    requestMessaage = new RequestMessageVoice()
                    {
                        Format = Request.Form["Format"],
                        Recognition = Request.Form["Recognition"],
                    };
                    break;
                case RequestMsgType.Video:
                    requestMessaage = new RequestMessageVideo()
                    {
                        MsgId = long.Parse(Request.Form["MsgId"]),
                        ThumbMediaId = Request.Form["ThumbMediaId"],
                    };
                    break;
                //case RequestMsgType.Link:
                //    break;
                case RequestMsgType.Event:
                    if (eventType.HasValue)
                    {
                        RequestMessageEventBase requestMessageEvent = null;
                        switch (eventType.Value)
                        {
                            //case Event.ENTER:
                            //    break;
                            case Event.LOCATION:
                                requestMessageEvent = new RequestMessageEvent_Location()
                                {
                                    Latitude = long.Parse(Request.Form["Event.Latitude"]),
                                    Longitude = long.Parse(Request.Form["Event.Longitude"]),
                                    Precision = double.Parse(Request.Form["Event.Precision"])
                                };
                                break;
                            case Event.subscribe:
                                requestMessageEvent = new RequestMessageEvent_Subscribe()
                                {
                                    EventKey = Request.Form["Event.EventKey"]
                                };
                                break;
                            case Event.unsubscribe:
                                requestMessageEvent = new RequestMessageEvent_Unsubscribe();
                                  break;
                            case Event.CLICK:
                                requestMessageEvent = new RequestMessageEvent_Click()
                                   {
                                       EventKey = Request.Form["Event.EventKey"]
                                   };
                                break;
                            case Event.scan:
                                requestMessageEvent = new RequestMessageEvent_Scan()
                                 {
                                     EventKey = Request.Form["Event.EventKey"],
                                     Ticket = Request.Form["Event.Ticket"]
                                 }; break;
                            case Event.VIEW:
                                requestMessageEvent = new RequestMessageEvent_View()
                                 {
                                     EventKey = Request.Form["Event.EventKey"]
                                 }; break;
                            case Event.MASSSENDJOBFINISH:
                                requestMessageEvent = new RequestMessageEvent_MassSendJobFinish()
                                {
                                    FromUserName = "mphelper",//系统指定
                                    ErrorCount = int.Parse(Request.Form["Event.ErrorCount"]),
                                    FilterCount = int.Parse(Request.Form["Event.FilterCount"]),
                                    SendCount = int.Parse(Request.Form["Event.SendCount"]),
                                    Status = Request.Form["Event.Status"],
                                    TotalCount = int.Parse(Request.Form["Event.TotalCount"])
                                }; break;
                            default:
                                throw new ArgumentOutOfRangeException("eventType");
                        }
                        requestMessaage = requestMessageEvent;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("eventType");
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException("requestType");
            }

            requestMessaage.CreateTime = DateTime.Now;
            requestMessaage.FromUserName = requestMessaage.FromUserName ?? "FromUserName(OpenId)";//用于区别不同的请求用户
            requestMessaage.ToUserName = "ToUserName";

            return requestMessaage.ConvertEntityToXml();
        }

        /// <summary>
        /// 默认页面
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            ViewData["Token"] = WeixinController.Token;
            return View();
        }

        /// <summary>
        /// 模拟发送并返回结果
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Index(string url, string token, RequestMsgType requestType, Event? eventType)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                var requestMessaageDoc = GetrequestMessaageDoc(url, token, requestType, eventType);
                requestMessaageDoc.Save(ms);
                ms.Seek(0, SeekOrigin.Begin);

                var responseMessageXml = MessageAgent.RequestXml(null, url, token, requestMessaageDoc.ToString());

                return Content(responseMessageXml);
            }
        }

        /// <summary>
        /// 返回模拟发送的XML
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult GetRequestMessageXml(string url, string token, RequestMsgType requestType, Event? eventType)
        {
            var requestMessaageDoc = GetrequestMessaageDoc(url, token, requestType, eventType);
            return Content(requestMessaageDoc.ToString());
        }
    }
}

  

三、View代码

  下面是MVC中View(razor)的代码(200行左右,文件位于源代码/Senparc.Weixin.MP.Sample/Senparc.Weixin.MP.Sample/Views/SimulateTool/Index.cshtml):

  1 @{
  2     ViewBag.Title = "微信消息模拟测试工具";
  3     Layout = "~/Views/Shared/_Layout.cshtml";
  4 
  5     var nonce = "JeffreySu";
  6     var timestamp = DateTime.Now.Ticks.ToString();
  7     var echostr = DateTime.Now.Ticks.ToString();
  8     var token = ViewData["Token"] as string;
  9 }
 10 @section HeaderContent
 11 {
 12     <style>
 13         .param {
 14             display: none;
 15         }
 16 
 17         .messageXmlArea {
 18             width: 100%;
 19         }
 20 
 21             .messageXmlArea textarea {
 22                 width: 100%;
 23                 height: 200px;
 24             }
 25 
 26         .paramAreaLeft {
 27             float: left;
 28             width: 45%;
 29             margin-right: 6%;
 30         }
 31 
 32         .paramArearight {
 33             width: 45%;
 34             float: left;
 35         }
 36 
 37         #requestType, #eventType {
 38             padding: 5px;
 39         }
 40     </style>
 41     <script>
 42         $(function () {
 43             $('#requestType').change(checkRequestType);
 44             $('#eventType').change(checkEventType);
 45             checkRequestType();
 46             checkEventType();
 47         });
 48 
 49         function checkRequestType() {
 50             var requestType = $('#requestType').val();
 51             var paramId = 'param' + requestType;
 52             $('div[id^=param]').hide();
 53             $('#' + paramId).show();
 54         }
 55 
 56         function checkEventType() {
 57             var requestType = $('#eventType').val();
 58             var eventId = 'event' + requestType;
 59             $('div[id^=event]').hide();
 60             $('#' + eventId).show();
 61         }
 62 
 63         function sendMessage() {
 64             var url = $('#Url').val();
 65             var token = $('#Token').val();
 66             var requestType = $('#requestType').val();
 67             var eventType = $('#eventType').val();
 68             var param = { url: url, token: token, requestType: requestType };
 69             var paramId = 'param' + requestType;
 70             var eventId = 'event' + eventType;
 71             //设置参数
 72             if (requestType != 'Event') {
 73                 $.each($('#' + paramId).find('input'), function (i, item) {
 74                     param[$(item).attr('name')] = $(item).val();
 75                 });
 76             } else {
 77                 param.eventType = eventType;
 78                 $.each($('#' + eventId).find('input'), function (i, item) {
 79                     param[$(item).attr('name')] = $(item).val();
 80                 });
 81             }
 82 
 83             var txtResponseMessageXML = $('#responseMessageXML');
 84             var txtRequestMessageXML = $('#requestMessageXML');
 85 
 86             txtResponseMessageXML.html('载入中...');
 87             txtRequestMessageXML.html('载入中...');
 88 
 89             $.post('@Url.Action("Index")', param, function (result) {
 90                 txtResponseMessageXML.html(result);
 91             });
 92 
 93             $.post('@Url.Action("GetRequestMessageXml")', param, function (result) {
 94                 txtRequestMessageXML.html(result);
 95             });
 96         }
 97     </script>
 98 }
 99 @section Featured
100 {
101 
102 }
103 <section class="content-wrapper main-content clear-fix">
104     <h1>消息模拟工具</h1>
105     <div class="clear-fix"></div>
106     <div id="simulateTool">
107         <div class="paramAreaLeft">
108             <h3>接口设置</h3>
109             <div>
110                 URL:@Html.TextBox("Url", Url.Action("Index", "Weixin", null, "http", Request.Url.Host))<br />
111                 Token:@Html.TextBox("Token", token)
112             </div>
113             <h3>发送参数</h3>
114             <div>
115                 类型:<select id="requestType">
116                     <option value="Text">文本</option>
117                     <option value="Location">地理位置</option>
118                     <option value="Image">图片</option>
119                     <option value="Voice">语音</option>
120                     <option value="Video">视频</option>
121                     @*<option value="Link">连接信息</option>*@
122                     <option value="Event">事件推送</option>
123                 </select>
124             </div>
125             <div>
126                 参数:
127                 <div id="paramText" class="param">
128                     Content:<input name="Content" />
129                 </div>
130                 <div id="paramLocation" class="param">
131                     Label:<input name="Label" /><br />
132                     Location_X:<input name="Location_X" type="number" value="0" /><br />
133                     Location_Y:<input name="Location_Y" type="number" value="0" /><br />
134                     Scale:<input name="Scale" type="number" value="0" step="1" /><br />
135                 </div>
136                 <div id="paramImage" class="param">
137                     PicUrl:<input name="PicUrl" /><br />
138                 </div>
139                 <div id="paramVoice" class="param">
140                     Format:<input name="Format" value="arm" /><br />
141                     Recognition:<input name="Recognition" /><br />
142                 </div>
143                 <div id="paramVideo" class="param">
144                     MsgId:<input name="MsgId" type="number" value="@DateTime.Now.Ticks" step="1" /><br />
145                     ThumbMediaId:<input name="ThumbMediaId" /><br />
146                 </div>
147                 @*<div id="paramLink" class="param"></div>*@
148                 <div id="paramEvent" class="param">
149                     事件类型:<select id="eventType">
150                         @*<option value="ENTER">进入会话</option>*@
151                         <option value="LOCATION">地理位置</option>
152                         <option value="subscribe">订阅</option>
153                         <option value="unsubscribe">取消订阅</option>
154                         <option value="CLICK">自定义菜单点击事件</option>
155                         <option value="scan">二维码扫描</option>
156                         <option value="VIEW">URL跳转</option>
157                         <option value="MASSSENDJOBFINISH">事件推送群发结果</option>
158                     </select>
159                     @*<div id="eventENTER" class="param"></div>*@
160                     <div id="eventLOCATION" class="param">
161                         Latitude:<input name="Event.Latitude" type="number" value="0"/><br />
162                         Longitude:<input name="Event.Longitude" type="number" value="0"/><br />
163                         Precision:<input name="Event.Precision" type="number" value="0"/><br />
164                     </div>
165                     <div id="eventsubscribe" class="param">
166                         EventKey:<input name="Event.EventKey" /><br />
167                     </div>
168                     <div id="eventunsubscribe" class="param"></div>
169                     <div id="eventCLICK" class="param">
170                         EventKey:<input name="Event.EventKey" /><br />
171                     </div>
172                     <div id="eventscan" class="param">
173                         EventKey:<input name="Event.EventKey" /><br />
174                         Ticket:<input name="Event.Ticket" /><br />
175                     </div>
176                     <div id="eventVIEW" class="param">
177                         EventKey:<input name="Event.EventKey" value="http://" /><br />
178                     </div>
179                     <div id="eventMASSSENDJOBFINISH" class="param">
180                         ErrorCount:<input name="Event.ErrorCount" type="number" value="0"/><br />
181                         FilterCount:<input name="Event.FilterCount" type="number" value="0"/><br />
182                         SendCount:<input name="Event.SendCount" type="number" value="0"/><br />
183                         Status:<input name="Event.Status"/><br />
184                         TotalCount:<input name="Event.TotalCount" type="number" value="0"/><br />
185                     </div>
186                 </div>
187                 <div>
188                     <input type="button" value="提交" onclick="sendMessage()" />
189                 </div>
190             </div>
191         </div>
192         <div class="paramArearight">
193 
194             <div class="messageXmlArea">
195                 <h3>发送内容(根据参数自动生成)</h3>
196                 <textarea id="requestMessageXML" readonly="readonly"></textarea>
197             </div>
198             <div class="messageXmlArea">
199                 <h3>接收内容</h3>
200                 <textarea id="responseMessageXML"></textarea>
201             </div>
202         </div>
203     </div>
204 </section>

 

  因为代码已经足够简单,所以不再一一详解,如果有任何问题可以在评论里面讨论,欢迎提各种建议!

 

QQ:498977166

http://szw.cnblogs.com/
研究、探讨.NET开发
转载请注明出处和作者,谢谢!

 


微信开发深度解析:微信公众号、小程序高效开发秘籍
Senparc官方教程《微信开发深度解析:微信公众号、小程序高效开发秘籍》,耗时2年精心打造的微信开发权威教程,点击这里,购买正版

 

目录
相关文章
|
3月前
|
JSON 小程序 JavaScript
uni-app开发微信小程序的报错[渲染层错误]排查及解决
uni-app开发微信小程序的报错[渲染层错误]排查及解决
819 7
|
26天前
|
机器学习/深度学习 人工智能 文字识别
POINTS 1.5:腾讯微信开源的多模态大模型,超越了业界其他的开源视觉语言模型,具备强大的视觉和语言处理能力
POINTS 1.5是腾讯微信推出的多模态大模型,基于LLaVA架构,具备强大的视觉和语言处理能力。它在复杂场景的OCR、推理能力、关键信息提取等方面表现出色,是全球10B以下开源模型中的佼佼者。
167 58
POINTS 1.5:腾讯微信开源的多模态大模型,超越了业界其他的开源视觉语言模型,具备强大的视觉和语言处理能力
|
3月前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
842 1
|
3天前
|
数据挖掘 测试技术 项目管理
2025年测试用例管理看这一篇就够了 ----Codes 开源免费、全面的测试管理解决方案
Codes 是国内首款重新定义 SaaS 模式的开源项目管理平台,支持云端认证、本地部署、全部功能开放,并且对 30 人以下团队免费。它通过整合迭代、看板、度量和自动化等功能,简化测试协同工作,使敏捷测试更易于实施。并提供低成本的敏捷测试解决方案,如同步在线离线测试用例、流程化管理缺陷、低代码接口自动化测试和 CI/CD,以及基于迭代的测试管理和测试用时的成本计算等,践行敏捷测试。
2025年测试用例管理看这一篇就够了 ----Codes 开源免费、全面的测试管理解决方案
|
6天前
|
机器学习/深度学习 人工智能 自然语言处理
MarS:微软开源金融市场模拟预测引擎,支持策略测试、风险管理和市场分析
MarS 是微软亚洲研究院推出的金融市场模拟预测引擎,基于生成型基础模型 LMM,支持无风险环境下的交易策略测试、风险管理和市场分析。
35 8
MarS:微软开源金融市场模拟预测引擎,支持策略测试、风险管理和市场分析
|
18天前
|
IDE 测试技术 开发工具
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
在Python开发中,调试是提升效率的关键技能。本文总结了10个实用的调试方法,涵盖内置调试器pdb、breakpoint()函数、断言机制、logging模块、列表推导式优化、IPython调试、警告机制、IDE调试工具、inspect模块和单元测试框架的应用。通过这些技巧,开发者可以更高效地定位和解决问题,提高代码质量。
136 8
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
|
27天前
|
人工智能 自然语言处理 前端开发
CodeArena:在线 LLM 编程竞技场!用于测试不同开源 LLM 的编程能力,实时更新排行榜
CodeArena 是一个在线平台,用于测试和比较不同大型语言模型(LLM)的编程能力。通过实时显示多个 LLM 的代码生成过程和结果,帮助开发者选择适合的 LLM,并推动 LLM 技术的发展。
54 7
CodeArena:在线 LLM 编程竞技场!用于测试不同开源 LLM 的编程能力,实时更新排行榜
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
71 1
|
2月前
|
存储 算法 C语言
用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容
本文探讨了用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容,旨在为开发者提供全面的指导和灵感。
55 2
|
2月前
|
编解码 人工智能 自然语言处理
迈向多语言医疗大模型:大规模预训练语料、开源模型与全面基准测试
【10月更文挑战第23天】Oryx 是一种新型多模态架构,能够灵活处理各种分辨率的图像和视频数据,无需标准化。其核心创新包括任意分辨率编码和动态压缩器模块,适用于从微小图标到长时间视频的多种应用场景。Oryx 在长上下文检索和空间感知数据方面表现出色,并且已开源,为多模态研究提供了强大工具。然而,选择合适的分辨率和压缩率仍需谨慎,以平衡处理效率和识别精度。论文地址:https://www.nature.com/articles/s41467-024-52417-z
55 2