'ASP.net core AntiForgeryToken issue : data doesn't bind to model

I have a working project for a booking system in asp.net core that uses a google Timeline chart. When you click on the chart a modal popup with a partial view pops up up to enter data. Javacript has a click event on the save button to send the data to the controller. The controller validates the data and sends the partial view back to javascript where it is sent back to the modal popup. I have two flags on the view that if set true, javascript hides the popup. This all works until I decorate the controller with [ValidateAntiForgeryToken]

I have the code as follows


StartUp:

services.AddAntiforgery(options => {
    options.HeaderName = "RequestVerificationToken";
});

Javascript:

(function() {
        var PlaceHolderElement = $('#PlaceHolderHere');
        //create popup save
        PlaceHolderElement.on('click', '[data-save="modal"]', function(event) {
            event.preventDefault();
            var form = $(this).parents('.modal').find('form');
            var token = $("input[name='__RequestVerificationToken']").val();
            var actionUrl = form.attr('action');
            var sendData = form.serialize();
            $.ajax({
                type: 'POST',
                url: actionUrl,
                data: sendData,
            }).done(function(data1) {
                var newBody = $('.modal-body', data1);
                PlaceHolderElement.find('.modal-body').replaceWith(newBody);
                var isValid = newBody.find('[name="IsValid"]').val() === 'True';
                var isValid2 = newBody.find('[name="BookingFree"]').val() === 'True';
                if (isValid && isValid2) {
                    PlaceHolderElement.find('.modal').modal('hide');
                    location.reload();
                }
            })
})

Controller:

[HttpPost]
public IActionResult EditBooking(BookingViewModel model) {

  if (ModelState.IsValid) {
    ... other code
  }
}

when I decorate the controller with [ValidateAntiForgeryToken] and change the jarvascript to

data: {
    model: sendData,
    __RequestVerificationToken: token,
}

the Validate works but the model is empty! if I declare the model as string then I get a string.

If I send the token in headers:, the token validation fails

I need the data in the model in order for the ModelState to set IsValid



Solution 1:[1]

1..serialize() will pass the form data together with __RequestVerificationToken value by default.

2.When you use form element with method="post" and tag helper, it will dynamically generate token input which name="__RequestVerificationToken" inside the form. But if you specific the action attribute for form like:<form action="/url" method="post"></form>, it will not generate the token input.

So if you specific the action attribute, you need manually add token input by using @Html.AntiForgeryToken() in the form:

<form action="/url" method="post">
     @Html.AntiForgeryToken()
     //....
</form>

A simple working demo you could follow:

View:

<form asp-action="EditBooking" asp-controller="Home" method="post">
    <input asp-for="Name" />
    <input type="button" onclick="PostForm()" value="Post" />
</form>

@section Scripts
{
    <script>    
        function PostForm() {
            //var token = $("input[name='__RequestVerificationToken']").val();
            var actionUrl = $('form').attr('action');
            var sendData = $('form').serialize();
            console.log(sendData)
            $.ajax({
                type: 'POST',
                url: actionUrl,
                data: sendData,
            }).done(function(data1) {                                
            })
}
    </script>
}

And no need add the following code:

services.AddAntiforgery(options => {
    options.HeaderName = "RequestVerificationToken";
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rena