Posting AJAX Requests to ASP.NET Core MVC
Introduction
In the past, I’ve had trouble doing something that is apparently simple: invoking a simple action method in a controller using AJAX. Although it is indeed simple, when using jQuery, it may require some attention, hence this post.
In this example I will show how to do something simple: how to invoke an action that just adds two integers and returns the result using jQuery AJAX. This can be extended to any other kind of data, mind you, it is not tied to simple data types.
Prerequisites
We will be using .NET Core (or .NET 5/6, doesn’t really matter for the purpose of this sample) and jQuery 3.x, although it should work the same with 2.x. There is no special setup required other than adding controllers and views to dependency injection (or full MVC, if you prefer).
Controller Side
The controller part is simple, but we have two options:
- We can have multiple parameters
- Or we can have a single parameter of a data type that holds all of the data that we wish to send
Generally, option #2 is more extensible, for we can add more parameters easily, without changing the action method’s signature, but I will show here how it works with both options.
Multiple Parameters
Our action method will look like this:
[HttpPost] public IActionResult Add(int a, int b) { return Json(a + b); }
And that’s it, pretty simple, the [HttpPost] attribute, as you probably know, is an action attribute that says that this action can only be called as a result of an HTTP POST.
Let’s see now what the single parameter version would look like.
Single Parameter
public record AddRequest(int A, int B);
[HttpPost] public IActionResult Add([FromBody] AddRequest req) { return Json(req.A + req.B); }
Here we see a few more things:
- The parameter is decorated with a [FromBody] attribute. This one instructs ASP.NET Core MVC to provide the value for the parameter from the body of the request. Its usage could be skipped if we instead decorated the whole controller class with an [ApiController] attribute, but that is beyond the scope of this post
Client Side
On the client side, we also need to match the decision we made on the controller side, regarding how we defined the parameters.
Multiple Parameters
The JavaScript version goes like this:
function calculate() { const data = { a: 1, b: 2 };
$.ajax({ url: '/Home/Add', type: 'POST', data: data, success: function(result, status, xhr) { /*hooray!*/ }, error: function(xhr, status, error) { /*houston, we have a problem!*/ } }); }
Single Parameter
And the single one is just two small changes:
function calculate() { const data = { a: 1, b: 2 };
$.ajax({ url: '/Home/Add', type: 'POST', data: JSON.stringify(data), contentType: 'application/json', success: function(result, status, xhr) { /*hooray!*/ }, error: function(xhr, status, error) { /*houston, we have a problem!*/ } }); }
As you can see, the difference is that here you need to explicitly serialize the data to JSON using the built-in JSON.stringify function and then also explicitly provide the content type application/json.
Pitfalls
There are a few possible pitfalls:
- You may get HTTP 400 Bad Request when you try to POST to your action method. This is likely because of Anti Cross Site Scripting Forgery (XSRF) protection, which is enabled by default in ASP.NET Core MVC. Please refer to my other post here, or, TL; DR, apply an [IgnoreAntiforgeryToken] to the action method
- When using the single parameter option, you may be getting a null value in the action method as the parameter value. This is likely the result of being unable to deserialize the contents that you are sending. Please ensure that you are allowing case-insensitive JSON serialization (the default) and that the parameters are well defined. See also here
Conclusion
AJAX has been around for quite a while and is a fun and safe option, but it has its tricks. Hope you find this post helpful!