ASP.NET Web Api 如何使用 Swagger 管理 API

前言

Swagger 是一个开源的框架,支持 OpenAPI 规范,可以根据 API 规范自动生成美观的、易于浏览的 API 文档页面,包括请求参数、响应示例等信息,并且,Swagger UI 提供了一个交互式的界面,可以帮助我们快速测试和调试 API,验证 API 的功能和正确性。

总的来说,Swagger 是一个强大的工具,可以帮助开发人员设计、构建和文档化 RESTful API,提高 API 的可读性、可维护性和互操作性,有了它,我们就可以更方便、更有效率地管理 API。

ASP.NET Core 中,已经内置了 Swagger,很方便就能使用。但在 ASP.NET 里,需要我们自己引用和配置才能使用它,下面通过一个 Step By Step 例子来看看 ASP.NET Web Api 如何使用 Swagger。

Step By Step 步骤

  1. 创建 .netframework webapi 项目

  2. 在项目上右键 - 项目属性 - 生成 - (输出)勾选 "XML文档文件"并填写自定义路径如"App_Data\apidoc.xml"

  3. Nuget 安装以下 Swagger 相关的两个包

    Swashbuckle

    Swagger.NET.UI(这个不装也可以)

  4. 创建 App_Start/SwaggerCacheProvider 辅助类,用于获取 xml 文件注释内容,留意注释

    c# 复制代码
    using Swashbuckle.Swagger;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Xml;
    
    namespace SwaggerTest
    {
    	/// <summary>
    	/// 支持方法注释
    	/// </summary>
    	public class SwaggerCacheProvider : ISwaggerProvider
    	{
    		private readonly ISwaggerProvider _swaggerProvider;
    		private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
    		private readonly string _xmlPath;
    
    		/// <summary>
    		/// 构造方法
    		/// </summary>
    		/// <param name="swaggerProvider"></param>
    		/// <param name="xmlpath"></param>
    		public SwaggerCacheProvider(ISwaggerProvider swaggerProvider, string xmlpath)
    		{
    			_swaggerProvider = swaggerProvider;
    			_xmlPath = xmlpath;
    		}
    
    		/// <summary>
    		/// 生成 Swagger 文档,并存入缓存
    		/// </summary>
    		/// <param name="rootUrl"></param>
    		/// <param name="apiVersion"></param>
    		/// <returns></returns>
    		/// <exception cref="NotImplementedException"></exception>
    		public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
    		{
    			var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
    			// 只读取一次
    			if (!_cache.TryGetValue(cacheKey, out SwaggerDocument srcDoc))
    			{
    				srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
    
    				srcDoc.vendorExtensions = new Dictionary<string, object>
    				{
    					{ "ControllerDesc", GetControllerDesc() }
    				};
    				_cache.TryAdd(cacheKey, srcDoc);
    			}
    			return srcDoc;
    		}
    
    		/// <summary>
    		/// 从API文档中读取控制器描述
    		/// </summary>
    		/// <returns></returns>
    		private ConcurrentDictionary<string, string> GetControllerDesc()
    		{
    			ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
    			if (File.Exists(_xmlPath))
    			{
    				// 1. 加载生成 xml
    				XmlDocument xmldoc = new XmlDocument();
    				xmldoc.Load(_xmlPath);
    
    				// 2. 读取控制器方法注释内容
    				string[] arrPath;
    				int cCount = "Controller".Length;
    				foreach (XmlNode node in xmldoc.SelectNodes("//member"))
    				{
    					string type = node.Attributes["name"].Value;
    					if (type.StartsWith("T:"))
    					{
    						arrPath = type.Split('.');
    						string controllerName = arrPath[arrPath.Length - 1];
    						if (controllerName.EndsWith("Controller"))  //控制器
    						{
    							// 获取控制器注释
    							XmlNode summaryNode = node.SelectSingleNode("summary");
    							string key = controllerName.Remove(controllerName.Length - cCount, cCount);
    							if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
    							{
    								controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
    							}
    						}
    					}
    				}
    			}
    			return controllerDescDict;
    		}
    	}
    }	
  5. 创建 Scripts\swagger.js,用于支持显示中文注释内容

    javascript 复制代码
    'use strict';
    window.SwaggerTranslator = {
    	_words: [],
    
    	translate: function () {
    		var $this = this;
    		$('[data-sw-translate]').each(function () {
    			$(this).html($this._tryTranslate($(this).html()));
    			$(this).val($this._tryTranslate($(this).val()));
    			$(this).attr('title', $this._tryTranslate($(this).attr('title')));
    		});
    	},
    
    	setControllerSummary: function () {
    		$.ajax({
    			type: "get",
    			async: true,
    			url: $("#input_baseUrl").val(),
    			dataType: "json",
    			success: function (data) {
    				var summaryDict = data.ControllerDesc;
    				var id, controllerName, strSummary;
    				$("#resources_container .resource").each(function (i, item) {
    					id = $(item).attr("id");
    					if (id) {
    						controllerName = id.substring(9);
    						strSummary = summaryDict[controllerName];
    						if (strSummary) {
    							$(item).children(".heading").children(".options").first().prepend('<li class="controller-summary" title="' + strSummary + '">' + strSummary + '</li>');
    						}
    					}
    				});
    			}
    		});
    	},
    	_tryTranslate: function (word) {
    		return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
    	},
    
    	learn: function (wordsMap) {
    		this._words = wordsMap;
    	}
    };
    
    
    /* jshint quotmark: double */
    window.SwaggerTranslator.learn({
    	"Warning: Deprecated": "警告:已过时",
    	"Implementation Notes": "实现备注",
    	"Response Class": "响应类",
    	"Status": "状态",
    	"Parameters": "参数",
    	"Parameter": "参数",
    	"Value": "值",
    	"Description": "描述",
    	"Parameter Type": "参数类型",
    	"Data Type": "数据类型",
    	"Response Messages": "响应消息",
    	"HTTP Status Code": "HTTP 状态码",
    	"Reason": "原因",
    	"Response Model": "响应模型",
    	"Request URL": "请求 URL",
    	"Response Body": "响应体",
    	"Response Code": "响应码",
    	"Response Headers": "响应头",
    	"Hide Response": "隐藏响应",
    	"Headers": "头",
    	"Try it out!": "试一下!",
    	"Show/Hide": "显示/隐藏",
    	"List Operations": "显示操作",
    	"Expand Operations": "展开操作",
    	"Raw": "原始",
    	"can't parse JSON.  Raw result": "无法解析 JSON。原始结果",
    	"Model Schema": "模型架构",
    	"Model": "模型",
    	"apply": "应用",
    	"Username": "用户名",
    	"Password": "密码",
    	"Terms of service": "服务条款",
    	"Created by": "创建者",
    	"See more at": "查看更多:",
    	"Contact the developer": "联系开发者",
    	"api version": "api 版本",
    	"Response Content Type": "响应 Content Type",
    	"fetching resource": "正在获取资源",
    	"fetching resource list": "正在获取资源列表",
    	"Explore": "浏览",
    	"Show Swagger Petstore Example Apis": "显示 Swagger Petstore 示例 Apis",
    	"Can't read from server.  It may not have the appropriate access-control-origin settings.": "无法从服务器读取。可能没有正确设置 access-control-origin。",
    	"Please specify the protocol for": "请指定协议:",
    	"Can't read swagger JSON from": "无法读取 swagger JSON于",
    	"Finished Loading Resource Information. Rendering Swagger UI": "已加载资源信息。正在渲染 Swagger UI",
    	"Unable to read api": "无法读取 api",
    	"from path": "从路径",
    	"server returned": "服务器返回"
    });
    $(function () {
    	window.SwaggerTranslator.translate();
    	window.SwaggerTranslator.setControllerSummary();
    });	
  6. 右键 Scripts\swagger.js - 属性 - 生成操作 - 改为 "嵌入的资源"

  7. 打开并修改 App_Start\SwaggerConfig.cs(安装以上包后自动生成此文件),以下是修改后的完整代码

    c# 复制代码
    using System.Web.Http;
    using WebActivatorEx;
    using SwaggerTest;
    using Swashbuckle.Application;
    using System.Reflection;
    
    [assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
    namespace SwaggerTest
    {
    	// 完整版 Swagger config 代码
    
    	/// <summary>
    	/// 配置 Swagger
    	/// </summary>
    	public class SwaggerConfig
    	{
    		/// <summary>
    		/// 注册
    		/// </summary>
    		public static void Register()
    		{
    			var thisAssembly = typeof(SwaggerConfig).Assembly;
    
    			GlobalConfiguration.Configuration
    				.EnableSwagger(c =>
    					{
    						//用于启用和设置Swagger的配置信息。
    						c.SingleApiVersion("v2", "测试 API 接口文档");
    						c.IncludeXmlComments($@"{System.AppDomain.CurrentDomain.BaseDirectory}\bin\SwaggerTest.xml");
    						//获取项目指定路径下xml文件
    						c.CustomProvider((defaultProvider) => new SwaggerCacheProvider(defaultProvider, $@"{System.AppDomain.CurrentDomain.BaseDirectory}\bin\SwaggerTest.xml"));
    					})
    				.EnableSwaggerUi(c =>
    					{
    						//用于启用UI界面上的东西。
    						//加载汉化的js文件,注意 swagger.js文件属性必须设置为"嵌入的资源"。 APIUI.Scripts.swagger.js依次是:项目名称->文件夹->js文件名 
    						c.InjectJavaScript(Assembly.GetExecutingAssembly(), "SwaggerTest.Scripts.swagger.js");
    					});
    		}
    	}
    }	
  8. 打开并注释掉 App_Start\SwaggerNet.cs 代码(安装以上包后自动生成此文件)

    c# 复制代码
    using System;
    using System.IO;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Description;
    using System.Web.Http.Dispatcher;
    using System.Web.Routing;
    using Swagger.Net;
    
    //[assembly: WebActivator.PreApplicationStartMethod(typeof(SwaggerTest.App_Start.SwaggerNet), "PreStart")]
    //[assembly: WebActivator.PostApplicationStartMethod(typeof(SwaggerTest.App_Start.SwaggerNet), "PostStart")]
    namespace SwaggerTest.App_Start 
    {
    	/// <summary>
    	/// Swagger Net 
    	/// </summary>
    	public static class SwaggerNet 
    	{
    		//public static void PreStart() 
    		//{
    		//    RouteTable.Routes.MapHttpRoute(
    		//        name: "SwaggerApi",
    		//        routeTemplate: "api/docs/{controller}",
    		//        defaults: new { swagger = true }
    		//    );            
    		//}
    		
    		//public static void PostStart() 
    		//{
    		//    var config = GlobalConfiguration.Configuration;
    
    		//    config.Filters.Add(new SwaggerActionFilter());
    			
    		//    try
    		//    {
    		//        config.Services.Replace(typeof(IDocumentationProvider),
    		//            new XmlCommentDocumentationProvider(HttpContext.Current.Server.MapPath("~/bin/SwaggerTest.XML")));
    		//    }
    		//    catch (FileNotFoundException)
    		//    {
    		//        throw new Exception("Please enable \"XML documentation file\" in project properties with default (bin\\SwaggerTest.XML) value or edit value in App_Start\\SwaggerNet.cs");
    		//    }
    		//}
    	}
    }	
  9. 至此,Swagger 配置就完成了,接着就可以运行看看效果了

测试

  • 配置完成后,直接运行项目,打开以下网址,即可看到效果

    复制代码
    https://localhost:44335/swagger/

其它

  • Swagger.NET.UI不是必要的,运行 SwaggerUI目录下面的 index 反而会出错

我是老杨,一个奋斗在一线的资深研发老鸟,让我们一起聊聊技术,聊聊人生。

都看到这了,求个点赞、关注、在看三连呗,感谢支持。

相关推荐
DXM05218 分钟前
牟乃夏《ArcGIS Engine地理信息系统开发教程》学习笔记1
开发语言·经验分享·笔记·学习·arcgis·c#·arcgis engine
Wythzhfrey31 分钟前
51单片机Day03---让一个LED灯闪烁
c语言·单片机·嵌入式硬件·c#·51单片机
浅陌sss36 分钟前
C#容器源码分析 --- List
c#
有过~2 小时前
CrystalDiskInfo电脑硬盘监控工具 v9.6.0中文绿色便携版
经验分享·电脑·办公软件·电脑软件
s_little_monster2 小时前
【Linux】线程控制函数
linux·运维·服务器·经验分享·笔记·学习·学习方法
努力的搬砖人.4 小时前
nacos配置达梦数据库驱动源代码步骤
java·服务器·数据库·经验分享·后端
mycm030412 小时前
新闻发稿软文发布投稿选择媒体时几大注意
经验分享·媒体
幻想趾于现实14 小时前
C# Winform 入门(15)之制作二维码和拼接(QR)
开发语言·c#·winform
霸道流氓气质14 小时前
Winform入门进阶企业级开发示例:http接口数据清洗转换、断线续传、mqtt数据传输实例详解(附代码资源下载)
http·c#·winform
小灿同学啊15 小时前
VSCode解决中文乱码方法
ide·经验分享·笔记·vscode·编辑器