Search code examples
c#asp.net-coreswaggernswag

How to load custom stylesheet with NSwag's UseSwaggerUi3


I'm trying to customize the swagger UI with my own .css stylesheet.

I am using asp net core 2.1 and NSwag.AspNetCore 12.2.5.

I've searched around and found that in previous versions this would be done by embedding my custom stylesheet and then injecting it in my middleware configuration with something like:

app.UseSwagger(o =>
{
   o.InjectStylesheet("/css/custom.css");
});

In the latest version of NSwag this seems to have changed to:

app.UseSwaggerUi3(cfg =>
{
   cfg.CustomStylesheetUri = new Uri("/css/custom.css", UriKind.Relative);
});

But either I'm not making the stylesheet available, or my uri is not pointing at it correctly.

I don't fully understand how the web server serves up the swagger files (I assume they are loaded from the NSwag nuget package, but I don't see them in my build output folder), so I assume I am not making the stylesheet available correctly.

Doing the above, I see the <link rel="stylesheet" href="css/custom.css"> added to the swagger index.html, but chrome developer tools says the file cannot be found.

I have tried: 1. Adding my stylesheet to wwwroot. 2. Adding my stylesheet somewhere in the project and explicitly copying it to the output folder in my csproj. 3. Embedding my stylesheet in the build artifact.

I have .UseStaticFiles() in my middleware pipeline.

What am I missing? Does anyone have a working example?


Solution

  • Main Answer

    If it does not exist, create a wwwroot folder in your project and create subfolders such as css, img, js within the wwwroot folder so that you'll have something like this:

    wwwroot\css
    wwwroot\img
    wwwroot\js
    

    The UseStaticFiles() method looks for the wwwroot folder and makes it servable.

    The next you need to make sure of is that your .csproj file for the project contains the following:

      <ItemGroup>
        <None Include="wwwroot\*" />
      </ItemGroup>
    

    Which basically says that all subfolders and files under wwwroot are going to be published.

    With that stuff set up, your cfg.CustomStylesheetUri = new Uri("/css/custom.css", UriKind.Relative) code should now work.


    Alternate Option

    As another option, if you want to serve your css file from a different directory outside of wwwroot, then you will need to specify the StaticFileOptions parameter in the UseStaticFiles() method in order to serve your css. Here's my working example but with ReDoc.

    I'm using NSwag which extends Swagger to generate and further customize my OpenAPI specification file. (ReDoc via NSwag uses CustomStylesheetUri insead of InjectStylesheet but I imagine it works the same way).

            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(
                    Path.Combine(Directory.GetCurrentDirectory(), "Content")),
                RequestPath = "/Content"
            });
    
            app.UseSwagger();
            app.UseSwaggerUi3();
            app.UseReDoc(c => {
                c.Path = "/redoc";
                c.DocumentPath = "/swagger/v1/swagger.json";
                c.CustomStylesheetUri = new Uri("/Content/redoc-styles.css", UriKind.Relative); //added towards the end of the <head>
                c.CustomJavaScriptUri = new Uri("/Content/redoc-javascript.js", UriKind.Relative);  //added at the end of the <body>
            });
    

    My above code references a folder that I created called Content in which I added css and js files. My folder is at the root of the project: MyAPIProject/Content/redoc-styles.css

    Along with this secondary example, an additional thing to make sure of is that your .csproj file contains the relevant entries (otherwise the folder and files won't be published):

      <ItemGroup>
        <Content Include="Content\css\redoc-styles.css">
          <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
        </Content>
        <Content Include="Content\js\redoc-javascript.js">
          <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
        </Content>
      </ItemGroup>