In this article, we are going to see how to add multiple POST actions to our Web API controller. For the demonstration, we are going to use the .Net 6 Web API project. 

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

The Issue With Multiple POST Actions in Web API

In this section, we are going to use a controller with two POST actions, and explain the routing issue and what error we are going to get once we send the POST request to one of these actions:

[ApiController]
[Route("[controller]")]
public class StudentsController : ControllerBase
{
    readonly List<Student> students = new()
    {
        new Student(1, "Pedro Whitted"),
        new Student(2, "Lester Harvin"),
        new Student(3, "Phyllis Wiggins")
    };

    readonly List<StudentGrade> grades = new()
    {
        new StudentGrade(1, 3.2),
        new StudentGrade(2, 2.5),
        new StudentGrade(3, 3.7)
    };

    [HttpPost]
    public ActionResult PostStudent(Student student)
    {
        students.Add(student);
        return StatusCode(201);
    }

    [HttpPost]
    public ActionResult PostGrade(StudentGrade grade)
    {
        grades.Add(grade);
        return StatusCode(201);
    }
}

In the PostStudent action, we add a new student to our local collection. Also, in the second action, we add the student’s grades to the collection.

At this point, if we send a POST HTTP request to the controller:

https://localhost:7042/Students

We are going to get a response with a 500 Internal Server Error status code.

Also, we can see the error message: 

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.

It means our application couldn’t determine which POST action to execute in our controller!

Now if we try to edit our URI and add the action name to it:

https://localhost:7042/Students/PostStudent

We will notice that the server responds with 404 Not Found status code. 

Resolving Multiple Post Actions Issue

We can solve this issue with one of two options: using RoutAttribute or by using HttpPostAttribute.

RouteAttribute

By default, we can see the Route  attribute above the controller with a string "[controller]" as a parameter:

[Route("[controller]")]
public class StudentsController : ControllerBase

This means the URI for this controller is: 

http[s]://[domain]/[controller]

But we can use this Route attribute above the action method as well:

[Route("[action]")]
[HttpPost]
public ActionResult PostStudent(Student student)

By using the "[action]" string as a parameter here, we state that the URI must contain this action’s name in addition to the controller’s name:

http[s]://[domain]/[controller]/[action]

Now, let’s try to call our API with the action’s name in the URI: 

https://localhost:7042/Students/PostStudent

After we do that, we notice the 201, created response. We don’t have the error anymore.

If we want, we can assign a different action name in the URI. For example, instead of using the PostStudent action name, we can use the AddStudent

[Route("AddStudent")] 
[HttpPost] 
public ActionResult PostStudent(Student student)

After this change, we have a different URI: 

https://localhost:7042/Students/AddStudent

HttpPostAttribute

We can simplify our code by removing the Route attribute, and use the HttpPost attribute solely. It has an override that takes the same string parameter as the Route attribute:

[HttpPost("[action]")] 
public ActionResult PostStudent(Student student)

Now, for the URI, we have to provide the name of the action: 

https://localhost:7042/Students/PostStudent

And if we need to change the name of the action in the URI, we can simply use a different string as with the [Route] example: 

[HttpPost("AddStudent")] 
public ActionResult PostStudent(Student student)

Now the AddStudent string will be part of the URI: 

https://localhost:7042/Students/AddStudent

Conclusion

In this article, we’ve learned how to add multiple POST actions in a single controller, and how to call each of them without forcing an error.