[開源]微信線上資訊模擬測試工具(基於Senparc.Weixin.MP開發)

SZW發表於2014-08-03

  目前為止似乎還沒有看到過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>

 

  因為程式碼已經足夠簡單,所以不再一一詳解,如果有任何問題可以在評論裡面討論,歡迎提各種建議!

相關文章