Pasar una lista de objetos a un método de controlador MVC usando jQuery Ajax

113

Estoy tratando de pasar una matriz de objetos a un método de controlador MVC usando la función ajax () de jQuery. Cuando entro en el método del controlador PassThing () C #, el argumento "cosas" es nulo. Intenté esto usando un tipo de Lista para el argumento, pero eso tampoco funciona. ¿Qué estoy haciendo mal?

<script type="text/javascript">
    $(document).ready(function () {
        var things = [
            { id: 1, color: 'yellow' },
            { id: 2, color: 'blue' },
            { id: 3, color: 'red' }
        ];

        $.ajax({
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            type: 'POST',
            url: '/Xhr/ThingController/PassThing',
            data: JSON.stringify(things)
        });
    });
</script>

public class ThingController : Controller
{
    public void PassThing(Thing[] things)
    {
        // do stuff with things here...
    }

    public class Thing
    {
        public int id { get; set; }
        public string color { get; set; }
    }
}
Martín pescador
fuente
3
Sus datos son una cadena, pero su método acepta una matriz. Cambie su método para aceptar una cadena, luego deserialícela dentro del método.
Bob Horn
2
Tu código es correcto. Lo probé y funcionó con MVC 4. Por favor, proporcione más datos para resolverlo.
Diego
Esto es genial, pero ¿qué sucede si no solo necesita una lista de cadenas para pasar, sino que necesita incluir una identificación separada asociada con la lista de cadenas? Así que, identificación de grupo, lista de grupos bajo identificación de grupo.
Nathan McKaskle

Respuestas:

188

Usando la sugerencia de NickW, pude hacer que esto funcionara usando things = JSON.stringify({ 'things': things });Aquí está el código completo.

$(document).ready(function () {
    var things = [
        { id: 1, color: 'yellow' },
        { id: 2, color: 'blue' },
        { id: 3, color: 'red' }
    ];      

    things = JSON.stringify({ 'things': things });

    $.ajax({
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        type: 'POST',
        url: '/Home/PassThings',
        data: things,
        success: function () {          
            $('#result').html('"PassThings()" successfully called.');
        },
        failure: function (response) {          
            $('#result').html(response);
        }
    }); 
});


public void PassThings(List<Thing> things)
{
    var t = things;
}

public class Thing
{
    public int Id { get; set; }
    public string Color { get; set; }
}

Hay dos cosas que aprendí de esto:

  1. Las configuraciones contentType y dataType son absolutamente necesarias en la función ajax (). No funcionará si faltan. Descubrí esto después de mucho ensayo y error.

  2. Para pasar una matriz de objetos a un método de controlador MVC, simplemente use el formato JSON.stringify ({'cosas': cosas}).

¡Espero que esto ayude a alguien más!

Martín pescador
fuente
8
Estaba teniendo el mismo problema y agregando el contentType lo solucionó. ¡Gracias!
Rochelle C
9
Dos cosas a tener en cuenta: JSON.stringify y especificando 'contentType'.
dinesh ygv
Crud. Todavía no me funciona. la URL de mi solicitud está http://localhost:52459/Sales/completeSale?itemsInCart=[{"ItemId":1,"Quantity":"1","Price":3.5}]y Sales.completeSaleestá public ActionResult completeSale(ItemInCart[] itemsInCart)anotada como HttpGet.
abalter
3
por alguna razón tuve que usarlodata: JSON.stringify(things),
Rob Scott
1
dataTypeno es necesario. Si se omite, la función ajax lo resolverá en función de los datos de retorno
32

¿No podrías simplemente hacer esto?

var things = [
    { id: 1, color: 'yellow' },
    { id: 2, color: 'blue' },
    { id: 3, color: 'red' }
];
$.post('@Url.Action("PassThings")', { things: things },
   function () {
        $('#result').html('"PassThings()" successfully called.');
   });

... y marca tu acción con

[HttpPost]
public void PassThings(IEnumerable<Thing> things)
{
    // do stuff with things here...
}
marisma
fuente
3
Esta debería ser la mejor respuesta. JSON.stringify no debe usarse en este caso
Esto no me funciona ... Estoy usando [HttpPost] public int SaveResults (List <ShortDetail> model) {} y $ .post ("@ Url.Action (" SaveResults "," Maps ")", {model: dataItems}, función (resultado) {});
Samra
2
Funcionó para mí. Absolutamente la mejor respuesta. No sé por qué la implementación de Halcyon no funcionó. Se invocó la función PassThings pero la variable de entrada 'cosas' estaba vacía incluso si se completó en el javascript justo antes de la llamada.
Leonardo Daga
12

Estoy usando una aplicación web .Net Core 2.1 y no pude obtener una sola respuesta aquí para que funcione. Obtuve un parámetro en blanco (si se llamó al método) o un error de servidor 500. Comencé a jugar con todas las combinaciones posibles de respuestas y finalmente obtuve un resultado funcional.

En mi caso la solución fue la siguiente:

Script: secuencia la matriz original (sin usar una propiedad con nombre)

    $.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        url: mycontrolleraction,
        data: JSON.stringify(things)
    });

Y en el método del controlador, use [FromBody]

    [HttpPost]
    public IActionResult NewBranch([FromBody]IEnumerable<Thing> things)
    {
        return Ok();
    }

Las fallas incluyen:

  • Nombrar el contenido

    datos: {contenido: nodos}, // Error 500 del servidor

  • No tener contentType = Error 500 del servidor

Notas

  • dataTypeno es necesario, a pesar de lo que dicen algunas respuestas, ya que se usa para la decodificación de respuesta (por lo que no es relevante para los ejemplos de solicitud aquí).
  • List<Thing> también funciona en el método del controlador
Codificación ido
fuente
10

Tengo la respuesta perfecta para todo esto: probé tantas soluciones que no pude finalmente administrarme, por favor encuentre la respuesta detallada a continuación:

       $.ajax({
            traditional: true,
            url: "/Conroller/MethodTest",
            type: "POST",
            contentType: "application/json; charset=utf-8",
            data:JSON.stringify( 
               [
                { id: 1, color: 'yellow' },
                { id: 2, color: 'blue' },
                { id: 3, color: 'red' }
                ]),
            success: function (data) {
                $scope.DisplayError(data.requestStatus);
            }
        });

Controlador

public class Thing
{
    public int id { get; set; }
    public string color { get; set; }
}

public JsonResult MethodTest(IEnumerable<Thing> datav)
    {
   //now  datav is having all your values
  }
Veera Induvasi
fuente
Debería tener más votos positivos: tradicional: verdadero es la forma recomendada en el sitio web de Jquery
DFTR
7

La única forma en que podría hacer que esto funcione es pasar el JSON como una cadena y luego deserializarlo usando JavaScriptSerializer.Deserialize<T>(string input), lo cual es bastante extraño si ese es el deserializador predeterminado para MVC 4.

Mi modelo tiene listas anidadas de objetos y lo mejor que pude obtener usando datos JSON es la lista superior para tener el número correcto de elementos, pero todos los campos de los elementos eran nulos.

Este tipo de cosas no debería ser tan difícil.

    $.ajax({
        type: 'POST',
        url: '/Agri/Map/SaveSelfValuation',
        data: { json: JSON.stringify(model) },
        dataType: 'text',
        success: function (data) {

    [HttpPost]
    public JsonResult DoSomething(string json)
    {
        var model = new JavaScriptSerializer().Deserialize<Valuation>(json);
broma más urgente
fuente
Para que esto funcione, siga de cerca el formato de la llamada Ajax.
Graham Laight
4

Este es un código de trabajo para su consulta, puede usarlo.

Controlador

    [HttpPost]
    public ActionResult save(List<ListName> listObject)
    {
    //operation return
    Json(new { istObject }, JsonRequestBehavior.AllowGet); }
    }

javascript

  $("#btnSubmit").click(function () {
    var myColumnDefs = [];
    $('input[type=checkbox]').each(function () {
        if (this.checked) {
            myColumnDefs.push({ 'Status': true, 'ID': $(this).data('id') })
        } else {
            myColumnDefs.push({ 'Status': false, 'ID': $(this).data('id') })
        }
    });
   var data1 = { 'listObject': myColumnDefs};
   var data = JSON.stringify(data1)
   $.ajax({
   type: 'post',
   url: '/Controller/action',
   data:data ,
   contentType: 'application/json; charset=utf-8',
   success: function (response) {
    //do your actions
   },
   error: function (response) {
    alert("error occured");
   }
   });
sach4all
fuente
2

Envolver su lista de objetos con otro objeto que contenga una propiedad que coincida con el nombre del parámetro que espera el controlador MVC funciona. Lo importante es el envoltorio alrededor de la lista de objetos.

$(document).ready(function () {
    var employeeList = [
        { id: 1, name: 'Bob' },
        { id: 2, name: 'John' },
        { id: 3, name: 'Tom' }
    ];      

    var Employees = {
      EmployeeList: employeeList
    }

    $.ajax({
        dataType: 'json',
        type: 'POST',
        url: '/Employees/Process',
        data: Employees,
        success: function () {          
            $('#InfoPanel').html('It worked!');
        },
        failure: function (response) {          
            $('#InfoPanel').html(response);
        }
    }); 
});


public void Process(List<Employee> EmployeeList)
{
    var emps = EmployeeList;
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Matón
fuente
1
     var List = @Html.Raw(Json.Encode(Model));
$.ajax({
    type: 'post',
    url: '/Controller/action',
    data:JSON.stringify({ 'item': List}),
    contentType: 'application/json; charset=utf-8',
    success: function (response) {
        //do your actions
    },
    error: function (response) {
        alert("error occured");
    }
});
Athul Nalupurakkal
fuente
Pruebe este código para pasar la lista de objetos modelo usando ajax. El modelo representa la IList <Model>. Utilice IList <Model> en el controlador para obtener los valores.
Athul Nalupurakkal
0

Si está utilizando ASP.NET Web API, simplemente debe aprobar data: JSON.stringify(things).

Y su controlador debería verse así:

public class PassThingsController : ApiController
{
    public HttpResponseMessage Post(List<Thing> things)
    {
        // code
    }
}
FleGMan
fuente
0

Modificación de @veeresh i

 var data=[

                        { id: 1, color: 'yellow' },
                        { id: 2, color: 'blue' },
                        { id: 3, color: 'red' }
                        ]; //parameter
        var para={};
        para.datav=data;   //datav from View


        $.ajax({
                    traditional: true,
                    url: "/Conroller/MethodTest",
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    data:para,
                    success: function (data) {
                        $scope.DisplayError(data.requestStatus);
                    }
                });

In MVC



public class Thing
    {
        public int id { get; set; }
        public string color { get; set; }
    }

    public JsonResult MethodTest(IEnumerable<Thing> datav)
        {
       //now  datav is having all your values
      }
Islam Minhajul
fuente
0

Lo que hice al intentar enviar algunos datos de varias filas seleccionadas en DataTable a la acción MVC:

HTML al comienzo de una página:

@Html.AntiForgeryToken()

(solo se muestra una fila, enlazar desde el modelo):

 @foreach (var item in Model.ListOrderLines)
                {
                    <tr data-orderid="@item.OrderId" data-orderlineid="@item.OrderLineId" data-iscustom="@item.IsCustom">
                        <td>@item.OrderId</td>
                        <td>@item.OrderDate</td>
                        <td>@item.RequestedDeliveryDate</td>
                        <td>@item.ProductName</td>
                        <td>@item.Ident</td>
                        <td>@item.CompanyName</td>
                        <td>@item.DepartmentName</td>
                        <td>@item.ProdAlias</td>
                        <td>@item.ProducerName</td>
                        <td>@item.ProductionInfo</td>
                    </tr>
                }

Botón que inicia la función de JavaScript:

 <button class="btn waves-effect waves-light btn-success" onclick="ProcessMultipleRows();">Start</button>

Función de JavaScript:

  function ProcessMultipleRows() {
            if ($(".dataTables_scrollBody>tr.selected").length > 0) {
                var list = [];
                $(".dataTables_scrollBody>tr.selected").each(function (e) {
                    var element = $(this);
                    var orderid = element.data("orderid");
                    var iscustom = element.data("iscustom");
                    var orderlineid = element.data("orderlineid");
                    var folderPath = "";
                    var fileName = "";

                    list.push({ orderId: orderid, isCustomOrderLine: iscustom, orderLineId: orderlineid, folderPath: folderPath, fileName : fileName});
                });

                $.ajax({
                    url: '@Url.Action("StartWorkflow","OrderLines")',
                    type: "post", //<------------- this is important
                    data: { model: list }, //<------------- this is important
                    beforeSend: function (xhr) {//<--- This is important
                      xhr.setRequestHeader("RequestVerificationToken",
                      $('input:hidden[name="__RequestVerificationToken"]').val());
                      showPreloader();
                    },
                    success: function (data) {

                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {

                    },
                     complete: function () {
                         hidePreloader();
                    }
                });
            }
        }

Acción MVC:

[HttpPost]
[ValidateAntiForgeryToken] //<--- This is important
public async Task<IActionResult> StartWorkflow(IEnumerable<WorkflowModel> model)

Y MODELO en C #:

public class WorkflowModel
 {
        public int OrderId { get; set; }
        public int OrderLineId { get; set; }
        public bool IsCustomOrderLine { get; set; }
        public string FolderPath { get; set; }
        public string FileName { get; set; }
 }

CONCLUSIÓN:

El motivo del ERROR:

"Failed to load resource: the server responded with a status of 400 (Bad Request)"

Es atributo: [ValidateAntiForgeryToken]para la acción MVCStartWorkflow

Solución en llamada Ajax:

  beforeSend: function (xhr) {//<--- This is important
                      xhr.setRequestHeader("RequestVerificationToken",
                      $('input:hidden[name="__RequestVerificationToken"]').val());
                    },

Para enviar la Lista de objetos, debe formar datos como en el ejemplo (objeto de lista de llenado) y:

datos: {modelo: lista},

tipo: "publicación",

cosquilleo
fuente
0

Así es como me funciona bien:

var things = [
    { id: 1, color: 'yellow' },
    { id: 2, color: 'blue' },
    { id: 3, color: 'red' }
];

$.ajax({
    ContentType: 'application/json; charset=utf-8',
    dataType: 'json',
    type: 'POST',
    url: '/Controller/action',
    data: { "things": things },
    success: function () {
        $('#result').html('"PassThings()" successfully called.');
    },
    error: function (response) {
        $('#result').html(response);
    }
});

Con "ContentType" en mayúscula "C".

Mixomatosis
fuente