如何在Swagger文档中显示.NET Framework 4.7.2 API模型的<remarks>内容
解决.NET Framework 4.7.2 API模型在Swagger中显示的问题
我之前也碰到过这个情况!默认情况下,Swashbuckle(.NET Framework里常用的Swagger工具)并不会自动解析并展示模型属性的<remarks>注释。不过别担心,我们可以通过自定义Schema过滤器来实现需求——不管是直接把备注内容显示在属性描述里,还是做成鼠标悬停提示都可以。
第一步:先确保XML注释已经被Swagger读取
首先得保证你的项目已经生成了XML注释文件,并且Swagger已经配置加载它:
- 右键你的API项目 → 属性 → 生成选项卡 → 勾选「XML文档文件」,记下生成的路径(比如
bin\Debug\YourApi.xml)。 - 打开
SwaggerConfig.cs(Swashbuckle默认生成的配置文件),在启用Swagger的代码里添加读取XML注释的配置:
GlobalConfiguration.Configuration .EnableSwagger(c => { c.SingleApiVersion("v1", "你的API名称"); // 加载项目生成的XML注释文件 var xmlPath = $@"{System.AppDomain.CurrentDomain.BaseDirectory}\bin\YourApi.xml"; c.IncludeXmlComments(xmlPath); }) .EnableSwaggerUi(c => { // 这里可以放Swagger UI的相关配置 });
第二步:创建自定义Schema过滤器
接下来要写一个实现ISchemaFilter的类,用来读取属性的<remarks>内容,然后根据需求处理展示方式。
方式一:把直接追加到后面(直接显示)
这种方式会让备注内容直接跟在属性的摘要后面,一目了然:
using System; using System.Xml.XPath; using Swashbuckle.Swagger; public class RemarksSchemaFilter : ISchemaFilter { private readonly XPathNavigator _xmlNavigator; public RemarksSchemaFilter(string xmlFilePath) { var xmlDoc = new XPathDocument(xmlFilePath); _xmlNavigator = xmlDoc.CreateNavigator(); } public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type) { if (type == null) return; // 遍历模型的所有属性 foreach (var property in schema.properties) { // 构建XML注释的查询路径,格式是P:命名空间.类名.属性名 var memberPath = $"P:{type.FullName}.{property.Key}"; var remarkNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{memberPath}']/remarks"); if (remarkNode != null && !string.IsNullOrWhiteSpace(remarkNode.Value)) { // 把remarks内容追加到summary后面,用HTML标签区分格式 if (!string.IsNullOrEmpty(property.Value.description)) { property.Value.description += $"<br/><strong>备注:</strong> {remarkNode.Value.Trim()}"; } else { property.Value.description = $"<strong>备注:</strong> {remarkNode.Value.Trim()}"; } } } } }
方式二:把做成鼠标悬停提示
如果不想让备注内容占太多空间,希望鼠标悬停在属性上时才显示,可以把<remarks>添加到Schema的扩展字段,再通过自定义脚本实现悬停效果:
using System; using System.Xml.XPath; using Swashbuckle.Swagger; public class RemarksSchemaFilter : ISchemaFilter { private readonly XPathNavigator _xmlNavigator; public RemarksSchemaFilter(string xmlFilePath) { var xmlDoc = new XPathDocument(xmlFilePath); _xmlNavigator = xmlDoc.CreateNavigator(); } public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type) { if (type == null) return; foreach (var property in schema.properties) { var memberPath = $"P:{type.FullName}.{property.Key}"; var remarkNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{memberPath}']/remarks"); if (remarkNode != null && !string.IsNullOrWhiteSpace(remarkNode.Value)) { // 添加自定义扩展字段x-remarks,存储备注内容 property.Value.extensions.Add("x-remarks", remarkNode.Value.Trim()); } } } }
第三步:注册自定义过滤器
回到SwaggerConfig.cs,在Swagger配置里注册刚才写的过滤器,记得传入XML注释文件的路径:
GlobalConfiguration.Configuration .EnableSwagger(c => { c.SingleApiVersion("v1", "你的API名称"); var xmlPath = $@"{System.AppDomain.CurrentDomain.BaseDirectory}\bin\YourApi.xml"; c.IncludeXmlComments(xmlPath); // 注册自定义的Schema过滤器 c.SchemaFilter<RemarksSchemaFilter>(xmlPath); }) .EnableSwaggerUi(c => { // 如果用方式二的悬停提示,需要注入自定义脚本 c.InjectJavaScript(System.Web.HttpContext.Current.Server.MapPath("~/Scripts/swagger-remarks-hover.js")); });
第四步(方式二专属):添加悬停提示的JS脚本
创建swagger-remarks-hover.js文件,放到项目的Scripts目录下,内容如下:
$(function() { // 等Swagger UI加载完成后处理 setTimeout(function() { // 遍历所有模型属性行 $('.model-properties tr').each(function() { var $propertyCell = $(this).find('td:first'); // 获取当前属性所属的模型名称 var modelName = $(this).closest('.model-container').attr('data-model'); // 获取属性名(去掉括号里的类型) var propertyName = $propertyCell.text().split('(')[0].trim(); // 从Swagger的API定义里拿到属性的x-remarks内容 var propertySchema = window.swaggerUi.api.definitions[modelName]?.properties[propertyName]; if (propertySchema && propertySchema['x-remarks']) { // 添加title属性,鼠标悬停时显示备注 $propertyCell.attr('title', propertySchema['x-remarks']); } }); }, 1000); });
一些注意点
- 部署到服务器时,要确保XML注释文件已经一起发布,并且路径配置正确。
- 如果用的是旧版本的Swashbuckle,API可能略有差异,但核心思路都是通过Schema过滤器读取XML注释并处理。
- 方式一中用了HTML标签,Swagger UI默认支持解析简单的HTML,所以格式会正常显示。
内容的提问来源于stack exchange,提问作者Johannes Wentu
相关产品推荐
相关产品推荐

