joydip_kanjilal
Contributor

How to use API Analyzers in ASP.NET Core

how-to
Jul 20, 20209 mins
APIsC#Microsoft .NET

Take advantage of API Analyzers and Swagger to improve the documentation of your ASP.NET Core APIs

woman code program monitor screen team
Credit: Getty Images

API Analyzers, introduced with ASP.NET Core 2.2, enable you to follow a set of conventions to improve the documentation of the APIs of your ASP.NET Core applications. API Analyzers work with any controller that is decorated with the [ApiController] attribute. This article discusses how we can work with API Analyzers in ASP.NET Core 3.1.

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here

Create an ASP.NET Core 3.1 API project

First off, let’s create an ASP.NET Core project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.NET Core project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.Net Core Web Application” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Click Create.
  7. In the “Create New ASP.Net Core Web Application” window shown next, select .NET Core as the runtime and ASP.NET Core 2.2 (or later) from the drop-down list at the top. I’ll be using ASP.NET Core 3.1 here.
  8. Select “API” as the project template to create a new ASP.NET Core API application.
  9. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here.
  10. Ensure that Authentication is set as “No Authentication” as we won’t be using authentication either.
  11. Click Create.

This will create a new ASP.NET Core API project in Visual Studio. Now select the Controllers solution folder in the Solution Explorer window and click “Add -> Controller…” to create a new controller named DefaultController. We’ll use this project in the subsequent sections of this article.

Install the API Analyzers NuGet package

If you are using with ASP.NET Core 2.2, to work with API Analyzers in ASP.NET Core, you should install the Microsoft.AspNetCore.Mvc.Api.Analyzers package from NuGet. You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, or by executing the following command in the NuGet Package Manager Console:

Install-Package Microsoft.AspNetCore.Mvc.Api.Analyzers

Note that you do not need to install the NuGet package if you are using ASP.NET Core 3.0 or higher because the analyzers are included as part of the .NET Core 3.x SDK.

Create the model and repository classes in ASP.NET Core

Select the Models folder of the project we’ve just created and create a model class as shown below.

    public class Author
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

We’ll also need a Repository class – a simple, minimalist implementation of a repository – we’re not connecting to the database here. The AuthorRepository class is shown in the code snippet given below.

public class AuthorRepository
    {
        List<Author> authors = new List<Author>()
        {
            new Author
            {
                Id = 1,
                FirstName = "Joydip",
                LastName = "Kanjilal"
            },
            new Author
            {
                Id = 2,
                FirstName = "Steve",
                LastName = "Smith"
            }
        };
        public async Task<Author> GetAuthor(int id)
        {           
            var author = authors.FirstOrDefault(a => a.Id == id);
            return await Task.FromResult<Author>(author);
        }
        public async Task<bool> SaveAuthor(Author author)
        {
            var result = authors.Where(a => a.Id == author.Id);
            if(result == null)
            {
                authors.Add(author);
                return await Task.FromResult(true);
            }
            return await Task.FromResult(false);
        }
    }

The AuthorRepository class contains two methods, namely GetAuthor and SaveAuthor. The former returns an instance of the Author class if the author is found in the collection, and the latter is used to add an instance of the Author class to the collection if the author doesn’t already exist in the collection. You may ignore the calls to Task.FromResult methods – these have been used only to satisfy the compiler.

Create the controller class in ASP.NET Core

Next, replace the source code of the DefaultController class with the following code.

    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        AuthorRepository authorRepository = new AuthorRepository();
        [HttpGet("{id}")]
        public async Task<ActionResult<Author>> Get(int id)
        {
            if (id <= 0)
            {
                return BadRequest();
            }
            try
            {
                var author = await authorRepository.GetAuthor(id);
                if (author == null)
                    return NotFound();
                return Ok(author);
            }
            catch
            {
                return BadRequest();
            }
        }
        [HttpPut]
        public async Task<ActionResult<bool>> Put([FromBody] Author author)
        {
            var result = await authorRepository.GetAuthor(author.Id);
            if (result == null)
                return NotFound();
            if (author == null)
            {
                return BadRequest();
            }
            try
            {
                var success = await authorRepository.SaveAuthor(author);
                if (!success)
                    return BadRequest();
                return Ok(author);
            }
            catch
            {
                return BadRequest();
            }
        }
    }

We’ll use this controller in the subsequent sections of this article.

Install and configure Swagger in ASP.NET Core

Next, you should install Swashbuckle in your project to generate Swagger documents for your ASP.NET Core API. You can do this either by installing the Swashbuckle.AspNetCore package via the NuGet Package Manager inside the Visual Studio 2019 IDE, or by executing the following command in the NuGet Package Manager Console:

<span class="hljs-pscommand">Install-Package</span> Swashbuckle.AspNetCore

Assuming Swashbuckle.AspNetCore package has been installed, write the following code in the ConfigureServices method of the Startup class to add Swagger to the request processing pipeline.

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "ApiAnalyzersDemo API",
    Version = "v1"});
});

The AddSwaggerGen extension method is used here to specify the metadata for the API documentation. You should also specify the Swagger URL and enable the Swagger UI in the Configure method of the Startup class as shown in the code snippet given below.

app.UseSwagger();
app.UseSwaggerUI(c =>
{
   c.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
});

Browse the Swagger endpoint for your ASP.NET Core application

So far so good. When you run the application and browse the Swagger endpoint, the documentation for the GET method should look like that in Figure 1.  

api analyzers 01 IDG

Figure 1. 

Note that the Swagger documentation shows only the details of the Http Status Code 200 that is returned from the method (if it succeeds) – it doesn’t capture the other status codes that the method returns. Here is exactly where API Analyzers can help. You can take advantage of API Analyzers to fix this missing piece of information in the documentation.

If you’re using ASP.NET Core 2.2, when you compile the code, you’ll see the warnings as shown in Figure 2.

api analyzers 02 IDG

Figure 2. 

Select any of the warnings and then press the “Ctrl” and “.” keys together to see the potential fixes. You can see that the recommended fix is to add the ProducesResponseType attribute as shown in Figure 3.

api analyzers 03 IDG

Figure 3. 

Since we’re using ASP.NET Core 3.1 here, you can add the following attributes at the top of your method or controller class in order to document all of the HTTP status codes being used in the action method, i.e., 200, 400, and 404.

[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]

Complete ASP.NET Core API Analyzers example

The following code listing shows the complete code of the DefaultController class for your reference.

    [Route("api/[controller]")]   
    [ApiController]
    [ApiConventionType(typeof(DefaultApiConventions))]
    public class DefaultController : ControllerBase
    {
        AuthorRepository authorRepository = new AuthorRepository();
        [HttpGet("{id}")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<Author>> Get(int id)
        {
            if (id <= 0)
            {
                return BadRequest();
            }
            try
            {
                var author = await authorRepository.GetAuthor(id);
                if (author == null)
                    return NotFound();
                return Ok(author);
            }
            catch
            {
                return BadRequest();
            }
        }
        [HttpPut]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<bool>> Put([FromBody] Author author)
        {
            var result = await authorRepository.GetAuthor(author.Id);
            if (result == null)
                return NotFound();
            if (author == null)
            {
                return BadRequest();
            }
            try
            {
                var success = await authorRepository.SaveAuthor(author);
                if (!success)
                    return BadRequest();
                return Ok(author);
            }
            catch
            {
                return BadRequest();
            }
        }
    }

Now run the application again and browse to the Swagger URL. Figure 4 shows what the output should look like.

api analyzers 04 IDG

Figure 4. 

API Analyzers is a useful addition to ASP.NET Core. As we’ve seen, you can take advantage of API Analyzers and Swashbuckle, an open source project for generating Swagger documents, to generate better API documentation. Because API Analyzers can document a status code that isn’t returned from an action method, it makes documenting your APIs faster and easier. For API documentation we’ve used Swashbuckle, an open source project for generating Swagger documents.

You can learn more about Swashbuckle from my previous article here

How to do more in ASP.NET Core:

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author