Mengapa kita harus menentukan FromBody dan FromUri?

157

Mengapa atribut FromBodydan FromUridiperlukan di ASP.NET Web API`?

Apa perbedaan antara menggunakan atribut dan tidak menggunakannya?

Rajneesh
sumber
11
Sekedar memberi petunjuk kapan berguna menggunakan anotasi [FromBody]: Praktik yang buruk misalnya mengirim kredensial statis seperti nama pengguna / kata sandi sebagai parameter yang dikodekan dalam URL. Meskipun enkripsi-SSL mungkin mencegah pihak ketiga mendapatkan akses membaca ke parameter dalam URL, itu tetap praktik yang buruk, karena kredensial ini mungkin disimpan dalam log browser dan sama dengan, yang jelas tidak diinginkan. Dalam kasus seperti itu, seseorang dapat menggunakan anotasi [FromBody], untuk memaksa penyimpanan parameter di dalam tubuh pesan HTTP, memperkenalkan pesan tinggi
Chris

Jawaban:

193

Ketika ASP.NET Web API memanggil metode pada pengontrol, ia harus menetapkan nilai untuk parameter, proses yang disebut pengikatan parameter .

Secara default, API Web menggunakan aturan berikut untuk mengikat parameter:

  • Jika parameternya adalah tipe "sederhana" , API Web mencoba untuk mendapatkan nilai dari URI . Tipe sederhana termasuk .NET tipe primitif (int, bool, dobel, dan sebagainya), ditambah TimeSpan, DateTime, Guid, desimal, dan string, ditambah semua tipe dengan konverter tipe yang dapat dikonversi dari sebuah string.

  • Untuk tipe yang kompleks , API Web mencoba membaca nilai dari badan pesan , menggunakan formatter tipe media.

Jadi, jika Anda ingin mengganti perilaku default di atas dan memaksa Web API untuk membaca tipe kompleks dari URI, tambahkan [FromUri]atribut ke parameter. Untuk memaksa API Web untuk membaca tipe sederhana dari badan permintaan, tambahkan [FromBody]atribut ke parameter.

Jadi, untuk menjawab pertanyaan Anda, kebutuhan atribut [FromBody]dan [FromUri]di API Web hanya untuk menimpa, jika perlu, perilaku default seperti dijelaskan di atas. Perhatikan bahwa Anda dapat menggunakan kedua atribut untuk metode pengontrol, tetapi hanya untuk parameter yang berbeda, seperti yang ditunjukkan di sini .

Ada lebih banyak informasi di web jika Anda Google "web api parameter binding".

jikay
sumber
2
@ user3510527: Anda tidak harus menggunakan atribut ini jika Anda tidak mau, selama Anda mengikuti perilaku default. Jika Anda ingin mengubah perilaku default, maka Anda harus menggunakannya.
djikay
1
jika melakukan perilaku default, lalu mengapa kita perlu ovveride dan manfaat apa yang akan kita dapatkan jika kita menyebutkan atribut ini?
Rajneesh
1
@ user3510527 Anda tidak perlu menimpa. Anda bisa menggunakan perilaku default. Salah satu contoh di mana seseorang mungkin ingin menimpa adalah jika mereka ingin menyediakan bilangan bulat sederhana di badan permintaan karena, secara default, itu akan berharap untuk menemukannya di URI. Pada dasarnya, Anda hanya dapat meninggalkan perilaku default jika Anda mau atau Anda dapat menimpanya, itu hanya opsi yang Anda miliki. Saya tidak mengerti apa kebingungannya.
djikay
saya hanya ingin tahu proses kerja internal jika kita menggunakan atribut form, jadi secara langsung itu akan mendapatkan nilai dan tidak memeriksa uri atau formbody ...
Rajneesh
7
Saya ingin tahu apakah seseorang dapat membuat atribut yang disebut JustGetItyang melayani tujuan yang sama untuk menambahkan beberapa atribut seperti [FromBody, FromQuery]dll
The Muffin Man
93

Perilaku default adalah:

  1. Jika parameter adalah primitif jenis ( int, bool, double, ...), Web API mencoba untuk mendapatkan nilai dari URI permintaan HTTP.

  2. Untuk tipe kompleks (objek Anda sendiri, misalnya Person:), Web API mencoba membaca nilai dari badan permintaan HTTP.

Jadi, jika Anda memiliki:

  • tipe primitif di URI, atau
  • tipe kompleks dalam tubuh

... maka Anda tidak perlu menambahkan atribut apa pun (tidak [FromBody]juga [FromUri]).

Tetapi, jika Anda memiliki tipe primitif di tubuh , maka Anda harus menambahkan [FromBody]di depan parameter tipe primitif Anda dalam metode pengontrol WebAPI Anda. (Karena, secara default, WebAPI mencari tipe primitif di URI dari permintaan HTTP.)

Atau, jika Anda memiliki tipe kompleks di URI Anda , maka Anda harus menambahkan [FromUri]. (Karena, secara default, WebAPI mencari tipe kompleks di tubuh permintaan HTTP secara default.)

Tipe primitif:

public class UsersController : ApiController
{
    // api/users
    public HttpResponseMessage Post([FromBody]int id)
    {

    }
    // api/users/id
    public HttpResponseMessage Post(int id)
    {

    }       
}

Jenis kompleks:

public class UsersController : ApiController
{       
    // api/users
    public HttpResponseMessage Post(User user)
    {

    }

    // api/users/user
    public HttpResponseMessage Post([FromUri]User user)
    {

    }       
}

Ini berfungsi selama Anda hanya mengirim satu parameter dalam permintaan HTTP Anda. Saat mengirim beberapa , Anda perlu membuat model khusus yang memiliki semua parameter Anda seperti ini:

public class MyModel
{
    public string MyProperty { get; set; }
    public string MyProperty2 { get; set; }
}

[Route("search")]
[HttpPost]
public async Task<dynamic> Search([FromBody] MyModel model)
{
    // model.MyProperty;
    // model.MyProperty2;
}

Dari dokumentasi Microsoft untuk pengikatan parameter di ASP.NET Web API :

Ketika parameter memiliki [FromBody], Web API menggunakan header Tipe-Konten untuk memilih formatter. Dalam contoh ini, tipe konten adalah "application / json" dan tubuh permintaan adalah string JSON mentah (bukan objek JSON). Paling banyak satu parameter diizinkan untuk membaca dari badan pesan.

Ini seharusnya bekerja:

public HttpResponseMessage Post([FromBody] string name) { ... }

Ini tidak akan berfungsi:

// Caution: This won't work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Alasan aturan ini adalah bahwa badan permintaan mungkin disimpan dalam aliran non-buffered yang hanya dapat dibaca sekali.

Tadej
sumber
5
"Paling banyak satu parameter diperbolehkan dibaca dari badan pesan" adalah informasi yang sangat membantu
Ryan
15

Selain jawaban di atas ..

[FromUri] juga dapat digunakan untuk mengikat tipe kompleks dari parameter uri alih-alih melewati parameter dari querystring

Misalnya ..

public class GeoPoint
{
    public double Latitude { get; set; } 
    public double Longitude { get; set; }
}

[RoutePrefix("api/Values")]
public ValuesController : ApiController
{
    [Route("{Latitude}/{Longitude}")]
    public HttpResponseMessage Get([FromUri] GeoPoint location) { ... }
}

Dapat disebut seperti:

http://localhost/api/values/47.678558/-122.130989
Utkarsh Patel
sumber
12

Ketika parameter memiliki [FromBody], Web API menggunakan header Tipe-Konten untuk memilih formatter. Dalam contoh ini, tipe konten adalah "application / json" dan tubuh permintaan adalah string JSON mentah (bukan objek JSON).

Paling banyak satu parameter diizinkan untuk membaca dari badan pesan. Jadi ini tidak akan berfungsi:

 // Caution: Will not work!    
public HttpResponseMessage Post([FromBody] int id, [FromBody] string name) { ... }

Alasan aturan ini adalah bahwa badan permintaan mungkin disimpan dalam aliran non-buffered yang hanya dapat dibaca sekali

Silakan kunjungi situs web untuk lebih jelasnya: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

pengguna5166729
sumber