¿Cómo pasar datos json POST al método Web API como un objeto?

Resuelto Andrus asked hace 11 años • 9 respuestas

La aplicación ASP.NET MVC4 Web API define el método de publicación para guardar al cliente. El cliente se pasa en formato json en el cuerpo de la solicitud POST. El parámetro del cliente en el método de publicación contiene valores nulos para las propiedades.

¿Cómo solucionar este problema para que los datos publicados se pasen como objeto de cliente?

Si es posible, se debe usar el tipo de contenido: application/x-www-form-urlencoded ya que no sé cómo cambiarlo en el método javascript que forma las publicaciones.

Controlador:

public class CustomersController : ApiController {

  public object Post([FromBody] Customer customer)
        {
            return Request.CreateResponse(HttpStatusCode.OK,
            new
            {
                customer = customer
            });
        }
    }
}

public class Customer
    {
        public string company_name { get; set; }
        public string contact_name { get; set; }
     }

Pedido:

POST http://localhost:52216/api/customers HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

{"contact_name":"sdfsd","company_name":"ssssd"}
Andrus avatar Nov 27 '13 02:11 Andrus
Aceptado

EDITAR : 31/10/2017

El mismo código/enfoque funcionará también para Asp.Net Core 2.0 . La principal diferencia es que, en asp.net core, tanto los controladores web api como los controladores Mvc se fusionan en un modelo de controlador único. Entonces su tipo de devolución podría ser IActionResulto una de sus implementaciones (Ejemplo OkObjectResult:)


Usar

contentType:"application/json"

Debe utilizar JSON.stringifyun método para convertirlo a una cadena JSON cuando lo envíe.

Y la carpeta de modelos vinculará los datos json a su objeto de clase.

El siguiente código funcionará bien (probado)

$(function () {
    var customer = {contact_name :"Scott",company_name:"HP"};
    $.ajax({
        type: "POST",
        data :JSON.stringify(customer),
        url: "api/Customer",
        contentType: "application/json"
    });
});

Resultado

ingrese la descripción de la imagen aquí

contentTypeLa propiedad le dice al servidor que estamos enviando los datos en formato JSON. Dado que enviamos una estructura de datos JSON, el enlace del modelo se realizará correctamente.

Si inspecciona los encabezados de la solicitud ajax, puede ver que el Content-Typevalor está establecido como application/json.

Si no especifica contentType explícitamente, utilizará el tipo de contenido predeterminado que esapplication/x-www-form-urlencoded;


Edite en noviembre de 2015 para abordar otros posibles problemas planteados en los comentarios.

Publicar un objeto complejo

Digamos que tiene una clase de modelo de vista compleja como parámetro del método de acción de su API web como este

public class CreateUserViewModel
{
   public int Id {set;get;}
   public string Name {set;get;}  
   public List<TagViewModel> Tags {set;get;}
}
public class TagViewModel
{
  public int Id {set;get;}
  public string Code {set;get;}
}

y el punto final de su API web es como

public class ProductController : Controller
{
    [HttpPost]
    public CreateUserViewModel Save([FromBody] CreateUserViewModel m)
    {
        // I am just returning the posted model as it is. 
        // You may do other stuff and return different response.
        // Ex : missileService.LaunchMissile(m);
        return m;
    }
}

Al momento de escribir este artículo, ASP.NET MVC 6 es la última versión estable y en MVC6, tanto los controladores de API web como los controladores MVC heredan de la Microsoft.AspNet.Mvc.Controllerclase base.

Para enviar datos al método desde el lado del cliente, el siguiente código debería funcionar bien

//Build an object which matches the structure of our view model class
var model = {
    Name: "Shyju",
    Id: 123,
    Tags: [{ Id: 12, Code: "C" }, { Id: 33, Code: "Swift" }]
};

$.ajax({
    type: "POST",
    data: JSON.stringify(model),
    url: "../product/save",
    contentType: "application/json"
}).done(function(res) {       
    console.log('res', res);
    // Do something with the result :)
});

La vinculación de modelos funciona para algunas propiedades, ¡pero no para todas! Por qué ?

Si no decora el parámetro del método de API web con [FromBody]atributo

[HttpPost]
public CreateUserViewModel Save(CreateUserViewModel m)
{
    return m;
}

Y envíe el modelo (objeto javascript sin formato, no en formato JSON) sin especificar el valor de la propiedad contentType

$.ajax({
    type: "POST",
    data: model,
    url: "../product/save"
}).done(function (res) {
     console.log('res', res);
});

El enlace de modelo funcionará para las propiedades planas del modelo, no para las propiedades donde el tipo es complejo/otro tipo. En nuestro caso, las propiedades Idy Nameestarán vinculadas correctamente al parámetro m, pero la Tagspropiedad será una lista vacía.

El mismo problema ocurrirá si está utilizando la versión corta, $.postque utilizará el tipo de contenido predeterminado al enviar la solicitud.

$.post("../product/save", model, function (res) {
    //res contains the markup returned by the partial view
    console.log('res', res);
});
Shyju avatar Nov 26 '2013 19:11 Shyju

¡Trabajar con POST en webapi puede ser complicado! Me gustaría agregar a la respuesta ya correcta.

Se centrará específicamente en POST ya que lidiar con GET es trivial. No creo que muchos busquen resolver un problema con GET con webapis. De todos modos..

Si su pregunta es: En MVC Web Api, ¿cómo? ¿Usar nombres de métodos de acción personalizados distintos de los verbos HTTP genéricos? - ¿Realizar múltiples publicaciones? - ¿Publicar varios tipos simples? - ¿Publicar tipos complejos a través de jQuery?

Entonces las siguientes soluciones pueden ayudar:

Primero, para utilizar métodos de acción personalizados en la API web, agregue una ruta de API web como:

public static void Register(HttpConfiguration config)
{
    config.Routes.MapHttpRoute(
        name: "ActionApi",
        routeTemplate: "api/{controller}/{action}");
}

Y luego puedes crear métodos de acción como:

[HttpPost]
public string TestMethod([FromBody]string value)
{
    return "Hello from http post web api controller: " + value;
}

Ahora, active el siguiente jQuery desde la consola de su navegador.

$.ajax({
    type: 'POST',
    url: 'http://localhost:33649/api/TestApi/TestMethod',
    data: {'':'hello'},
    contentType: 'application/x-www-form-urlencoded',
    dataType: 'json',
    success: function(data){ console.log(data) }
});

En segundo lugar, para realizar múltiples publicaciones , es simple: cree múltiples métodos de acción y decore con el atributo [HttpPost]. Utilice [ActionName("MyAction")] para asignar nombres personalizados, etc. Llegará a jQuery en el cuarto punto a continuación.

En tercer lugar, en primer lugar, no es posible publicar varios tipos SIMPLES en una sola acción. Además, existe un formato especial para publicar incluso un solo tipo simple (aparte de pasar el parámetro en la cadena de consulta o estilo REST). Este fue el punto que me hizo golpearme la cabeza con Rest Clients (como Fiddler y la extensión de cliente REST avanzada de Chrome) y buscar en la web durante casi 5 horas cuando, finalmente, la siguiente URL resultó ser de ayuda. ¡Citaremos el contenido relevante porque el enlace podría quedar inactivo!

Content-Type: application/x-www-form-urlencoded
in the request header and add a = before the JSON statement:
={"Name":"Turbo Tina","Email":"[email protected]"}

PD: ¿Notaste la sintaxis peculiar ?

http://forums.asp.net/t/1883467.aspx?El+valor+recibido+es+nulo+cuando+intento+publicar+en+mi+Api+Web

De todos modos, superemos esa historia. Hacia adelante:

Cuarto, al publicar tipos complejos a través de jQuery, por supuesto, $.ajax() asumirá rápidamente el rol:

Digamos que el método de acción acepta un objeto Persona que tiene una identificación y un nombre. Entonces, desde javascript:

var person = { PersonId:1, Name:"James" }
$.ajax({
    type: 'POST',
    url: 'http://mydomain/api/TestApi/TestMethod',
    data: JSON.stringify(person),
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function(data){ console.log(data) }
});

Y la acción se verá así:

[HttpPost]
public string TestMethod(Person person)
{
    return "Hello from http post web api controller: " + person.Name;
}

¡Todo lo anterior funcionó para mí! ¡Salud!

Vaibhav avatar Mar 19 '2014 05:03 Vaibhav

Estuve jugando con esto y descubrí un resultado bastante extraño. Digamos que tienes propiedades públicas en tu clase en C# como esta:

public class Customer
{
    public string contact_name;
    public string company_name;
}

entonces debes hacer el truco JSON.stringify como lo sugiere Shyju y llamarlo así:

var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
    type: "POST",
    data :JSON.stringify(customer),
    url: "api/Customer",
    contentType: "application/json"
});

Sin embargo, si define captadores y definidores en su clase de esta manera:

public class Customer
{
    public string contact_name { get; set; }
    public string company_name { get; set; }
}

entonces puedes llamarlo de manera mucho más simple:

$.ajax({
    type: "POST",
    data :customer,
    url: "api/Customer"
});

Esto utiliza el encabezado HTTP:

Content-Type:application/x-www-form-urlencoded

No estoy muy seguro de lo que está pasando aquí, pero parece un error (¿característica?) en el marco. Presumiblemente, los diferentes métodos de enlace llaman a diferentes "adaptadores", y aunque el adaptador para aplicación/json funciona con propiedades públicas, el de datos codificados en formato no lo hace.

Sin embargo, no tengo idea de cuál se consideraría la mejor práctica.

Andy avatar Apr 21 '2015 15:04 Andy

Utilice JSON.stringify() para obtener la cadena en formato JSON, asegúrese de que al realizar la llamada AJAX pase los atributos mencionados a continuación:

  • tipo de contenido: 'aplicación/json'

A continuación se muestra el código jquery para realizar una llamada posterior ajax a la API web de asp.net:

var product =
    JSON.stringify({
        productGroup: "Fablet",
        productId: 1,
        productName: "Lumia 1525 64 GB",
        sellingPrice: 700
    });

$.ajax({
    URL: 'http://localhost/api/Products',
    type: 'POST',
    contentType: 'application/json',
    data: product,
    success: function (data, status, xhr) {
        alert('Success!');
    },
    error: function (xhr, status, error) {
        alert('Update Error occurred - ' + error);
    }
});
Expandir fragmento

Dilip Nannaware avatar Oct 02 '2015 23:10 Dilip Nannaware