Nesne olarak json POST verileri Web API yöntemine nasıl geçirilir?


304

ASP.NET MVC4 Web API uygulaması müşteri kurtarmak için post yöntemini tanımlar. Müşteri POST istek gövdesinde json biçiminde iletilir. Posta yöntemindeki müşteri parametresi, özellikler için boş değerler içeriyor.

Kaydedilen verilerin müşteri nesnesi olarak geçmesi için bunu nasıl düzeltirim?

Mümkünse Content-Type: application / x-www-form-urlencoded kullanılmalıdır çünkü formun hangi javascript yönteminde değiştirileceğini bilmiyorum.

Denetleyici:

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; }
     }

İstek:

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"}

Yanıtlar:


525

DÜZENLEME : 31/10/2017

Aynı kod / yaklaşım Asp.Net Core 2.0 için de geçerli olacaktır. En büyük fark, asp.net çekirdeğinde, hem web api denetleyicileri hem de Mvc denetleyicileri tek denetleyici modeliyle birleştirilir. Dönüş tipi olabilir Yani IActionResult's uygulaması bir veya (Ex: OkObjectResult)


kullanım

contentType:"application/json"

JSON.stringifyGönderirken JSON dizesine dönüştürmek için yöntem kullanmanız gerekir,

Ve model bağlayıcı, json verilerini sınıf nesnenize bağlayacaktır.

Aşağıdaki kod iyi çalışır (test edilmiştir)

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

Sonuç

resim açıklamasını buraya girin

contentTypeözelliği sunucuya verileri JSON biçiminde gönderdiğimizi bildirir. Bir JSON veri yapısı gönderdiğimizden, model bağlama düzgün bir şekilde gerçekleşecektir.

Ajax isteğinin üstbilgilerini incelerseniz, Content-Typedeğerin olarak ayarlandığını görebilirsiniz application/json.

ContentType'ı açıkça belirtmezseniz, varsayılan içerik türünü kullanır. application/x-www-form-urlencoded;


Yorumlarda dile getirilen diğer olası sorunları ele almak için Kasım 2015'te düzenleyin

Karmaşık bir nesne gönderme

Diyelim ki web api eylem yöntemi parametreniz gibi karmaşık bir görünüm model sınıfınız var.

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;}
}

ve web api uç noktanız

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;
    }
}

Bu yazma sırasında, ASP.NET MVC 6 en son kararlı sürümdür ve MVC6'da, hem Web api denetleyicileri hem de MVC denetleyicileri Microsoft.AspNet.Mvc.Controllertemel sınıftan miras alır .

Yönteme istemci tarafından veri göndermek için aşağıdaki kodun iyi çalışması gerekir

//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 :)
});

Model bağlama bazı özellikler için çalışır, ancak hepsi için geçerli değildir! Neden ?

Web api yöntemi parametresini [FromBody]öznitelikle süslemezseniz

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

Ve contentType özellik değerini belirtmeden modeli (JSON biçiminde değil ham javascript nesnesi) gönderin

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

Model bağlama, türün karmaşık olduğu özellikler / başka bir tür için değil, modeldeki düz özellikler için çalışır. Bizim durumumuzda Idve Nameözellikleri parametreye uygun şekilde bağlanacaktır m, ancak Tagsözellik boş bir liste olacaktır.

$.postİsteği gönderirken varsayılan İçerik Türü'nü kullanacak olan kısa sürümü kullanıyorsanız aynı sorun ortaya çıkar .

$.post("../product/save", model, function (res) {
    //res contains the markup returned by the partial view
    console.log('res', res);
});

4
Ne yaptığımdan emin değilim, ama bu sabah ve aynı tekneye geri döndüm. Denetleyicide nesne null. işte yine gidiyoruz lol
Grayson

1
kemancı kullanırken içerik türünün "Content-Type: application / json" yazıldığından emin olun. Şerefe!
ioWint

1
Bana bir iş günü çözdün !!! Bu küçük işlevi "JSON.stringify (veri)" yaptı!
Gil Allen

1
Bunu yaparsanız (İçerik Türü başlığını değiştirirseniz) ve bir CORS isteğinde bulunursanız, jQuery, sunucunuzun işlemesi gereken POST'unuzdan önce ön kontrol SEÇENEKLERİ istekleri eklemeye başlayacağını unutmayın.
Hakem

1
Karmaşık tiplerle ilgili sorun nedeniyle, sadece 'contentType:' application / json; ' ve json js nesnesini dizgi yapar ve sonra [FromBody] özniteliğini kullanmaya gerek yoktur.
BornToCode

69

Webapi'de POST ile çalışmak zor olabilir! Zaten doğru cevaba eklemek istiyorum ..

GET ile ilgilenmek önemsiz olduğu için özellikle POST'a odaklanacaktır. Pek çok kişinin webapis ile GET ile ilgili bir sorunu çözmek için arama yapacağını düşünmüyorum. Neyse..

Sorunuz - MVC Web Api'de, genel HTTP fiilleri dışında özel eylem yöntemi adları nasıl kullanılır? - Birden fazla yayın mı yapıyorsunuz? - Birden fazla basit tür yayınlamak? - Karmaşık türleri jQuery ile mi gönderirsiniz?

Daha sonra aşağıdaki çözümler yardımcı olabilir:

İlk olarak, Web API'sında Özel İşlem Yöntemleri'ni kullanmak için , bir web API yolu ekleyin:

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

Ve sonra aşağıdaki gibi eylem yöntemleri oluşturabilirsiniz:

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

Şimdi tarayıcı konsolunuzdan aşağıdaki jQuery'yi çalıştırın

$.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) }
});

İkinci olarak, birden çok yazı gerçekleştirmek için , basit, birden fazla eylem yöntemi oluşturmak ve [HttpPost] özniteliği ile süsleyin. Özel adlar vb. Atamak için [ActionName ("MyAction")] kullanın. Aşağıdaki dördüncü noktada jQuery'ye gelecek

Üçüncüsü, Her şeyden önce, tek bir eylemde birden çok BASİT tipinin yayınlanması mümkün değildir. Dahası, tek bir basit tür bile (parametreyi sorgu dizesinde veya REST stilinde iletmek dışında) göndermek için özel bir format vardır . Geri kalan müşterilerle (Fiddler ve Chrome'un Gelişmiş REST istemci uzantısı gibi) kafamı vurmamı ve sonunda yaklaşık 5 saat boyunca web'de avlanmamı sağlayan nokta, aşağıdaki URL'nin yardımcı olduğu kanıtlandı. Bağlantı için ilgili içeriği öldürebilir alıntı olacak!

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

PS: Tuhaf sözdizimini fark ettiniz mi?

http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api

Her neyse, bu hikayeyi aşalım. Hareketli:

Dördüncüsü, jQuery, ofcourse, $ .ajax () yoluyla karmaşık türler göndermek derhal devreye girecek:

Eylem yönteminin kimliği ve adı olan bir Person nesnesini kabul ettiğini varsayalım. Javascript'ten:

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) }
});

Ve eylem şöyle görünecek:

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

Yukarıdakilerin hepsi, benim için çalıştı! Şerefe!


2
Bu sorunu birkaç ayda bir vuruyorum, çoğu zaman sonunda çözdüm, ama bu sefer vazgeçtim. Yukarıdaki ipuçlarından hiçbiri benim için çözmedi, bu yüzden bunu bir yaklaşım olarak koymaya karar verdim. Doğruyu bulmak çok zorsa neden rahatsız oluyorsun? Zaten bu sadece bir kolaylık - içeriği bir dize olarak alın ve dönüştürmek için newtonsoft kullanın. Bitti. "Kolay" bir şekilde çözmek için yaklaşık bir saat denedikten sonra "zor" bir şekilde çözmek için muhtemelen 30 saniye sürdü. Yaklaşım konusunda çılgın değilim, ancak bununla ilgili temel bir sorun var mı?
Kinetic

Not: WebApi2'de artık Rota Dekoratörleri kullanabiliriz. Dolayısıyla bu konu öncelikle ele alınmıştır. asp.net/web-api/overview/web-api-routing-and-actions/…
Vaibhav

2
Bir gözlem eklemek ister misiniz? Bazen, karmaşık bir tür (ör: DTO) iletilirken model bağlamanın WebAPI tarafında başarısız olmasının (null) nedeni, modeldeki bir veya daha fazla özelliğin uyumsuz (veya ayrıştırılamaması) olmasıdır. Örneğin. Geçersiz bir GUID atanan bir Guid özelliğine. Bu durumda, tüm nesne özellikleri için varsayılan / boş değerleri kullanmayı deneyin ve tekrar deneyin.
Vaibhav

10

Sadece bununla oynadım ve oldukça garip bir sonuç keşfettim. Diyelim ki sınıfınızda C # gibi genel mülkleriniz var:

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

o zaman Shyju tarafından önerildiği gibi JSON.stringify hile yapmalı ve şöyle çağırmalısınız:

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

Ancak, sınıfınızdaki alıcıları ve ayarlayıcıları şu şekilde tanımlarsanız:

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

o zaman çok daha basit bir şekilde arayabilirsiniz:

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

HTTP üstbilgisini kullanır:

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

Burada neler olduğundan emin değilim ama çerçevede bir hata (özellik?) Gibi görünüyor. Muhtemelen farklı bağlama yöntemleri farklı "bağdaştırıcılar" olarak adlandırılır ve application / json one için bağdaştırıcı genel özelliklerle çalışırken form kodlu veriler için olan bağdaştırıcıyı kullanmaz.

Hangisinin en iyi uygulama olacağı konusunda hiçbir fikrim yok.


6
Özellikler ve alanlar neden farklıdır. Özellikler en iyi uygulamadır. Bu ilk örnekte özellikler dediğiniz şey aslında alanlar. Onlara bir get / set koyduğunuzda, otomatik olarak oluşturulan bir destek alanına sahip olurlar.
paqogomez

Bu çok doğru ve tuhaf. Yalnızca alanları olan normal sınıflar form yayınlarına bağlanmaz, ancak özellikler yayınlanır. BTW: Neden böyle olduğunu açıklamıyor ...? Ben sadece dahili mantık sadece alanlara JSON verileri bağlar ve özelliklere yazı verileri oluşturmak tahmin edebilir, ve bu sadece ...?
James Wilkins

1
Bu durum, kodun yalnızca özellikleri aradığı için geçerlidir. Kamusal alanları kullanmak en iyi uygulama olmadığından , MS ekibi en iyi uygulama senaryolarına izin vermemeye karar verdi , IMHO'nun oldukça iyi bir nedeni.
Erik Philips

1

Dizeyi JSON biçiminde almak için JSON.stringify () yöntemini kullanın, AJAX çağrısı yaparken belirtilen özelliklerin altına geçtiğinizden emin olun:

  • contentType: 'application / json'

Aşağıda asp.net web api ajax sonrası çağrı yapmak için jquery kodu vermek:

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);
    }
});


2
dataType gerekli değildir.
Erik Philips

0

WebAPI hizmetinizin, geçmekte olduğunuz JSON ile eşleşen bir yapıya sahip güçlü yazılan bir nesne beklediğinden emin olun. Ve POST yapmakta olduğunuz JSON dize emin olun.

İşte benim JavaScript (AngluarJS kullanarak):

$scope.updateUserActivity = function (_objuserActivity) {
        $http
        ({
            method: 'post',
            url: 'your url here',
            headers: { 'Content-Type': 'application/json'},
            data: JSON.stringify(_objuserActivity)
        })
        .then(function (response)
        {
            alert("success");
        })
        .catch(function (response)
        {
            alert("failure");
        })
        .finally(function ()
        {
        });

Ve işte benim WebAPI Denetleyicim:

[HttpPost]
[AcceptVerbs("POST")]
public string POSTMe([FromBody]Models.UserActivity _activity)
{
    return "hello";
}

0

Verileri xml -Web API 2 yerine json biçiminde döndürmek için aşağıdaki kod: -

Global.asax dosyasına aşağıdaki satırı koy

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

0
@model MVCClient.Models.ProductDetails

@{
    ViewBag.Title = "ProductDetails";
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript">

    $(document).ready(function () {
        $("#Save").click(function () {
            var ProductDetails = new Object();
            ProductDetails.ProductName =  $("#txt_productName").val();
            ProductDetails.ProductDetail = $("#txt_desc").val();
            ProductDetails.Price= $("#txt_price").val();
            $.ajax({
                url: "http://localhost:24481/api/Product/addProduct",
                type: "Post",
                dataType:'JSON',
                data:ProductDetails, 

                success: function (data) {
                    alert('Updated Successfully');
                    //window.location.href = "../Index";
                },
                error: function (msg) { alert(msg); }
            });
        });
    });
    </script>
<h2>ProductDetails</h2>

<form id="form1" method="post">
    <fieldset>
        <legend>ProductDetails</legend>


        <div class="editor-label">
            @Html.LabelFor(model => model.ProductName)
        </div>
        <div class="editor-field">

            <input id="txt_productName" type="text" name="fname">
            @Html.ValidationMessageFor(model => model.ProductName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductDetail)
        </div>
        <div class="editor-field">

            <input id="txt_desc" type="text" name="fname">
            @Html.ValidationMessageFor(model => model.ProductDetail)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">

            <input id="txt_price" type="text" name="fname">
            @Html.ValidationMessageFor(model => model.Price)
        </div>



        <p>
            <input id="Save" type="button" value="Create" />
        </p>
    </fieldset>

</form>
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>

</form>



@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}


0

1) müşteri tarafında size aşağıdaki gibi dize http.post isteği gönderebilirsiniz

var IndexInfo = JSON.stringify(this.scope.IndexTree);
this.$http.post('../../../api/EvaluationProcess/InsertEvaluationProcessInputType', "'" + IndexInfo + "'" ).then((response: any) => {}

2) Daha sonra web api kontrol cihazınızda serisini kaldırabilirsiniz

public ApiResponce InsertEvaluationProcessInputType([FromBody]string IndexInfo)
    {
var des = (ApiReceivedListOfObjects<TempDistributedIndex>)Newtonsoft.Json.JsonConvert.DeserializeObject(DecryptedProcessInfo, typeof(ApiReceivedListOfObjects<TempDistributedIndex>));}

3) ApiReceivedListOfObjects sınıfınız aşağıdaki gibi olmalıdır

public class ApiReceivedListOfObjects<T>
    {
        public List<T> element { get; set; }

    }

4) adım 2'de JsonConvert.DeserializeObject komutundan önce serileştirilmiş dizenizin (burada IndexInfo) aşağıdaki yapıya benzediğinden emin olun

var resp = @"
    {
        ""element"": [
        {
            ""A"": ""A Jones"",
            ""B"": ""500015763""
        },
        {
            ""A"": ""B Smith"",
            ""B"": ""504986213""
        },
        {
            ""A"": ""C Brown"",
            ""B"": ""509034361""
        }
        ]
    }";
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.