From 78b9850bf19f564d92efaba6b8e418e838128ae4 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 13 Nov 2018 19:39:41 -0800 Subject: [PATCH] Add docs for api conventions and analyzers (#9453) * Add docs for api conventions and analyzers Fixes #8332 * Edit pass on API conventions and analyzers content (#9574) * Edit pass on 2.2 API docs (#9578) * Scottaddie/open api patch (#9582) * Edit pass on 2.2 API docs * Resolve build warning * Fix list formatting --- aspnetcore/toc.md | 2 + aspnetcore/web-api/advanced/analyzers.md | 69 ++++++++++++++ aspnetcore/web-api/advanced/conventions.md | 67 ++++++++++++++ .../advanced/conventions/_static/Analyzer.gif | Bin 0 -> 57695 bytes .../conventions/sample/ApiConventions.csproj | 13 +++ .../sample/Controllers/ContactsController.cs | 87 ++++++++++++++++++ .../ContactsConventionController.cs | 83 +++++++++++++++++ .../conventions/sample/Models/Contact.cs | 14 +++ .../sample/Models/ContactRepository.cs | 49 ++++++++++ .../sample/Models/IContactRepository.cs | 13 +++ .../advanced/conventions/sample/Program.cs | 24 +++++ .../advanced/conventions/sample/Startup.cs | 40 ++++++++ .../sample/appsettings.Development.json | 10 ++ .../conventions/sample/appsettings.json | 8 ++ 14 files changed, 479 insertions(+) create mode 100644 aspnetcore/web-api/advanced/analyzers.md create mode 100644 aspnetcore/web-api/advanced/conventions.md create mode 100644 aspnetcore/web-api/advanced/conventions/_static/Analyzer.gif create mode 100644 aspnetcore/web-api/advanced/conventions/sample/ApiConventions.csproj create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsController.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsConventionController.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Models/Contact.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Models/ContactRepository.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Models/IContactRepository.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Program.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/Startup.cs create mode 100644 aspnetcore/web-api/advanced/conventions/sample/appsettings.Development.json create mode 100644 aspnetcore/web-api/advanced/conventions/sample/appsettings.json diff --git a/aspnetcore/toc.md b/aspnetcore/toc.md index a249a166deb5..8e4d6818a439 100644 --- a/aspnetcore/toc.md +++ b/aspnetcore/toc.md @@ -185,6 +185,8 @@ ## [Action return types](xref:web-api/action-return-types) ## [Format response data](xref:web-api/advanced/formatting) ## [Custom formatters](xref:web-api/advanced/custom-formatters) +## [Analyzers](xref:web-api/advanced/analyzers) +## [Conventions](xref:web-api/advanced/conventions) # Real-time apps ## [Overview](xref:signalr/introduction) diff --git a/aspnetcore/web-api/advanced/analyzers.md b/aspnetcore/web-api/advanced/analyzers.md new file mode 100644 index 000000000000..f172c59265d1 --- /dev/null +++ b/aspnetcore/web-api/advanced/analyzers.md @@ -0,0 +1,69 @@ +--- +title: Use web API analyzers +author: pranavkm +description: Learn about the web API analyzers in Microsoft.AspNetCore.Mvc.Api.Analyzers. +monikerRange: '>= aspnetcore-2.2' +ms.author: pranavkm +ms.custom: mvc +ms.date: 11/13/2018 +uid: web-api/advanced/analyzers +--- +# Use web API analyzers + +ASP.NET Core 2.2 introduces the [Microsoft.AspNetCore.Mvc.Api.Analyzers](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Api.Analyzers) NuGet package containing analyzers for web APIs. The analyzers work with controllers annotated with , while building on [API conventions](xref:web-api/advanced/conventions). + +## Package installation + +`Microsoft.AspNetCore.Mvc.Api.Analyzers` can be added with one of the following approaches: + +### [Visual Studio](#tab/visual-studio) + +* From the **Package Manager Console** window: + * Go to **View** > **Other Windows** > **Package Manager Console**. + * Navigate to the directory in which the *ApiConventions.csproj* file exists. + * Execute the following command: + + ```powershell + Install-Package Microsoft.AspNetCore.Mvc.Api.Analyzers + ``` + +* From the **Manage NuGet Packages** dialog: + * Right-click the project in **Solution Explorer** > **Manage NuGet Packages**. + * Set the **Package source** to "nuget.org". + * Enter "Microsoft.AspNetCore.Mvc.Api.Analyzers" in the search box. + * Select the "Microsoft.AspNetCore.Mvc.Api.Analyzers" package from the **Browse** tab and click **Install**. + +### [Visual Studio for Mac](#tab/visual-studio-mac) + +* Right-click the *Packages* folder in **Solution Pad** > **Add Packages...**. +* Set the **Add Packages** window's **Source** drop-down to "nuget.org". +* Enter "Microsoft.AspNetCore.Mvc.Api.Analyzers" in the search box. +* Select the "Microsoft.AspNetCore.Mvc.Api.Analyzers" package from the results pane and click **Add Package**. + +### [Visual Studio Code](#tab/visual-studio-code) + +Run the following command from the **Integrated Terminal**: + +```console +dotnet add ApiConventions.csproj package Microsoft.AspNetCore.Mvc.Api.Analyzers +``` + +### [.NET Core CLI](#tab/netcore-cli) + +Run the following command: + +```console +dotnet add ApiConventions.csproj package Microsoft.AspNetCore.Mvc.Api.Analyzers +``` + +--- + +## Analyzers for API conventions + +Open API documents contain status codes and response types that an action may return. In ASP.NET Core MVC, attributes such as and are used to document an action. goes into further detail on documenting your API. + +One of the analyzers in the package inspects controllers annotated with and identifies actions that don't entirely document their responses. Consider the following example: + +[!code-csharp[](conventions/sample/Controllers/ContactsController.cs?name=missing404docs&highlight=9)] + +The preceding action documents the HTTP 200 success return type but doesn't document the HTTP 404 failure status code. The analyzer reports the missing documentation for the HTTP 404 status code as a warning. An option to fix the problem is provided. diff --git a/aspnetcore/web-api/advanced/conventions.md b/aspnetcore/web-api/advanced/conventions.md new file mode 100644 index 000000000000..c9dfd8afaf2c --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions.md @@ -0,0 +1,67 @@ +--- +title: Use web API conventions +author: pranavkm +description: Learn about web API conventions in ASP.NET Core. +monikerRange: '>= aspnetcore-2.2' +ms.author: pranavkm +ms.custom: mvc +ms.date: 11/13/2018 +uid: web-api/advanced/conventions +--- +# Use web API conventions + +ASP.NET Core 2.2 introduces a way to extract common [API documentation](xref:tutorials/web-api-help-pages-using-swagger) and apply it to multiple actions, controllers, or all controllers within an assembly. Web API conventions are a substitute for decorating individual actions with [[ProducesResponseType]](xref:Microsoft.AspNetCore.Mvc.ProducesResponseTypeAttribute). It allows you to define the most common "conventional" return types and status codes that you return from your action with a way to select the convention method that applies to an action. + +By default, ASP.NET Core MVC 2.2 ships with a set of default conventions, `Microsoft.AspNetCore.Mvc.DefaultApiConventions`. The conventions are based on the controller that ASP.NET Core scaffolds. If your actions follow the pattern that scaffolding produces, you should be successful using the default conventions. + +At runtime, understands conventions. `ApiExplorer` is MVC's abstraction to communicate with Open API document generators. Attributes from the applied convention get associated with an action and are included in the action's Swagger documentation. API analyzers also understand conventions. If your action is unconventional (for example, it returns a status code that isn't documented by the applied convention), it produces a warning, encouraging you to document it. + +[View or download sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/web-api/advanced/conventions/sample) ([how to download](xref:index#how-to-download-a-sample)) + +## Apply web API conventions + +There are three ways to apply a convention. Conventions don't compose, each action may be associated with exactly one convention. More specific conventions (detailed below) take precedence over less specific ones. The selection is non-deterministic when two or more conventions of the same priority apply to an action. The following options exist to apply a convention to an action, from the most specific to the least specific: + +1. `Microsoft.AspNetCore.Mvc.ApiConventionMethodAttribute` — Applies to individual actions and specifies the convention type and the convention method that applies. In the following sample, the convention method `Microsoft.AspNetCore.Mvc.DefaultApiConventions.Put` is applied to the `Update` action: + + [!code-csharp[](conventions/sample/Controllers/ContactsConventionController.cs?name=apiconventionmethod&highlight=2-3)] + +1. `Microsoft.AspNetCore.Mvc.ApiConventionTypeAttribute` applied to a controller — Applies the convention type to all actions on the controller. Convention methods are decorated with hints that determine which actions it would apply to (details as part of authoring conventions). For example: + + [!code-csharp[](conventions/sample/Controllers/ContactsConventionController.cs?name=apiconventiontypeattribute)] + +1. `Microsoft.AspNetCore.Mvc.ApiConventionTypeAttribute` applied to an assembly — Applies the convention type to all controllers in the current assembly. For example: + + [!code-csharp[](conventions/sample/Startup.cs?name=apiconventiontypeattribute)] + +## Create web API conventions + +A convention is a static type with methods. These methods are annotated with `[ProducesResponseType]` or `[ProducesDefaultResponseType]` attributes. + +```csharp +public static class MyAppConventions +{ + [ProducesResponseType(200)] + [ProducesResponseType(404)] + public static void Find(int id) + { + } +} +``` + +Applying this convention to an assembly results in the convention method applying to any action with the name `Find` and having exactly one parameter named `id`, as long as they don't have other more specific metadata attributes. + +In addition to `[ProducesResponseType]` and `[ProducesDefaultResponseType]`, `[ApiConventionNameMatch]` and `[ApiConventionTypeMatch]` can be applied to the convention method that determines the methods they apply to. For example: + +```csharp +[ProducesResponseType(200)] +[ProducesResponseType(404)] +[ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)] +public static void Find( + [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Suffix)] + int id) +{ } +``` + +* The `Microsoft.AspNetCore.Mvc.ApiExplorer.ApiConventionNameMatchBehavior.Prefix` option applied to the method, indicates that the convention can match any action as long as it's prefixed with "Find". This includes methods such as `Find`, `FindPet`, or `FindById`. +* The `Microsoft.AspNetCore.Mvc.ApiExplorer.ApiConventionNameMatchBehavior.Suffix` applied to the parameter indicates that the convention can match methods with exactly one parameter ending in the suffix identifier. This includes parameters such as `id` or `petId`. `ApiConventionTypeMatch` can be similarly applied to types to constrain the type of the parameter. A `params[]` argument can be used to indicate remaining parameters that don't need to be explicitly matched. diff --git a/aspnetcore/web-api/advanced/conventions/_static/Analyzer.gif b/aspnetcore/web-api/advanced/conventions/_static/Analyzer.gif new file mode 100644 index 0000000000000000000000000000000000000000..5e9c4f63d57180afbe9170ca436b13bf6be24553 GIT binary patch literal 57695 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 F{{XJ}xJ3W} literal 0 HcmV?d00001 diff --git a/aspnetcore/web-api/advanced/conventions/sample/ApiConventions.csproj b/aspnetcore/web-api/advanced/conventions/sample/ApiConventions.csproj new file mode 100644 index 000000000000..be9699e4149d --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/ApiConventions.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp2.2 + 2.2.0-preview3-27014-02 + + + + + + + + diff --git a/aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsController.cs b/aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsController.cs new file mode 100644 index 000000000000..04807940ad60 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsController.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using ApiConventions.Models; +using Microsoft.AspNetCore.Http; + +namespace ApiConventions.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class ContactsController : Controller + { + public ContactsController(IContactRepository contacts) + { + Contacts = contacts; + } + public IContactRepository Contacts { get; set; } + + + // GET api/contacts + [HttpGet] + public IEnumerable Get() + { + return Contacts.GetAll(); + } + + #region missing404docs + // GET api/contacts/{guid} + [HttpGet("{id}")] + [ProducesResponseType(typeof(Contact), StatusCodes.Status200OK)] + public IActionResult Get(string id) + { + var contact = Contacts.Get(id); + if (contact == null) + { + return NotFound(); + } + return Ok(contact); + } + #endregion + + // POST api/contacts + [HttpPost] + public IActionResult Post(Contact contact) + { + if (ModelState.IsValid) + { + Contacts.Add(contact); + return CreatedAtRoute("Get", new { id = contact.ID }, contact); + } + return BadRequest(); + } + + // PUT api/contacts/{guid} + [HttpPut("{id}")] + public IActionResult Put(string id, Contact contact) + { + if (ModelState.IsValid && id == contact.ID) + { + var contactToUpdate = Contacts.Get(id); + if (contactToUpdate != null) + { + Contacts.Update(contact); + return new NoContentResult(); + } + return NotFound(); + } + return BadRequest(); + } + + // DELETE api/contacts/{guid} + [HttpDelete("{id}")] + public IActionResult Delete(string id) + { + var contact = Contacts.Get(id); + if (contact == null) + { + return NotFound(); + } + + Contacts.Remove(id); + return NoContent(); + } + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsConventionController.cs b/aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsConventionController.cs new file mode 100644 index 000000000000..053c7b394642 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Controllers/ContactsConventionController.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using ApiConventions.Models; +using Microsoft.AspNetCore.Http; + +namespace ApiConventions.Controllers +{ + [ApiController] +#region apiconventiontypeattribute + [ApiConventionType(typeof(DefaultApiConvention))] +#endregion + [Route("api/[controller]")] + public class ContactsConventionController : Controller + { + public ContactsConventionController(IContactRepository contacts) + { + Contacts = contacts; + } + public IContactRepository Contacts { get; set; } + + + // GET api/contacts + [HttpGet] + public IEnumerable Get() + { + return Contacts.GetAll(); + } + + // GET api/contacts/{guid} + [HttpGet("{id}")] + public ActionResult Get(string id) + { + var contact = Contacts.Get(id); + if (contact == null) + { + return NotFound(); + } + return Ok(contact); + } + + // POST api/contacts + [HttpPost] + public IActionResult Post(Contact contact) + { + Contacts.Add(contact); + return CreatedAtRoute("Get", new { id = contact.ID }, contact); + } + + #region apiconventionmethod + // PUT api/contacts/{guid} + [HttpPut("{id}")] + [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Put))] + public IActionResult Update(string id, Contact contact) + { + var contactToUpdate = Contacts.Get(id); + if (contactToUpdate == null) + { + return NotFound(); + } + + Contacts.Update(contact); + return new NoContentResult(); + } + #endregion + + // DELETE api/contacts/{guid} + [HttpDelete("{id}")] + public IActionResult Delete(string id) + { + var contact = Contacts.Get(id); + if (contact == null) + { + return NotFound(); + } + + Contacts.Remove(id); + return NoContent(); + } + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/Models/Contact.cs b/aspnetcore/web-api/advanced/conventions/sample/Models/Contact.cs new file mode 100644 index 000000000000..720b4311566b --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Models/Contact.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ApiConventions.Models +{ + public class Contact + { + public string ID { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/Models/ContactRepository.cs b/aspnetcore/web-api/advanced/conventions/sample/Models/ContactRepository.cs new file mode 100644 index 000000000000..109cf7788ba7 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Models/ContactRepository.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ApiConventions.Models +{ + public class ContactRepository : IContactRepository + { + private static ConcurrentDictionary _contacts = + new ConcurrentDictionary(); + + public ContactRepository() + { + Add(new Contact() { FirstName = "Nancy", LastName = "Davolio" }); + } + + public void Add(Contact contact) + { + contact.ID = Guid.NewGuid().ToString(); + _contacts[contact.ID] = contact; + } + + public Contact Get(string id) + { + Contact contact; + _contacts.TryGetValue(id, out contact); + return contact; + } + + public IEnumerable GetAll() + { + return _contacts.Values; + } + + public Contact Remove(string id) + { + Contact contact; + _contacts.TryRemove(id, out contact); + return contact; + } + + public void Update(Contact contact) + { + _contacts[contact.ID] = contact; + } + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/Models/IContactRepository.cs b/aspnetcore/web-api/advanced/conventions/sample/Models/IContactRepository.cs new file mode 100644 index 000000000000..8bdbf947321d --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Models/IContactRepository.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace ApiConventions.Models +{ + public interface IContactRepository + { + void Add(Contact contact); + IEnumerable GetAll(); + Contact Get(string key); + Contact Remove(string key); + void Update(Contact contact); + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/Program.cs b/aspnetcore/web-api/advanced/conventions/sample/Program.cs new file mode 100644 index 000000000000..06d972d17f78 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Program.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace ApiConventions +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/Startup.cs b/aspnetcore/web-api/advanced/conventions/sample/Startup.cs new file mode 100644 index 000000000000..5f9c33b7e578 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/Startup.cs @@ -0,0 +1,40 @@ +using ApiConventions.Models; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +#region apiconventiontypeattribute +[assembly: ApiConventionType(typeof(DefaultApiConventions))] +#endregion + +namespace ApiConventions +{ + public class Startup + { + public Startup(IHostingEnvironment env) + { + var builder = new ConfigurationBuilder() + .SetBasePath(env.ContentRootPath) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) + .AddEnvironmentVariables(); + Configuration = builder.Build(); + } + + public IConfigurationRoot Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc(); + services.AddSingleton(); + } + + public void Configure(IApplicationBuilder app) + { + app.UseMvc(); + } + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/appsettings.Development.json b/aspnetcore/web-api/advanced/conventions/sample/appsettings.Development.json new file mode 100644 index 000000000000..fa8ce71a97a3 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/aspnetcore/web-api/advanced/conventions/sample/appsettings.json b/aspnetcore/web-api/advanced/conventions/sample/appsettings.json new file mode 100644 index 000000000000..5fff67bacc46 --- /dev/null +++ b/aspnetcore/web-api/advanced/conventions/sample/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Warning" + } + } +}