Forma correcta de usar AJAX Post en jquery para pasar el modelo desde la vista MVC3 fuertemente tipada

100

Soy un programador web novato, así que perdóneme si parte de mi "jerga" no es correcta. Tengo un proyecto que usa ASP.NET usando el marco MVC3.

Estoy trabajando en una vista de administrador donde el administrador modificará una lista de equipos. Una de las funciones es un botón "actualizar" que quiero usar jquery para editar dinámicamente la entrada en la página web después de enviar una publicación al controlador MVC.

Supongo que este enfoque es "seguro" en una única configuración de administrador donde existe una mínima preocupación de que la página web no esté sincronizada con la base de datos.

Creé una vista fuertemente tipada y esperaba pasar los datos del modelo al control MVC usando una publicación AJAX.

En la siguiente publicación, encontré algo similar a lo que estoy buscando hacer: JQuery Ajax y ASP.NET MVC3 que causan parámetros nulos

Usaré el ejemplo de código de la publicación anterior.

Modelo:

public class AddressInfo 
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}

Controlador:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Check(AddressInfo addressInfo)
    {
        return Json(new { success = true });
    }
}

secuencia de comandos en vista:

<script type="text/javascript">
var ai = {
    Address1: "423 Judy Road",
    Address2: "1001",
    City: "New York",
    State: "NY",
    ZipCode: "10301",
    Country: "USA"
};

$.ajax({
    url: '/home/check',
    type: 'POST',
    data: JSON.stringify(ai),
    contentType: 'application/json; charset=utf-8',
    success: function (data.success) {
        alert(data);
    },
    error: function () {
        alert("error");
    }
});
</script>

Todavía no he tenido la oportunidad de usar lo anterior. Pero me preguntaba si este era el "mejor" método para pasar los datos del modelo al control MVC usando AJAX.

¿Debería preocuparme por exponer la información del modelo?

John Stone
fuente

Respuestas:

72

Puede omitir la declaración var y stringify. De lo contrario, funcionará bien.

$.ajax({
    url: '/home/check',
    type: 'POST',
    data: {
        Address1: "423 Judy Road",
        Address2: "1001",
        City: "New York",
        State: "NY",
        ZipCode: "10301",
        Country: "USA"
    },
    contentType: 'application/json; charset=utf-8',
    success: function (data) {
        alert(data.success);
    },
    error: function () {
        alert("error");
    }
});
Craig M
fuente
Gracias por señalar el ligero ajuste. ¿Existe alguna preocupación por exponer la estructura del modelo desde el punto de vista de la seguridad?
John Stone
Para mí, nada llamativo es un problema de seguridad. Sin embargo, si realmente le preocupa, siempre puede hacer una carpeta de modelos personalizada en el lado de mvc.
Craig M
8
Esto me falló. Tuve que usar JSON.stringify ({...}) para que la llamada funcionara en MVC5.
Johncl
Noté que tengo que hacer lo mismo cuando trabajo con controladores API. Sin embargo, esta respuesta se escribió hace 4 años, antes de que existieran los controladores API.
Craig M
1
Dios mío, tenía dataType en lugar de contentType, ¡ese siempre me atrapa!
Phil
175

Encontré 3 formas de implementar esto:

Clase C #:

public class AddressInfo {
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}

Acción:

[HttpPost]
public ActionResult Check(AddressInfo addressInfo)
{
    return Json(new { success = true });
}

JavaScript puede hacerlo de tres formas:

1) Cadena de consulta:

$.ajax({
    url: '/en/Home/Check',
    data: $('#form').serialize(),
    type: 'POST',
});

Los datos aquí son una cadena.

"Address1=blah&Address2=blah&City=blah&State=blah&ZipCode=blah&Country=blah"

2) Matriz de objetos:

$.ajax({
    url: '/en/Home/Check',
    data: $('#form').serializeArray(),
    type: 'POST',
});

Los datos aquí son una matriz de pares clave / valor:

=[{name: 'Address1', value: 'blah'}, {name: 'Address2', value: 'blah'}, {name: 'City', value: 'blah'}, {name: 'State', value: 'blah'}, {name: 'ZipCode', value: 'blah'}, {name: 'Country', value: 'blah'}]

3) JSON:

$.ajax({
      url: '/en/Home/Check',
      data: JSON.stringify({ addressInfo:{//missing brackets
          Address1: $('#address1').val(),
          Address2: $('#address2').val(),
          City: $('#City').val(),
          State: $('#State').val(),
          ZipCode: $('#ZipCode').val()}}),
      type: 'POST',
      contentType: 'application/json; charset=utf-8'
});

Los datos aquí son una cadena JSON serializada. Tenga en cuenta que el nombre debe coincidir con el nombre del parámetro en el servidor.

='{"addressInfo":{"Address1":"blah","Address2":"blah","City":"blah","State":"blah", "ZipCode", "blah", "Country", "blah"}}'
Jazaret
fuente
1
Acabo de encontrar esta excelente y completa respuesta que resolvió preguntas que aún no sabía que tenía. +1, gracias!
SeanKilleen
# 2 era lo que estaba buscando. Esta debería ser la respuesta.
TheGeekZn
EDITAR: tuve que usar data: $('input, textarea, select').serialize(),para que el mío funcionara.
TheGeekZn
¡¡Oye Jazaret !! ¿Cómo pasar la fecha al modelo con el tercer enfoque?
Guruprasad Rao
1
Perdón por la demora @GuruprasadRao Para pasar una fecha, puede hacer que la fecha y la hora sean una cadena en el código javascript y MVC la traducirá a un objeto DateTime.
Jazaret
12

Esta es la forma en que funcionó para mí:

$.post("/Controller/Action", $("#form").serialize(), function(json) {       
        // handle response
}, "json");

[HttpPost]
public ActionResult TV(MyModel id)
{
    return Json(new { success = true });
}
Sanchitos
fuente
8

lo que tiene está bien; sin embargo, para ahorrar algo de escritura, simplemente puede usar para sus datos

datos: $ ('# formId'). serialize ()

consulte http://www.ryancoughlin.com/2009/05/04/how-to-use-jquery-to-serialize-ajax-forms/ para obtener más detalles, la sintaxis es bastante básica.

Adam Tuliper - MSFT
fuente
Para usar la función serializar, tengo entendido que cada miembro de la clase debe usarse en un objeto de formulario. Si eso es correcto, puedo ser SOL.
John Stone
1
ah ya .. si no, no puedes usar serializar entonces. Sin embargo, siempre puede manipular el DOM y crear un formulario con esos elementos y serializarlo, pero ... probablemente sería más limpio tener los campos escritos manualmente en ese momento.
Adam Tuliper - MSFT
@TahaRehmanSiddiqui serialize de hecho funciona en IE, ¿qué no funciona? ¿Le da un error?
Adam Tuliper - MSFT
todas las propiedades de mi modelo salen nulas
Taha Rehman Siddiqui
@TahaRehmanSiddiqui ¿el 'nombre' de los campos de su formulario coincide con los nombres de las propiedades de su modelo?
MongooseNX
0

Si usa MVC 5, lea esta solución.

Sé que la pregunta pedía específicamente MVC 3, pero me topé con esta página con MVC 5 y quería publicar una solución para cualquier otra persona en mi situación. Probé las soluciones anteriores, pero no funcionaron para mí, el Filtro de Acción nunca se alcanzó y no pude entender por qué. Estoy usando la versión 5 en mi proyecto y terminé con el siguiente filtro de acción:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Filters;

namespace SydHeller.Filters
{
    public class ValidateJSONAntiForgeryHeader : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            string clientToken = filterContext.RequestContext.HttpContext.Request.Headers.Get(KEY_NAME);
            if (clientToken == null)
            {
                throw new HttpAntiForgeryException(string.Format("Header does not contain {0}", KEY_NAME));
            }

            string serverToken = filterContext.HttpContext.Request.Cookies.Get(KEY_NAME).Value;
            if (serverToken == null)
            {
                throw new HttpAntiForgeryException(string.Format("Cookies does not contain {0}", KEY_NAME));
            }

            System.Web.Helpers.AntiForgery.Validate(serverToken, clientToken);
        }

        private const string KEY_NAME = "__RequestVerificationToken";
    }
}

- Tome nota de using System.Web.Mvcy using System.Web.Mvc.Filters, no de las httpbibliotecas (creo que esa es una de las cosas que cambió con MVC v5. -

Entonces solo aplica el filtro [ValidateJSONAntiForgeryHeader] a su acción (o controlador) y debería llamarse correctamente.

En mi página de diseño justo arriba </body>tengo@AntiForgery.GetHtml();

Finalmente, en mi página de Razor, hago la llamada ajax de la siguiente manera:

var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();

$.ajax({
  type: "POST",
  url: serviceURL,
  contentType: "application/json; charset=utf-8",
  dataType: "json",
  data: requestData,
  headers: {
     "__RequestVerificationToken": formForgeryToken
  },
     success: crimeDataSuccessFunc,
     error: crimeDataErrorFunc
});
blubberbo
fuente
1
¿Está recuperando todos los valores de su formulario manualmente? ¿Por qué no data: $("#the-form").serialize()?
Sinjai
1
@Sinjai Tendría que mirar mi código nuevamente, pero creo que también estoy haciendo algún otro procesamiento allí. ".serialize ()" también funcionaría si solo necesita los valores de entrada
blubberbo
No te preocupes, solo tenía curiosidad.
Sinjai