How to make an API with dotnet core

jpblancodb profile image JPBlancoDB ・3 min read

The goal of this post is to explain the purposes of the most important stuff going on in the process of creating an API for a blog. One consideration before starting is that I'm using netcore 2.2 at the moment of writing this post. If you use netcore 3.0 or higher, you are going to have a different controller created from scratch but the explanation on what the annotations mean is the same.

Initializing the project:

  1. Let's create the project:
dotnet new webapi -n BlogApi
  1. Create .sln file:
dotnet new sln -n BlogApi
dotnet sln add BlogApi/BlogApi.csproj
  1. Create respective folders for unit tests and integration tests (we are going to put hands on this within the upcoming posts):
dotnet new xunit -n BlogApi.UnitTests
dotnet new xunit -n BlogApi.IntegrationTests
dotnet sln add BlogApi.UnitTests/BlogApi.UnitTests.csproj
dotnet sln add BlogApi.IntegrationTests/BlogApi.IntegrationTests.csproj
  1. We are going to delete wwwroot since we won’t be going to use it. If you are using an IDE like Rider, you can just delete the folder, but if you are using Visual Studio Code you need to remove the reference from BlogApi.csproj.
  <Folder Include="wwwroot\" />
  1. We are now ready to start putting hands on. Let’s go to the ValuesController.
public class ValuesController : Controller

Before declaring the class, we have this Route annotation. In case you don’t know what it means, it is the route where you can access that controller. For example, in this case, we have:


So, to access that controller you must go to:


And here, the important thing that we're interested in is /api/values. You can notice there that [controller] is a variable defined by NetCore and it is going to get the name of the controller. For example, if you have “PostsController” then, in this case, [controller] = posts. But, you can always define the route yourself as for example: [Route("this-is-my-route")] then your endpoint to access this controller will be:


Let’s go to our methods.

public IEnumerable<string> Get()
  return new string[] { "value1", "value2" };

The first method begins with [HttpGet], which is the verb of the method. Therefore, we can also have: [HttpGet], [HttpPost], [HttpPut], [HttpDelete], [HttpPatch] and [HttpOptions].

What if we want to specify the explicit action in the url?

In this case, we can add a parameter to this annotation with the “name”. If we have [HttpGet("my-action")] then to access this method we have to go to:


Also, we could have [HttpGet("[action]")] (as we have with [controller]) and then it will take the name of the method. For example, let’s take the original example again:

public IEnumerable<string> Get()
  return new string[] { "value1", "value2" };

To have access to it, we need to go to:


Lastly, we could receive variables to our methods included an object.

public void Put(int id, [FromBody]string value)

In this example, we have [HttpPut("{id}")] whatever goes between curly brackets is a variable, so here we have to make a PUT request to:


Being in this case, id = 1. In addition, we can also send objects in the body of the request. In this case, to access the body we need [FromBody] as well as [FromQuery] to access whatever we send in the querystring.

That’s it! If you have any doubt don’t hesitate to leave your comments or ask me ​​via Twitter.

Posted on by:

jpblancodb profile



Developer, writing tech articles. Football fan and terrible defender. He/him.


Editor guide

I just tried this but there was no ValuesController generated. There was only a WeatherForecastController with just a Get method. There was also no wwwroot generated. I'm running .Net Core 3.0.100 on Windows 10.
I was able to start it and got a result through the browser. Now I can look through the attributes for defining the routes.
Thanks for the post.


Hi Katie! Thanks for your comment, indeed you have differences because I've used netcore 2.2. I'll clarify this in the post. Nevertheless, the explanation of how it works and what the different annotations mean remains the same.
Thanks again!


Hi there Katie, are you using Visual Studio 2019? or are you on VS Code?


I used VS Code. Why, is there a difference?

Not really but I was gonna recommend simply creating the web API project via Visual Studio 2019, since visual studio will template it for you.

Or alternatively using the visual studio 2019 create conroller function, which will create a controller skeleton for you

Odd that the dotnet new webapi did not correctly create your project template.

perhaps if you were to install
dotnet tool install --global dotnet-aspnet-codegenerator

via powershell, more info on that available here and here

In the future, I'll probably scaffold using VS2019. I only did it through the command line to follow the post.

I think I got different results because I'm using a newer version of .NET Core. There is so much stuff here to learn 😄

Could be, I can't say I tried the dotnet new command yet on .NET Core 3.0.

If you'd like I could give it a test at home and let you know my results.

Oh, that's so sweet of you, but it's not really necessary, I've got the gist of what's going on with this. I need to concentrate on building this API for our project. Now at least the structure of how to do it is put together. I'm adjusting things to run async for the rest of the methods.

Well happy developing!