ทำไมเราต้องระบุ FromBody และ FromUri


157

เหตุใดจึงต้องมีFromBodyและFromUriแอตทริบิวต์ใน ASP.NET Web API`

อะไรคือความแตกต่างระหว่างการใช้คุณลักษณะและไม่ได้ใช้งาน


11
เพียงให้คำแนะนำเมื่อมันอาจมีประโยชน์ในการใช้คำอธิบายประกอบ [FromBody]: มันเป็นตัวอย่างการปฏิบัติที่ไม่ดีในการส่งข้อมูลประจำตัวแบบคงที่เช่นชื่อผู้ใช้ / รหัสผ่านเป็นพารามิเตอร์ที่เข้ารหัสภายใน URL แม้ว่าการเข้ารหัส SSL อาจป้องกันไม่ให้บุคคลที่สามสามารถเข้าถึงการอ่านพารามิเตอร์ภายใน URL แต่ก็ยังคงใช้งานได้ไม่ดีเนื่องจากข้อมูลประจำตัวเหล่านี้อาจถูกเก็บไว้ในบันทึกของเบราว์เซอร์และเท่ากับซึ่งไม่ต้องการแน่นอน ในกรณีเช่นนี้เราสามารถใช้คำอธิบายประกอบ [FromBody] เพื่อบังคับให้มีการจัดเก็บพารามิเตอร์ภายในเนื้อความของข้อความ HTTP ได้แนะนำให้รู้จักระดับสูง
Chris

คำตอบ:


193

เมื่อเว็บ ASP.NET API เรียกวิธีการในการควบคุมก็จะต้องตั้งค่าสำหรับพารามิเตอร์กระบวนการที่เรียกว่าพารามิเตอร์ที่มีผลผูกพัน

โดยค่าเริ่มต้น Web API ใช้กฎต่อไปนี้เพื่อผูกพารามิเตอร์:

  • ถ้าพารามิเตอร์เป็น"ง่าย" ประเภทเว็บ API พยายามที่จะได้รับค่าจาก URI ประเภทที่เรียบง่าย ได้แก่ . NET primitive types (int, bool, double และอื่น ๆ ), รวมถึง TimeSpan, DateTime, Guid, ทศนิยมและสตริงรวมถึงประเภทใด ๆ ที่มีตัวแปลงประเภทที่สามารถแปลงจากสตริง

  • สำหรับประเภทที่ซับซ้อน Web API จะพยายามอ่านค่าจากเนื้อหาข้อความโดยใช้ตัวจัดรูปแบบชนิดสื่อ

ดังนั้นหากคุณต้องการแทนที่พฤติกรรมเริ่มต้นข้างต้นและบังคับให้ Web API อ่านประเภทที่ซับซ้อนจาก URI ให้เพิ่ม[FromUri]แอตทริบิวต์ลงในพารามิเตอร์ หากต้องการบังคับให้ Web API อ่านประเภทอย่างง่ายจากส่วนเนื้อหาคำขอให้เพิ่ม[FromBody]แอตทริบิวต์เข้ากับพารามิเตอร์

ดังนั้นในการตอบคำถามของคุณความต้องการ[FromBody]และ[FromUri]คุณลักษณะใน Web API นั้นเป็นการแทนที่หากจำเป็นพฤติกรรมเริ่มต้นตามที่อธิบายไว้ข้างต้น โปรดทราบว่าคุณสามารถใช้คุณลักษณะทั้งสำหรับวิธีการควบคุม แต่สำหรับพารามิเตอร์ที่แตกต่างกันที่แสดงให้เห็นที่นี่

มีเป็นจำนวนมาก มากขึ้น ข้อมูลบนเว็บถ้าคุณ google "API เว็บพารามิเตอร์ผูกพัน"


2
@ user3510527: คุณไม่จำเป็นต้องใช้แอตทริบิวต์เหล่านี้หากคุณไม่ต้องการตราบใดที่คุณทำตามพฤติกรรมเริ่มต้น หากคุณต้องการเปลี่ยนพฤติกรรมเริ่มต้นคุณต้องใช้มัน
djikay

1
ถ้ามันทำพฤติกรรมเริ่มต้นแล้วทำไมเราต้อง ovveride และประโยชน์ที่เราจะได้รับถ้าเรากล่าวถึงคุณลักษณะนี้
Rajneesh

1
@ user3510527 คุณไม่จำเป็นต้องแทนที่ คุณสามารถใช้พฤติกรรมเริ่มต้น ตัวอย่างหนึ่งที่ใครบางคนอาจต้องการแทนที่คือถ้าพวกเขาต้องการที่จะให้จำนวนเต็มง่าย ๆ ในร่างกายของการร้องขอเพราะโดยปกติแล้วมันจะคาดหวังว่าจะพบมันใน URI โดยทั่วไปคุณสามารถออกจากพฤติกรรมเริ่มต้นหากคุณต้องการหรือคุณสามารถแทนที่มันเป็นเพียงตัวเลือกที่คุณมี ฉันไม่เข้าใจว่าความสับสนคืออะไร
djikay

ฉันแค่อยากรู้กระบวนการทำงานภายในถ้าเราใช้ attribute form ดังนั้นมันจะได้รับค่าโดยตรงและไม่ได้ตรวจสอบ uri หรือ formbody ...
Rajneesh

7
ฉันสงสัยว่าใครสามารถสร้างคุณสมบัติที่เรียกว่าJustGetItมีจุดประสงค์เดียวกันในการเพิ่มคุณสมบัติหลายอย่างเช่น[FromBody, FromQuery]อื่น ๆ
The Muffin Man

93

พฤติกรรมเริ่มต้นคือ:

  1. ถ้าพารามิเตอร์เป็นดั้งเดิมประเภท ( int, bool, double, ... ), Web API พยายามที่จะได้รับค่าจากURIของคำขอ HTTP

  2. สำหรับประเภทที่ซับซ้อน (เช่นวัตถุของคุณเอง:) PersonWeb API พยายามอ่านค่าจากเนื้อความของคำขอ HTTP

ดังนั้นถ้าคุณมี:

  • ประเภทดั้งเดิมใน URI หรือ
  • ชนิดที่ซับซ้อนในร่างกาย

... จากนั้นคุณไม่ต้องเพิ่มคุณสมบัติใด ๆ (ไม่ใช่[FromBody]หรือ[FromUri])

แต่ถ้าคุณมีประเภทดั้งเดิมในร่างกายคุณจะต้องเพิ่ม[FromBody]ด้านหน้าของพารามิเตอร์ประเภทดั้งเดิมในวิธีการควบคุม WebAPI ของคุณ (เนื่องจากโดยค่าเริ่มต้น WebAPI กำลังมองหาประเภทดั้งเดิมใน URI ของคำขอ HTTP)

หรือหากคุณมีประเภทที่ซับซ้อนของคุณในURI[FromUri]แล้วคุณจะต้องเพิ่ม (เนื่องจากโดยค่าเริ่มต้น WebAPI กำลังค้นหาชนิดที่ซับซ้อนในเนื้อความของคำขอ HTTP โดยค่าเริ่มต้น)

ประเภทดั้งเดิม:

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

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

    }       
}

ประเภทที่ซับซ้อน:

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

    }

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

    }       
}

สิ่งนี้ใช้ได้ตราบใดที่คุณส่งพารามิเตอร์เดียวในคำขอ HTTP ของคุณ เมื่อส่งหลายรายการคุณต้องสร้างโมเดลที่กำหนดเองซึ่งมีพารามิเตอร์ทั้งหมดของคุณดังนี้:

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

จากเอกสารของ Microsoft สำหรับการผูกพารามิเตอร์ใน ASP.NET Web API :

เมื่อพารามิเตอร์มี [FromBody], Web API จะใช้ส่วนหัว Content-Type เพื่อเลือกฟอร์แมตเตอร์ ในตัวอย่างนี้ประเภทเนื้อหาคือ "application / json" และเนื้อหาคำขอเป็นสตริง JSON แบบดิบ (ไม่ใช่วัตถุ JSON) อย่างน้อยหนึ่งพารามิเตอร์ที่ได้รับอนุญาตให้อ่านจากเนื้อหาของข้อความ

สิ่งนี้น่าจะใช้ได้:

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

สิ่งนี้จะไม่ทำงาน:

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

เหตุผลสำหรับกฎนี้คืออาจมีการจัดเก็บเนื้อหาคำขอไว้ในสตรีมที่ไม่มีบัฟเฟอร์ซึ่งสามารถอ่านได้เพียงครั้งเดียว


5
"อย่างน้อยหนึ่งพารามิเตอร์ที่ได้รับอนุญาตให้อ่านจากเนื้อหาของข้อความ" เป็นข้อมูลที่มีประโยชน์โดยเฉพาะอย่างยิ่ง
Ryan

15

เพียงเติมคำตอบข้างบน ..

[FromUri] สามารถใช้ในการผูกชนิดที่ซับซ้อนจากพารามิเตอร์ uri แทนการส่งพารามิเตอร์จากการสอบถาม

สำหรับอดีต ..

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) { ... }
}

สามารถเรียกได้ว่าชอบ:

http://localhost/api/values/47.678558/-122.130989

12

เมื่อพารามิเตอร์มี [FromBody], Web API จะใช้ส่วนหัว Content-Type เพื่อเลือกฟอร์แมตเตอร์ ในตัวอย่างนี้ประเภทเนื้อหาคือ "application / json" และเนื้อหาคำขอเป็นสตริง JSON แบบดิบ (ไม่ใช่วัตถุ JSON)

อย่างน้อยหนึ่งพารามิเตอร์ที่ได้รับอนุญาตให้อ่านจากเนื้อหาของข้อความ ดังนั้นสิ่งนี้จะไม่ทำงาน:

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

เหตุผลสำหรับกฎนี้คือเนื้อหาของคำขออาจถูกเก็บไว้ในสตรีมที่ไม่มีบัฟเฟอร์ซึ่งสามารถอ่านได้เพียงครั้งเดียว

โปรดไปที่เว็บไซต์เพื่อรับรายละเอียดเพิ่มเติม: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.