.NET/C#
  • ASP.NET Core Overview
  • ASP.NET Core API tutorial
    • How to create ASP.NET Core C# API tutorial
      • launchSettings
      • Install swagger
        • Swagger best practices
      • Run the app
      • Fix CORS problem
      • Add AutoMapper
      • Add JWT reference
      • Add .gitignore
      • Basic structure & EF Core
      • AddSingleton
    • Loading Related Entities
  • Unit test controller logic in ASP.NET Core
    • Unit testing controllers
  • .NET Q&A
    • dotnet try
    • LINQ
      • LINQ Query Syntax
      • Lambda Expression
      • Standard Query Operators
  • .NET C# Interview questions
    • C# - .NET interview questions and answers [Part 1]
    • C# - .NET interview questions and answers [Part 2]
    • C# Interview questions [Part 3] General questions
  • C#
    • Object-Oriented Programming (Principles)
      • N-tier architecture style
      • Command and Query Responsibility Segregation (CQRS) pattern
      • Project architecture
    • C# Advanced review
      • Implicit typing
      • Generics
      • Attributes
      • Reflection
      • Delegates
      • Anonymous Methods and Lambda Expressions
      • Events
      • Ref vs Out
      • Task
        • TaskFactory Class
  • MySQL
    • MySQL Lerning
      • SELECT
      • ORDER BY
      • WHERE
      • DISTINCT
      • IN
      • BETWEEN
      • Join
      • INNER JOIN
      • LEFT JOIN
      • RIGHT JOIN
      • GROUP BY
      • Subquery
      • UNION
    • Stored Procedures
      • CREATE PROCEDURE
  • Versioning API, MongoDB and ci-cd
    • Create a web API with ASP.NET Core and MongoDB
    • REST API versioning with ASP.NET Core
    • Design a CI/CD pipeline using Azure DevOps
      • Create a CI/CD pipeline for GitHub repo using Azure DevOps Starter
  • TFS & TFCV
    • What is Team Foundation Version Control
      • Develop and share your code in TFVC using Visual Studio
      • Suspend your work and manage your shelvesets
    • Newtonsoft Json.NET
      • Serializing and Deserializing JSON
  • MS-SQL
    • Quick tutorial
      • Add new column to a table
      • LEFT/RIGHT Reverse operator
      • Dates (Transact-SQL)
      • CAST and CONVERT (Transact-SQL)
      • Types of JOIN
      • Our first Left Outer Join
      • CROSS JOIN
Powered by GitBook
On this page
  • Package installation
  • Add and configure Swagger middleware
  • Next step
  • Customize and extend

Was this helpful?

  1. ASP.NET Core API tutorial
  2. How to create ASP.NET Core C# API tutorial

Install swagger

PreviouslaunchSettingsNextSwagger best practices

Last updated 4 years ago

Was this helpful?

There are three main components to Swashbuckle:

  • : a Swagger object model and middleware to expose SwaggerDocument objects as JSON endpoints.

  • : a Swagger generator that builds SwaggerDocument objects directly from your routes, controllers, and models. It's typically combined with the Swagger endpoint middleware to automatically expose Swagger JSON.

  • : an embedded version of the Swagger UI tool. It interprets Swagger JSON to build a rich, customizable experience for describing the web API functionality. It includes built-in test harnesses for the public methods.

Package installation

Swashbuckle can be added with the following approaches:

  • From the Package Manager Console window:

    • Go to View > Other Windows > Package Manager Console

    • Navigate to the directory in which the TodoApi.csproj file exists

    • Execute the following command

      Install-Package Swashbuckle.AspNetCore -Version 5.5.0
  • From the Manage NuGet Packages dialog:

    • Right-click the project in Solution Explorer > Manage NuGet Packages

    • Set the Package source to "nuget.org"

    • Ensure the "Include prerelease" option is enabled

    • Enter "Swashbuckle.AspNetCore" in the search box

    • Select the latest "Swashbuckle.AspNetCore" package from the Browse tab and click Install

Add and configure Swagger middleware

Add the Swagger generator to the services collection in the Startup.ConfigureServices method:C#Copy

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<TodoContext>(opt =>
        opt.UseInMemoryDatabase("TodoList"));
    services.AddControllers();

    // Register the Swagger generator, defining 1 or more Swagger documents
    services.AddSwaggerGen();
}

In the Startup.Configure method, enable the middleware for serving the generated JSON document and the Swagger UI:C#Copy

public void Configure(IApplicationBuilder app)
{
    // Enable middleware to serve generated Swagger as a JSON endpoint.
    app.UseSwagger();

    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });

    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Note

The Swagger UI can be found at http://localhost:<port>/swagger. Explore the API via Swagger UI and incorporate it in other programs.

Tip

To serve the Swagger UI at the app's root (http://localhost:<port>/), set the RoutePrefix property to an empty string:C#Copy

app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    c.RoutePrefix = string.Empty;
});

If using directories with IIS or a reverse proxy, set the Swagger endpoint to a relative path using the ./ prefix. For example, ./swagger/v1/swagger.json. Using /swagger/v1/swagger.json instructs the app to look for the JSON file at the true root of the URL (plus the route prefix, if used). For example, use http://localhost:<port>/<route_prefix>/swagger/v1/swagger.json instead of http://localhost:<port>/<virtual_directory>/<route_prefix>/swagger/v1/swagger.json.

Note

By default, Swashbuckle generates and exposes Swagger JSON in version 3.0 of the specification—officially called the OpenAPI Specification. To support backwards compatibility, you can opt into exposing JSON in the 2.0 format instead. This 2.0 format is important for integrations such as Microsoft Power Apps and Microsoft Flow that currently support OpenAPI version 2.0. To opt into the 2.0 format, set the SerializeAsV2 property in Startup.Configure:C#Copy

public void Configure(IApplicationBuilder app)
{
    // Enable middleware to serve generated Swagger as a JSON endpoint.
    app.UseSwagger(c =>
    {
        c.SerializeAsV2 = true;
    });

    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });

    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Next step

Our launchSettings.json should look like the following:

{
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:62757",
      "sslPort": 44302
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "api_seed": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Customize and extend

Swagger provides options for documenting the object model and customizing the UI to match your theme.

In the Startup class, add the following namespaces:C#Copy

using System;
using System.Reflection;
using System.IO;

API info and description

The configuration action passed to the AddSwaggerGen method adds information such as the author, license, and description:

In the Startup class, import the following namespace to use the OpenApiInfo class:C#Copy

using Microsoft.OpenApi.Models;

Using the OpenApiInfo class, modify the information displayed in the UI:C#Copy

// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "ToDo API",
        Description = "A simple example ASP.NET Core Web API",
        TermsOfService = new Uri("https://example.com/terms"),
        Contact = new OpenApiContact
        {
            Name = "Shayne Boyer",
            Email = string.Empty,
            Url = new Uri("https://twitter.com/spboyer"),
        },
        License = new OpenApiLicense
        {
            Name = "Use under LICX",
            Url = new Uri("https://example.com/license"),
        }
    });
});

The Swagger UI displays the version's information:

XML comments

XML comments can be enabled with the following approaches:

  • Right-click the project in Solution Explorer and select Edit <project_name>.csproj.

  • Manually add the highlighted lines to the .csproj file:

XMLCopy

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Enabling XML comments provides debug information for undocumented public types and members. Undocumented types and members are indicated by the warning message. For example, the following message indicates a violation of warning code 1591:textCopy

warning CS1591: Missing XML comment for publicly visible type or member 'TodoController.GetAll()'
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
namespace TodoApi
{
#pragma warning disable CS1591
    public class Program
    {
        public static void Main(string[] args) =>
            BuildWebHost(args).Run();

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .Build();
    }
#pragma warning restore CS1591
}

Configure Swagger to use the XML file that's generated with the preceding instructions. For Linux or non-Windows operating systems, file names and paths can be case-sensitive. For example, a TodoApi.XML file is valid on Windows but not CentOS.C#Copy

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<TodoContext>(opt =>
        opt.UseInMemoryDatabase("TodoList"));
    services.AddControllers();

    // Register the Swagger generator, defining 1 or more Swagger documents
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo
        {
            Version = "v1",
            Title = "ToDo API",
            Description = "A simple example ASP.NET Core Web API",
            TermsOfService = new Uri("https://example.com/terms"),
            Contact = new OpenApiContact
            {
                Name = "Shayne Boyer",
                Email = string.Empty,
                Url = new Uri("https://twitter.com/spboyer"),
            },
            License = new OpenApiLicense
            {
                Name = "Use under LICX",
                Url = new Uri("https://example.com/license"),
            }
        });

        // Set the comments path for the Swagger JSON and UI.
        var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        c.IncludeXmlComments(xmlPath);
    });
}
/// <summary>
/// Deletes a specific TodoItem.
/// </summary>
/// <param name="id"></param>        
[HttpDelete("{id}")]
public IActionResult Delete(long id)
{
    var todo = _context.TodoItems.Find(id);

    if (todo == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todo);
    _context.SaveChanges();

    return NoContent();
}

The Swagger UI displays the inner text of the preceding code's <summary> element:

The UI is driven by the generated JSON schema:JSONCopy

"delete": {
    "tags": [
        "Todo"
    ],
    "summary": "Deletes a specific TodoItem.",
    "operationId": "ApiTodoByIdDelete",
    "consumes": [],
    "produces": [],
    "parameters": [
        {
            "name": "id",
            "in": "path",
            "description": "",
            "required": true,
            "type": "integer",
            "format": "int64"
        }
    ],
    "responses": {
        "200": {
            "description": "Success"
        }
    }
}
/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>            
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<TodoItem> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    _context.SaveChanges();

    return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
}

Notice the UI enhancements with these additional comments:

Data annotations

Add the [Required] attribute to the Name property of the TodoItem class:C#Copy

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }

        [Required]
        public string Name { get; set; }

        [DefaultValue(false)]
        public bool IsComplete { get; set; }
    }
}

The presence of this attribute changes the UI behavior and alters the underlying JSON schema:JSONCopy

"definitions": {
    "TodoItem": {
        "required": [
            "name"
        ],
        "type": "object",
        "properties": {
            "id": {
                "format": "int64",
                "type": "integer"
            },
            "name": {
                "type": "string"
            },
            "isComplete": {
                "default": false,
                "type": "boolean"
            }
        }
    }
},

Add the [Produces("application/json")] attribute to the API controller. Its purpose is to declare that the controller's actions support a response content type of application/json:C#Copy

[Produces("application/json")]
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
    private readonly TodoContext _context;

The Response Content Type drop-down selects this content type as the default for the controller's GET actions:

As the usage of data annotations in the web API increases, the UI and API help pages become more descriptive and useful.

Describe response types

Developers consuming a web API are most concerned with what's returned—specifically response types and error codes (if not standard). The response types and error codes are denoted in the XML comments and data annotations.

The Create action returns an HTTP 201 status code on success. An HTTP 400 status code is returned when the posted request body is null. Without proper documentation in the Swagger UI, the consumer lacks knowledge of these expected outcomes. Fix that problem by adding the highlighted lines in the following example:C#Copy

/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>            
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult<TodoItem> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    _context.SaveChanges();

    return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
}

The Swagger UI now clearly documents the expected HTTP response codes:

Customize the UI

The default UI is both functional and presentable. However, API documentation pages should represent your brand or theme. Branding the Swashbuckle components requires adding the resources to serve static files and building the folder structure to host those files.

<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" />

Enable Static File Middleware:C#Copy

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();

    // Enable middleware to serve generated Swagger as a JSON endpoint.
    app.UseSwagger();

    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });

    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

To inject additional CSS stylesheets, add them to the project's wwwroot folder and specify the relative path in the middleware options:C#Copy

app.UseSwaggerUI(c =>
{
     c.InjectStylesheet("/swagger-ui/custom.css");
}

Swashbuckle relies on MVC's to discover the routes and endpoints. If the project calls , routes and endpoints are discovered automatically. When calling , the method must be explicitly called. For more information, see .

The preceding UseSwaggerUI method call enables the . If targeting .NET Framework or .NET Core 1.x, add the NuGet package to the project.

Launch the app, and navigate to http://localhost:<port>/swagger/v1/swagger.json. The generated document describing the endpoints appears as shown in .

Swagger UI with version information: description, author, and see more link

To suppress warnings project-wide, define a semicolon-delimited list of warning codes to ignore in the project file. Appending the warning codes to $(NoWarn); applies the too.XMLCopy

To suppress warnings only for specific members, enclose the code in preprocessor directives. This approach is useful for code that shouldn't be exposed via the API docs. In the following example, warning code CS1591 is ignored for the entire Program class. Enforcement of the warning code is restored at the close of the class definition. Specify multiple warning codes with a comma-delimited list.C#Copy

In the preceding code, is used to build an XML file name matching that of the web API project. The property is used to construct a path to the XML file. Some Swagger features (for example, schemata of input parameters or HTTP methods and response codes from the respective attributes) work without the use of an XML documentation file. For most features, namely method summaries and the descriptions of parameters and response codes, the use of an XML file is mandatory.

Adding triple-slash comments to an action enhances the Swagger UI by adding the description to the section header. Add a element above the Delete action:C#Copy

Swagger UI showing XML comment 'Deletes a specific TodoItem.' for the DELETE method

Add a element to the Create action method documentation. It supplements information specified in the <summary> element and provides a more robust Swagger UI. The <remarks> element content can consist of text, JSON, or XML.C#Copy

Swagger UI with additional comments shown

Mark the model with attributes, found in the namespace, to help drive the Swagger UI components.

Swagger UI with default response content type
Swagger UI showing POST Response Class description 'Returns the newly created Todo item' and '400 - If the item is null' for status code and reason under Response Messages

In ASP.NET Core 2.2 or later, conventions can be used as an alternative to explicitly decorating individual actions with [ProducesResponseType]. For more information, see .

To support the [ProducesResponseType] decoration, the package offers extensions to enable and enrich the response, schema, and parameter metadata.

If targeting .NET Framework or .NET Core 1.x, add the NuGet package to the project:XMLCopy

The preceding NuGet package is already installed if targeting .NET Core 2.x and using the .

Swashbuckle.AspNetCore.Swagger
Swashbuckle.AspNetCore.SwaggerGen
Swashbuckle.AspNetCore.SwaggerUI
Visual Studio
Visual Studio for Mac
Visual Studio Code
.NET Core CLI
Microsoft.AspNetCore.Mvc.ApiExplorer
AddMvc
AddMvcCore
AddApiExplorer
Swashbuckle, ApiExplorer, and Routing
Static File Middleware
Microsoft.AspNetCore.StaticFiles
OpenAPI specification (openapi.json)
Visual Studio
Visual Studio for Mac
Visual Studio Code
.NET Core CLI
C# default values
#pragma warning
Reflection
AppContext.BaseDirectory
<summary>
<remarks>
System.ComponentModel.DataAnnotations
Use web API conventions
Swashbuckle.AspNetCore.Annotations
Microsoft.AspNetCore.StaticFiles
metapackage