上一篇博客中咱們能夠得知經過Swagger插件能夠很方便的提供給接口開發者在線調試,可是實際上Swagger附帶的功能還有不少,前端
好比使用NSwag生成客戶端調用代碼,進一步解放接口開發者。git
NSwag是一個發佈在GitHub上的開源項目,它能夠根據Swagger說明頁上的swagger.json文件生成C#、TypeScript客戶端代碼。程序員
NSwag的項目地址:https://github.com/RSuter/NSwaggithub
Nswag提供4種代碼生成方法web
一、使用 NSwagStudio,這是一款 Windows 桌面應用,用於在 C# 和 TypeScript 中爲 API 生成客戶端代碼。json
二、使用 NSwag.CodeGeneration.CSharp 或 NSwag.CodeGeneration.TypeScript NuGet 包在項目中執行代碼生成。api
三、使用命令行中的 NSwag。瀏覽器
四、使用 NSwag.MSBuild NuGet 包。app
這裏推薦使用NSwagStudio,能夠從GitHub上下載該工具,地址:https://github.com/RSuter/NSwag/wiki/NSwagStudioasync
下載後開始安裝,安裝完畢後打開NSwagStudio,以下圖,在左側選擇Tab頁菜單裏選擇Documents
如上圖框框選中的幾點,咱們須要留意。其中Swagger Specification URL就是咱們WebAPI的swagger.json的在線地址。
若是點擊【Create local Copy 】按鈕時你的WebAPI未在線則代碼生成工具會彈出錯誤對話框,以下圖:
因此採起讀取Swagger Specification URL 方式進行生成代碼的前提條件是你必須保證swagger.json文件能在線讀取!
其次你能夠選擇RunTime(運行時),這裏應該是服務端WebAPI的運行時(畢竟TypeScript是不關心你服務端是.NET Core仍是.NET Framework).
由於個人環境是.NET Core2.1,因此這裏選擇NET Core21。
接下來,點擊【Create local Copy】按鈕,點擊後NSwagStudio會與WebAPI服務端進行交互,成功後會將swagger.json文件格式化到左邊的文本編輯器中,以下圖:
此時,你能夠在右側的Outputs中勾選你須要輸出的文件格式,這裏我選擇TypeScript和CSharp Client,
這個地方有個C# WebAPI Controller,我有點納悶,我都有swagger.json文件了絕壁是已經存在webapi了,
沒有必要反向再去生成一遍webapi的控制器啦。 不懂,反正只管生成客戶端代碼就好。
咱們勾選好後下面就會出現相應的輸出配合頁面,以下圖:
咱們選擇CSharp Client頁面,該頁面左側分爲Setting和Output兩個頁面,Setting頁能夠對輸出的cs文件進行配置,如命名空間、類名稱、輸出文件路徑等等(不少配置我也不會....)
咱們點擊【Generate Outputs】後NSwagStudio會根據配置生成客戶端操做類,在Output頁面便可檢查,檢查無誤後再點擊【Generate Files】可將類文件導出到配置的輸出目錄。
TypeScript亦是如此,同時NSwagStudio也可支持加載DLL反射生成,具體方法可根據官網操做(畢竟能夠直接使用json文件在線生成不必再本身手工選擇dll..)
這裏截圖看SwagerUI頁和NSwagStudio生成後的客戶端cs文件
生成的客戶端C#代碼:
//---------------------- // <auto-generated> // Generated using the NSwag toolchain v11.17.19.0 (NJsonSchema v9.10.58.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org) // </auto-generated> //---------------------- namespace Test { #pragma warning disable // Disable all warnings [System.CodeDom.Compiler.GeneratedCode("NSwag", "11.17.19.0 (NJsonSchema v9.10.58.0 (Newtonsoft.Json v9.0.0.0))")] public partial class Client { private string _baseUrl = "http://localhost:58985"; private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings; public Client() { _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(() => { var settings = new Newtonsoft.Json.JsonSerializerSettings(); UpdateJsonSerializerSettings(settings); return settings; }); } public string BaseUrl { get { return _baseUrl; } set { _baseUrl = value; } } protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); /// <summary>巴拉巴拉</summary> /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> public System.Threading.Tasks.Task ApiTestGetAsync() { return ApiTestGetAsync(System.Threading.CancellationToken.None); } /// <summary>巴拉巴拉</summary> /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async System.Threading.Tasks.Task ApiTestGetAsync(System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Test"); var client_ = new System.Net.Http.HttpClient(); try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { request_.Method = new System.Net.Http.HttpMethod("GET"); PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); try { var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); if (response_.Content != null && response_.Content.Headers != null) { foreach (var item_ in response_.Content.Headers) headers_[item_.Key] = item_.Value; } ProcessResponse(client_, response_); var status_ = ((int)response_.StatusCode).ToString(); if (status_ == "200") { return; } else if (status_ != "200" && status_ != "204") { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new SwaggerException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null); } } finally { if (response_ != null) response_.Dispose(); } } } finally { if (client_ != null) client_.Dispose(); } } /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> public System.Threading.Tasks.Task ApiTestPostAsync(string value) { return ApiTestPostAsync(value, System.Threading.CancellationToken.None); } /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async System.Threading.Tasks.Task ApiTestPostAsync(string value, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Test"); var client_ = new System.Net.Http.HttpClient(); try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(value, _settings.Value)); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("POST"); PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); try { var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); if (response_.Content != null && response_.Content.Headers != null) { foreach (var item_ in response_.Content.Headers) headers_[item_.Key] = item_.Value; } ProcessResponse(client_, response_); var status_ = ((int)response_.StatusCode).ToString(); if (status_ == "200") { return; } else if (status_ != "200" && status_ != "204") { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new SwaggerException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null); } } finally { if (response_ != null) response_.Dispose(); } } } finally { if (client_ != null) client_.Dispose(); } } /// <summary>我是get測試</summary> /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> public System.Threading.Tasks.Task<string> ApiTestByIdGetAsync(int id) { return ApiTestByIdGetAsync(id, System.Threading.CancellationToken.None); } /// <summary>我是get測試</summary> /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async System.Threading.Tasks.Task<string> ApiTestByIdGetAsync(int id, System.Threading.CancellationToken cancellationToken) { if (id == null) throw new System.ArgumentNullException("id"); var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Test/{id}"); urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); var client_ = new System.Net.Http.HttpClient(); try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); try { var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); if (response_.Content != null && response_.Content.Headers != null) { foreach (var item_ in response_.Content.Headers) headers_[item_.Key] = item_.Value; } ProcessResponse(client_, response_); var status_ = ((int)response_.StatusCode).ToString(); if (status_ == "200") { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); var result_ = default(string); try { result_ = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(responseData_, _settings.Value); return result_; } catch (System.Exception exception_) { throw new SwaggerException("Could not deserialize the response body.", (int)response_.StatusCode, responseData_, headers_, exception_); } } else if (status_ != "200" && status_ != "204") { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new SwaggerException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null); } return default(string); } finally { if (response_ != null) response_.Dispose(); } } } finally { if (client_ != null) client_.Dispose(); } } /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> public System.Threading.Tasks.Task ApiTestByIdPutAsync(int id, string value) { return ApiTestByIdPutAsync(id, value, System.Threading.CancellationToken.None); } /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async System.Threading.Tasks.Task ApiTestByIdPutAsync(int id, string value, System.Threading.CancellationToken cancellationToken) { if (id == null) throw new System.ArgumentNullException("id"); var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Test/{id}"); urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); var client_ = new System.Net.Http.HttpClient(); try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(value, _settings.Value)); content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data"); request_.Content = content_; request_.Method = new System.Net.Http.HttpMethod("PUT"); PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); try { var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); if (response_.Content != null && response_.Content.Headers != null) { foreach (var item_ in response_.Content.Headers) headers_[item_.Key] = item_.Value; } ProcessResponse(client_, response_); var status_ = ((int)response_.StatusCode).ToString(); if (status_ == "200") { return; } else if (status_ != "200" && status_ != "204") { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new SwaggerException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null); } } finally { if (response_ != null) response_.Dispose(); } } } finally { if (client_ != null) client_.Dispose(); } } /// <summary>小魔仙</summary> /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> public System.Threading.Tasks.Task ApiTestByIdDeleteAsync(int id) { return ApiTestByIdDeleteAsync(id, System.Threading.CancellationToken.None); } /// <summary>小魔仙</summary> /// <returns>Success</returns> /// <exception cref="SwaggerException">A server side error occurred.</exception> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> public async System.Threading.Tasks.Task ApiTestByIdDeleteAsync(int id, System.Threading.CancellationToken cancellationToken) { if (id == null) throw new System.ArgumentNullException("id"); var urlBuilder_ = new System.Text.StringBuilder(); urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/api/Test/{id}"); urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id, System.Globalization.CultureInfo.InvariantCulture))); var client_ = new System.Net.Http.HttpClient(); try { using (var request_ = new System.Net.Http.HttpRequestMessage()) { request_.Method = new System.Net.Http.HttpMethod("DELETE"); PrepareRequest(client_, request_, urlBuilder_); var url_ = urlBuilder_.ToString(); request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); PrepareRequest(client_, request_, url_); var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); try { var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); if (response_.Content != null && response_.Content.Headers != null) { foreach (var item_ in response_.Content.Headers) headers_[item_.Key] = item_.Value; } ProcessResponse(client_, response_); var status_ = ((int)response_.StatusCode).ToString(); if (status_ == "200") { return; } else if (status_ != "200" && status_ != "204") { var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); throw new SwaggerException("The HTTP status code of the response was not expected (" + (int)response_.StatusCode + ").", (int)response_.StatusCode, responseData_, headers_, null); } } finally { if (response_ != null) response_.Dispose(); } } } finally { if (client_ != null) client_.Dispose(); } } private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) { if (value is System.Enum) { string name = System.Enum.GetName(value.GetType(), value); if (name != null) { var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); if (field != null) { var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) as System.Runtime.Serialization.EnumMemberAttribute; if (attribute != null) { return attribute.Value; } } } } else if (value is byte[]) { return System.Convert.ToBase64String((byte[]) value); } else if (value != null && value.GetType().IsArray) { var array = System.Linq.Enumerable.OfType<object>((System.Array) value); return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); } return System.Convert.ToString(value, cultureInfo); } } [System.CodeDom.Compiler.GeneratedCode("NSwag", "11.17.19.0 (NJsonSchema v9.10.58.0 (Newtonsoft.Json v9.0.0.0))")] public partial class SwaggerException : System.Exception { public int StatusCode { get; private set; } public string Response { get; private set; } public System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; } public SwaggerException(string message, int statusCode, string response, System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Exception innerException) : base(message, innerException) { StatusCode = statusCode; Response = response; Headers = headers; } public override string ToString() { return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); } } [System.CodeDom.Compiler.GeneratedCode("NSwag", "11.17.19.0 (NJsonSchema v9.10.58.0 (Newtonsoft.Json v9.0.0.0))")] public partial class SwaggerException<TResult> : SwaggerException { public TResult Result { get; private set; } public SwaggerException(string message, int statusCode, string response, System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> headers, TResult result, System.Exception innerException) : base(message, statusCode, response, headers, innerException) { Result = result; } } }
若是嫌代碼生成工具須要下載或大家前端的電腦操做系統是MacOs則能夠考慮使用Swagger在線代碼生成,地址: https://editor.swagger.io/
Swagger線上代碼生成支持導入swagger.json文件和引用SwaggerUI線上地址兩種模式。
推薦使用Import File,我使用Import URL壓根就沒成功過。。。。
導入方法以下圖
導入後能夠選擇導出的方式(服務端 OR 客戶端),而且這個比前面的代碼生成器exe要強大啊,它支持導出的語言真是把我驚呆了,牛逼啊。
沒圖我會亂說?? 是否是很牛逼。
選擇生成後,瀏覽器就會下載代碼啦~~~~~~真的牛批啊~~!~!!!
給大家貼一張線上生成TypeScript-angular的代碼,真的比那個exe生成出來的代碼規範多了,線上生成的會根據每個Controller生成一個Service.ts,
exe工具是把全部Controllser的action都生成在一個Service.ts文件裏(尼瑪,這也能不一樣。。我仍是之後都從線上生成算了....)
不得不讚嘆Swagger的強大,它的出現解放了多少程序員啊,後續但凡是有客戶端碼農說不會調用哥的API,哥均可以直接給他代碼生成器生成的代碼,一個字:爽。