-1

In my ASP:NET MVC app I have a method as shown below and I try to pass the form data (single item of a list) to the Controller. I also need to pass __RequestVerificationToken as I use POST method in the Controller. I have look at many topics on stackoverflow but none of them has fixed this problem.

Razor:

@model IEnumerable<DemoViewModel>

@using (Html.BeginForm("Save", "Employee", FormMethod.Post, 
    new { id = "frmEmployee", enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()

    @foreach (var item in Model)
    {
        @item.Name
        @item.Surname
        @item.Town
        <!-- code omitted for brevity -->                                                
    }
}

<a href="javascript:save();">
    Save
</a>


<script>

    function save() {

        var selectedEmpId = 0;
        var employeeList = @Html.Raw(Json.Encode(Model));        
        var employee = employeeList.filter(function (e) { return e.Id === selectedEmpId; });

        var formdata = JSON.stringify({employee});
        var token = $('[name=__RequestVerificationToken]').val();

        $.ajax({
            type: "POST",
            url: '@Url.Action("Save", "Employee")',
            cache: false,
            dataType: "json",
            data: { model: formdata, __RequestVerificationToken: token },

            //I also tried  to add this
            //contentType: "application/json; charset=utf-8", 
        });
    };

</script>

On the other hand, normally I would use var formdata = $('#frmEmployee').serialize(); or var formdata = new FormData($('#frmEmployee').get(0)); but in this example I need to get a single data from list rather than form data.

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save([Bind(Exclude = null)] DemoViewModel model)
{
    if (ModelState.IsValid)
    {
        //stuff
    }
}

When passing the data to Controller model variable is null or when trying something the values of the model are null. Any idea to fix the problem?

  • Does anybody have no idea on whether it is possible or not? –  Dec 19 '19 at 08:05
  • Please show your action method implementation! and have you made sure that you get correct data in employee after filtering from list in Save method? – Mukesh Modhvadiya Dec 19 '19 at 08:06
  • @MukeshModhvadiya Sorry, I added Save method. Thanks in advance... –  Dec 19 '19 at 08:12
  • var formdata = JSON.stringify({employee}); so in your contrtolller should be string model. – Nhien Dec 19 '19 at 08:31
  • @hexadecimal, you are passing object containing your model and verification code, which will not match param in action method. Just pass employee model as data and pass verification code in header. Or on server create new view model containing properties DemoViewModel and string verification code. – Mukesh Modhvadiya Dec 19 '19 at 08:52
  • @MukeshModhvadiya Could you pls post your suggestion as an example code? Thanks. –  Dec 19 '19 at 09:06
  • @Nhien What is the fix method? –  Dec 19 '19 at 09:07
  • use string instead of DemoViewModel – Nhien Dec 19 '19 at 09:29
  • @hexadecimal, your question is been closed, so it cannot be answered. You can try as I have suggested in last comment. – Mukesh Modhvadiya Dec 19 '19 at 09:45
  • @ErikPhilips This is not **AntiForgeryToken** related question, rather it is related to pass model to Controller besides AntiForgeryToken. So, I had already fixed **AntiForgeryToken** part and need to pass ViewModel to Controller. So, the answer you suggested does not solve my problem. –  Dec 19 '19 at 14:12
  • @ErikPhilips For this reason cyp open the question and help? –  Dec 19 '19 at 14:12
  • @MukeshModhvadiya As I had already fixed AntiForgeryToken problem before asking the question and failed to pass/convert JavaScript array to Controller, the question is reopened again. So, could you please inform me on how to pass JavaScript array to Controller as ViewModel or convert in ViewModel? –  Dec 19 '19 at 20:41
  • @Nhien I do not want to pass string, so how can I pass the JavaScript array as ViewModel to the Controller? –  Dec 19 '19 at 20:42
  • @ErikPhilips Thanks a lot for reopening the issue and look at my call. –  Dec 19 '19 at 20:43
  • 1
    you use var formdata = JSON.stringify({employee}); so the formdata will send to controller as string. In controller, you need to receive as string in controller and use DeserializeObject to convert it to your model. – Nhien Dec 20 '19 at 01:25

2 Answers2

0

By filtering an array you are getting result as array with one employee item, and at controller action an object is required not the array/list. So pass first element of filtered list or better use find method,

var employee = employeeList.find(e => e.Id === selectedEmpId);
var formdata = JSON.stringify(employee);

And post it

$.ajax({
        type: "POST",
        url: '@Url.Action("Save", "Employee")',
        cache: false,
        dataType: "json",
        data: formdata,
        contentType: 'application/json; charset=utf-8', 

        //....success,error functions
    });

That should bind model correctly in action method. If still facing issue in binding you can use FromBody attribute with parameter.

Mukesh Modhvadiya
  • 2,088
  • 2
  • 21
  • 31
  • Thanks a lot, but I have also tried to use this approach and see that it does not work. I fixed the problem using the following approach. On the other hand, for your help I voted up. –  Dec 20 '19 at 11:27
0

Finally I fixed the problem using the following approach. So, anyone who need to convert JSON to ViewModel in ASP.NET MVC can use the following approach:

View:

$.ajax({
    type: "POST",
    url: '@Url.Action("Save", "DemoContoller")',
    cache: false,
    dataType: "json",
    data: { json: JSON.stringify(demoData), "__RequestVerificationToken": 
        $('input[name=__RequestVerificationToken]').val() },

    //...
});

Controller:

public ActionResult Save(string json)
{ 
    IList<DemoViewModel> model = new
        JavaScriptSerializer().Deserialize<IList<DemoViewModel>>(json);

    //or

    List<DemoViewModel> model = new 
        JavaScriptSerializer().Deserialize<List<DemoViewModel>>(json);
}