Podstawowa konfiguracja Swagger jest bardzo skromna. Zróbmy zatem coś więcej i dołączmy dokumentacje XML do Swagger UI. Jeśli dla kogoś temat Swagger jest nowością odsyłam do wcześniejszego mojego wpisu poruszającego tematykę Importu Swagger API do Postman dla ASP.NET Core Web API

Dokumentacja XML

W pierwszej kolejności musimy włączyć generowanie dokumentacji XML w ustawianiach projektu. Wspomnę na wstępie, że w powyższym artykule bazuję na API w ASP.NET Core 3.1. Edytujemy plik <projectName>.csproj i dodajemy poniższy kod.

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

Ustawiając wartość true dla właściwości GenerateDocumentationFile włączamy generowanie dokumentacji xml w trybie Debug i Release. To ustawienie także powoduję wyświetlenie ostrzeżeń w całym projekcie dla klas i metod, które nie zawierają opisów.

Warning 1591

W trzeciej dodanej linii (NoWarn) ignorujemy ostrzeżenia w całym projekcie dla kodu 1591.

Konfiguracja Swagger

W drugim kroku musimy skonfigurować Swagger, aby używał wygenerowane pliki dokumentacji XML na UI. Konfiguracja Swagger odbywa się w klasie Startup. W celu wydzielenia logiki powiązanej z Swagger w jedno miejsce w projekcie utworzyłem klasę SwaggerMiddlewareExtensions z implementacją extension method. Metody wykorzystywane są do rejestracji Swagger middleware w pipeline. W celu dodania komentarzy xml do Swagger wywołujemy metodę IncludeXmlComments.

using System;
using System.IO;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;

namespace RunnerTracker.API.Extensions.Middleware
{
	public static class SwaggerMiddlewareExtensions
	{
		public static IServiceCollection AddCustomSwagger(this IServiceCollection services)
		{
			services.AddSwaggerGen(c =>
			{
				c.SwaggerDoc("v1", new OpenApiInfo { Title = "Runner Tracker API", Version = "v1" });

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

			return services;
		}

		public static IApplicationBuilder UseCustomSwagger(this IApplicationBuilder app)
		{
			app.UseSwagger();

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

			return app;
		}
	}
}

Metody AddCustomSwagger i UseCustomSwagger wywołujemy w klasie Startup.

Komentarze XML na UI

W celu zaprezentowania efektu konfiguracji musimy w trzecim kroku do kontrolera napisać kilka summary do akcji. Poniżej przykład RunnerController.

using System.Collections.Generic;
using System.Threading.Tasks;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using RunnerTracker.API.Domain.Runners.Commands;
using RunnerTracker.API.Domain.Runners.Dtos;
using RunnerTracker.API.Domain.Runners.Queries;

namespace RunnerTracker.API.Controllers
{
	[Route("api/[controller]")]
	[ApiController]
	public class RunnerController : ControllerBase
	{
		private readonly IMediator _mediator;

		public RunnerController(IMediator mediator)
		{
			_mediator = mediator;
		}

		/// <summary>
		/// Get runner by id
		/// </summary>
		/// <remarks>
		/// Here are remarks
		/// </remarks>
		/// <param name="runnerId">Runner id</param>
		/// <returns>Runner</returns>
		[HttpGet("{runnerId}")]
		public async Task<ActionResult<RunnerDto>> Get(int runnerId)
		{
			var runner = await _mediator.Send(new GetRunnerDetailQuery() {RunnerId = runnerId});
			return Ok(runner);
		}

		/// <summary>
		/// Get all runners
		/// </summary>
		/// <returns>List of runners</returns>
		[HttpGet]
		public async Task<ActionResult<IEnumerable<RunnerDto>>> GetAll()
		{
			var runners = await _mediator.Send(new GetRunnersQuery());
			return Ok(runners);
		}

		/// <summary>
		/// Add new runner
		/// </summary>
		/// <param name="command">Runner data</param>
		/// <returns>Runner id</returns>
		[HttpPost]
		public async Task<IActionResult> Create(CreateRunnerCommand command)
		{
			var runnerCreatedDto = await _mediator.Send(command);
			return CreatedAtAction(nameof(Get), new {runnerId = runnerCreatedDto.RunnerId}, runnerCreatedDto);
		}

		/// <summary>
		/// Update an existing runner
		/// </summary>
		/// <param name="command">Runner data</param>
		[HttpPut]
		public async Task<IActionResult> Change(UpdateRunnerCommand command)
		{
			await _mediator.Send(command);
			return NoContent();
		}

		/// <summary>
		/// Delete a runner
		/// </summary>
		/// <param name="runnerId">Runner id</param>
		[HttpDelete("{runnerId}")]
		public async Task<IActionResult> Delete(int runnerId)
		{
			await _mediator.Send(new DeleteRunnerCommand() {RunnerId = runnerId});
			return NoContent();
		}
	}
}

Mamy opisy, tym samym możemy uruchomić API i zobaczyć efekt wykonanej pracy. Na poniższym screenie, widzimy opisy akcji przy url punktu końcowego w Swagger UI.

Runner Tracker API Swagger UI

Przejdźmy do metody GET, na zrzucie widać opisy z sekcji summary, remarks i param.

Get runner by id

Podsumowanie

Czwartego kroku już nie ma, skończone. Biblioteka Swagger umożliwia generowanie dokumentacji w prosty sposób dla API. Wykonując tylko trzy kroki, pokazałem jak dla projektu ASP.NET Core API wygenerować dokumentacje Swagger UI z komentarzami XML. Do kolejnego wpisu 🙂