一、前言
現在使用WebAPI來作為實現企業服務化的需求非常常見,不可否認它也是很便於使用的,基於注釋可以生成對應的幫助文檔(Microsoft.AspNet.WebApi.HelpPage),但是比較便利和可持久化的調試官方卻沒有相應的集成,雖然我們可以使 用諸如Fiddler、Swagger、PostMan、及其他手寫代碼的方式等等來調試我們的WebAPI,但是卻依然不是很方便,對於公司來說也需要有一種可以統一、可持久化、且行之有效的規范。
調試接口我希望他能達到以下3點:
1:可根據接口定義生成測試數據。
2:測試數據可持久化,便於持續迭代。
3:測試數據可共享。文本主要介紹如何利用PostMan實現這3點。
二、有哪些調試方法
目前所知道的調試方式有:
1:耳熟能詳的Fiddler就不說了,功能非常強大,但不是我們想要的。
2:PostMan,使用方便且滿足上面的2和3,這是一個谷歌插件(地址在這),也有App版本(https://www.getpostman.com/)推薦。
3:Swagger,已有人將其結合SwaggerUI集成到WebAPI中,Nuget上安裝
install-package Swashbuckle即可,項目地址https://github.com/domaindrivendev/Swashbuckle。
4:手寫HttpClient來實現,其他的還有https://github.com/wuchang/WebApiTestClient。
以上這幾種方法比較推薦的自然是PostMan。
三、PostMan的基本操作
我們先來看看使用PosMan的一些基本操作。
如下所示,我們定義了幾個簡單的方法來作為我們調試的接口。
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using WebAPI2PostMan.Models; namespace WebAPI2PostMan.Controllers { /// <summary> /// 產品服務 /// </summary> [RoutePrefix("Product")] public class ProductController : ApiController { private static readonly List<Product> Products = new List<Product> { new Product{Id = Guid.NewGuid(), Description = "產品描述",Name = "產品名稱",Price = 123}, new Product{Id = Guid.NewGuid(), Description = "產品描述",Name = "產品名稱",Price = 124}, new Product{Id = Guid.NewGuid(), Description = "產品描述",Name = "產品名稱",Price = 125}, new Product{Id = Guid.NewGuid(), Description = "產品描述",Name = "產品名稱",Price = 126} }; /// <summary> /// 獲取所有產品 /// </summary> [HttpGet, Route("All")] public IEnumerable<Product> Get() { return Products; } /// <summary> /// 獲取產品 /// </summary> /// <param name="id">產品編號</param> [HttpGet, Route("{id}")] public string Get(Guid id) { return "value"; } /// <summary> /// 添加產品 /// </summary> /// <param name="request">產品請求</param> [HttpPost, Route("")] public string Post(Product request) { Products.Add(request); return "ok"; } /// <summary> /// 編輯產品 /// </summary> /// <param name="id">產品編號</param> /// <param name="request">編輯后的產品</param> [HttpPut, Route("{id}")] public void Put(int id, Product request) { } /// <summary> /// 刪除產品 /// </summary> /// <param name="id">產品編號</param> [HttpDelete, Route("{id}")] public string Delete(Guid id) { var model = Products.FirstOrDefault(x => x.Id.Equals(id)); Products.Remove(model); var result = string.Format("編號為{0}的產品刪除成功!", id); return result; } } }在Nuget里添加了Microsoft.AspNet.WebApi.HelpPage之后生成的幫助文檔如下圖。
接下來,我們使用PostMan來調試我們定義的接口。在這里我使用插件版的PostMan作為演示。
獲取所有產品這種其實直接使用瀏覽器訪問就可以達到調試的目的,但是若有特殊Header或身份驗證時就不太方便了,如下在PostMan中輸入對應地址點擊【Send】即可看到返回的數據及消耗的時間和HttpStatus等。
對於我們常用的我們可以點擊Add to collection將其加入到Collections中便於下次測試。
接下來,我們對新增產品添加調試。
其余的類似,請求的方法類型與Http請求類型一致。
四、生成PostMan導入數據
那么,對於參數較多的接口時第一次添加參數是比較繁瑣的,所以我希望能有根據接口定義生成出可以導入到PostMan中的方法,分析Postman下載出來的數據格式可見其實就是一個Json格式的文件。
那既然是Json格式的文件,我們就可以根據它所需要的格式生成。首先我們定義出需要的類,並沒有包含全部的屬性,APP版本有一些是否同步等屬性並沒有加進來,有興趣的朋友可以研究一下。
public class PostmanCollection { public string id { get; set; } public string name { get; set; } public string description { get; set; } public List<string> order { get; set; } public long timestamp { get; set; } public List<PostmanRequest> requests { get; set; } } public class PostmanRequest { public string collection { get; set; } public string id { get; set; } public string name { get; set; } public string dataMode { get; set; } public List<PostmanData> data { get; set; } public string description { get; set; } public string descriptionFormat { get; set; } public string headers { get; set; } public string method { get; set; } public Dictionary<string, string> pathVariables { get; set; } public string url { get; set; } public int version { get; set; } public string collectionId { get; set; } } public class PostmanData { public string key { get; set; } public string value { get; set; } public string type { get { return "text"; } } public bool enabled { get { return true; } } }PostMan支持從地址導入,所以我們可以定義個PostManController要根據接口定義來生成我們的Json數據。
using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Web.Http.Description; using System.Web.Http.Results; using Newtonsoft.Json; using WebAPI2PostMan.Areas.HelpPage; using WebAPI2PostMan.Models; namespace WebAPI2PostMan.Controllers { /// <summary> /// /// </summary> [RoutePrefix("PostMan")] public class PostManController : ApiController { private const string Host = "http://localhost:11488/"; /// <summary> /// 獲取PostMan集合 /// </summary> /// <returns></returns> [Route("")] public JsonResult<PostmanCollection> GetPostmanCollection() { var collectionId = PostMan.GetId(); var apis = Configuration.Services.GetApiExplorer().ApiDescriptions.Where(x => x.Documentation != null); var requests = GetPostmanRequests(apis, collectionId); var collection = new PostmanCollection { id = collectionId, name = "WebAPI2PostMan", description = "", order = requests.Select(x => x.id).ToList(), timestamp = 0, requests = requests }; return Json(collection); } private List<PostmanRequest> GetPostmanRequests(IEnumerable<ApiDescription> apis, string collectionId) { return apis.Select(api => new PostmanRequest { collection = collectionId, id = PostMan.GetId(), name = api.Documentation, dataMode = "urlencoded", data = GetPostmanDatas(api), description = "", descriptionFormat = "html", headers = "", method = api.HttpMethod.Method, pathVariables = new Dictionary<string, string>(), url = Host + api.RelativePath, version = 2, collectionId = collectionId }).ToList(); } private List<PostmanData> GetPostmanDatas(ApiDescription api) { var postmandatas = new List<PostmanData>(); var apiModel = Configuration.GetHelpPageApiModel(api.GetFriendlyId()); var raw = apiModel.SampleRequests.Values.FirstOrDefault(); if (raw == null) return postmandatas; var pdata = JsonConvert.DeserializeObject<Dictionary<string,string>>(raw.ToString()); postmandatas.AddRange(pdata.Select(model => new PostmanData {key = model.Key, value = model.Value})); return postmandatas; } } }主要生成代碼就是獲取所有接口和接口定義的參數。值得一提的是,我們可以借助Microsoft.AspNet.WebApi.HelpPage來獲取SampleRequests,從而使用SampleRequests來填充我們的測試數據。
運行程序訪問http://localhost:11488/PostMan 並將其導入到PostMan。
效果還是可以接受的,還有寫可以拓展的地方,比如可以直接一鍵導入到PostMan程序中,用谷歌瀏覽器審查元素可以發現導入的方法是importCollectionFromUrl,在console中輸入
window.open("chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm/index.html"); pm.collections.importCollectionFromUrl("http://localhost:11488/postman");就可以達到一鍵導入的目的了。但是遺憾的是,必須要在插件內調用才有效,代碼匆忙,還有很多地方可以繼續拓展,不過本文的目的已經達到了。