พารามิเตอร์การโพสต์เป็นโมฆะเสมอ


197

ตั้งแต่อัปเกรดเป็น RC สำหรับ WebAPI ฉันมีปัญหาแปลก ๆ จริง ๆ เมื่อเรียก POST บน WebAPI ของฉัน ฉันกลับไปที่เวอร์ชันพื้นฐานที่สร้างในโครงการใหม่ ดังนั้น:

public void Post(string value)
{
}

และโทรจาก Fiddler:

Header:
User-Agent: Fiddler
Host: localhost:60725
Content-Type: application/json
Content-Length: 29

Body:
{
    "value": "test"
}

เมื่อฉันดีบักสตริง "value" จะไม่ถูกกำหนดให้ มันเป็น NULL เสมอ ใครมีปัญหานี้

(ฉันแรกเห็นปัญหาด้วยประเภทที่ซับซ้อนมากขึ้น)

ปัญหาไม่ได้ถูกผูกไว้กับ ASP.NET MVC 4 เท่านั้นปัญหาเดียวกันนี้เกิดขึ้นสำหรับโครงการ ASP.NET MVC 3 ใหม่หลังจากการติดตั้ง RC


เพียงเพิ่มปัญหา - มันไม่ได้เป็นเอกสิทธิ์ของ JSON มันเกิดขึ้นกับ XML ด้วย
ianrathbone

3
ฉันมีปัญหากับเรื่องนี้เป็นเวลาสองวันและหลังจากอ่านบทความทุกเรื่องที่ฉันพบแล้วมันก็กลายเป็นเรื่องง่ายเหมือนการจัดรูปแบบสตริง JSON อย่างถูกต้องใน WebRequest: ข้อมูลจะต้องเริ่มต้นและสิ้นสุดด้วยเครื่องหมายคำพูดคู่และถ้าคุณ ใช้เครื่องหมายคำพูดเดี่ยวตลอดข้อมูล json ของคุณทุกอย่างเล่นได้ดี
Gineer

คำตอบ:


101

เนื่องจากคุณมีเพียงพารามิเตอร์เดียวคุณสามารถลองตกแต่งด้วย[FromBody]แอตทริบิวต์หรือเปลี่ยนวิธีรับ DTO ที่มีค่าเป็นคุณสมบัติตามที่ฉันแนะนำไว้ที่นี่: การผูกพารามิเตอร์ MVC4 RC WebApi

อัปเดต: เว็บไซต์ ASP.NET อย่างเป็นทางการได้รับการอัปเดตในวันนี้พร้อมคำอธิบายที่ยอดเยี่ยม: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part- 1

สั้นเมื่อส่งประเภทง่ายเดียวในร่างกายส่งเพียงค่านำหน้าด้วยเครื่องหมายเท่ากับ (=) เช่นร่างกาย:

=test


9
ฉันให้ [FromBody] หมุนวน แต่ก็ไม่มีอะไรเปลี่ยนแปลง
ianrathbone

11
ส่งผ่านค่า (เช่นไม่ใช่วัตถุ JSON) และควรใช้งานได้ตามblogs.msdn.com/b/jmstall/archive/2012/04/16/…
Jim Harte

8
การผนวก=อยู่ข้างหน้าไม่เคยทำงานให้ฉันจนกว่าฉันจะทำตามคำแนะนำของจิมในความคิดเห็นของเขา (ไม่ใช่วัตถุ JSON) และมันก็ใช้ได้ นี่คือกุญแจ! ฉันไม่ชอบวิธีที่พิถีพิถันของ WebAPI
gitsitgo

16
นี่มันช่างงี่เง่าและน่ารำคาญที่ฉันไม่รู้ว่าจะขึ้นหรือลงคำตอบที่ช่วยฉันแก้ปัญหาของฉัน ... ทำไมบนโลกนี้ถึงต้องอยู่ในรูปแบบนี้? (ขออภัยสำหรับทัศนคติเสียเวลากับเรื่องนี้มากเกินไปและมันก็ไม่สมเหตุสมผลเลย ... :() คุณควรเพิ่มการสนับสนุนสำหรับรูปแบบที่คนคาดหวังให้ยอมรับ
gdoron ให้การสนับสนุนโมนิกา

6
ขอบคุณ! เราควรทราบได้อย่างไรว่าเราต้องลบชื่อพารามิเตอร์เมื่อส่งพารามิเตอร์เดียว? นกตัวไหนมากับแนวคิดนี้
Jenny O'Reilly

104

วันนี้ฉันเกาหัวไปแล้ว

วิธีแก้ปัญหาของฉันคือเปลี่ยน[FromBody]a เป็นHttpRequestMessage, โดยการย้าย HTTP stack ขึ้นมา

ในกรณีของฉันฉันกำลังส่งข้อมูลข้ามสายซึ่งถูกบีบอัด json ซึ่งเป็น base64'd ทั้งหมดนี้จากแอพ Android

ลายเซ็นดั้งเดิมของจุดปลายเว็บของฉันมีลักษณะดังนี้ (ใช้[FromBody]):

จุดสิ้นสุดดั้งเดิมของฉัน

การแก้ไขของฉันสำหรับปัญหานี้คือการกลับไปใช้HttpRequestMessageสำหรับลายเซ็นของจุดสิ้นสุดของฉัน

ป้อนคำอธิบายรูปภาพที่นี่

จากนั้นคุณสามารถเข้าถึงข้อมูลโพสต์โดยใช้รหัสบรรทัดนี้:

ป้อนคำอธิบายรูปภาพที่นี่

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

นอกจากนี้ก่อนอื่นฉันพยายามทำตามคำตอบข้อใดข้อหนึ่งข้างต้นซึ่งเปลี่ยนประเภทเนื้อหาเป็น: "Content-Type: application / x-www-form-urlencoded" สำหรับข้อมูลดิบนี่เป็นคำแนะนำที่ไม่ดีเพราะมันจะตัด + อักขระ

ดังนั้นสตริงเบส 64 ที่เริ่มต้นเช่นนี้: "MQ0AAB + LCAAAAAA" กลายเป็นเช่นนี้ "MQ0AAB LCAAAAAA"! ไม่ใช่สิ่งที่คุณต้องการ

ประโยชน์อีกอย่างของการใช้HttpRequestMessageคือคุณสามารถเข้าถึงส่วนหัว http ทั้งหมดจากภายในจุดปลายของคุณ


6
ทางออกที่ดีเยี่ยม ... ใช้เวลา 9 ชั่วโมงในการค้นหาปัญหาของฉันหลังจากที่ฉันลบค่าสตริง [FromBody] และแทนที่ด้วย HttpRequestMessage
Kev

1
ทำงานเหมือนจับใจ! แต่ไม่มีวิธีใช้ชนิดพารามิเตอร์จริงของวัตถุบางอย่างใช่ไหม เช่นพารามิเตอร์ประเภทการสั่งซื้อสำหรับวิธีการ API ของเว็บ?
Ron Nuni

7
เพียงแค่บันทึกด้านข้างคุณไม่จำเป็นต้องHttpRequestMessage requestใช้ลายเซ็นวิธีการเนื่องจากคุณมีสิ่งนี้อยู่แล้ว ในเนื้อความวิธีการนั้นสามารถเข้าถึงได้บนRequestวัตถุ เช่นRequest.Content.ReadAsStringAsync().Result;
Morvael

โดยปกติปัญหานี้เป็นเพราะวัตถุ JSON ของคุณไม่ถูกต้อง ฉันพบสิ่งนี้อยู่เสมอเพราะในตัวสร้างมีประเภทที่ไม่ถูกต้องและ Json ไม่ทราบวิธีการแปลง 'Like Guid ให้เป็นสตริง ดังนั้นเพิ่มตัวแปลงผ่านการตั้งค่าหรือเพิ่มตัวสร้างเปล่าและคุณไม่จำเป็นต้องกลับไปใช้รหัสเก่าเช่นนี้
Nick Turner

วิธีที่ง่ายที่สุดคือการเปลี่ยนวัตถุเป็นสตริงจากนั้นลองและแปลงมันและคุณจะเห็นข้อผิดพลาด JSON ตรวจสอบว่าคุณเป็นส่วนหัว
Nick Turner

71

ฉันเพิ่งเกิดเหตุการณ์นี้โดยใช้พู้ทำเล่น Content-Typeปัญหาคือว่าผมไม่ได้ระบุ

ลองใส่หัวข้อContent-Typeในคำขอ POST ของคุณ

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

หรือตามความเห็นด้านล่างคุณอาจต้องรวมส่วนหัว JSON

Content-Type: application/json

11
ฉันมีปัญหาที่คล้ายกันยกเว้นว่าฉันต้องตั้งค่า Content-Type: application / json
dvallejo

2
ตามที่ระบุในโพสต์ - ฉันได้เพิ่ม Content-Type: application / json แล้ว
ianrathbone

2
application / x-www-form-urlencoded ไม่ทำงานสำหรับฉัน Content-Type: application / json ทำ
เหลียง

1
ไม่ว่าจะเป็น content-type ใดหากคุณมีเพียงพารามิเตอร์เดียวคุณต้องส่งเฉพาะค่าที่ไม่มีชื่อพารามิเตอร์ในเนื้อความของคำขอ ดังนั้น id = 13 จะไม่ทำงาน คุณต้องส่ง 13 อย่างเดียว ดูคำตอบของจิม
Jenny O'Reilly

ฉันต้องใช้contentType: "application/x-www-form-urlencoded; charset=UTF-8"ยกตัวอย่างดูComplete Cient และ Server
RyBolt

57

ฉันพบปัญหานี้เช่นกันและนี่คือวิธีที่ฉันแก้ไขปัญหาของฉัน

รหัส webapi:

public void Post([FromBody] dynamic data)
{
    string value = data.value;
    /* do stuff */
}

รหัสลูกค้า:

$.post( "webapi/address", { value: "some value" } );

1
ใช้งานได้ถ้าไคลเอ็นต์กำลังส่ง JSON ถ้าผมส่งค่าที่เรียบง่ายเช่นสตริงsome valueแล้วdataเป็นโมฆะ
brianestey

ง่ายเปลี่ยนรหัสลูกค้าของคุณเพื่อส่งวัตถุ js กลับ
George

วิธีที่ยอดเยี่ยมและสะอาดในการรับข้อมูลจาก JSON
Wouter Vanherck

หากคุณกำลังส่ง json ให้ var json = JsonConvert.SerializeObject (data);
dvallejo

41

ฉันใช้Postmanและฉันทำผิดพลาดเหมือนกัน .. ส่งผ่านvalueเป็นวัตถุ json แทนที่จะเป็นสตริง

{
    "value": "test"
}

เห็นได้ชัดว่าข้างต้นผิดเมื่อพารามิเตอร์ api เป็นสตริงประเภท

ดังนั้นเพียงแค่ส่งสตริงด้วยเครื่องหมายอัญประกาศคู่ในเนื้อหา api:

"test"

2
นี่คือปัญหาของฉันและน่าจะแก้ปัญหาได้จริง สตริงที่เข้ารหัสของ JSON มีเครื่องหมายคำพูด
Kyle W

1
ฉันยังพบปัญหานี้กับบุรุษไปรษณีย์ ปรากฎว่าฉันเลือก "form-data" อย่างผิดพลาดแทน "raw" สำหรับ Body เมื่อตั้งค่า Content-Type เป็น application / json คุณสามารถดูภาพหน้าจอของ zzyykk123456 ได้ที่ปัญหาของ aspnet Github: github.com/aspnet/Home/issues/2202
Chun Lin

สิ่งนี้ใช้ได้สำหรับฉัน ใช้ Swagger (swashbuckle) ฉันต้องตั้งค่า Content Type: application / json และใช้เครื่องหมายคำพูดคู่
John Henckel

1
ปัญหาของฉัน แต่ฉันต้องทราบว่าในคำขอ Ajax คุณควรทำ 'data: JSON.stringify ("YourString")'
Amir Hossein Ahmadi

1
@AmirHosseinAhmadi ฉันได้พบเพียงแค่นี้ในอาแจ็กซ์และเห็นว่าการใช้จริงJSON.stringifyที่ก่อให้เกิดของฉันจะเป็น[frombody] nullหลังจากตั้งค่าเขตข้อมูลเป็นค่าสตริง (นั่นคือสตริง json) มันทำงานได้
Nexaspx

19

ลองสร้างคลาสเพื่อใช้เป็นโมเดลข้อมูลจากนั้นส่งอ็อบเจ็กต์ JSON ที่มีคุณสมบัติที่ตรงกับคุณสมบัติของคลาสโมเดลข้อมูลของคุณ (หมายเหตุ: ฉันได้ทดสอบสิ่งนี้แล้วและทำงานได้กับ MVC 4 RC 2012 ใหม่ล่าสุดที่ฉันเพิ่งดาวน์โหลดวันนี้)

public HttpResponseMessage Post(ValueModel model)
{
    return Request.CreateResponse<string>(HttpStatusCode.OK, "Value Recieved: " + model.Value);
}

public class ValueModel
{
    public string Value { get; set; }
}

วัตถุ JSON ด้านล่างนี้ถูกส่งใน HTTP-POST body-type content เป็น application / json

{ "value": "In MVC4 Beta you could map to simple types like string, but testing with RC 2012 I have only been able to map to DataModels and only JSON (application/json) and url-encoded (application/x-www-form-urlencoded body formats have worked. XML is not working for some reason" }

ฉันเชื่อว่าเหตุผลที่คุณต้องสร้างคลาสโมเดลข้อมูลคือเนื่องจากค่าง่าย ๆ ถูกสันนิษฐานว่ามาจากพารามิเตอร์ url และค่าคอมเพล็กซ์เดียวจะถือว่ามาจากเนื้อความ พวกเขามี[FromBody]และ[FromUrl]คุณสมบัติ แต่การใช้[FromBody] string valueยังไม่ได้ผลสำหรับฉัน ดูเหมือนว่าพวกเขายังคงทำงานกับข้อบกพร่องมากมายดังนั้นฉันแน่ใจว่าสิ่งนี้จะเปลี่ยนแปลงในอนาคต

แก้ไข: Got XML เพื่อทำงานในเนื้อความ XML serializer เริ่มต้นถูกเปลี่ยนเป็น DataContractSerializer แทน XmlSerializer การใส่บรรทัดต่อไปนี้ในไฟล์ Global.asax ของฉันแก้ไขปัญหานี้ ( อ้างอิง )

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

สิ่งนี้ใช้ได้กับฉันด้วย request.ContentType = "application / json; charset = UTF-8";
Arvind Krmar

15

หลังจากลองแล้วฉันคิดว่าพฤติกรรมเริ่มต้นนั้นถูกต้องและไม่มีอะไรที่จะแฮ็ก

เคล็ดลับเพียงอย่างเดียวคือ: หากอาร์กิวเมนต์วิธีการโพสต์ของคุณเป็นstringเหมือนด้านล่างคุณควรส่งสตริงธรรมดาพร้อมเครื่องหมายคำพูดคู่ในเนื้อหา (เมื่อใช้ ajax หรือบุรุษไปรษณีย์) เช่น

//send "{\"a\":1}" in body to me, note the outer double quotes
[HttpPost("api1")]
public String PostMethod1([FromBody]string value)
{
    return "received " + value; //  "received {\"a\":1}"
}

มิฉะนั้นถ้าคุณส่งสตริง json ในเนื้อความโพสต์โดยไม่มีเครื่องหมายอัญประกาศคู่ด้านนอกและหลีกเลี่ยงอัญประกาศด้านในก็จะสามารถแยกวิเคราะห์ไปยังคลาสโมเดล (ประเภทอาร์กิวเมนต์) เช่น{"a":1, "b":2}

public class MyPoco{
    public int a;
    public int b;
}

//send {"a":1, "b":2} in body to me
[HttpPost("api2")]
public String PostMethod2([FromBody]MyPoco value)
{
    return "received " + value.ToString();  //"received your_namespace+MyPoco"
}

11

ฉันกำลังมองหาวิธีแก้ไขปัญหานี้ในไม่กี่นาทีดังนั้นฉันจะแบ่งปันวิธีแก้ปัญหาของฉัน

หากคุณโพสต์โมเดลของคุณโมเดลของคุณจะต้องมีคอนสตรัคเตอร์ว่าง / ค่าเริ่มต้นไม่เช่นนั้นจะไม่สามารถสร้างโมเดลได้ ใช้ความระมัดระวังในขณะที่ทำการเปลี่ยนใหม่ ;)


Refactoring เป็นสิ่งที่ฉันบิตที่นี่ขอบคุณสำหรับเคล็ดลับ!
Alan

10

สิ่งนี้ใช้ได้กับฉัน:

  1. สร้างคลาส C # DTO พร้อมด้วยคุณสมบัติสำหรับทุกคุณสมบัติที่คุณต้องการส่งผ่านจาก jQuery / Ajax

    public class EntityData
    {
        public string Attr1 { get; set; }
        public string Attr2 { get; set; }
    }
  2. กำหนดวิธีการ API ของเว็บ:

    [HttpPost()]
    public JObject AddNewEntity([FromBody] EntityData entityData)
    {
  3. โทรหาเว็บ API ดังกล่าว:

    var entityData = {
        "attr1": "value1",
        "attr2": "value2"
    };
    
    $.ajax({
        type: "POST",
        url: "/api/YOURCONTROLLER/addnewentity",
        async: true,
        cache: false,
        data: JSON.stringify(entityData),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            ...
        }
    });

ขอบคุณที่โพสต์ข้อความนี้ฉันลองใช้ตัวอย่างมากมาย แต่สิ่งนี้ใช้ได้สำหรับฉัน!
Satbir

10

สำหรับผู้ที่มีปัญหาเดียวกันกับSwaggerหรือบุรุษไปรษณีย์อย่างที่ฉันเคยทำถ้าคุณส่งแอททริบิวต์ง่าย ๆ เป็นสตริงในโพสต์แม้จะมีการระบุ "ContentType" คุณก็ยังคงได้รับค่า Null

ผ่านเพียง:

MyValue

จะได้รับในตัวควบคุมเป็นโมฆะ

แต่ถ้าคุณผ่าน:

"MyValue"

มูลค่าจะได้รับสิทธิ

คำพูดสร้างความแตกต่างได้ที่นี่ แน่นอนว่านี่เป็นเพียงสำหรับ Swagger และบุรุษไปรษณีย์ ตัวอย่างเช่นในแอป Frontend โดยใช้ Angular สิ่งนี้ควรได้รับการแก้ไขโดยกรอบงานโดยอัตโนมัติ


6

ฉันมีปัญหาเดียวกันและพบว่าเมื่อเปลี่ยนประเภทเนื้อหาเป็น "application / json" ไม่ได้แก้ปัญหา อย่างไรก็ตาม "application / json; charset = utf-8" ได้ผล


ใช่ Web API จะไม่ทำการดีซีเรียลไลซ์โดยไม่มี charset = utf-8 blog.codenamed.nl/2015/05/12/…
Sam Rueby

4

ฉันมีปัญหาที่คล้ายกันซึ่งวัตถุคำขอสำหรับวิธีการ API ของเว็บของฉันเป็นโมฆะเสมอ ฉันสังเกตเห็นว่าตั้งแต่ชื่อการกระทำของตัวควบคุมถูกขึ้นต้นด้วย "รับ" Web API จึงถือว่าเป็น HTTP GET แทนที่จะเป็น POST หลังจากเปลี่ยนชื่อแอ็คชันคอนโทรลเลอร์แล้วจะทำงานตามที่ตั้งใจไว้


3

ด้วย Angular ฉันสามารถส่งผ่านข้อมูลในรูปแบบนี้:

 data: '=' + JSON.stringify({ u: $scope.usrname1, p: $scope.pwd1 }),
 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }

และใน Web API Controler:

    [HttpPost]
    public Hashtable Post([FromBody]string jsonString)
    {
        IDictionary<string, string> data = JsonConvert.DeserializeObject<IDictionary<string, string>>(jsonString);
        string username = data["u"];
        string pwd = data["p"];
   ......

หรือฉันอาจโพสต์ข้อมูล JSON เช่นนี้:

    data: { PaintingId: 1, Title: "Animal show", Price: 10.50 } 

และในคอนโทรลเลอร์ให้ยอมรับประเภทคลาสเช่นนี้:

    [HttpPost]
    public string POST(Models.PostModel pm)
    {

     ....
    }

หากคุณมีคลาสสาธารณะที่กำหนดไว้แล้วใน API แล้วโพสต์ JSON มิฉะนั้นจะโพสต์ '=' + JSON.stringify ({.. : ... , .. : ... })


3

ในกรณีของฉันปัญหาคือว่าพารามิเตอร์เป็นสตริงและไม่ใช่วัตถุฉันเปลี่ยนพารามิเตอร์เป็น JObject ของ Newsoft.Json และใช้งานได้


2

กำลังเพิ่มสาย

        ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

ท้ายฟังก์ชั่นprotected void Application_Start()ใน Global.asax.cs แก้ไขปัญหาที่คล้ายกันสำหรับฉันใน ASP.NET MVC3


ขอบคุณสำหรับความช่วยเหลือ แต่น่าเสียดายที่มันไม่ได้ช่วย ฉันจะให้สายในขณะที่มันอาจช่วยออกไป!
ianrathbone

เพียงเพื่อเพิ่มปัญหาเดียวกันเกิดขึ้นเมื่อฉันโพสต์ XML
ianrathbone

2

หากคุณใช้DataContractSerializerสำหรับฟอร์แมต Xml หรือ JSON ฟอร์แมตคุณต้องกำจัดมันทิ้ง ฉันมีสิ่งนี้ในไฟล์ WebApiConfig ของฉัน:

public static void Register(HttpConfiguration config)
{
     config.Routes.MapHttpRoute(
           name: "DefaultApi",
           routeTemplate: "api/{controller}/{id}",
           defaults: new { id = RouteParameter.Optional }
     );    

     var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
     jsonFormatter.UseDataContractJsonSerializer = true;
}

เพียงแค่ฉันแสดงความคิดเห็นjsonFormatter.UseDataContractJsonSerializer = true;และพารามิเตอร์ป้อนข้อมูลของฉันจะไม่เป็นโมฆะอีกต่อไป ขอบคุณ 'Despertar' ที่ให้เบาะแสกับฉัน


2

หากคุณแน่ใจเกี่ยวกับ JSON ที่ส่งไปคุณต้องติดตาม API ของคุณอย่างรอบคอบ:

  1. ติดตั้งMicrosoft.AspNet.WebApi.Tracingแพ็คเกจ
  2. เพิ่มconfig.EnableSystemDiagnosticsTracing();ในWebApiConfigชั้นเรียนRegisterวิธีการภายใน

ตอนนี้ดูที่ผลลัพธ์การดีบักและคุณอาจจะพบModelStateรายการบันทึกที่ไม่ถูกต้อง

หากModelStateไม่ถูกต้องคุณอาจพบสาเหตุที่แท้จริงในErrors:

ไม่มีใครสามารถคาดเดาข้อยกเว้นเช่นนี้ได้:

Could not load file or assembly 'Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

คุณช่วยชีวิตฉัน. รับค่า null เป็นโมเดลและหลังจากติดตั้งแพ็กเกจพบว่า JSON ของฉันไม่ได้อยู่ในรูปแบบที่ถูกต้อง
Khizar Iqbal

2

ฉันมีปัญหาเดียวกันกับการรับค่า null เป็นพารามิเตอร์ แต่มันเกี่ยวข้องกับวัตถุขนาดใหญ่ มันเปิดออกปัญหาที่เกี่ยวข้องกับความยาวสูงสุด IIS สามารถกำหนดค่าใน web.config

  <system.web>
    <httpRuntime targetFramework="4.7" maxRequestLength="1073741824" />
  </system.web>

ฉันสงสัยว่าเหตุใด Web API จึงระงับข้อผิดพลาดและส่งวัตถุ Null ไปยัง API ของฉัน ฉันพบข้อผิดพลาดในการใช้ Microsoft.AspNet.WebApi.Tracing



1

ฉันรู้ว่านี่ไม่ใช่คำตอบสำหรับคำถามนี้ แต่ฉันเจอเมื่อค้นหาวิธีแก้ไขปัญหาของฉัน

ในกรณีของฉันประเภทที่ซับซ้อนไม่ได้ถูกผูกไว้ แต่ฉันไม่ได้ทำ POST ฉันได้รับ GET กับพารามิเตอร์การสอบถาม ทางออกคือการเพิ่ม [FromUri] ให้กับ arg:

public class MyController : ApiController
{
    public IEnumerable<MyModel> Get([FromUri] MyComplexType input)
    {
        // input is not null as long as [FromUri] is present in the method arg
    }
}

นั่นเป็นเพราะเนื้อความของคำขอถูกละเว้น (และบางครั้งทำให้เกิดข้อผิดพลาด) เมื่อใช้ GET เหตุผลที่ใช้งานได้ตอนนี้คือ b / c ตอนนี้คุณผ่าน params บนสตริงการสืบค้นและร่างกายของคุณว่างเปล่าอย่างที่ควรจะเป็นบน GET
RyBolt

1

ฉันมีปัญหาเดียวกันในพู้ทำเล่น ฉันมีอยู่แล้วContent-Type: application/json; charset=utf-8หรือContent-Type: application/jsonในส่วนหัวของคำขอ

{'controller':'ctrl'}ร่างกายคำขอของฉันก็ยังเป็นสตริงธรรมดาและในไวโอลินผมเคยเขียน: นี้ทำให้พารามิเตอร์สตริงในวิธี nullพ.ศ.

คงที่ : จำไว้ว่าให้ใช้เครื่องหมายอัญประกาศซึ่งจะเป็นการระบุสตริง "{'controller':'ctrl'}"นั่นคือผมคงได้โดยการเขียน (หมายเหตุ: เมื่อเขียน JSON ทั้งให้แน่ใจว่าจะใช้ apostrophes หรือหลบหนีเครื่องหมายคำพูดเช่นนี้"{\"controller\":\"ctrl\"}")


ฉันต้องทำสิ่งเดียวกันในบุรุษไปรษณีย์ แต่ฉันไม่จำเป็นต้องทำสิ่งนี้เมื่อฉันเรียกใช้บริการของสปริง ดูเหมือนว่าปัญหาในด้าน. สุทธิ
Malcolm McRoberts

1

วิธีที่ง่ายที่สุดที่ฉันพบเพื่อจัดการกับออบเจ็กต์ JSON แบบง่ายๆที่ฉันส่งไปยัง MVC 6 คือการรับพารามิเตอร์โพสต์ประเภทเช่น NewtonSoft jObject:

public ActionResult Test2([FromBody] jObject str)
{
        return Json(new { message = "Test1 Returned: "+ str }); ;
}

การทดสอบ ( [FromBody] object body, [FromHeader(Name="Content-Type")] string bodyMediaType) สามารถทำงานได้ดีขึ้นเช่นการตรวจสอบbodyMediaType == "application.json"ก่อนที่จะส่งร่างไปที่ JObject ให้โอกาสสำหรับการสลับ
VladH

1

ทางออกที่ดีที่สุดสำหรับฉันคือ HTTP แบบเต็มดังต่อไปนี้:

[Route("api/open")]
[HttpPost]
public async Task<string> open(HttpRequestMessage request)
{
    var json = await request.Content.ReadAsStringAsync();
    JavaScriptSerializer jss = new JavaScriptSerializer();            
    WS_OpenSession param = jss.Deserialize<WS_OpenSession>(json);
    return param.sessionid;
}

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

คุณสามารถใช้วัตถุ param และเข้าถึงคุณสมบัติได้

มีประสิทธิภาพมากมาก

ฉันบอกว่ามาจาก url นี้:

http://bizcoder.com/posting-raw-json-to-web-api


1

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

โปรดตรวจสอบว่าคุณมี[Serializable]แอตทริบิวต์ที่ตกแต่งคลาสโมเดลของคุณหรือไม่

ลบแอตทริบิวต์เพื่อดูว่าใช้งานได้หรือไม่ สิ่งนี้ใช้ได้สำหรับฉัน


1

ฉันไปงานเลี้ยงเล็กน้อย แต่ใครก็ตามที่สะดุดข้ามค่า NULL ที่ส่งผ่านเมื่อใช้คอนโทรลเลอร์เพียงแค่เพิ่ม "=" ที่ด้านหน้าของคำขอ POST ของคุณ

คอนโทรลเลอร์ยังส่งผ่านค่า NULL เมื่อฉันใช้application / json Content-Type โปรดทราบว่า "application / x-www-form-urlencoded" Content-Type ด้านล่าง ชนิดส่งคืนจาก API คือ "application / json"

 public static string HttpPostRequest(string url, Dictionary<string, string> postParameters)
    {
        string postData = "=";

        foreach (string key in postParameters.Keys)
        {
            postData += HttpUtility.UrlEncode(key) + "="
                  + HttpUtility.UrlEncode(postParameters[key]) + ",";
        }

        HttpWebRequest myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
        myHttpWebRequest.Method = "POST";

        byte[] data = System.Text.Encoding.ASCII.GetBytes(postData);

        myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
        myHttpWebRequest.ContentLength = data.Length;

        Stream requestStream = myHttpWebRequest.GetRequestStream();
        requestStream.Write(data, 0, data.Length);
        requestStream.Close();

        HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

        Stream responseStream = myHttpWebResponse.GetResponseStream();

        StreamReader myStreamReader = new StreamReader(responseStream, System.Text.Encoding.Default);

        string pageContent = myStreamReader.ReadToEnd();

        myStreamReader.Close();
        responseStream.Close();

        myHttpWebResponse.Close();

        return pageContent;
    }

1

ไม่สำคัญว่าคุณต้องการโพสต์มูลค่าประเภทใดเพียงใส่ไว้ในเครื่องหมายคำพูดเพื่อให้เป็นสตริง ไม่เหมาะสำหรับประเภทที่ซับซ้อน

javascript:

    var myData = null, url = 'api/' + 'Named/' + 'NamedMethod';

    myData = 7;

    $http.post(url, "'" + myData + "'")
         .then(function (response) { console.log(response.data); });

    myData = "some sentence";

    $http.post(url, "'" + myData + "'")
         .then(function (response) { console.log(response.data); });

    myData = { name: 'person name', age: 21 };

    $http.post(url, "'" + JSON.stringify(myData) + "'")
         .then(function (response) { console.log(response.data); });

    $http.post(url, "'" + angular.toJson(myData) + "'")
         .then(function (response) { console.log(response.data); });

ค#:

    public class NamedController : ApiController
    {
        [HttpPost]
        public int NamedMethod([FromBody] string value)
        {
            return value == null ? 1 : 0;
        }
    }

1

หากคุณใส่คำอธิบายประกอบ [FromBody] และคุณมีวัตถุ Dto เป็นพารามิเตอร์ในวิธีการของคุณและยังไม่สามารถรับข้อมูลได้ให้เริ่มมองหาคุณสมบัติและฟิลด์ของ DTO ของคุณ

ฉันมีปัญหาเดียวกันนี้ที่ DTO ของฉันกำลังจะว่าง ฉันพบเหตุผลว่ามีคุณสมบัติอย่างใดอย่างหนึ่งที่ชี้ไปยังวัตถุที่ไม่สามารถต่อเนื่องกันได้ :( ซึ่งทำให้ตัวจัดรูปแบบสื่อล้มเหลวในการแยกวิเคราะห์ข้อมูลดังนั้นวัตถุจึงเป็นโมฆะเสมอหวังว่ามันจะช่วยผู้อื่นด้วย


1

ตรวจสอบประเภทข้อมูลของคุณอีกครั้ง dotnet model binder จะไม่แปลง float เป็นจำนวนเต็ม (และฉันถือว่าเป็นแนวคิดที่เกี่ยวข้องอื่น ๆ ) นี่จะทำให้แบบจำลองทั้งหมดถูกปฏิเสธ

หากคุณมี json เช่นนี้:

{
    "shoeSize": 10.5
}

แต่โมเดล c # ของคุณมีลักษณะดังนี้:

class Shoe{
    public int shoeSize;
}

ตัวยึดโมเดลจะปฏิเสธโมเดลและคุณจะได้รับ null


1

ฉันค่อนข้างช้าไปนี้ แต่ก็มีปัญหาที่คล้ายกันและหลังจากผ่านไปหลายวันด้วยคำตอบมากมายที่นี่และการหาพื้นหลังฉันพบวิธีแก้ปัญหาที่ง่ายที่สุด / มีน้ำหนักเบาในการส่งคืนพารามิเตอร์หนึ่งพารามิเตอร์ไปยัง Web API 2 Action เป็นดังนี้ ดังต่อไปนี้:

สิ่งนี้ถือว่าคุณรู้วิธีตั้งค่าตัวควบคุม / การกระทำของเว็บ API ด้วยการกำหนดเส้นทางที่ถูกต้องหากไม่ได้อ้างอิง: https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with -aspnet

ก่อนอื่น Controller Action โซลูชันนี้ต้องใช้ไลบรารี Newtonsoft.Json

[HttpPost]
public string PostProcessData([FromBody]string parameters) {
    if (!String.IsNullOrEmpty(parameters)) {
        JObject json = JObject.Parse(parameters);

        // Code logic below
        // Can access params via json["paramName"].ToString();
    }
    return "";
}

ฝั่งไคลเอ็นต์ใช้ jQuery

var dataToSend = JSON.stringify({ param1: "value1", param2: "value2"...});
$.post('/Web_API_URI', { '': dataToSend }).done(function (data) {
     console.debug(data); // returned data from Web API
 });

ปัญหาสำคัญที่ฉันพบคือทำให้แน่ใจว่าคุณส่งพารามิเตอร์โดยรวมเพียงตัวเดียวกลับไปที่ Web API และตรวจสอบให้แน่ใจว่าไม่มีชื่อเพียงค่า{ '': dataToSend }มิฉะนั้นค่าของคุณจะเป็นโมฆะในฝั่งเซิร์ฟเวอร์

ด้วยสิ่งนี้คุณสามารถส่งพารามิเตอร์หนึ่งหรือหลายพารามิเตอร์ไปยัง Web API ในโครงสร้าง JSON และคุณไม่จำเป็นต้องประกาศด้านเซิร์ฟเวอร์วัตถุใด ๆ เพิ่มเติมเพื่อจัดการข้อมูลที่ซับซ้อน JObject ยังอนุญาตให้คุณวนซ้ำพารามิเตอร์ทั้งหมดที่ส่งผ่านแบบไดนามิกเพื่อให้ปรับขยายได้ง่ายขึ้นหากพารามิเตอร์ของคุณเปลี่ยนแปลงตลอดเวลา หวังว่าจะช่วยให้ใครบางคนที่กำลังดิ้นรนอย่างฉัน


0

แก้ไขผ่านพารามิเตอร์เดียวในร่างกายเพื่อ WebAPI ทำงานรหัสนี้ $.post(url, { '': productId }

และจับได้ในการกระทำ [HttpPost] public ShoppingCartAddRemoveViewModel Delete([FromBody]string value)

กุญแจสำคัญคือการใช้ 'ค่า' คำวิเศษ มันอาจจะยัง int หรือบางชนิดดั้งเดิม ไม่ว่าจะเป็นประเภทเนื้อหาหรือการแก้ไขส่วนหัวของระเบียบคือรหัสนี้ไม่ทำงานในการดำเนินการโพสต์ mvc

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