简体   繁体   English

Swashbuckle 是否支持将自定义操作标签表示为 UI 中的徽章的方法?

[英]Does Swashbuckle support a way to represent custom operation tags as badges in the UI?

I'm developing an ASP.NET Core application and there are some endpoints that I want to tag as "developer tool", indicating that these endpoints exist purely for the benefit of the development team to take investigative/corrective action and are not intended for third-party consumption.我正在开发一个 ASP.NET 核心应用程序,并且有一些端点我想标记为“开发人员工具”,这表明这些端点的存在纯粹是为了开发团队采取调查/纠正措施的利益,而不是用于第三方-聚会消费。 Something like this:像这样的东西:

在此处输入图像描述

I've checked the Swashbuckle repo and can't find anything to suggest this is supported, but I thought it's best to check.我检查了 Swashbuckle 存储库,找不到任何表明支持此功能的信息,但我认为最好检查一下。

Since there doesn't seem to be built-in way to do this, I managed to achieve this result through a pretty hacky (but effective) approach of using an operation filter to append text to the operation summary in a particular format and then injecting custom CS/JSS that converts these parts of the summary description into custom elements in the DOM.由于似乎没有内置的方法来做到这一点,我设法通过一种非常hacky(但有效)的方法来实现这个结果,即使用操作过滤器将 append 文本以特定格式添加到操作摘要中,然后注入自定义 CS/JSS 将摘要描述的这些部分转换为 DOM 中的自定义元素。

First I define a custom attribute:首先我定义一个自定义属性:

/// <summary>
/// Indicates that this operation is intended for use solely by the development team.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class DeveloperToolAttribute : Attribute
{
}

Then I create an operation filter to process these:然后我创建一个操作过滤器来处理这些:

public class DeveloperToolOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (!context.ApiDescription.CustomAttributes().Any(x => x is DeveloperToolAttribute))
            return;

        operation.Summary = $"[Developer Tool] {operation.Summary}";
    }
}

I register this filter after the other filters that set the operation summary based on the XML documentation:我在其他根据 XML 文档设置操作摘要的过滤器之后注册此过滤器:

services.AddSwaggerGen(options =>
{
    // ...

    void AddXmlDocumentation(Assembly assembly)
    {
        var xmlFile = $"{assembly.GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        options.IncludeXmlComments(xmlPath, includeControllerXmlComments: true);
    }

    // Set the comments path for the Swagger JSON and UI.
    AddXmlDocumentation(Assembly.GetExecutingAssembly());
    AddXmlDocumentation(typeof(StatementReadModel).Assembly);
    // ...
    options.OperationFilter<DeveloperToolOperationFilter>();
});

This would then make it so that I could annotate my API methods with [DeveloperTool] and have that become part of the operation summary:这样我就可以使用[DeveloperTool]注释我的 API 方法,并将其作为操作摘要的一部分:

[HttpGet]
[DeveloperTool]
public async Task<CommissionAuthorisationsReadModel> GetAuthorisations()
{
    var result = await _mediator.Send(CommissionAuthorisationsQuery.Instance);

    return result;
}

在此处输入图像描述

Next up I used TamperMonkey to build a userscript that allowed me to iterate through all the DOM elements containing these operation summaries and transform any text within braces (such as [Developer Tool] ) into badges.接下来,我使用 TamperMonkey 构建了一个用户脚本,它允许我遍历包含这些操作摘要的所有 DOM 元素,并将大括号中的任何文本(例如[Developer Tool] )转换为徽章。

This allowed me to produce the following Javascript file which I saved as wwwroot/ext/custom-swagger-javascript.js :这使我能够生成以下 Javascript 文件,我将其保存为wwwroot/ext/custom-swagger-javascript.js

var callback = function() {
    var elements = document.getElementsByClassName("opblock-summary-description");

    for (const summaryDescription of elements) {
        const match = summaryDescription.textContent.match(/\[(\w|\s)+\]\s/);
    
        if (!match) {
            continue;
        }

        const trimmedTextContent = summaryDescription.textContent.replaceAll(match[0], "");
        summaryDescription.textContent = trimmedTextContent;

        const customTag = match[0].substring(1, match[0].length - 2);
        const summary = summaryDescription.parentElement;
        const customTagElement = document.createElement("div");

        customTagElement.innerText = customTag;
        customTagElement.className = "opblock-custom-tag";
        summary.appendChild(customTagElement);
    }
};

// Repeat just in case page is slow to load.
for (let attempts = 1; attempts <= 5; attempts++) {
    setTimeout(callback, attempts * 200);
}

Alongside this I created a CSS stylesheet saved as wwwroot/ext/custom-swagger-stylesheet.css :除此之外,我创建了一个 CSS 样式表,保存为wwwroot/ext/custom-swagger-stylesheet.css 8CBA22E28EB17B5F5C6AE2A266AZ :

.opblock-custom-tag {
    font-size: 10px;
    font-weight: 700;
    min-width: 80px;
    padding: 6px 15px;
    text-align: center;
    border-radius: 3px;
    background: #9d45d4;
    text-shadow: 0 1px 0 rgba(0,0,0,.1);
    font-family: sans-serif;
    color: #fff;
}

In Startup, I ensured that these Javascript and CSS files would be injected:在启动中,我确保将注入这些 Javascript 和 CSS 文件:

app.UseSwaggerUI(c =>
{
    // ...
    
    c.InjectStylesheet("/ext/custom-swagger-stylesheet.css");
    c.InjectJavascript("/ext/custom-swagger-javascript.js");
});

This also required me to ensure that ASP.NET Core would serve static files:这还要求我确保 ASP.NET 内核可以为 static 文件提供服务:

app.UseHttpsRedirection();
app.UseStaticFiles(); // Added this
app.UseRouting();

Finally this all allowed me to get the result that I wanted:最后,这一切都让我得到了我想要的结果:

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM