swagger文档转换为WebApiClient声明式代码
1 swagger简介
Swagger是一个规范且完整的框架,提供描述、生产、消费和可视化RESTful Web Service。其核心是使用json来规范描述RESTful接口,另外有提供UI来查看接口说明,并有一套生成不同语言的客户端调用代码生成器。
1.1 对Api提供者
自顶向下
使用Swagger编辑器创建Swagger定义,然后使用Swagger代码生成工具生成服务器实现。
自底向上
为已有的REST API创建Swagger定义。一般的,Api提供者都会选择这种方式,比如在asp.net里集成swagger的支持,在写好接口代码之后,访问对应的swagger的访问Uri地址,就可以得到swagger.json。例如:http://petstore.swagger.io/v2/swagger.json
{
  "swagger": "2.0",
  "info": {
    "tags": null,
    "description": "This is a sample server Petstore server.  You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).  For this sample, you can use the api key `special-key` to test the authorization filters.",
    "version": "1.0.0",
    "title": "Swagger Petstore",
    "termsOfService": "http://swagger.io/terms/",
    "contact": {
      "email": "apiteam@swagger.io"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    }
  },
  "host": "petstore.swagger.io",
  "basePath": "/v2",
  "tags": [
  ...
1.2 对Api使用者
使用swagger UI
一些提供者的站点会提供swagger ui来查看其swagger.json,例如:http://petstore.swagger.io/ 有了这些UI,自己手工编写客户端调用代码也非常简单了。
使用Swagger Codegen
可以Swagger Codegen的将swagger.json逆向生成你需要的客户端调用接口代码,本质上是使用了代码模板结合swagger.json描述来生成代码。在.net里,有一个Nswag项目,可以将swagger.json生成使用HttpClient来请求接口的c#代码。但是这些代码的质量也比较差,比如以下代码的HttpClient的生命周期也就无法很好的维护。
/// <summary>Add a new pet to the store</summary>
/// <param name="body">Pet object that needs to be added to the store</param>
/// <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 AddPetAsync(Pet body, System.Threading.CancellationToken cancellationToken)
{
    var urlBuilder_ = new System.Text.StringBuilder();
    urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/pet");
    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(body, _settings.Value));
            content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
            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_ == "405")
                {
                    var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
                    throw new SwaggerException("Invalid input", (int)response_.StatusCode, responseData_, headers_, null);
                }
                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();
    }
}
2 WebApiClient.tools简介
WebApiClient是.net平台的一款RESTful声明式的面向切面客户端,其几乎100%实现了swagger定义的规范,WebApiClient.tools.swagger旨在将swagger.json逆向生成符合WebApiClient的声明式c#代码。
2.1 作用
使用原生HttpClient,你可能需要20行代码包装调用一个接口;使用WebApiClient,你可能只需要一行代码来定义接口方法;使用WebApiClient + WebApiClient.tools.swagger,你一行代码都不用写。
2.2 工作原理
- 使用NSwag解析json得到SwaggerDocument
 - 使用RazorEngine将SwaggerDocument传入cshtml模板编译得到html
 - 使用AngleSharp将html的文本代码提取,得到WebApiClient的声明式代码
 - 代码美化,输出到本地文件
 
2.3 样例效果
接口代码
    /// <summary>
    /// Everything about your Pets
    /// </summary>
    [TraceFilter]
    [HttpHost("https://petstore.swagger.io/v2/")]
    public interface IPetApi : IHttpApi
    {
        /// <summary>
        /// Add a new pet to the store
        /// </summary>
        /// <param name="body">Pet object that needs to be added to the store</param>
        [HttpPost("pet")]
        ITask<HttpResponseMessage> AddPetAsync( [Required] [JsonContent] Pet body );
        /// <summary>
        /// Update an existing pet
        /// </summary>
        /// <param name="body">Pet object that needs to be added to the store</param>
        [HttpPut("pet")]
        ITask<HttpResponseMessage> UpdatePetAsync( [Required] [JsonContent] Pet body );
    ...
模型代码
    public class Pet
    {
        [AliasAs("id")]
        public long? Id { get; set; }
        [AliasAs("category")]
        public Category Category { get; set; }
        [AliasAs("name")]
        [Required(AllowEmptyStrings = true)]
        public string Name { get; set; }
        [AliasAs("photoUrls")]
        [Required]
        public List<string> PhotoUrls { get; set; } = new List<string>();
    ...
3 相关资源
WebApiClient
github: https://github.com/dotnetcore/WebApiClient
WebApiClient.tools
github: https://github.com/xljiulang/WebApiClient.Tools
NSwag
github: https://github.com/RSuter/NSwag
RazorEngine
github: https://github.com/Antaris/RazorEngine
swagger文档转换为WebApiClient声明式代码的更多相关文章
- 使用 Swagger 文档化和定义 RESTful API
		
大部分 Web 应用程序都支持 RESTful API,但不同于 SOAP API——REST API 依赖于 HTTP 方法,缺少与 Web 服务描述语言(Web Services Descript ...
 - 懒得写文档,swagger文档导出来不香吗
		
导航 前言 离线文档 1 保存为html 2 导出成pdf文档 3 导出成Word文档 参考 前言 早前笔者曾经写过一篇文章<研发团队,请管好你的API文档>.团队协作中,开发文档的重 ...
 - 把office文档转换为html过程中的一些坑
		
之前和我们项目的团队一起酝酿了一个项目,公司的业务文档技术文档比较多,但都比较分散,虽然通过FTP或其他方式聚合起来了,但感觉还是不够方便. 另外公司每次都来新员工,新员工都需要一些培训,比较耗时,比 ...
 - revel + swagger 文档也能互动啦
		
beego 从 1.3 后开始支持自动化API文档,不过,目测比较复杂,一直期望 revel 能有官方支持. revel 确实已经有了官方支持的计划,有可能将在 0.14 版本支持,现在才 0.11. ...
 - Swagger文档转Word 文档
		
GitHub 地址:https://github.com/JMCuixy/SwaggerToWord/tree/developer 原创作品,转载请注明出处:http://www.cnblogs.co ...
 - 利用typescript生成Swagger文档
		
项目地址:https://github.com/wz2cool/swagger-ts-doc demo代码地址:https://github.com/wz2cool/swagger-ts-doc-de ...
 - 转:C#实现office文档转换为PDF或xps的一些方法
		
代码支持任意office格式 需要安装office 2007 还有一个office2007的插件OfficeSaveAsPDFandXPS 下载地址 [url]http://www.microsoft ...
 - PDF文档转换为图片、图片转成PDF 及PDF合并
		
简介 功能:PDF文档按每页转换成一张图片,一张图片转换成一张PDF 并将多张PDF合成一个多页的PDF文档. 经历:在各个网站上搜索始终出现各种问题,尤其是遇到引用的版本问题尤其头疼,不是不能适用当 ...
 - C#,VB.NET将PPT文档转换为HTML
		
PPT文档主要用于展示,有时候我们需要将PPT文档转换为HTML格式方便查看.本文将介绍如何使用C#和VB.NET将PPT文档转换为HTML格式.该方案使用了.NET PowerPoint 组件Spi ...
 
随机推荐
- dnscache --源码笔记
			
) } } //通过net包 解析域名对应的ip集合 func (r *Resolver) Lookup(address string) ([]net.IP, error) { ips, err := ...
 - 在vs中编写代码常用的快捷键
			
作为一个程序员,能够熟悉使用各种快捷键,可以增加我们编写和调试代码的速度,下面我就对常使用的快捷键做一些总结,下面这些快捷键基本适用于所有版本的vs: 最给力: Ctrl+K+F 快速整理代码格式 ...
 - 【最小生成树+子集枚举】Uva1151 Buy or Build
			
Description 平面上有n个点(1<=N<=1000),你的任务是让所有n个点连通,为此,你可以新建一些边,费用等于两个端点的欧几里得距离的平方. 另外还有q(0<=q< ...
 - 解决非root用户使用docker的办法
			
通常我们使用Docker的时候都是使用的root,官方说法如下 The docker daemon binds to a Unix socket instead of a TCP port. By d ...
 - Django 基础一(安装和启动)
			
在开始跟着本文学习Django进行Web开发之前你需要有一定的python编程基础,会用一些简单的Linux系统命令.如果你对python一无所知,请先去这个网站学习一下python编程的基础 Lin ...
 - Java SPI机制用法demo
			
①构建一个maven工程 包含如下目录结构: src/main/java src/main/resources src/test/java src/test/resources ②在src/main/ ...
 - 使用jdbc拼接条件查询语句时如何防止sql注入
			
本人微信公众号,欢迎扫码关注! 使用jdbc拼接条件查询语句时如何防止sql注入 最近公司的项目在上线时需要进行安全扫描,但是有几个项目中含有部分老代码,操作数据库时使用的是jdbc,并且竟然好多都是 ...
 - Caffe源码理解2:SyncedMemory CPU和GPU间的数据同步
			
目录 写在前面 成员变量的含义及作用 构造与析构 内存同步管理 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 在Caffe源码理解1中介绍了Blob类,其中的数据成 ...
 - LDA && NCA: 降维与度量学习
			
已迁移到我新博客,阅读体验更佳LDA && NCA: 降维与度量学习 代码实现放在我的github上:click me 一.Linear Discriminant Analysis(L ...
 - 第四节 pandas 数据加载
			
pandas提供了一些用于将表格型数据读取为DataFrame对象的函数,其中read_csv和read_table这两个使用最多. #导包import pandas as pd from panda ...