Introducción a Swashbuckle y ASP.NET Core

Nota:

La generación de documentos OpenAPI en el momento de la compilación con Swashbuckle no se admite en .NET 8 ni versiones posteriores. Para una alternativa compatible en tiempo de compilación, consulte Documentación de la API Web ASP.NET Core con Swagger / OpenAPI. La generación de documentos en tiempo de ejecución todavía se admite en .NET 8.

Hay tres componentes principales de Swashbuckle:

  • Swashbuckle.AspNetCore.Swagger: modelo de objetos de Swagger y middleware para exponer objetos SwaggerDocument como puntos de conexión JSON.

  • Swashbuckle.AspNetCore.SwaggerGen: generador de Swagger que genera objetos SwaggerDocument directamente desde las rutas, controladores y modelos. Se suele combinar con el middleware de punto de conexión de Swagger para exponer automáticamente el JSON de Swagger.

  • Swashbuckle.AspNetCore.SwaggerUI: versión insertada de la herramienta de interfaz de usuario de Swagger. Interpreta el JSON de Swagger para crear una experiencia enriquecida y personalizable para describir la funcionalidad de la API web. Incluye herramientas de ejecución de pruebas integradas para los métodos públicos.

Instalación del paquete

Se puede agregar Swashbuckle con los métodos siguientes:

  • En la ventana Consola del Administrador de paquetes:

    • Vaya a Vista>Otras ventanas>Consola del Administrador de paquetes.

    • Vaya al directorio en el que está el archivo .csproj.

    • Ejecute el siguiente comando:

      Install-Package Swashbuckle.AspNetCore -Version 6.5.0
      
  • En el cuadro de diálogo Administrar paquetes NuGet:

    • Haga clic con el botón derecho en el proyecto en el Explorador de soluciones>Administrar paquetes NuGet.
    • Establezca el origen del paquete en "nuget.org".
    • Asegúrese de que la opción "Incluir versión preliminar" está habilitada.
    • Escriba "Swashbuckle.AspNetCore" en el cuadro de búsqueda.
    • Seleccione el paquete "Swashbuckle.AspNetCore" más reciente en la pestaña Examinar y haga clic en Instalar.

Agregar y configurar el middleware de Swagger

Agregue el generador de Swagger a la colección de servicios en Program.cs:

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

La llamada a AddEndpointsApiExplorer que se muestra en el ejemplo anterior solo es necesaria para las API mínimas. Para obtener más información, vea esta publicación de StackOverflow.

Habilite el middleware para servir el documento JSON generado y la UI de Swagger, también en Program.cs:

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

El código anterior agrega el middleware de Swagger solo si el entorno actual está establecido en Desarrollo. La llamada de método UseSwaggerUI habilita una versión insertada de la herramienta de interfaz de usuario de Swagger.

Inicie la aplicación y vaya a https://localhost:<port>/swagger/v1/swagger.json. El documento generado en el que se describen los puntos de conexión aparecerá según se muestra en la especificación de OpenAPI (openapi.json).

La interfaz de usuario de Swagger se encuentra en https://localhost:<port>/swagger. Explore la API a través de la interfaz de usuario de Swagger e incorpórela a otros programas.

Sugerencia

Para servir la interfaz de usuario de Swagger en la raíz de la aplicación (https://localhost:<port>/), establezca la propiedad RoutePrefix en una cadena vacía:

if (builder.Environment.IsDevelopment())
{
    app.UseSwaggerUI(options => // UseSwaggerUI is called only in Development.
    {
        options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
        options.RoutePrefix = string.Empty;
    });
}

Si usa directorios con IIS o un proxy inverso, establezca el punto de conexión de Swagger en una ruta de acceso relativa mediante el prefijo ./. Por ejemplo: ./swagger/v1/swagger.json. El uso de /swagger/v1/swagger.json indica a la aplicación que debe buscar el archivo JSON en la verdadera raíz de la dirección URL (junto con el prefijo de ruta, si se usa). Por ejemplo, use https://localhost:<port>/<route_prefix>/swagger/v1/swagger.json en lugar de https://localhost:<port>/<virtual_directory>/<route_prefix>/swagger/v1/swagger.json.

Nota

De forma predeterminada, Swashbuckle genera y expone JSON de Swagger en la versión 3.0 de la especificación (denominada oficialmente la especificación OpenAPI). Para admitir la compatibilidad con versiones anteriores, puede optar por exponer JSON en el formato 2.0 en su lugar. Este formato 2.0 es importante para integraciones como Microsoft Power Apps y Microsoft Flow, que actualmente admiten la versión 2.0 de OpenAPI. Para optar por el formato 2.0, establezca la propiedad SerializeAsV2 en Program.cs:

app.UseSwagger(options =>
{
    options.SerializeAsV2 = true;
});

Personalizar y ampliar

Swagger proporciona opciones para documentar el modelo de objetos y personalizar la interfaz de usuario para que coincida con el tema.

Información y descripción de la API

La acción de configuración que se pasa al método AddSwaggerGen agrega información, como el autor, la licencia y la descripción.

En Program.cs, importe el siguiente espacio de nombres para que use la clase OpenApiInfo:

using Microsoft.OpenApi.Models;

Con la clase OpenApiInfo, modifique la información que se muestra en la interfaz de usuario:

builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "ToDo API",
        Description = "An ASP.NET Core Web API for managing ToDo items",
        TermsOfService = new Uri("https://example.com/terms"),
        Contact = new OpenApiContact
        {
            Name = "Example Contact",
            Url = new Uri("https://example.com/contact")
        },
        License = new OpenApiLicense
        {
            Name = "Example License",
            Url = new Uri("https://example.com/license")
        }
    });
});

La interfaz de usuario de Swagger muestra información de la versión:

Interfaz de usuario de Swagger con información de la versión: descripción, autor y licencia.

comentarios XML

Los comentarios XML se pueden habilitar con los métodos siguientes:

  • Haga clic con el botón derecho en el Explorador de soluciones y seleccione Edit <project_name>.csproj.
  • Agregue GenerateDocumentationFile al archivo .csproj:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

Puede habilitar los comentarios XML para proporcionar información de depuración para miembros y tipos públicos sin documentación. Los miembros y tipos que no estén documentados se indican por medio del mensaje de advertencia. Por ejemplo, el siguiente mensaje señala una infracción con el código de advertencia 1591:

warning CS1591: Missing XML comment for publicly visible type or member 'TodoController'

Para eliminar las advertencias a nivel de proyecto, defina una lista delimitada por punto y coma de códigos de advertencia que se deban omitir en el archivo de proyecto. Al anexar los códigos de advertencia a $(NoWarn);, se aplican también los valores predeterminados de C#.

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

Para suprimir las advertencias solo para miembros específicos, incluya el código en directivas de preprocesador de advertencias #pragma. Este enfoque es útil para el código que no debe exponerse mediante los documentos de API. En el ejemplo siguiente, se omite el código de advertencia CS1591 para toda la clase TodoContext. La ejecución del código de advertencia se restaura al cerrar la definición de clase. Especifique varios códigos de advertencia con una lista delimitada por comas.

namespace SwashbuckleSample.Models;

#pragma warning disable CS1591
public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options) : base(options) { }

    public DbSet<TodoItem> TodoItems => Set<TodoItem>();
}
#pragma warning restore CS1591

Configure Swagger para usar el archivo XML que se generó con las instrucciones anteriores. En Linux o sistemas operativos que no sean Windows, las rutas de acceso y los nombres de archivo pueden distinguir entre mayúsculas y minúsculas. Por ejemplo, un archivo TodoApi.XML es válido en Windows, pero no en Ubuntu.

builder.Services.AddSwaggerGen(options =>
{
    options.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "ToDo API",
        Description = "An ASP.NET Core Web API for managing ToDo items",
        TermsOfService = new Uri("https://example.com/terms"),
        Contact = new OpenApiContact
        {
            Name = "Example Contact",
            Url = new Uri("https://example.com/contact")
        },
        License = new OpenApiLicense
        {
            Name = "Example License",
            Url = new Uri("https://example.com/license")
        }
    });

    // using System.Reflection;
    var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});

En el código anterior, Reflection se usa para crear un nombre de archivo XML que coincida con el proyecto de API web. La propiedad AppContext.BaseDirectory sirve para crear una ruta de acceso al archivo XML. Algunas características de Swagger (por ejemplo, esquemas de parámetros de entrada o métodos HTTP y códigos de respuesta de los atributos respectivos) funcionan sin el uso de un archivo de documentación XML. Para la mayoría de las características, es decir, los resúmenes de los métodos y las descripciones de los parámetros y los códigos de respuesta, el uso de un archivo XML es obligatorio.

Agregar comentarios con la triple barra diagonal a una acción mejora la interfaz de usuario de Swagger en tanto agrega una descripción de la acción al encabezado de la sección. Agregue un elemento <summary> antes de la acción Delete:

/// <summary>
/// Deletes a specific TodoItem.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
    var item = await _context.TodoItems.FindAsync(id);

    if (item is null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(item);
    await _context.SaveChangesAsync();

    return NoContent();
}

La interfaz de usuario de Swagger muestra el texto interno del elemento <summary> del código anterior:

Interfaz de usuario de Swagger en la que se muestra el comentario XML

La UI se controla por medio del esquema JSON generado:

"delete": {
    "tags": [
        "Todo"
    ],
    "summary": "Deletes a specific TodoItem.",
    "parameters": [
        {
            "name": "id",
            "in": "path",
            "description": "",
            "required": true,
            "schema": {
                "type": "integer",
                "format": "int64"
            }
        }
    ],
    "responses": {
        "200": {
            "description": "Success"
        }
    }
},

Agregue un elemento <remarks> a la documentación del método de acción Create. Este elemento complementa la información especificada en el elemento <summary> y proporciona una interfaz de usuario de Swagger más sólida. El contenido del elemento <remarks> puede estar formado por texto, JSON o XML.

/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item #1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <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 async Task<IActionResult> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(Get), new { id = item.Id }, item);
}

Fíjese en las mejoras de la interfaz de usuario con estos comentarios extra:

Interfaz de usuario de Swagger con comentarios adicionales.

Anotaciones de datos

Marque el modelo con atributos, que se encuentran en el espacio de nombres System.ComponentModel.DataAnnotations, para controlar los componentes de la interfaz de usuario de Swagger.

Agregue el atributo [Required] a la propiedad Name de la clase TodoItem:

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

namespace SwashbuckleSample.Models;

public class TodoItem
{
    public long Id { get; set; }

    [Required]
    public string Name { get; set; } = null!;

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

La presencia de este atributo cambia el comportamiento de la UI y modifica el esquema JSON subyacente:

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

Agregue el atributo [Produces("application/json")] al controlador de API. Su propósito consiste en declarar que las acciones del controlador admiten un contenido de respuesta de tipo application/json:

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class TodoController : ControllerBase
{

En el menú desplegable Tipo de medio se selecciona este tipo de contenido como el valor predeterminado para las acciones GET del controlador:

Interfaz de usuario de Swagger con el tipo de contenido de respuesta predeterminado

A medida que aumenta el uso de anotaciones de datos en la API web, la interfaz de usuario y las páginas de ayuda de la API pasan a ser más descriptivas y útiles.

Describir los tipos de respuesta

Lo que más preocupa a los desarrolladores que consumen una API web es lo que se devuelve; sobre todo, los tipos de respuesta y los códigos de error (si no son los habituales). Los tipos de respuesta y los códigos de error se indican en las anotaciones de datos y los comentarios XML.

La acción Create devuelve un código de estado HTTP 201 cuando se ha ejecutado correctamente. Cuando el cuerpo de solicitud enviado es null, se devuelve un código de estado HTTP 400. Sin la documentación correcta en la interfaz de usuario de Swagger, el consumidor no dispone de la información necesaria de estos resultados esperados. Corrija este problema agregando las líneas resaltadas en el siguiente ejemplo:

/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item #1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <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 async Task<IActionResult> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(Get), new { id = item.Id }, item);
}

Ahora, la interfaz de usuario de Swagger documenta de forma clara los códigos de respuesta HTTP esperados:

Interfaz de usuario de Swagger en la que se muestra la descripción de la clase de respuesta POST

Las convenciones se pueden usar como alternativa a la representación explícita de acciones individuales con [ProducesResponseType]. Para más información, consulte Uso de convenciones de API web.

Para admitir la decoración [ProducesResponseType], el paquete Swashbuckle.AspNetCore.Annotations ofrece extensiones para habilitar y enriquecer los metadatos de respuesta, esquema y parámetro.

Personalizar la interfaz de usuario

La interfaz de usuario predeterminada es funcional y tiene un aspecto adecuado. Pero las páginas de documentación de la API deben ostentar su marca o tema. Para incluir la personalización de marca en los componentes de Swashbuckle, se deben agregar los recursos para servir archivos estáticos y generar la estructura de carpetas que hospedará estos archivos.

Habilitar middleware de archivos estáticos:

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

Para insertar hojas de estilos CSS adicionales, agréguelas a la carpeta wwwroot del proyecto y especifique la ruta de acceso relativa en las opciones de middleware:

if (app.Environment.IsDevelopment())
{
    app.UseSwaggerUI(options => // UseSwaggerUI is called only in Development.
    {
        options.InjectStylesheet("/swagger-ui/custom.css");
    });
}

Recursos adicionales

Vea o descargue el código de ejemplo (cómo descargarlo)

Hay tres componentes principales de Swashbuckle:

  • Swashbuckle.AspNetCore.Swagger: modelo de objetos de Swagger y middleware para exponer objetos SwaggerDocument como puntos de conexión JSON.

  • Swashbuckle.AspNetCore.SwaggerGen: generador de Swagger que genera objetos SwaggerDocument directamente desde las rutas, controladores y modelos. Se suele combinar con el middleware de punto de conexión de Swagger para exponer automáticamente el JSON de Swagger.

  • Swashbuckle.AspNetCore.SwaggerUI: versión insertada de la herramienta de interfaz de usuario de Swagger. Interpreta el JSON de Swagger para crear una experiencia enriquecida y personalizable para describir la funcionalidad de la API web. Incluye herramientas de ejecución de pruebas integradas para los métodos públicos.

Instalación del paquete

Se puede agregar Swashbuckle con los métodos siguientes:

  • En la ventana Consola del Administrador de paquetes:

    • Vaya a Vista>Otras ventanas>Consola del Administrador de paquetes.

    • Vaya al directorio en el que está el archivo TodoApi.csproj.

    • Ejecute el siguiente comando:

      Install-Package Swashbuckle.AspNetCore -Version 5.6.3
      
  • En el cuadro de diálogo Administrar paquetes NuGet:

    • Haga clic con el botón derecho en el proyecto en el Explorador de soluciones>Administrar paquetes NuGet.
    • Establezca el origen del paquete en "nuget.org".
    • Asegúrese de que la opción "Incluir versión preliminar" está habilitada.
    • Escriba "Swashbuckle.AspNetCore" en el cuadro de búsqueda.
    • Seleccione el paquete "Swashbuckle.AspNetCore" más reciente en la pestaña Examinar y haga clic en Instalar.

Agregar y configurar el middleware de Swagger

Agregue el generador de Swagger a la colección de servicios en el método Startup.ConfigureServices:

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();
}

En el método Startup.Configure, habilite el middleware para servir el documento JSON generado y la UI de Swagger:

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

        // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.)
        app.UseSwaggerUI();
    }

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

Nota

Swashbuckle se basa en Microsoft.AspNetCore.Mvc.ApiExplorer de MVC para detectar las rutas y los puntos de conexión. Si el proyecto llama a AddMvc, las rutas y los puntos de conexión se detectan automáticamente. Al llamar a AddMvcCore, se debe llamar explícitamente al método AddApiExplorer. Para más información, consulte Swashbuckle, ApiExplorer y enrutamiento.

En desarrollo, la llamada al método UseSwaggerUI anterior habilita una versión insertada de la herramienta de interfaz de usuario de Swagger. Esto depende del middleware de archivos estáticos. Si el destino es .NET Framework o .NET Core 1.x, agregue el paquete NuGet Microsoft.AspNetCore.StaticFiles al proyecto.

Inicie la aplicación y vaya a http://localhost:<port>/swagger/v1/swagger.json. El documento generado en el que se describen los puntos de conexión aparecerá según se muestra en la especificación de OpenAPI (openapi.json).

La interfaz de usuario de Swagger se encuentra en http://localhost:<port>/swagger. Explore la API a través de la interfaz de usuario de Swagger e incorpórela a otros programas.

Sugerencia

Para servir la interfaz de usuario de Swagger en la raíz de la aplicación (http://localhost:<port>/), establezca la propiedad RoutePrefix en una cadena vacía:

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

Si usa directorios con IIS o un proxy inverso, establezca el punto de conexión de Swagger en una ruta de acceso relativa mediante el prefijo ./. Por ejemplo: ./swagger/v1/swagger.json. El uso de /swagger/v1/swagger.json indica a la aplicación que debe buscar el archivo JSON en la verdadera raíz de la dirección URL (junto con el prefijo de ruta, si se usa). Por ejemplo, use http://localhost:<port>/<route_prefix>/swagger/v1/swagger.json en lugar de http://localhost:<port>/<virtual_directory>/<route_prefix>/swagger/v1/swagger.json.

Nota

De forma predeterminada, Swashbuckle genera y expone JSON de Swagger en la versión 3.0 de la especificación (denominada oficialmente la especificación OpenAPI). Para admitir la compatibilidad con versiones anteriores, puede optar por exponer JSON en el formato 2.0 en su lugar. Este formato 2.0 es importante para integraciones como Microsoft Power Apps y Microsoft Flow, que actualmente admiten la versión 2.0 de OpenAPI. Para optar por el formato 2.0, establezca la propiedad SerializeAsV2 en Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        // 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.
        // UseSwaggerUI is called only in Development.
        app.UseSwaggerUI(c => // UseSwaggerUI Protected by if (env.IsDevelopment())
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });
    }

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

Personalizar y ampliar

Swagger proporciona opciones para documentar el modelo de objetos y personalizar la interfaz de usuario para que coincida con el tema.

En la clase Startup, agregue los siguientes espacios de nombres:

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

Información y descripción de la API

La acción de configuración que se pasa al método AddSwaggerGen agrega información, como el autor, la licencia y la descripción:

En la clase Startup, importe el siguiente espacio de nombres para que use la clase OpenApiInfo:

using Microsoft.OpenApi.Models;

Con la clase OpenApiInfo, modifique la información que se muestra en la interfaz de usuario:

// 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"),
        }
    });
});

La interfaz de usuario de Swagger muestra información de la versión:

Interfaz de usuario de Swagger con información de la versión: descripción, autor y el vínculo See more (Ver más).

comentarios XML

Los comentarios XML se pueden habilitar con los métodos siguientes:

  • Haga clic con el botón derecho en el Explorador de soluciones y seleccione Edit <project_name>.csproj.
  • Agregue manualmente las líneas resaltadas al archivo .csproj:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Puede habilitar los comentarios XML para proporcionar información de depuración para miembros y tipos públicos sin documentación. Los miembros y tipos que no estén documentados se indican por medio del mensaje de advertencia. Por ejemplo, el siguiente mensaje señala una infracción con el código de advertencia 1591:

warning CS1591: Missing XML comment for publicly visible type or member 'TodoController.GetAll()'

Para eliminar las advertencias a nivel de proyecto, defina una lista delimitada por punto y coma de códigos de advertencia que se deban omitir en el archivo de proyecto. Al anexar los códigos de advertencia a $(NoWarn);, se aplican también los valores predeterminados de C#.

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

Para suprimir las advertencias solo para miembros específicos, incluya el código en directivas de preprocesador de advertencias #pragma. Este enfoque es útil para el código que no debe exponerse mediante los documentos de API. En el ejemplo siguiente, se omite el código de advertencia CS1591 para toda la clase Program. La ejecución del código de advertencia se restaura al cerrar la definición de clase. Especifique varios códigos de advertencia con una lista delimitada por comas.

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 para usar el archivo XML que se generó con las instrucciones anteriores. En Linux o sistemas operativos que no sean Windows, las rutas de acceso y los nombres de archivo pueden distinguir entre mayúsculas y minúsculas. Por ejemplo, un archivo TodoApi.XML es válido en Windows, pero no en Ubuntu.

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);
    });
}

En el código anterior, Reflection se usa para crear un nombre de archivo XML que coincida con el proyecto de API web. La propiedad AppContext.BaseDirectory sirve para crear una ruta de acceso al archivo XML. Algunas características de Swagger (por ejemplo, esquemas de parámetros de entrada o métodos HTTP y códigos de respuesta de los atributos respectivos) funcionan sin el uso de un archivo de documentación XML. Para la mayoría de las características, es decir, los resúmenes de los métodos y las descripciones de los parámetros y los códigos de respuesta, el uso de un archivo XML es obligatorio.

Agregar comentarios con la triple barra diagonal a una acción mejora la interfaz de usuario de Swagger en tanto agrega una descripción de la acción al encabezado de la sección. Agregue un elemento <summary> antes de la acción Delete:

/// <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();
}

La interfaz de usuario de Swagger muestra el texto interno del elemento <summary> del código anterior:

Interfaz de usuario de Swagger en la que se muestra el comentario XML

La UI se controla por medio del esquema JSON generado:

"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"
        }
    }
}

Agregue un elemento <remarks> a la documentación del método de acción Create. Este elemento complementa la información especificada en el elemento <summary> y proporciona una interfaz de usuario de Swagger más sólida. El contenido del elemento <remarks> puede estar formado por texto, JSON o XML.

/// <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);
}

Fíjese en las mejoras de la interfaz de usuario con estos comentarios extra:

Interfaz de usuario de Swagger con comentarios adicionales.

Anotaciones de datos

Marque el modelo con atributos, que se encuentran en el espacio de nombres System.ComponentModel.DataAnnotations, para controlar los componentes de la interfaz de usuario de Swagger.

Agregue el atributo [Required] a la propiedad Name de la clase TodoItem:

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; }
    }
}

La presencia de este atributo cambia el comportamiento de la UI y modifica el esquema JSON subyacente:

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

Agregue el atributo [Produces("application/json")] al controlador de API. Su propósito consiste en declarar que las acciones del controlador admiten un contenido de respuesta de tipo application/json:

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

En el menú desplegable Response Content Type (Tipo de contenido de respuesta) se selecciona este tipo de contenido como el valor predeterminado para las acciones GET del controlador:

Interfaz de usuario de Swagger con el tipo de contenido de respuesta predeterminado.

A medida que aumenta el uso de anotaciones de datos en la API web, la interfaz de usuario y las páginas de ayuda de la API pasan a ser más descriptivas y útiles.

Describir los tipos de respuesta

Lo que más preocupa a los desarrolladores que consumen una API web es lo que se devuelve; sobre todo, los tipos de respuesta y los códigos de error (si no son los habituales). Los tipos de respuesta y los códigos de error se indican en las anotaciones de datos y los comentarios XML.

La acción Create devuelve un código de estado HTTP 201 cuando se ha ejecutado correctamente. Cuando el cuerpo de solicitud enviado es null, se devuelve un código de estado HTTP 400. Sin la documentación correcta en la interfaz de usuario de Swagger, el consumidor no dispone de la información necesaria de estos resultados esperados. Corrija este problema agregando las líneas resaltadas en el siguiente ejemplo:

/// <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);
}

Ahora, la interfaz de usuario de Swagger documenta de forma clara los códigos de respuesta HTTP esperados:

Interfaz de usuario de Swagger, donde se muestra la descripción de la clase de respuesta POST

En ASP.NET Core 2.2 o versiones posteriores, las convenciones se pueden usar como alternativa a la representación explícita de acciones individuales con [ProducesResponseType]. Para más información, consulte Uso de convenciones de API web.

Para admitir la decoración [ProducesResponseType], el paquete Swashbuckle.AspNetCore.Annotations ofrece extensiones para habilitar y enriquecer los metadatos de respuesta, esquema y parámetro.

Personalizar la interfaz de usuario

La interfaz de usuario predeterminada es funcional y tiene un aspecto adecuado. Pero las páginas de documentación de la API deben ostentar su marca o tema. Para incluir la personalización de marca en los componentes de Swashbuckle, se deben agregar los recursos para servir archivos estáticos y generar la estructura de carpetas que hospedará estos archivos.

Si el destino es .NET Framework o .NET Core 1.x, agregue el paquete NuGet Microsoft.AspNetCore.StaticFiles al proyecto:

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

El paquete NuGet anterior ya estará instalado si el destino es .NET Core 2.x y se usa el metapaquete.

Habilitar middleware de archivos estáticos:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseStaticFiles();

    if (env.IsDevelopment())
    {
        // 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 => // UseSwaggerUI Protected by if (env.IsDevelopment())
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });
    }

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

Para insertar hojas de estilos CSS adicionales, agréguelas a la carpeta wwwroot del proyecto y especifique la ruta de acceso relativa en las opciones de middleware:

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

Recursos adicionales