วิธีดึงค่าฟอร์มจาก HTTPPOST พจนานุกรมหรือ?


112

ฉันมีตัวควบคุม MVC ที่มีวิธีการดำเนินการนี้:

[HttpPost]
public ActionResult SubmitAction()
{
     // Get Post Params Here
 ... return something ...
}

แบบฟอร์มเป็นรูปแบบที่ไม่สำคัญพร้อมด้วยกล่องข้อความธรรมดา

คำถาม

ฉันจะเข้าถึงค่าพารามิเตอร์ได้อย่างไร

ฉันไม่ได้โพสต์จากมุมมองโพสต์นี้มาจากภายนอก ฉันสมมติว่ามีคอลเลกชันของคู่คีย์ / ค่าที่ฉันสามารถเข้าถึงได้

ฉันลองแล้วRequest.Params.Get("simpleTextBox");แต่กลับแสดงข้อผิดพลาด "ขออภัยเกิดข้อผิดพลาดขณะดำเนินการตามคำขอของคุณ"

คำตอบ:


155

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

[HttpPost]
public ActionResult SubmitAction(SomeModel model)
{
    var value1 = model.SimpleProp1;
    var value2 = model.SimpleProp2;
    var value3 = model.ComplexProp1.SimpleProp1;
    ...

    ... return something ...
}

อีกวิธีหนึ่ง (เห็นได้ชัดว่าน่าเกลียดกว่า) คือ:

[HttpPost]
public ActionResult SubmitAction()
{
    var value1 = Request["SimpleProp1"];
    var value2 = Request["SimpleProp2"];
    var value3 = Request["ComplexProp1.SimpleProp1"];
    ...

    ... return something ...
}

5
ฉันแค่อยากจะชี้ให้เห็นว่าคุณสูญเสียการสำรองข้อมูลของคอมไพเลอร์ในตัวเลือกที่ 2 หากโมเดลมีการเปลี่ยนแปลงคอมไพลเลอร์จะไม่จับการเปลี่ยนแปลงในตัวควบคุมที่เกี่ยวข้อง มีกรณีที่ดีสำหรับตัวเลือก 2 แต่ฉันไม่สนับสนุนให้ใช้อย่างกว้างขวาง
Serguei Fedorov

1
บางครั้งคุณต้องการของที่น่าเกลียดเป็นเรื่องดีที่จะมีทางเลือกเมื่อคุณรู้แล้วว่าแนวทางปฏิบัติที่ดีที่สุดคืออะไร
Oscar Ortiz

ในฐานะที่ยังมีคนเรียนดอทเน็ตทำไมวิธีที่สองจึงน่าเกลียดกว่านี้?
Goose

3
@ ห่านเพราะมันเป็นสายเวทย์ คุณไม่ได้รับความปลอดภัยในการรวบรวมเวลา รหัสของคุณจะล้มเหลวในขณะรันไทม์หากคุณพิมพ์ชื่อตัวแปรผิดในขณะที่ถ้าคุณใช้การพิมพ์แรงคอมไพเลอร์จะเป็นเพื่อนของคุณ
Darin Dimitrov

@DarinDimitrov เข้าท่า. แตกต่างจากโลกที่ฉันจากมา คุณสมบัติที่ดีมาก
Goose

104

เพียงคุณสามารถใช้FormCollectionเช่น:

[HttpPost] 
public ActionResult SubmitAction(FormCollection collection)
{
     // Get Post Params Here
 string var1 = collection["var1"];
}

คุณยังสามารถใช้คลาสที่แมปกับค่าฟอร์มและเอ็นจิน asp.net mvc เติมโดยอัตโนมัติ:

//Defined in another file
class MyForm
{
  public string var1 { get; set; }
}

[HttpPost]
public ActionResult SubmitAction(MyForm form)
{      
  string var1 = form1.Var1;
}

ฉันชอบวิธีการแก้ปัญหาของคลาสที่ง่ายและสะดวก
Basheer AL-MOMANI

36

คำตอบนั้นดีมาก แต่มีอีกวิธีหนึ่งใน MVC และ. NET รุ่นล่าสุดที่ฉันชอบใช้แทนที่จะใช้ FormCollection และ Request keys "โรงเรียนเก่า"


พิจารณาข้อมูลโค้ด HTML ที่อยู่ในแท็กฟอร์มที่ทำ AJAX หรือ FORM POST

<input type="hidden"   name="TrackingID" 
<input type="text"     name="FirstName"  id="firstnametext" />
<input type="checkbox" name="IsLegal"  value="Do you accept terms and conditions?" />

ตัวควบคุมของคุณจะแยกวิเคราะห์ข้อมูลแบบฟอร์มและพยายามส่งให้คุณเป็นพารามิเตอร์ของประเภทที่กำหนด ฉันรวมช่องทำเครื่องหมายเพราะเป็นช่องที่ยุ่งยาก จะส่งคืนข้อความ "on" หากทำเครื่องหมายและเป็นโมฆะหากไม่ได้ตรวจสอบ ข้อกำหนดแม้ว่าตัวแปรที่กำหนดเหล่านี้จะต้องมีอยู่ (เว้นแต่เป็นโมฆะ (โปรดจำไว้ว่าstringเป็นโมฆะ)) มิฉะนั้น AJAX หรือ POST back จะล้มเหลว

[HttpPost]
public ActionResult PostBack(int TrackingID, string FirstName, string IsLegal){
    MyData.SaveRequest(TrackingID,FirstName, IsLegal == null ? false : true);
}

นอกจากนี้คุณยังสามารถโพสต์แบบจำลองได้โดยไม่ต้องใช้ตัวช่วยมีดโกน ฉันพบว่าสิ่งนี้จำเป็นบางครั้ง

public Class HomeModel
{
  public int HouseNumber { get; set; }
  public string StreetAddress { get; set; }
}

มาร์กอัป HTML จะเป็น ...

<input type="text" name="variableName.HouseNumber" id="whateverid" >

และคอนโทรลเลอร์ของคุณ (Razor Engine) จะดักจับ "variableName" ของ Form Variable (ชื่อเป็นไปตามที่คุณต้องการ แต่ทำให้สอดคล้องกัน) และพยายามสร้างขึ้นและส่งไปยัง MyModel

[HttpPost]
public ActionResult PostBack(HomeModel variableName){
    postBack.HouseNumber; //The value user entered
    postBack.StreetAddress; //the default value of NULL.
}

เมื่อคอนโทรลเลอร์คาดหวัง Model (ในกรณีนี้คือ HomeModel) คุณไม่จำเป็นต้องกำหนดฟิลด์ทั้งหมดเนื่องจากตัวแยกวิเคราะห์จะปล่อยให้เป็นค่าเริ่มต้นโดยปกติจะเป็น NULL สิ่งที่ดีคือคุณสามารถผสมและจับคู่โมเดลต่างๆบน Mark-up และการแยกโพสต์กลับจะถูกเติมให้มากที่สุด คุณไม่จำเป็นต้องกำหนดโมเดลบนเพจหรือใช้ตัวช่วยใด ๆ

เคล็ดลับ: ชื่อของพารามิเตอร์ในคอนโทรลเลอร์คือชื่อที่กำหนดในมาร์กอัป HTML "name =" ไม่ใช่ชื่อของ Model แต่เป็นชื่อของตัวแปรที่คาดหวังใน!


การใช้List<>มีความซับซ้อนกว่าเล็กน้อยในการมาร์กอัป

<input type="text" name="variableNameHere[0].HouseNumber" id="id"           value="0">
<input type="text" name="variableNameHere[1].HouseNumber" id="whateverid-x" value="1">
<input type="text" name="variableNameHere[2].HouseNumber"                   value="2">
<input type="text" name="variableNameHere[3].HouseNumber" id="whateverid22" value="3">

ดัชนีในรายการ <> ต้องเป็นศูนย์และตามลำดับเสมอ 0,1,2,3

[HttpPost]
public ActionResult PostBack(List<HomeModel> variableNameHere){
     int counter = MyHomes.Count()
     foreach(var home in MyHomes)
     { ... }
}

ใช้IEnumerable<>สำหรับดัชนีที่ไม่อิงตามศูนย์และไม่ใช่ตามลำดับจะโพสต์กลับ เราจำเป็นต้องเพิ่มอินพุตพิเศษที่ซ่อนอยู่เพื่อช่วยในการประสาน

<input type="hidden" name="variableNameHere.Index" value="278">
<input type="text" name="variableNameHere[278].HouseNumber" id="id"      value="3">

<input type="hidden" name="variableNameHere.Index" value="99976">
<input type="text" name="variableNameHere[99976].HouseNumber" id="id3"   value="4">

<input type="hidden" name="variableNameHere.Index" value="777">
<input type="text" name="variableNameHere[777].HouseNumber" id="id23"    value="5">

และรหัสก็ต้องใช้ IEnumerable และโทร ToList()

[HttpPost]
public ActionResult PostBack(IEnumerable<MyModel> variableNameHere){
     int counter = variableNameHere.ToList().Count()
     foreach(var home in variableNameHere)
     { ... }
}

ขอแนะนำให้ใช้ Model เดียวหรือ ViewModel (Model contianing other models to create a complex 'View' Model) ต่อหน้า การผสมและจับคู่ตามที่เสนออาจถือเป็นการปฏิบัติที่ไม่ดี แต่ตราบใดที่มันใช้งานได้และอ่านได้มันก็ไม่ใช่ BAD อย่างไรก็ตามมันแสดงให้เห็นถึงพลังและความยืดหยุ่นของเครื่องยนต์ Razor

ดังนั้นหากคุณจำเป็นต้องทิ้งบางสิ่งบางอย่างโดยพลการหรือแทนที่ค่าอื่นจากตัวช่วย Razor หรือเพียงแค่ไม่รู้สึกอยากสร้างตัวช่วยของคุณเองสำหรับรูปแบบเดียวที่ใช้ข้อมูลที่ผิดปกติคุณสามารถใช้วิธีการเหล่านี้เพื่อยอมรับส่วนเกินได้อย่างรวดเร็ว ข้อมูล.


การใช้ตัวเลือกดัชนีไม่ชัดเจน ใครบนโลกสีเขียวของพระเจ้าจะรู้จักใช้สิ่งนั้นหรือว่ามันมีอยู่จริง! แต่ฉันดีใจที่พบโพสต์นี้ จะช่วยประหยัดปริมาณการใช้งานเครือข่ายได้มาก
Michael Silver

1
สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่หลังจากที่ฉันเปลี่ยน <input type = "hidden" id = "myId"> เป็น @ Html.Hidden ("myId")
radkan

@Piotr - โปรดแก้ไขความไม่สอดคล้องกันในการอ้างอิงของคุณด้วย MyModel และ MyHomes มันทำให้เกิดความสับสนว่าปัจจุบันเป็นอย่างไร
Spencer Sullivan

15

หากคุณต้องการรับข้อมูลแบบฟอร์มโดยตรงจากคำขอ Http โดยไม่มีการผูกโมเดลใด ๆ หรือFormCollectionคุณสามารถใช้สิ่งนี้:

[HttpPost] 
public ActionResult SubmitAction() {

    // This will return an string array of all keys in the form.
    // NOTE: you specify the keys in form by the name attributes e.g:
    // <input name="this is the key" value="some value" type="test" />
    var keys = Request.Form.AllKeys;

    // This will return the value for the keys.
    var value1 = Request.Form.Get(keys[0]);
    var value2 = Request.Form.Get(keys[1]);
}

2
ข้อควรระวังว่านี่อาจเป็นรูปแบบที่ไม่ดี (ไม่มีการเล่นสำนวน) แต่บางครั้งคุณแค่ต้องการค่าแบบฟอร์มและคุณไม่สามารถเปลี่ยนลายเซ็นฟังก์ชันได้ทั้งหมด นี่เป็นทางออกเดียวที่เหมาะกับสถานการณ์เฉพาะของฉัน
Ryan

จะทดสอบหน่วยวิธีนี้ด้วยการอ้างอิงแบบคงที่ได้อย่างไร FormCollection จะเป็นที่ต้องการมากขึ้นในการทดสอบ
Kees de Wit

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