Rasik
Rasik

Reputation: 2420

How to customize the swagger UI using my own custom design

I wanted to customize the swagger UI using my own custom design. I have the following configuration in a startup.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddSwaggerGen(c =>
    {
        c.DocumentFilter<DescriptionsDocumentFilter>();

        c.SwaggerDoc("v1", new OpenApiInfo { Title = "LoggerDemo", Version = "v1" });

        var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        c.IncludeXmlComments(xmlPath);
    });
    services.AddHttpClient();
    services.AddMemoryCache();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger(o =>
        {
            o.RouteTemplate = "docs/{documentName}/docs.json";
        });

        app.UseSwaggerUI(c =>
        {
            c.RoutePrefix = "docs";
            c.SwaggerEndpoint("/docs/v1/docs.json", "Geo API");

            c.IndexStream = () => GetType().Assembly.GetManifestResourceStream
            (
                GetType().Namespace + ".Resources.Swagger_Custom_index.html"
            );
        });
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Here are the steps I have followed:

enter image description here

app.UseSwaggerUI(c =>
{
    c.IndexStream = () => GetType().Assembly.GetManifestResourceStream
    (
        GetType().Namespace + ".Resources.Swagger_Custom_index.html"
    );
});

But I am struggling to access the custom HTML file, How to access the custom HTML file? What URL should I use to access those files?

Upvotes: 2

Views: 13842

Answers (1)

abdusco
abdusco

Reputation: 11101

You need to embed the HTML file in the DLL with an EmbeddedResource directive in your .csproj file:

Resources/swagger.html

<!-- replace this with the actual swagger.html -->
<h1>hello swagger</h1>

.csproj

<Project Sdk="Microsoft.NET.Sdk">
    <!-- ... -->
    <ItemGroup>
        <Content Remove="Resources\*" />
        <EmbeddedResource Include="Resources\*" />
    </ItemGroup>
</Project>

Then you can access it with Assembly.GetManifestResourceStream:

// Startup.Configure

app.UseSwaggerUI(options =>
{
    options.IndexStream = () => GetType().Assembly.GetManifestResourceStream($"{GetType().Namespace}.Resources.swagger.html");
});

Bonus: Generating OpenAPI Document outside Swagger:

SwaggerMiddleware handles serving OpenAPI documents. We can use that as reference to build the document ourselves.

First register SwaggerGenerator with DI:

// Startup.Configure
services.AddTransient<SwaggerGenerator>();

Then inject it inside a class, here I'm using an endpoint to serve it directly:

// Startup.Configure
app.UseEndpoints(e =>
{
    // ...
    e.MapGet("/openapi.json", context =>
    {
        // inject SwaggerGenerator
        var swaggerGenerator = context.RequestServices.GetRequiredService<SwaggerGenerator>();
        // document name is defined in Startup.ConfigureServices method inside the AddSwaggerGen call
        var doc = swaggerGenerator.GetSwagger("v1");

        // serialize the document as json
        using var writer = new StringWriter(CultureInfo.InvariantCulture);
        var serializer = new OpenApiJsonWriter(writer);
        doc.SerializeAsV3(serializer);
        var json = writer.ToString(); // this is the openapi document
        
        // serve it as json
        context.Response.ContentType = MediaTypeNames.Application.Json;
        return context.Response.WriteAsync(json, new UTF8Encoding(false));
    });
});

Upvotes: 2

Related Questions