Skip to content

AspNetCore Middleware

Rico Suter edited this page Apr 26, 2019 · 54 revisions
  • Package: NSwag.AspNetCore (.NETStandard 1.6+, .NET Standard 2.0, .NET Core and .NET 4.5.1+)

The NuGet package provides extension methods to register the NSwag ASP.NET Core services and middlewares:

The middleware is based on the AspNetCoreToSwaggerGenerator class which generates OpenAPI/Swagger specifications from ASP.NET Core controllers with the ASP.NET Core API Explorer.

To use the middlewares, open Startup.cs and add the following code to ConfigureServices() (full samples below):

  • services.AddOpenApiDocument(configure) (OpenAPI v3.0.0)
  • services.AddSwaggerDocument(configure) (Swagger v2.0): Adds a new OpenAPI/Swagger document registration to the DI system
    • The default document name is v1
    • The document instance implements the AspNetCoreToSwaggerGeneratorSettings
    • To configure multiple documents, just call the methods multiple times and define a DocumentName per document:
services.AddOpenApiDocument(document => document.DocumentName = "a");
services.AddSwaggerDocument(document => document.DocumentName = "b");

In Startup.Configure():

  • app.UseSwagger(configure): Adds the OpenAPI/Swagger document generator middleware (serves openapi.json/swagger.json).
    • The default route is /swagger/{documentName}/swagger.json; when using the {documentName} placeholder in the Path setting, multiple documents can be served
  • app.UseSwaggerUi3(configure):
  • app.UseReDoc(configure): Adds only the Swagger UI or ReDoc web UI
    • The default UI route in Path is /swagger which - in the case of Swagger UI - serves one UI with all available documents
    • The default document route in DocumentPath is /swagger/{documentName}/swagger.json
app.UseOpenApi(); // serve documents (same as app.UseSwagger())
app.UseSwaggerUi3(); // serve Swagger UI
app.UseReDoc(); // serve ReDoc UI

Sample projects:

Usage

Install required NuGet packages

First, you need to install the required NSwag NuGet packages.

Register the middleware

public class Startup
{
    ...

    public void ConfigureServices(IServiceCollection services)
    {
        // SetCompatibilityVersion is only needed for the UseSwagger() methods on ASP.NET Core >= 2.1
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        // Add OpenAPI/Swagger document
        services.AddOpenApiDocument(); // registers a OpenAPI v3.0 document with the name "v1" (default)
        // services.AddSwaggerDocument(); // registers a Swagger v2.0 document with the name "v1" (default)
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
        
        // Add OpenAPI/Swagger middlewares
        app.UseSwagger(); // Serves the registered OpenAPI/Swagger documents by default on `/swagger/{documentName}/swagger.json`
        app.UseSwaggerUi3(); // Serves the Swagger UI 3 web ui to view the OpenAPI/Swagger documents by default on `/swagger`

Customization

The AspNetCoreToSwaggerGenerator class provides lots of customization and extension possibilities.

Use API Versioning

Use the ApiGroupNames setting to select the operation version filter:

services.AddOpenApiDocument(document => 
{
    document.DocumentName = "v1";
    document.ApiGroupNames = new [] { "1" };
});
services.AddOpenApiDocument(document => 
{
    document.DocumentName = "v2";
    document.ApiGroupNames = new [] { "2" };
});

Post process the served OpenAPI/Swagger specification document

You can post process a generated document with the PostProcess setting from AddSwaggerDocument() or UseSwagger() or use a custom Document Processor or Operation Processor (recommended).

services.AddSwaggerDocument(document =>
{
    document.PostProcess = d => 
    {
        d.Info.Title = "Hello world!";
    };
});

Caution: Only use PostProces from UseSwagger() to transform the document related to the request. Other modifications should be done with a custom Document Processor or Operation Processor which is added in AddSwaggerDocument(document => document.DocumentProcessors) or AddSwaggerDocument(document => document.PostProcess = ...). The post processing in UseSwagger() will not be called from the NSwag CLI or MSBuild, i.e. only when served via HTTP!

app.UseSwagger(settings =>
{
    settings.PostProcess = (document, request) => 
    {
        document.Host = request...
    };
});

The PostProcess and TransformToExternalPath config might be needed when serving through a reverse proxy. See sample:

Generate multiple Swagger specifications

See sample project: Advanced Config (.NET Core 2.0)

Enable authorization in generator and Swagger UI

Add OAuth2 authorization (OpenAPI 3)

// Add security definition and scopes to document
services.AddOpenApiDocument(document =>
{
    document.AddSecurity("bearer", Enumerable.Empty<string>(), new SwaggerSecurityScheme
    {
        Type = SwaggerSecuritySchemeType.OAuth2,
        Description = "My Authentication",
        Flow = SwaggerOAuth2Flow.Implicit,
        Flows = new OpenApiOAuthFlows()
        {
            Implicit = new OpenApiOAuthFlow()
            {
                Scopes = new Dictionary<string, string>
                {
                    { "read", "Read access to protected resources" },
                    { "write", "Write access to protected resources" }
                },
                AuthorizationUrl = "https://localhost:44333/core/connect/authorize",
                TokenUrl = "https://localhost:44333/core/connect/token"
            },
        }
    });

    document.OperationProcessors.Add(
        new AspNetCoreOperationSecurityScopeProcessor("bearer"));
//      new OperationSecurityScopeProcessor("bearer"));
);

Define the configuration for the Swagger UI 3's OAuth2 client in Startup.Configure():

app.UseSwagger();
app.UseSwaggerUi3(settings =>
{
    settings.OAuth2Client = new OAuth2ClientSettings
    {
        ClientId = "foo",
        ClientSecret = "bar",
        AppName = "my_app",
        Realm = "my_realm",
        AdditionalQueryStringParameters =
        {
            { "foo", "bar" }
        }
    };
});
  • OAuth2Client: Defines the settings for the OAuth2 client (i.e. the Swagger UI frontend)
  • DocumentSecurityDefinitionProcessor: Adds a security definition to the Swagger specification
  • OperationSecurityScopeAppender (Reflection based): Scans the AuthorizeAttribute attributes on controllers and action methods and adds the given roles as security scopes to the Swagger specification
  • AspNetCoreOperationSecurityScopeProcessor (ASP.NET Core metadata based): For ASP.NET Core 2.2+ it is recommended to use the AspNetCoreOperationSecurityScopeProcessor instead of the OperationSecurityScopeAppender as it will use the metadata exposed by ASP.NET Core and should produce better results.

Enable API Key authorization

services.AddOpenApiDocument(document => 
{
    document.AddSecurity("apikey", Enumerable.Empty<string>(), new SwaggerSecurityScheme
    {
        Type = SwaggerSecuritySchemeType.ApiKey,
        Name = "api_key",
        In = SwaggerSecurityApiKeyLocation.Header
    });

    document.OperationProcessors.Add(
        new AspNetCoreOperationSecurityScopeProcessor("bearer"));
//      new OperationSecurityScopeProcessor("bearer"));
});

Enable JWT authorization

You achieve this by telling NSwag to use API key authorization. Inside the API key text box in the Swagger UI you will need to paste in Bearer {your JWT key}

services.AddMvc();
services.AddSwaggerDocument(document =>
{
    document.AddSecurity("JWT", Enumerable.Empty<string>(), new SwaggerSecurityScheme
    {
        Type = SwaggerSecuritySchemeType.ApiKey,
        Name = "Authorization",
        In = SwaggerSecurityApiKeyLocation.Header,
        Description = "Type into the textbox: Bearer {your JWT token}."
    });

    document.OperationProcessors.Add(
        new AspNetCoreOperationSecurityScopeProcessor("bearer"));
//      new OperationSecurityScopeProcessor("bearer"));
});

Hack: Ask user for client ID and client secret

To let the user enter the client ID and client secret, use the following code for now:

new OAuth2ClientSettings
{
    ClientId = "\" + prompt('Please enter ClientId: ') + \"",
    ClientSecret = "\" + prompt('Please enter ClientSecret: ') + \""
}

Hosting behind a reverse proxy or as an IIS virtual application

When the application is hosted as an IIS virtual application or behind a (reverse) proxy, the request path to swagger.json is missing the path of the virtual application. For example, https://example.com/myapi/swagger will make a request to https://example.com/swagger/v1/swagger.json

To work around this, the request can be intercepted to modify the path, as demonstrated in the Reverse Proxy Config (.NET Core 2.1) sample project.

app.UseSwaggerUi3(config => config.TransformToExternalPath = (internalUiRoute, request) =>
{
    if (internalUiRoute.StartsWith("/") == true && internalUiRoute.StartsWith(request.PathBase) == false)
    {
        return request.PathBase + internalUiRoute;
    }
    else
    {
        return internalUiRoute;
    }
});

Generate specification via CLI

Run a customized build and select the assembly in NSwagStudio, create an nswag.json and execute it via CLI (nswag run nswag.json:

For more info, see CommandLine or MSBuild.