zoukankan      html  css  js  c++  java
  • .NetCore2.1 WebAPI 根据swagger.json自动生成客户端代码

    前言

    上一篇博客中我们可以得知通过Swagger插件可以很方便的提供给接口开发者在线调试,但是实际上Swagger附带的功能还有很多,

    比如使用NSwag生成客户端调用代码,进一步解放接口开发者。

    NSwag 

    NSwag是一个发布在GitHub上的开源项目,它可以根据Swagger说明页上的swagger.json文件生成C#、TypeScript客户端代码。

    NSwag的项目地址:https://github.com/RSuter/NSwag

    Nswag提供4种代码生成方法

    1、使用 NSwagStudio,这是一款 Windows 桌面应用,用于在 C# 和 TypeScript 中为 API 生成客户端代码。

    2、使用 NSwag.CodeGeneration.CSharp 或 NSwag.CodeGeneration.TypeScript NuGet 包在项目中执行代码生成。

    3、使用命令行中的 NSwag。

    4、使用 NSwag.MSBuild NuGet 包。

    这里推荐使用NSwagStudio,可以从GitHub上下载该工具,地址:https://github.com/RSuter/NSwag/wiki/NSwagStudio

    下载后开始安装,安装完毕后打开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: 
    
    {0}
    
    {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,哥都可以直接给他代码生成器生成的代码,一个字:爽。

  • 相关阅读:
    JavaScript跳转到指定页面并且到指定的tab切换窗口
    三层架构之基础篇(对数据库增删改查)
    三层架构之基础篇(三层架构模型)
    过一天不登QQ的生活
    MVC + EF 框架 对数据库做增删改查
    想说的话
    新的2019年,向上
    C#读取txt文档
    C#写的 电子邮件客户端(winform窗体)
    C# 鼠标任意拖动无边框窗体(调用API函数)。
  • 原文地址:https://www.cnblogs.com/hunanzp/p/9297361.html
Copyright © 2011-2022 走看看