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 反而会出错

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

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

相关推荐
momo_aa1 小时前
mac找到主目录下的文件夹
经验分享
Envyᥫᩣ2 小时前
C#语言:从入门到精通
开发语言·c#
IT技术分享社区8 小时前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
天行健PLUS8 小时前
【经验分享】六西格玛管理培训适合哪些人参加?
经验分享
小奥超人9 小时前
PPT文件设置了修改权限,如何取消权?
windows·经验分享·microsoft·ppt·办公技巧
Jack黄从零学c++12 小时前
C++ 的异常处理详解
c++·经验分享
△曉風殘月〆15 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
逐·風17 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
m0_6569747420 小时前
C#中的集合类及其使用
开发语言·c#
九鼎科技-Leo20 小时前
了解 .NET 运行时与 .NET 框架:基础概念与相互关系
windows·c#·.net