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

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

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

相关推荐
stm 学习ing4 分钟前
HDLBits训练4
经验分享·笔记·fpga开发·课程设计·fpga·eda·verilog hdl
吾与谁归in2 小时前
【C#联合halcon实现绘制ROI功能】
c#·halcon·roi
志-AOX2 小时前
使用R语言高效去除低丰度OTU:从概念到实操
经验分享
ling1s3 小时前
C#核心(18)面向对象多态vob
java·开发语言·c#
小顧同學3 小时前
PPT画图——如何设置导致图片为600dpi
经验分享
月巴月巴白勺合鸟月半4 小时前
一个C#开发的APP
c#·web
番茄电脑全能王5 小时前
《鸣潮》运行时提示找不到emp.dll是什么原因?缺失emp.dll文件要怎么解决?
网络·数据库·经验分享·游戏·电脑
我曾经是个程序员5 小时前
C#File文件基础操作大全
开发语言·c#
三天不学习6 小时前
C# 中的记录类型简介 【代码之美系列】
后端·c#·微软技术·record·记录类型