Bagaimana cara mengirimkan data POST json ke metode API Web sebagai objek?

304

Aplikasi ASP.NET MVC4 Web API mendefinisikan metode posting untuk menyelamatkan pelanggan. Pelanggan diteruskan dalam format json di badan permintaan POST. Parameter pelanggan dalam metode posting berisi nilai null untuk properti.

Bagaimana cara memperbaikinya sehingga data yang diposting akan dikirimkan sebagai objek pelanggan?

Jika memungkinkan Content-Type: application / x-www-form-urlencoded harus digunakan karena saya tidak tahu bagaimana mengubahnya dalam metode javascript yang memposting bentuk.

Pengendali:

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

Permintaan:

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
sumber

Jawaban:

525

EDIT : 31/10/2017

Kode / pendekatan yang sama juga akan bekerja untuk Asp.Net Core 2.0 . Perbedaan utama adalah, Pada inti asp.net, baik pengontrol api web dan pengontrol Mvc digabung bersama menjadi model pengontrol tunggal. Jadi jenis laba mungkin IActionResultatau salah satu dari itu implementasi (Ex: OkObjectResult)


Menggunakan

contentType:"application/json"

Anda perlu menggunakan JSON.stringifymetode untuk mengubahnya menjadi string JSON ketika Anda mengirimnya,

Dan pengikat model akan mengikat data json ke objek kelas Anda.

Kode di bawah ini akan berfungsi dengan baik (diuji)

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

Hasil

masukkan deskripsi gambar di sini

contentTypeproperti memberi tahu server bahwa kami mengirim data dalam format JSON. Karena kami mengirim struktur data JSON, pengikatan model akan terjadi dengan benar.

Jika Anda memeriksa tajuk permintaan ajax, Anda dapat melihat bahwa Content-Typenilainya ditetapkan sebagai application/json.

Jika Anda tidak menentukan tipe konten secara eksplisit, itu akan menggunakan tipe konten default yang application/x-www-form-urlencoded;


Edit pada November 2015 untuk mengatasi masalah lain yang mungkin muncul dalam komentar

Posting objek yang kompleks

Katakanlah Anda memiliki kelas model tampilan kompleks sebagai parameter metode aksi api web Anda seperti ini

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

dan titik api web Anda seperti

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

Pada saat penulisan ini, ASP.NET MVC 6 adalah versi stabil terbaru dan di MVC6, Baik pengendali api web dan pengendali MVC mewarisi dari Microsoft.AspNet.Mvc.Controllerkelas dasar.

Untuk mengirim data ke metode dari sisi klien, kode di bawah ini akan berfungsi dengan baik

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

Penjilidan model berfungsi untuk beberapa properti, tetapi tidak semua! Mengapa

Jika Anda tidak menghias parameter metode api web dengan [FromBody]atribut

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

Dan mengirim model (objek javascript mentah, bukan dalam format JSON) tanpa menentukan nilai properti contentType

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

Penjilidan model akan berfungsi untuk properti flat pada model, bukan properti di mana jenisnya kompleks / tipe lain. Dalam kasus kami, Iddan Nameproperti akan terikat dengan benar ke parameter m, Tapi Tagsproperti akan menjadi daftar kosong.

Masalah yang sama akan terjadi jika Anda menggunakan versi pendek, $.postyang akan menggunakan Tipe Konten default saat mengirim permintaan.

$.post("../product/save", model, function (res) {
    //res contains the markup returned by the partial view
    console.log('res', res);
});
Shyju
sumber
4
Tidak yakin apa yang saya lakukan, tetapi saya kembali pagi ini dan kembali dengan perahu yang sama. Objek adalah nol di controller. ini dia lagi lol
Grayson
1
pastikan jenis konten ditulis "Content-Type: application / json" saat Anda menggunakan fiddler. Bersulang!
ioWint
1
Anda hanya menyelesaikan saya sehari kerja !!! Fungsi mungil ini "JSON.stringify (data)" berhasil!
Gil Allen
1
Ingatlah bahwa jika Anda melakukan ini (ubah header Jenis-Konten) dan Anda membuat permintaan CORS, jQuery akan mulai menambahkan permintaan PILIHAN prelight sebelum POST Anda yang harus ditangani oleh server.
Arbiter
1
Karena masalah dengan tipe kompleks saya pikir itu kebiasaan untuk hanya menentukan 'contentType:' application / json; ' dan json merangkai objek js dan kemudian tidak perlu menggunakan atribut [FromBody].
BornToCode
69

Bekerja dengan POST di webapi bisa rumit! Ingin menambahkan ke jawaban yang sudah benar ..

Akan fokus secara khusus pada POST karena berurusan dengan GET itu sepele. Saya tidak berpikir banyak orang akan mencari-cari penyelesaian masalah dengan GET dengan webapis. Bagaimanapun ..

Jika pertanyaan Anda adalah - Di MVC Web Api, bagaimana caranya - - Menggunakan nama metode tindakan khusus selain kata kerja HTTP umum? - Lakukan beberapa posting? - Posting beberapa tipe sederhana? - Posting jenis yang rumit via jQuery?

Maka solusi berikut dapat membantu:

Pertama, untuk menggunakan Metode Tindakan Kustom di API Web, tambahkan rute api web sebagai:

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

Dan kemudian Anda dapat membuat metode tindakan seperti:

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

Sekarang, jalankan jQuery berikut dari konsol browser Anda

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

Kedua, untuk melakukan banyak posting , itu sederhana, buat beberapa metode aksi dan hiasi dengan attrib [HttpPost]. Gunakan [ActionName ("MyAction")] untuk menetapkan nama kustom, dll. Akan datang ke jQuery di titik keempat di bawah

Ketiga, Pertama-tama, memposting beberapa jenis SIMPLE dalam satu tindakan tidak dimungkinkan. Selain itu, ada format khusus untuk memposting bahkan tipe tunggal tunggal (selain melewati parameter dalam string kueri atau gaya REST). Ini adalah titik yang membuat saya membenturkan kepala saya dengan Klien Istirahat (seperti Fiddler dan ekstensi klien Lanjutan REST Chrome) dan berburu di sekitar web selama hampir 5 jam ketika akhirnya, URL berikut terbukti membantu. Akan mengutip konten yang relevan untuk tautan itu bisa mati!

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

PS: Memerhatikan sintaksis yang aneh ?

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

Bagaimanapun, mari kita selesaikan cerita itu. Bergerak:

Keempat, memposting tipe kompleks melalui jQuery, ofcourse, $ .ajax () akan segera muncul di peran:

Katakanlah metode tindakan menerima objek Orang yang memiliki id dan nama. Jadi, dari 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) }
});

Dan aksinya akan terlihat seperti:

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

Semua hal di atas, bekerja untuk saya !! Bersulang!

Vaibhav
sumber
2
Saya sepertinya mendapatkan masalah ini setiap beberapa bulan, sebagian besar waktu saya akhirnya menyelesaikannya, tetapi kali ini saya menyerah. Tidak ada tips di atas yang menyelesaikannya untuk saya, jadi saya memutuskan untuk membuang ini sebagai pendekatan. Jika sulit untuk memperbaiki, mengapa repot-repot? Ini hanya kenyamanan - ambil konten sebagai string dan gunakan newtonsoft untuk mengubahnya. Selesai Butuh waktu 30 detik untuk menyelesaikannya dengan cara "sulit" setelah mencoba sekitar satu jam untuk menyelesaikannya dengan cara "mudah". Saya tidak liar dengan pendekatan itu, tetapi apakah ada masalah mendasar dengannya?
Kinetic
PS: Di WebApi2, sekarang kita bisa menggunakan Dekorator Rute. Jadi masalah ini terutama, ditangani. asp.net/web-api/overview/web-api-routing-and-actions/…
Vaibhav
2
Ingin menambahkan pengamatan. Kadang-kadang, alasan pengikatan model gagal (nol) di sisi WebAPI, ketika melewati tipe kompleks (mis: DTO), adalah bahwa satu atau lebih properti dalam model akan tidak kompatibel (atau gagal diurai). Misalnya. Properti Guid diberi GUID yang tidak valid. Dalam hal ini, coba gunakan nilai default / kosong untuk semua properti objek dan coba lagi.
Vaibhav
10

Saya baru saja bermain dengan ini dan menemukan hasil yang agak aneh. Katakanlah Anda memiliki properti publik di kelas Anda di C # seperti ini:

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

maka Anda harus melakukan trik JSON.stringify seperti yang disarankan oleh Shyju dan menyebutnya seperti ini:

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

Namun, jika Anda mendefinisikan getter dan setter di kelas Anda seperti ini:

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

maka Anda dapat menyebutnya lebih sederhana:

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

Ini menggunakan header HTTP:

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

Saya tidak begitu yakin apa yang terjadi di sini tetapi sepertinya ada bug (fitur?) Dalam framework. Mungkin metode pengikatan yang berbeda memanggil "adapter" yang berbeda, dan sementara adaptor untuk aplikasi / json bekerja dengan properti publik, yang untuk data yang dikodekan dalam formulir tidak.

Saya tidak tahu mana yang akan dianggap praktik terbaik.

Andy
sumber
6
Properti vs bidang adalah mengapa ini berbeda. Properti adalah praktik terbaik. Apa yang Anda sebut properti dalam contoh pertama sebenarnya adalah bidang. Ketika Anda menempatkan get / set pada mereka, mereka kemudian memiliki bidang dukungan yang dibuat secara otomatis yang membuat mereka properti.
paqogomez
Ini sangat benar, dan aneh. Kelas normal dengan hanya bidang tidak akan mengikat untuk membentuk posting, tetapi properti akan melakukannya. BTW: Masih tidak menjelaskan mengapa ini terjadi ...? Saya hanya bisa menebak logika internal hanya akan mengikat data JSON ke bidang, dan membentuk pos data ke properti, dan hanya itu ...?
James Wilkins
1
Ini terjadi karena kode hanya mencari properti. Karena menggunakan bidang publik bukan praktik terbaik, tim MS memutuskan untuk tidak mengizinkan skenario praktik terbaik, alasan IMHO yang cukup bagus.
Erik Philips
1

Gunakan JSON.stringify () untuk mendapatkan string dalam format JSON, pastikan bahwa ketika membuat panggilan AJAX Anda melewati atribut yang disebutkan di bawah ini:

  • contentType: 'application / json'

Di bawah ini adalah kode berikan jquery untuk melakukan panggilan posting ajax ke api web 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);
    }
});

Dilip Nannaware
sumber
2
tipe data tidak diperlukan.
Erik Philips
0

Pastikan bahwa layanan WebAPI Anda mengharapkan objek yang diketik dengan struktur yang cocok dengan JSON yang Anda lewati. Dan pastikan Anda meregangkan JSON yang Anda POSTing.

Ini JavaScript saya (menggunakan AngluarJS):

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

Dan inilah Pengontrol WebAPI saya:

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

Kode berikut untuk mengembalikan data dalam format json, bukan xml -Web API 2: -

Letakkan baris berikut di file Global.asax

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
UJS
sumber
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")
}
Debendra Dash
sumber
0

1) Di sisi klien Anda, Anda dapat mengirimkan permintaan http.post dalam string seperti di bawah ini

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

2) Kemudian di pengontrol api web Anda, Anda dapat membatalkan deserialisasi

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

3) Kelas ApiReceivedListOfObjects Anda harus seperti di bawah ini

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

    }

4) pastikan bahwa string serial Anda (IndexInfo di sini) menjadi seperti di bawah struktur sebelum perintah JsonConvert.DeserializeObject pada langkah 2

var resp = @"
    {
        ""element"": [
        {
            ""A"": ""A Jones"",
            ""B"": ""500015763""
        },
        {
            ""A"": ""B Smith"",
            ""B"": ""504986213""
        },
        {
            ""A"": ""C Brown"",
            ""B"": ""509034361""
        }
        ]
    }";
Mahdi ghafoorian
sumber