ไม่สามารถจัดลำดับการตอบสนองใน Web API


86

ฉันกำลังทำงานกับ ASP.NET MVC web API ฉันพบข้อผิดพลาดนี้:

ประเภท 'ObjectContent'1' ล้มเหลวในการจัดลำดับเนื้อหาการตอบสนองสำหรับประเภทเนื้อหา 'application / xml; charset = utf-8 '

ตัวควบคุมของฉันคือ:

public Employee GetEmployees()
{
    Employee employees = db.Employees.First();
    return employees;
}

ทำไมฉันถึงได้รับข้อผิดพลาดนี้


6
ข้อยกเว้นที่คุณเห็นเป็นข้อยกเว้นทั่วไปซึ่งอาจเกิดจากหลายปัจจัย ตรวจสอบInnerExceptionคุณสมบัติของข้อยกเว้นการทำให้เป็นอนุกรมเพื่อดูว่าอะไรทำให้การทำให้เป็นอนุกรมล้มเหลว
ชื่อที่ปรากฏ

คุณสามารถแบ่งปันรหัสสำหรับประเภทพนักงานของคุณได้หรือไม่? อาจเป็นเพราะประเภทของพนักงานไม่สามารถต่อเนื่องกันได้ ...
Maggie Ying


คำตอบ:


121

สำหรับฉันนี่เป็นปัญหาเกี่ยวกับการอ้างอิงแบบวงกลม

คำตอบที่ยอมรับใช้ไม่ได้สำหรับฉันเพราะมันเปลี่ยนพฤติกรรมของตัวจัดรูปแบบ JSON เท่านั้น แต่ฉันได้รับ XML เมื่อฉันเรียกใช้บริการจากเบราว์เซอร์

ในการแก้ไขปัญหานี้ฉันปิด XML และบังคับให้ส่งคืนเฉพาะ JSON

ในไฟล์ Global.asax ให้วางบรรทัดต่อไปนี้ที่ด้านบนของเมธอด Application_Start ของคุณ:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

ตอนนี้จะแสดงเฉพาะผลลัพธ์ JSON เท่านั้น หากคุณต้องการผลลัพธ์ XML คุณจะต้องหาวิธีแก้ไขปัญหาอื่น


ทำงานให้ฉัน แต่สิ่งนี้คือฉันใช้ POSTMAN มันเป็นส่วนขยายของ Chrome เมื่อฉันโพสต์ข้อมูลด้วย POSTMAN มันใช้งานได้ดี แต่เมื่อฉันใช้ restsharp มันทำให้ฉันเกิดข้อผิดพลาดนี้ อย่างไรก็ตามวิธีการแก้ปัญหาของคุณแก้ไขปัญหาของฉัน
ArgeKumandan

คำตอบนี้ไม่มีวิธีแก้ปัญหาในการใช้ xml และนั่นคือสิ่งที่เขาขอ
honestduane

ใช้งานได้สำหรับฉันเมื่อฉันเปิดเป็น json จาก xml
Sike12

ที่จริงคำตอบนี้ไปถึงต้นตอของปัญหา ข้อผิดพลาดแรกที่ฉันได้รับคือข้อผิดพลาดในการอ้างอิงแบบวงกลม (พยายามส่งคืน JSON จากตัวควบคุม MVC) เมื่อฉันเปลี่ยนไปใช้ตัวควบคุมที่สืบทอด API ฉันเริ่มได้รับข้อผิดพลาดนี้แทน เมื่อฉันเพิ่มรหัสด้านบนใน Global.asax ข้อผิดพลาดก็หายไป
Matthew Pitts

43

ในไฟล์ global.asax ของคุณในวิธี Application_start () ให้เพิ่มบรรทัดนี้:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

ฉันหวังว่าจะช่วยคุณได้!


3
application_start คืออะไรและจะพบได้ที่ไหน แล้วเส้นนี้ควรวางตรงไหน?
Ciaran Gallagher

4
ขออภัยความหมายของข้อความนี้คืออะไร?
Blaise

5
เพิ่มบรรทัดในGlobal.asaxของApplication_Startแล้ว แต่ไม่มีการเปลี่ยนแปลง
cheesus

8
สิ่งนี้ยังไม่ได้ผลสำหรับฉัน อย่างไรก็ตามฉันเพิ่มอีกบรรทัดหลังจากหนึ่งในคำตอบนี้และใช้งานได้: GlobalConfiguration.Configuration.Formatters.Remove (GlobalConfiguration.Configuration.Formatters.XmlFormatter); ฉันได้สร้างคำตอบที่สมบูรณ์มากขึ้นด้านล่าง
Zane

2
ไม่ควรยอมรับคำตอบนี้เนื่องจากจะลบ XmlSerializer แทนที่จะแก้ไขปัญหาการอ้างอิงแบบวงกลมด้วย XmlSerializer
Believe2014

29

ฉันมีปัญหาเดียวกัน และฉันแก้ไขมัน ฉันใส่ตัวสร้างเริ่มต้นให้กับคลาส DTO

เช่น:

public class User
{
    public User()
    {
    }
}

หวังว่าจะได้ผลกับคุณ!


ขอบคุณสำหรับคำแนะนำสิ่งนี้ช่วยฉันในการตอบสนอง xml แต่มีใครรู้บ้างว่าทำไมจึงต้องมีตัวสร้างเริ่มต้น เรามีข้อมูลแล้ว ...
Ilya Chernomordik

ฉันคิดว่าเมื่ออ็อบเจ็กต์ถูกทำให้เป็นอนุกรมจากการตอบสนองก่อนอื่นตัวสร้างถูกเรียกให้สร้างอินสแตนซ์ของอ็อบเจ็กต์หลังจากนั้นจะใช้เมธอด set เพื่อตั้งค่าข้อมูลไปยังอ็อบเจ็กต์อินสแตนซ์ นั่นคือการคาดเดาของฉัน
taynguyen

นี่ควรเป็นคำตอบที่เลือกไว้เนื่องจากไม่ได้ตั้งสมมติฐานเกี่ยวกับประเภทผลตอบแทนที่คุณต้องการ ซึ่งจะใช้ได้กับทั้ง XML และ JSON ขอบคุณสำหรับการโพสต์สิ่งนี้
Allen Underwood

22

ใส่สิ่งนี้ในตัวสร้าง หวังว่านี่จะช่วยแก้ปัญหาได้:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }

ทางออกที่ยอดเยี่ยม ฉันต้องใส่ลงในตัวสร้างและมันก็ใช้งานได้
InsParbo

สิ่งนี้ใช้ได้ผลสำหรับฉันเมื่อใช้ร่วมกับการตั้งค่า GlobalConfiguration แต่ทำไมถึงได้ผล? มีคำอธิบายว่าวิธีนี้แก้ไขปัญหาอย่างไร และปัญหาที่แท้จริงคืออะไร?
Ciaran Gallagher

หากต้องการทำความเข้าใจว่าพร็อกซีเอนทิตีคืออะไร: msdn.microsoft.com/en-us/library/jj592886(v=vs.113).aspx เพื่อทำความเข้าใจว่า ProxyCreationEnabled คืออะไร: stackoverflow.com/questions/7111109/…
Sadjad Khazaie

16

ฉันพบสองวิธีแก้ปัญหานี้ วิธีแรกและง่ายที่สุดในการนำไปใช้คือการเปลี่ยน IEnumerables, ICollections เป็นประเภท List WebAPI สามารถทำให้เป็นอนุกรมของอ็อบเจ็กต์นี้ได้ แต่ไม่สามารถทำให้เป็นอนุกรมประเภทอินเทอร์เฟซได้

public class Store
{

  [StringLength(5)]
    public string Zip5 { get; set; }

    public virtual List<StoreReport> StoreReports { get; set; }  //use a list here
 }

อีกทางเลือกหนึ่งคือไม่ใช้ Serializer JSON ดั้งเดิมและรันการแทนที่นี้ในเมธอด Register ของ WebApi Config:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

1
ในขณะที่การเปลี่ยนเป็นรายการทำงานให้ฉันการเพิ่มตัวสร้างแบบไม่มีพารามิเตอร์ก็ใช้งานได้สำหรับฉันและฉันสามารถส่งคืน IEnumerable <วิดเจ็ต>
Mike Cheel

8

วิธีแก้ปัญหานั้นง่ายมาก

หลังจากการสืบค้น LINQ เพิ่ม .oList () (หรือ ToDictionary ถ้าต้องการ)

มันจะทำการโหลดมากกว่าที่ขี้เกียจโหลดข้อมูล


1
การเปลี่ยนประเภทการส่งคืนการกระทำIENumerableและการเพิ่ม.TiList()ผลตอบแทนได้ผลสำหรับฉัน
Ricardo Souza

5

** ข้อผิดพลาดนี้เกิดขึ้นเมื่อโทรจากขอเว็บ api / wcf / ... จากฝั่งไคลเอ็นต์ แต่เป็นผลข้างเคียงคุณจะต้องรวมขึ้นอยู่กับความสัมพันธ์โดยรวมคีย์เวิร์ด **

public CustomerPortalContext()
            : base("Name=CustomerPortalContext")
        {
            base.Configuration.ProxyCreationEnabled = false;
        }

4

หากคุณกำลังทำงานกับ EF นอกเหนือจากการเพิ่มโค้ดด้านล่างบน Global.asax

            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);          

อย่าลืมนำเข้า

using System.Data.Entity;

จากนั้นคุณสามารถคืนโมเดล EF ของคุณเองได้



3

หากคุณใช้ web api กับ Entity Framework โซลูชันอาจ ล้มเหลวในการจัดลำดับการตอบสนองใน Web API ด้วย Json

โดยพื้นฐานแล้วคุณต้องสร้างโมเดลที่สอดคล้องกับ EF แต่ละรุ่นซึ่งจะลบการอ้างอิงระหว่างคลาสและอนุญาตให้จัดลำดับได้ง่าย

รหัส: (นำมาจากลิงค์อ้างอิง)

สร้าง UserModel

public class UserModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

เปลี่ยนวิธีการ GetAll ของฉัน ()

public IEnumerable<UserModel> GetAll()
{
    using (Database db = new Database ())
    {
        List<UserModel> listOfUsers = new List<UserModel>();
        UserModel userModel = new UserModel();
        foreach(var user in db.Users)
        {
           userModel.FirstName = user.FirstName;
           userModel.LastName = user.LastName;
           listOfUsers.Add(userModel);
        }
        IEnumerable<UserModel> users = listOfUsers;

        return users;
    }
}

2

เอนทิตี 6 เริ่มต้นใช้ XMLกับ apis ในโปรเจ็กต์ของคุณค้นหาไฟล์"Global.asax" Fileและเพิ่มบรรทัดนี้:

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

บรรทัดนี้ลบ XML Formatter


สวัสดี Web API จัดลำดับการตอบสนองใน XML และ JSON หากคุณเพิ่มส่วนหัว Content-Type: application / json การตอบสนองจะอยู่ใน JSON คุณต้องกำหนดส่วนหัวนี้ในเบราว์เซอร์เสมอคุณจะเห็นเป็นรูปแบบ XML
Roberth Solís

1

แต่ถ้าคุณพบปัญหานี้กับเอนทิตี / คลาสอื่น ๆ คุณต้องสร้าง DTO ใหม่สำหรับแต่ละคลาสและถ้าคุณมีจำนวนมากคุณจะพบปัญหาได้เช่นกันฉันคิดว่าสร้าง DTO เพื่อแก้ปัญหานี้เท่านั้น ไม่ใช่วิธีที่ดีที่สุด ...

ลองทำดูไหม

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
Newtonsoft.Json.PreserveReferencesHandling.All;

ความนับถือ


1

อืมการติดตามอาจช่วยได้

ฉันได้รับข้อยกเว้นเดียวกันและในกรณีของฉันฉันส่งผ่านเอนทิตี poco จริงที่สร้างขึ้นสำหรับรหัสเอนทิตีก่อน เนื่องจากมีความสัมพันธ์กับเอนทิตีอื่นฉันจึงสร้างเอนทิตี viewmapper / dto ที่ด้านบนเพื่อส่งคืน

ตอนนี้ใช้งานได้ดี

เอนทิตี Poco:

public class Tag
{
public int Id{get;set;}
public string Title{get;set;}
public IList<Location> Locations{get;set;}
}

ViewMapper / Dto

public class TagResultsViewMapper
{
public int Id{get;set;}
public string Title{get;set;}
//just remove the following relationship 
//public IList<Location> Locations{get;set;}
}

0

คำถามของคุณค่อนข้างคล้ายกับของฉัน คุณต้องไม่ส่งคืนข้อมูลจากฐานข้อมูลโดยตรง สำหรับสิ่งนี้คุณต้องสร้าง Model และเชื่อมโยงข้อมูลที่คุณต้องการแสดง

ในตัวอย่างของฉันมีข้อมูลเกี่ยวกับ User ที่ Json ไม่สามารถทำให้เป็นอนุกรมได้ฉันได้สร้าง userModel และใน API ของฉันฉันส่งคืน userModel แทน User จากฐานข้อมูล

ตรรกะของการแปลงหรือเชื่อมโยงข้อมูลระหว่าง User และ UserModel ต้องอยู่ใน API

ไม่สามารถจัดลำดับการตอบสนองใน Web API ด้วย Json


0

นี่เป็นข้อผิดพลาดเฉพาะที่ฉันได้รับกลับมาจากการเรียก odata Web API ของฉัน:

The 'ObjectContent`1' type failed to serialize the response 
body for content type 'application/json; odata.metadata=minimal'.

ในที่สุดฉันก็พบว่าคลาส dbContext ของฉันมีชื่อตารางที่จัดรูปแบบไม่ดีถูกกำหนดใน onModelCreating .. ดังนั้น SqlClient กำลังมองหาตารางที่ไม่มีอยู่ในฐานข้อมูลของฉัน !!

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