¿Cómo publicar una matriz de objetos complejos con JSON, jQuery en ASP.NET MVC Controller?


92

Mi código actual se parece a lo siguiente. ¿Cómo puedo pasar mi matriz al controlador y qué tipo de parámetros debe aceptar la acción de mi controlador?

function getplaceholders() {
    var placeholders = $('.ui-sortable');
    var result = new Array();
    placeholders.each(function() {
        var ph = $(this).attr('id');
        var sections = $(this).find('.sort');
        var section;

        sections.each(function(i, item) {
            var sid = $(item).attr('id');

            result.push({ 'SectionId': sid, 'Placeholder': ph, 'Position': i });
        });
    });
    alert(result.toString());
    $.post(
        '/portal/Designer.mvc/SaveOrUpdate',
        result,
        function(data) {
            alert(data.Result);
        }, "json");
};

El método de acción de mi controlador parece

public JsonResult SaveOrUpdate(IList<PageDesignWidget> widgets)

Respuestas:


84

Encontré una solución. Utilizo una solución de Steve Gentile, jQuery y ASP.NET MVC: envío de JSON a una acción: revisado .

Mi código de vista ASP.NET MVC se ve así:

function getplaceholders() {
        var placeholders = $('.ui-sortable');
        var results = new Array();
        placeholders.each(function() {
            var ph = $(this).attr('id');
            var sections = $(this).find('.sort');
            var section;

            sections.each(function(i, item) {
                var sid = $(item).attr('id');
                var o = { 'SectionId': sid, 'Placeholder': ph, 'Position': i };
                results.push(o);
            });
        });
        var postData = { widgets: results };
        var widgets = results;
        $.ajax({
            url: '/portal/Designer.mvc/SaveOrUpdate',
            type: 'POST',
            dataType: 'json',
            data: $.toJSON(widgets),
            contentType: 'application/json; charset=utf-8',
            success: function(result) {
                alert(result.Result);
            }
        });
    };

y la acción de mi controlador está decorada con un atributo personalizado

[JsonFilter(Param = "widgets", JsonDataType = typeof(List<PageDesignWidget>))]
public JsonResult SaveOrUpdate(List<PageDesignWidget> widgets

El código para el atributo personalizado se puede encontrar aquí (el enlace ahora está roto).

Debido a que el enlace está roto, este es el código para JsonFilterAttribute

public class JsonFilter : ActionFilterAttribute
{
    public string Param { get; set; }
    public Type JsonDataType { get; set; }
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
        {
            string inputContent;
            using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
            {
                inputContent = sr.ReadToEnd();
            }
            var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
            filterContext.ActionParameters[Param] = result;
        }
    }
}

JsonConvert.DeserializeObject es de Json.NET

Enlace: serializar y deserializar JSON con Json.NET


Se ve muy bien: la publicación del blog y los enlaces del código de atributo personalizado ya no funcionan, ¿puede volver a publicar?
— littlechris

4
Esta solución requiere cambios en el lado del cliente y del servidor. Sé que necesitabas esto hace mucho tiempo, pero también puedo proporcionar un enlace a un enfoque diferente, que usa un complemento jQuery simple que hace posible convertir cualquier objeto Javascript en un formulario que el enlazador de modelos predeterminado entiende y el modelo se une a los parámetros. No se necesitan filtros. erraticdev.blogspot.com/2010/12/… No sé cómo resolvió los errores de validación, pero también tengo una solución para eso: erraticdev.blogspot.com/2010/11/…
— Robert Koritnik

3
¿Puede dar la fuente / origen de JavaScriptConvert.DeserializeObject?
— Matthieu

Es la biblioteca Newtonsoft Json: si abre el administrador de paquetes nuget y busca en Newtonsoft, se mostrará (ahora que es 2016). Probablemente esto ahora sea obvio, pero en caso de que alguien se lo pregunte.
— Robb Sadler

22

Filtros de acción, jquery stringify, bleh ...

Peter, esta funcionalidad es nativa de MVC. Esa es una de las cosas que hace que MVC sea tan grandioso.

$.post('SomeController/Batch', { 'ids': ['1', '2', '3']}, function (r) {
   ...
});

Y en la accion

[HttpPost]
public ActionResult Batch(string[] ids)
{
}

Funciona de maravilla:

ingrese la descripción de la imagen aquí

Si está usando jQuery 1.4+, entonces desea considerar la configuración del modo tradicional:

jQuery.ajaxSettings.traditional = true;

Como se describe aquí: http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/02/24/jquery-1-4-breaks-asp-net-mvc-actions-with-array-parameters

Esto incluso funciona para objetos complejos. Si está interesado, debe consultar la documentación de MVC sobre Model Binding: http://msdn.microsoft.com/en-us/library/dd410405.aspx


1
Puede que tenga razón, pero el enlazador de modelos JSON es nuevo en MVC3 y la pregunta se hizo en 2008 cuando no se admitía. Vale la pena mencionarlo en su respuesta.
— Piotr Owsiak

3
¿Cómo es este un ejemplo de pasar una matriz de objetos complejos ?
— DuckMaestro

No lo es, pero el ejemplo sigue siendo válido (MVC 3+). Siempre que los nombres de sus parámetros coincidan con el modelo que espera, no tendrá ningún problema.
— J. Mitchell

La clave aquí es crear un objeto JSON con el nombre del parámetro del método ("ids") y luego poner la matriz de objetos complejos dentro de ese. Además, haga que el tercer parámetro sea "verdadero" y se encargará del modo tradicional.
— redwards510

11

En .NET4.5, MVC 5no hay necesidad de widgets.

Javascript:

objeto en JS: ingrese la descripción de la imagen aquí

mecanismo que hace publicar.

    $('.button-green-large').click(function() {
        $.ajax({
            url: 'Quote',
            type: "POST",
            dataType: "json",
            data: JSON.stringify(document.selectedProduct),
            contentType: 'application/json; charset=utf-8',
        });
    });

C#

Objetos:

public class WillsQuoteViewModel
{
    public string Product { get; set; }

    public List<ClaimedFee> ClaimedFees { get; set; }
}

public partial class ClaimedFee //Generated by EF6
{
    public long Id { get; set; }
    public long JourneyId { get; set; }
    public string Title { get; set; }
    public decimal Net { get; set; }
    public decimal Vat { get; set; }
    public string Type { get; set; }

    public virtual Journey Journey { get; set; }
}

Controlador:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Quote(WillsQuoteViewModel data)
{
....
}

Objeto recibido:

ingrese la descripción de la imagen aquí

Espero que esto te ahorre algo de tiempo.


8

Hacia la segunda mitad de Create REST API usando ASP.NET MVC que habla tanto JSON como XML simple , para citar:

Ahora necesitamos aceptar la carga útil JSON y XML, entregada a través de HTTP POST. A veces, es posible que su cliente desee cargar una colección de objetos de una sola vez para el procesamiento por lotes. Por lo tanto, pueden cargar objetos usando formato JSON o XML. No hay soporte nativo en ASP.NET MVC para analizar automáticamente JSON o XML publicado y mapear automáticamente los parámetros de acción. Entonces, escribí un filtro que lo hace ".

Luego implementa un filtro de acción que mapea el JSON a objetos C # con el código mostrado.


Solo estaba escribiendo mi respuesta. Pero lo publicaré de todos modos ;-)
— JSC

7

Primero descargue este código JavaScript, JSON2.js , que nos ayudará a serializar el objeto en una cadena.

En mi ejemplo, estoy publicando las filas de un jqGrid a través de Ajax:

    var commissions = new Array();
    // Do several row data and do some push. In this example is just one push.
    var rowData = $(GRID_AGENTS).getRowData(ids[i]);
    commissions.push(rowData);
    $.ajax({
        type: "POST",
        traditional: true,
        url: '<%= Url.Content("~/") %>' + AREA + CONTROLLER + 'SubmitCommissions',
        async: true,
        data: JSON.stringify(commissions),
        dataType: "json",
        contentType: 'application/json; charset=utf-8',
        success: function (data) {
            if (data.Result) {
                jQuery(GRID_AGENTS).trigger('reloadGrid');
            }
            else {
                jAlert("A problem ocurred during updating", "Commissions Report");
            }
        }
    });

Ahora en el controlador:

    [HttpPost]
    [JsonFilter(Param = "commissions", JsonDataType = typeof(List<CommissionsJs>))]
    public ActionResult SubmitCommissions(List<CommissionsJs> commissions)
    {
        var result = dosomething(commissions);
        var jsonData = new
        {
            Result = true,
            Message = "Success"
        };
        if (result < 1)
        {
            jsonData = new
            {
                Result = false,
                Message = "Problem"
            };
        }
        return Json(jsonData);
    }

Cree una clase JsonFilter (gracias a la referencia JSC).

    public class JsonFilter : ActionFilterAttribute
    {
        public string Param { get; set; }
        public Type JsonDataType { get; set; }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
            {
                string inputContent;
                using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
                {
                    inputContent = sr.ReadToEnd();
                }
                var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
                filterContext.ActionParameters[Param] = result;
            }
        }
    }

Cree otra clase para que el filtro pueda analizar la cadena JSON hasta el objeto manipulable real: esta clase comissionsJS son todas las filas de mi jqGrid.

    public class CommissionsJs
    {
        public string Amount { get; set; }

        public string CheckNumber { get; set; }

        public string Contract { get; set; }
        public string DatePayed { get; set; }
        public string DealerName { get; set; }
        public string ID { get; set; }
        public string IdAgentPayment { get; set; }
        public string Notes { get; set; }
        public string PaymentMethodName { get; set; }
        public string RowNumber { get; set; }
        public string AgentId { get; set; }
    }

Espero que este ejemplo ayude a ilustrar cómo publicar un objeto complejo.


0

Oh Dios mío. No es necesario hacer nada especial. solo en tu sección de publicaciones haz lo siguiente:

    $.post(yourURL,{ '': results})(function(e){ ...}

En el servidor usa esto:

   public ActionResult MethodName(List<yourViewModel> model){...}

este enlace te ayudará a hacerlo ...


-1
    [HttpPost]
    public bool parseAllDocs([FromBody] IList<docObject> data)
    {
        // do stuff

    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.