前言
作为后台的"搬运工",常常会涉及到一些前后端分离的情况。后端也大多数是使用RESTful 风格的接口。写完之后,就需要使用接口调试工具(postman)给出接口使用实例,还要提供接口说明文档。开发过程中常常会因为修改代码后文档没有及时更新,造成前端调用报错或者取数不正确等问题。赶巧有一个项目需要新建接口工程,为了避免这样的事情发现,我发现了Swagger这个架构,可以有效避免这类问题的出现。
Swagger简介
什么是Swagger?
Swagger是一个规范且完整的框架,用于生成、描述、调试和可视化Restfull风格的Web服务。它使用一种易于理解的格式提供了 API 的整体概览,帮助开发人员理解 API 的功能,并于开发和测试期间与 API 进行交互。Swagger 优点
可读性和可视化:Swagger 提供了强大的可视化界面,开发者可以通过 Swagger UI 直接查看 API 的具体内容,包括每个 API 的路径,可接受的参数等等。这使得开发者更好的理解 API 的工作方式。以代码为中心的 API 设计:Swagger 允许你以代码为中心来设计 API。这意味着你可以直观地分析和设计你的 API,而不需要切换到其他编辑器或工具。此外,Swagger 默认会提供提示和错误修复,这使得开发者可以在设计阶段就能找出潜在的错误。跨平台兼容:Swagger 是跨平台的,可以兼容各种编程语言。自动文档化:Swagger 可以在开发时自动生成 API 文档,减少了开发者编写文档的压力。这意味着你可以在编写代码的同时更新开发文档,确保文档的准确和一致。上面我个人对Swagger的理解,在 ASP.NET Core 中,已经内置了 Swagger,很方便就能使用。但在 ASP.NET 里,需要我们自己引用和配置才能使用它,下面我们看看 ASP.NET Web Api 如何使用 Swagger
开发环境
开发工具:Visual Studio 2022使用技术:ASP.NET Web Api创建Web Api项目
等待项目创建完成之后,解决方案结构如下
使用NuGet控制台安装Swagger
在菜单中选择工具->NuGet包管理器->程序包管理器控制台 输入指令Install-Package Swashbuckle 选择安装的项目,回车即可。如下图所示:
安装完成后,直接运行项目:IP地址:端口号+swagger/ui/index 即可浏览成功,如下图:(因为我们创建的是空白的webApi,so没有Controller)
添加Controller
在此我创建了一个DefaultController,代码如下
using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Net.Http;using System.Web.Http;using WebApplication1.Models;namespace WebApplication1.Controllers{ public class DefaultController : ApiController { [HttpGet, Route("api/get")] public string Get() { return string.Empty; } [HttpPost,Route("api/post")] public string Post() { return string.Empty; } [HttpDelete,Route("api/delete")] public string Delete(deleteMode mode) { return string.Empty; } [HttpPut,Route("api/put")] public string Put() { return string.Empty; } }}
添加完Controller之后执行项目,如下图
到此ASP.NET Web Api 添加Swagger,就已经完成了。但是这个页面都是英文,so我们做一下配置添加一下翻译
配置Swagger
在App_Start中配置增加 SwaggerControllerDescProvider.cs 类。代码如下图所示: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 WebApplication1.App_Start{ /// <summary> /// Swagger 配置信息 /// </summary> public class SwaggerControllerDescProvider : ISwaggerProvider { private readonly ISwaggerProvider _swaggerProvider; private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>(); private readonly string _xml; /// <summary> /// /// </summary> /// <param name="swaggerProvider"></param> /// <param name="xml">xml文档路径</param> public SwaggerControllerDescProvider(ISwaggerProvider swaggerProvider, string xml) { _swaggerProvider = swaggerProvider; _xml = xml; } /// <summary> /// GetSwagger /// </summary> /// <param name="rootUrl"></param> /// <param name="apiVersion"></param> /// <returns></returns> public SwaggerDocument GetSwagger(string rootUrl, string apiVersion) { var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion); SwaggerDocument srcDoc = null; //只读取一次 if (!_cache.TryGetValue(cacheKey, out 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> public ConcurrentDictionary<string, string> GetControllerDesc() { string xmlpath = _xml; ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>(); if (File.Exists(xmlpath)) { XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(xmlpath); string type = string.Empty, path = string.Empty, controllerName = string.Empty; string[] arrPath; int length = -1, cCount = "Controller".Length; XmlNode summaryNode = null; foreach (XmlNode node in xmldoc.SelectNodes("//member")) { type = node.Attributes["name"].Value; if (type.StartsWith("T:")) { //控制器 arrPath = type.Split('.'); length = arrPath.Length; controllerName = arrPath[length - 1]; if (controllerName.EndsWith("Controller")) { //获取控制器注释 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; } }}
新键Scripts文件夹增加SwaggerConfig.js。如下代码所示: '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();});
注意:添加JS后,将文件设置为“嵌入的资源”。如下:
修改App_Start文件夹中的SwaggerConfig.cs,具体修改代码如下:using System.Web.Http;using WebActivatorEx;using WebApplicationAndSwaggerDemo;using Swashbuckle.Application;using System.Linq;using WebApplication1.App_Start;using System.Reflection;[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]namespace WebApplicationAndSwaggerDemo{ public class SwaggerConfig { public static void Register() { var thisAssembly = typeof(SwaggerConfig).Assembly; GlobalConfiguration.Configuration .EnableSwagger(c => { c.SingleApiVersion("v1", "WebApplicationAndSwaggerDemo"); //设置接口描述xml路径地址 var xmlFile = string.Format("{0}/bin/WebApplicationAndSwaggerDemo..XML", System.AppDomain.CurrentDomain.BaseDirectory); if (System.IO.File.Exists(xmlFile)) { c.IncludeXmlComments(xmlFile); } c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); c.CustomProvider((defaultProvider) => new SwaggerControllerDescProvider(defaultProvider, xmlFile)); }) .EnableSwaggerUi(b => { b.InjectJavaScript(Assembly.GetExecutingAssembly(), "WebApplicationAndSwaggerDemo.Scripts.SwaggerConfig.js"); }); } }}
修改项目属性生成XML文件,如下图:
到目前为止,配置已经完成,最终界面。如下图所示:
部署
在这里我选择 iis 部署
首先生成部署文件:项目右击->选择发布->选择文件夹,如下图:此时需要修改也可以修改路径,反之默认路劲即可
点击发布
看到如图所示字样,表示发布成功
登录服务器,安装iis,并新建站点,如图所示
发布完成后http://id地址:端口swagger/ui/index,外网访问效果如下图:
结束语
此文档防止后续忘记简单记录一下。希望可以帮助到大家,欢迎留言交流 谢谢!