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

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

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

相关推荐
bluefox19794 小时前
使用 Oracle.DataAccess.Client 驱动 和 OleDB 调用Oracle 函数的区别
开发语言·c#
东莞梦幻网络科技软件开发公司5 小时前
开发体育赛事直播平台防止数据泄露的技术安全方案
经验分享·安全
鲤籽鲲6 小时前
C# MethodTimer.Fody 使用详解
开发语言·c#·mfc
工业3D_大熊6 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
yngsqq6 小时前
c#使用高版本8.0步骤
java·前端·c#
售后宝7 小时前
服务机器人三甲坎德拉:用智能化开启售后服务新篇章
经验分享·制造
志-AOX7 小时前
Python编程艺术:优雅与实用的完美平衡(推导式)
经验分享
LZXCyrus7 小时前
【杂记】vLLM如何指定GPU单卡/多卡离线推理
人工智能·经验分享·python·深度学习·语言模型·llm·vllm
志-AOX8 小时前
AI安全:从现实关切到未来展望
经验分享
hccee9 小时前
C# IO文件操作
开发语言·c#