前言
作为后台的"搬运工",常常会涉及到一些前后端分离的情况。后端也大多数是使用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,代码如下
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net;usingSystem.Net.Http;usingSystem.Web.Http;usingWebApplication1.Models;namespaceWebApplication1.Controllers{publicclassDefaultController:ApiController{[HttpGet,Route("api/get")]publicstringGet(){returnstring.Empty;}[HttpPost,Route("api/post")]publicstringPost(){returnstring.Empty;}[HttpDelete,Route("api/delete")]publicstringDelete(deleteMode mode){returnstring.Empty;}[HttpPut,Route("api/put")]publicstringPut(){returnstring.Empty;}}}
添加完Controller之后执行项目,如下图
到此ASP.NET Web Api 添加Swagger,就已经完成了。但是这个页面都是英文,so我们做一下配置添加一下翻译
配置Swagger
- 在App_Start中配置增加 SwaggerControllerDescProvider.cs 类。代码如下图所示:
usingSwashbuckle.Swagger;usingSystem;usingSystem.Collections.Concurrent;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Web;usingSystem.Xml;namespaceWebApplication1.App_Start{/// <summary>/// Swagger 配置信息/// </summary>publicclassSwaggerControllerDescProvider:ISwaggerProvider{privatereadonlyISwaggerProvider _swaggerProvider;privatestaticConcurrentDictionary<string, SwaggerDocument> _cache =newConcurrentDictionary<string, SwaggerDocument>();privatereadonlystring _xml;/// <summary>/// /// </summary>/// <param name="swaggerProvider"></param>/// <param name="xml">xml文档路径</param>publicSwaggerControllerDescProvider(ISwaggerProvider swaggerProvider,string xml){
_swaggerProvider = swaggerProvider;
_xml = xml;}/// <summary>/// GetSwagger/// </summary>/// <param name="rootUrl"></param>/// <param name="apiVersion"></param>/// <returns></returns>publicSwaggerDocumentGetSwagger(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 =newDictionary<string,object>{{"ControllerDesc",GetControllerDesc()}};
_cache.TryAdd(cacheKey, srcDoc);}return srcDoc;}/// <summary>/// 从API文档中读取控制器描述/// </summary>/// <returns>所有控制器描述</returns>publicConcurrentDictionary<string,string>GetControllerDesc(){string xmlpath = _xml;ConcurrentDictionary<string,string> controllerDescDict =newConcurrentDictionary<string,string>();if(File.Exists(xmlpath)){XmlDocument xmldoc =newXmlDocument();
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){returnthis._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,具体修改代码如下:
usingSystem.Web.Http;usingWebActivatorEx;usingWebApplicationAndSwaggerDemo;usingSwashbuckle.Application;usingSystem.Linq;usingWebApplication1.App_Start;usingSystem.Reflection;[assembly:PreApplicationStartMethod(typeof(SwaggerConfig),"Register")]namespaceWebApplicationAndSwaggerDemo{publicclassSwaggerConfig{publicstaticvoidRegister(){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)=>newSwaggerControllerDescProvider(defaultProvider, xmlFile));}).EnableSwaggerUi(b =>{
b.InjectJavaScript(Assembly.GetExecutingAssembly(),"WebApplicationAndSwaggerDemo.Scripts.SwaggerConfig.js");});}}}
修改项目属性生成XML文件,如下图:
到目前为止,配置已经完成,最终界面。如下图所示:
部署
在这里我选择 iis 部署
- 首先生成部署文件:项目右击->选择发布->选择文件夹,如下图: 此时需要修改也可以修改路径,反之默认路劲即可 点击发布 看到如图所示字样,表示发布成功
- 登录服务器,安装iis,并新建站点,如图所示
- 发布完成后http://id地址:端口swagger/ui/index,外网访问效果如下图:![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6def30dd89ed465dbe91eb82cde04fae.png)
结束语
此文档防止后续忘记简单记录一下。希望可以帮助到大家,欢迎留言交流 谢谢!
版权归原作者 攻无不克- 所有, 如有侵权,请联系我们删除。