Возможно ли динамически добавлять SwaggerEndpoints для SwaggerUI? - PullRequest
0 голосов
/ 12 октября 2018

Мы создаем сервис-ориентированную архитектуру в .NET Core.Мы решили использовать Ocelot в качестве нашего шлюза API.Я объединил Ocelot с Консулом для обнаружения обслуживания.Сейчас я пытаюсь создать унифицированный интерфейс Swagger для всех нисходящих сервисов.

До обнаружения сервиса у нас была настроена Swagger, например:

// Enable middleware to serve generated Swagger as a JSON endpoint
app.UseSwagger(c => { c.RouteTemplate = "{documentName}/swagger.json"; });

// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
app.UseSwaggerUI(c =>
{
  c.SwaggerEndpoint("/docs/customer/swagger.json", "Customers Api Doc");
  c.SwaggerEndpoint("/docs/employee/swagger.json", "Employee Api Doc");
  c.SwaggerEndpoint("/docs/report/swagger.json", "Reports Api Doc");
});

В интерфейсе Swagger этопредоставляет раскрывающийся список «выберите спецификацию».Разработчикам нравится эта функциональность, и мы хотели бы сохранить ее.Однако теперь, когда мы удалили ручную настройку в пользу обнаружения службы, мы также хотели бы, чтобы эти конечные точки динамически обновлялись.

Имеется ли в наличии текущее решение Swagger, возможно ли это?Я не видел ничего, связанного с обнаружением службы или возможностью динамической настройки пользовательского интерфейса.Мысли и предложения?

Обновление

Я придумал способ сделать это.Это немного хакерство, и я надеюсь, что есть способ сделать это, который не так жесток.

public class Startup 
{
    static object LOCK = new object();

    SwaggerUIOptions options;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<SwaggerUIOptions>((provider) =>
        {
            return this.options;
        });
        services.AddSingleton<IHostedService, SwaggerUIDocsAggregator>();
        services.AddSingleton<IConsulDiscoveryService, MyCounsulDiscoveryServiceImplementation>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // Enable middleware to serve generated Swagger as a JSON endpoint
        app.UseSwagger(c => { c.RouteTemplate = "{documentName}/swagger.json"; });
        // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
        app.UseSwaggerUI(c =>
        {
            this.options = c;
        });
    }
}

public class SwaggerUIDocsAggregator : IHostedService
{
    static object LOCK = new object();

    IConsulDiscoveryService discoveryService;
    SwaggerUIOptions options;
    Timer timer;
    bool polling = false;
    int pollingInterval = 600;

    public ConsulHostedService(IConsulDiscoveryService discoveryService, SwaggerUIOptions options)
    {
        this.discoveryService = discoveryService;
        this.options = options;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        this.timer = new Timer(async x =>
        {
            if (this.polling)
            {
                return;
            }

            lock (LOCK)
            {
                this.polling = true;
            }

            await this.UpdateDocs();

            lock (LOCK)
            {
                this.polling = false;
            }

        }, null, 0, pollingInterval);
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        this.timer.Dispose();
        this.timer = null;
    }

    private async Task UpdateDocs()
    {
        var discoveredServices = await this.discoveryService.LookupServices();

        var urls = new JArray();

        foreach (var kvp in discoveredServices)
        {
            var serviceName = kvp.Key;

            if (!urls.Any(u => (u as JObject).GetValue("url").Value<string>().Equals($"/{serviceName}/docs/swagger.json")))
            {

                urls.Add(JObject.FromObject(new { url = $"/{serviceName}/docs/swagger.json", name = serviceName }));
            }
        }

        this.options.ConfigObject["urls"] = urls;
    }
}
...