[开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)
目前为止似乎还没有看到过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):
@{
ViewBag.Title = "微信消息模拟测试工具";
Layout = "~/Views/Shared/_Layout.cshtml";
var nonce = "JeffreySu";
var timestamp = DateTime.Now.Ticks.ToString();
var echostr = DateTime.Now.Ticks.ToString();
var token = ViewData["Token"] as string;
}
@section HeaderContent
{
<style>
.param {
display: none;
}
.messageXmlArea {
width: 100%;
}
.messageXmlArea textarea {
width: 100%;
height: 200px;
}
.paramAreaLeft {
float: left;
width: 45%;
margin-right: 6%;
}
.paramArearight {
width: 45%;
float: left;
}
#requestType, #eventType {
padding: 5px;
}
</style>
<script>
$(function () {
$('#requestType').change(checkRequestType);
$('#eventType').change(checkEventType);
checkRequestType();
checkEventType();
});
function checkRequestType() {
var requestType = $('#requestType').val();
var paramId = 'param' + requestType;
$('div[id^=param]').hide();
$('#' + paramId).show();
}
function checkEventType() {
var requestType = $('#eventType').val();
var eventId = 'event' + requestType;
$('div[id^=event]').hide();
$('#' + eventId).show();
}
function sendMessage() {
var url = $('#Url').val();
var token = $('#Token').val();
var requestType = $('#requestType').val();
var eventType = $('#eventType').val();
var param = { url: url, token: token, requestType: requestType };
var paramId = 'param' + requestType;
var eventId = 'event' + eventType;
//设置参数
if (requestType != 'Event') {
$.each($('#' + paramId).find('input'), function (i, item) {
param[$(item).attr('name')] = $(item).val();
});
} else {
param.eventType = eventType;
$.each($('#' + eventId).find('input'), function (i, item) {
param[$(item).attr('name')] = $(item).val();
});
}
var txtResponseMessageXML = $('#responseMessageXML');
var txtRequestMessageXML = $('#requestMessageXML');
txtResponseMessageXML.html('载入中...');
txtRequestMessageXML.html('载入中...');
$.post('@Url.Action("Index")', param, function (result) {
txtResponseMessageXML.html(result);
});
$.post('@Url.Action("GetRequestMessageXml")', param, function (result) {
txtRequestMessageXML.html(result);
});
}
</script>
}
@section Featured
{
}
<section class="content-wrapper main-content clear-fix">
<h1>消息模拟工具</h1>
<div class="clear-fix"></div>
<div id="simulateTool">
<div class="paramAreaLeft">
<h3>接口设置</h3>
<div>
URL:@Html.TextBox("Url", Url.Action("Index", "Weixin", null, "http", Request.Url.Host))<br />
Token:@Html.TextBox("Token", token)
</div>
<h3>发送参数</h3>
<div>
类型:<select id="requestType">
<option value="Text">文本</option>
<option value="Location">地理位置</option>
<option value="Image">图片</option>
<option value="Voice">语音</option>
<option value="Video">视频</option>
@*<option value="Link">连接信息</option>*@
<option value="Event">事件推送</option>
</select>
</div>
<div>
参数:
<div id="paramText" class="param">
Content:<input name="Content" />
</div>
<div id="paramLocation" class="param">
Label:<input name="Label" /><br />
Location_X:<input name="Location_X" type="number" value="0" /><br />
Location_Y:<input name="Location_Y" type="number" value="0" /><br />
Scale:<input name="Scale" type="number" value="0" step="1" /><br />
</div>
<div id="paramImage" class="param">
PicUrl:<input name="PicUrl" /><br />
</div>
<div id="paramVoice" class="param">
Format:<input name="Format" value="arm" /><br />
Recognition:<input name="Recognition" /><br />
</div>
<div id="paramVideo" class="param">
MsgId:<input name="MsgId" type="number" value="@DateTime.Now.Ticks" step="1" /><br />
ThumbMediaId:<input name="ThumbMediaId" /><br />
</div>
@*<div id="paramLink" class="param"></div>*@
<div id="paramEvent" class="param">
事件类型:<select id="eventType">
@*<option value="ENTER">进入会话</option>*@
<option value="LOCATION">地理位置</option>
<option value="subscribe">订阅</option>
<option value="unsubscribe">取消订阅</option>
<option value="CLICK">自定义菜单点击事件</option>
<option value="scan">二维码扫描</option>
<option value="VIEW">URL跳转</option>
<option value="MASSSENDJOBFINISH">事件推送群发结果</option>
</select>
@*<div id="eventENTER" class="param"></div>*@
<div id="eventLOCATION" class="param">
Latitude:<input name="Event.Latitude" type="number" value="0"/><br />
Longitude:<input name="Event.Longitude" type="number" value="0"/><br />
Precision:<input name="Event.Precision" type="number" value="0"/><br />
</div>
<div id="eventsubscribe" class="param">
EventKey:<input name="Event.EventKey" /><br />
</div>
<div id="eventunsubscribe" class="param"></div>
<div id="eventCLICK" class="param">
EventKey:<input name="Event.EventKey" /><br />
</div>
<div id="eventscan" class="param">
EventKey:<input name="Event.EventKey" /><br />
Ticket:<input name="Event.Ticket" /><br />
</div>
<div id="eventVIEW" class="param">
EventKey:<input name="Event.EventKey" value="http://" /><br />
</div>
<div id="eventMASSSENDJOBFINISH" class="param">
ErrorCount:<input name="Event.ErrorCount" type="number" value="0"/><br />
FilterCount:<input name="Event.FilterCount" type="number" value="0"/><br />
SendCount:<input name="Event.SendCount" type="number" value="0"/><br />
Status:<input name="Event.Status"/><br />
TotalCount:<input name="Event.TotalCount" type="number" value="0"/><br />
</div>
</div>
<div>
<input type="button" value="提交" onclick="sendMessage()" />
</div>
</div>
</div>
<div class="paramArearight">
<div class="messageXmlArea">
<h3>发送内容(根据参数自动生成)</h3>
<textarea id="requestMessageXML" readonly="readonly"></textarea>
</div>
<div class="messageXmlArea">
<h3>接收内容</h3>
<textarea id="responseMessageXML"></textarea>
</div>
</div>
</div>
</section>
因为代码已经足够简单,所以不再一一详解,如果有任何问题可以在评论里面讨论,欢迎提各种建议!
[开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)的更多相关文章
- 微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引
Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到比较稳定的版本,这个过程中我觉得有必要整理一些思路和经验,和大家一起分享. ...
- 微信公众平台C# SDK:Senparc.Weixin.MP.dll
https://github.com/Senparc/WeiXinMPSDK [转] http://www.cnblogs.com/szw/archive/2013/01/13/senparc-wei ...
- 【转】微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引
微信公众账号 Senparc.Weixin.MP SDK 开发教程 索引 Senparc.Weixin.MP SDK从一开始就坚持开源的状态,这个过程中得到了许多朋友的认可和支持. 目前SDK已经达到 ...
- 在线GET/POST API接口请求模拟测试工具
在前后端开发过程中经常需要对HTTP接口进行测试,推荐几款比较好用的测试工具 Postman https://www.getpostman.com/ 强大的HTTP请求测试工具 支持多平台 Advan ...
- 用c#开发微信 (4) 基于Senparc.Weixin框架的接收事件推送处理 (源码下载)
本文讲述使用Senparc.Weixin框架来快速处理各种接收事件推送.这里的消息指的是传统的微信公众平台消息交互,微信用户向公众号发送消息后,公众号回复消息给微信用户.包括以下类型: 1 subsc ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二):成为开发者
Senparc.Weixin.MP SDK 微信公众平台开发教程(二):成为开发者 这一篇主要讲作为一名使用公众平台接口的开发者,你需要知道的一些东西.其中也涉及到一些微信官方的规定或比较掩蔽的注意点 ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二十一):在小程序中使用 WebSocket (.NET Core)
本文将介绍如何在 .NET Core 环境下,借助 SignalR 在小程序内使用 WebSocket.关于 WebSocket 和 SignalR 的基础理论知识不在这里展开,已经有足够的参考资料, ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十七):个性化菜单接口说明
前不久微信上线了个性化菜单接口,Senparc.Weixin SDK也已经同步更新. 本次更新升级Senparc.Weixin.MP版本到v13.5.2,依赖Senparc.Weixin版本4.5.4 ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(五):使用Senparc.Weixin.MP SDK
Senparc.Weixin.MP SDK已经涵盖了微信6.x的所有公共API. 整个项目的源代码以及已经编译好的程序集可以在这个项目中获取到:https://github.com/JeffreySu ...
随机推荐
- nodejs的url参数获取
express封装了多种http请求方式,我们主要使用get和post两种,即qpp.get和qpp.post.qpp.get和qpp.post的第一个参数都为请求的路径,第二个参数为处理请求的回调函 ...
- PhoneGap--001 入门 安装
PhoneGap 百度百科 PhoneGap 中文网 3.0 安装使用 今天也配置好phonegap3.0 android开发环境了,操作系统是win7,就楼主文章做些补充. 我是按phonegap官 ...
- mysql 事件调度
适用于mysql 5.1 及以后版本 1.查看是否开启 show variables like '%scheduler%' 2.查看进程 show processlist 3.事件调度器默认是关闭的, ...
- Win7上的ASP.NET MVC3项目在Win10上运行的一个坑
先解释一下问题:我原来的电脑环境是Win7+VS2015,因为新换了个电脑环境变成Win10+VS2015了,所以就把原先的项目复制到新的机器上,那么问题来了,原先的一个项目在VS2015上打开竟然直 ...
- Ip地址查询
$url = 'http://ip.taobao.com/service/getIpInfo.php?ip=115.239.211.112'; $info = file_get_contents($u ...
- 解决SQL server 2014 修改表中的字段,无法保存的问题。
修改PROJECT表中的字段,保存时,弹出上面的窗体,无法保存. 解决方法为:[工具]->[选项]->[设计器]中,去掉“阻止保存要求重新创建表的更改”前的勾选.
- OD使用教程
OD使用教程: 跳转指令.满足才能跳转成功
- jquery选择器使用说明
在jquery中选择器是一个非常重要的东西,几乎做什么都离不开它,下面我总结了jquery几种选择器的用法.以方便后面直接可以用到!! 层次选择器: 1.find()://找到该元素的子元素以及孙子元 ...
- Android PowerImageView实现,可以播放动画的强大ImageView
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11100315 我个人是比较喜欢逛贴吧的,贴吧里总是会有很多搞笑的动态图片,经常看一 ...
- hadoop显示ConnectionrRefused
产生原因重启了服务器 (1)在安装目录/root/cloud/hadoop-2.2.0/ 重新hdfs namenode -format (2) 目录/root/cloud/hadoop-2.2.0/ ...