Die Antwort in der Web-API konnte nicht serialisiert werden

85

Ich habe an der ASP.NET MVC-Web-API gearbeitet und habe folgenden Fehler:

Der Typ 'ObjectContent`1' konnte den Antworttext für den Inhaltstyp 'application / xml nicht serialisieren. Zeichensatz = utf-8 '.

Mein Controller ist:

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

Warum bekomme ich diesen Fehler?

Tamal Kanti Dey
quelle
6
Die Ausnahme, die Sie sehen, ist eine allgemeine Ausnahme, die durch eine beliebige Anzahl von Faktoren verursacht werden kann. Überprüfen Sie die InnerExceptionEigenschaft der Serialisierungsausnahme, um herauszufinden, was genau dazu geführt hat, dass die Serialisierung fehlgeschlagen ist.
Anzeigename
Können Sie den Code für Ihren Mitarbeitertyp freigeben? Es könnte sein, dass der Typ Mitarbeiter nicht serialisierbar ist ...
Maggie Ying
Schauen Sie sich auch diese stackoverflow.com/questions/8173524/…
sttaq

Antworten:

119

Für mich war dies ein Problem mit der Zirkelreferenzierung.

Die akzeptierte Antwort hat bei mir nicht funktioniert, da sie nur das Verhalten des JSON-Formatierers ändert. Ich habe jedoch XML erhalten, als ich den Dienst über den Browser aufgerufen habe.

Um dies zu beheben, habe ich XML ausgeschaltet und nur die Rückgabe von JSON erzwungen.

Fügen Sie in der Datei Global.asax die folgenden Zeilen oben in Ihre Application_Start-Methode ein:

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

Jetzt werden nur JSON-Ergebnisse zurückgegeben. Wenn Sie XML-Ergebnisse benötigen, müssen Sie eine andere Lösung finden.

Zane
quelle
hat für mich gearbeitet. Aber die Sache ist, ich benutze POSTMAN. Es ist eine Chrom-Erweiterung. Wenn ich Daten mit POSTMAN poste, funktioniert es gut. aber wenn ich restsharp benutze, gibt es mir diesen Fehler.
Trotzdem
Diese Antwort bietet keine Lösung für die Verwendung von XML, und darum hat er gebeten.
ehrlichduane
Funktioniert für mich, da ich von XML auf json umgeschaltet habe.
Sike12
Tatsächlich geht diese Antwort dem Problem auf den Grund. Der erste Fehler, den ich erhielt, war ein Zirkelreferenzfehler (Versuch, JSON vom MVC-Controller zurückzugeben). Als ich zu einem von der API geerbten Controller wechselte, wurde stattdessen dieser Fehler angezeigt. Als ich den obigen Code zu Global.asax hinzufügte, verschwand der Fehler.
Matthew Pitts
43

Fügen Sie in Ihrer Datei global.asax in der Methode Application_start () diese Zeile hinzu:

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

Ich hoffe das hilft dir!

Julito Avellaneda
quelle
3
Was ist application_start und wo ist es zu finden? Und wo genau soll diese Linie platziert werden?
Ciaran Gallagher
4
Entschuldigung, aber was bedeutet diese Aussage?
Blaise
5
Zeile zu Global.asax's hinzugefügt Application_Start, aber keine Änderung.
Cheesus
8
Das hat bei mir immer noch nicht funktioniert. Ich habe jedoch eine weitere Zeile nach der in dieser Antwort eingefügt und es hat funktioniert: GlobalConfiguration.Configuration.Formatters.Remove (GlobalConfiguration.Configuration.Formatters.XmlFormatter); Ich habe eine ausführlichere Antwort unten erstellt
Zane
2
Diese Antwort sollte nicht akzeptiert werden, da sie tatsächlich XmlSerializer entfernt, anstatt das Problem des Zirkelverweises mit XmlSerializer zu lösen.
Believe2014
29

Ich habe das gleiche Problem. Und ich habe es gelöst. Ich habe den Standardkonstruktor in die DTO-Klasse eingefügt.

Ex:

public class User
{
    public User()
    {
    }
}

Hoffe es funktioniert mit dir!

taynguyen
quelle
Vielen Dank für den Vorschlag, dies hat mir bei der XML-Antwort geholfen, aber weiß jemand, warum ein Standardkonstruktor benötigt wird? Wir haben die Daten bereits ...
Ilya Chernomordik
Ich denke, wenn ein Objekt aus der Antwort serialisiert wird, wurde zuerst der Konstruktor aufgerufen, um eine Instanz des Objekts zu erstellen. Danach wird die set-Methode verwendet, um Daten auf die Objektinstanz zu setzen. Das ist meine Vermutung.
Taynguyen
Dies sollte eigentlich die gewählte Antwort sein, da keine Annahme über die von Ihnen benötigten Rückgabetypen getroffen wird. Dies funktioniert sowohl für XML als auch für JSON. Vielen Dank für die Veröffentlichung.
Allen Underwood
21

Setzen Sie dies in Konstruktor. Hoffe das löst das Problem:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }
Sadjad Khazaie
quelle
Hervorragende Lösung. Ich muss es in den Konstruktor einfügen und es hat funktioniert.
InsParbo
Dies funktionierte bei mir in Kombination mit den GlobalConfiguration-Einstellungen. Aber warum funktioniert das? Gibt es eine Erklärung, wie dies das Problem behebt? Und was war das Problem eigentlich?
Ciaran Gallagher
Um zu verstehen, was Entity-Proxys sind: msdn.microsoft.com/en-us/library/jj592886(v=vs.113).aspx Um zu verstehen, was ProxyCreationEnabled ist: stackoverflow.com/questions/7111109/…
Sadjad Khazaie
16

Ich habe zwei Lösungen dafür gefunden. Die erste und am einfachsten zu implementierende Methode besteht darin, IEnumerables und ICollections in einen Listentyp zu ändern. Die WebAPI kann diese Objekte serialisieren, jedoch keine Schnittstellentypen serialisieren.

public class Store
{

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

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

Die andere Option besteht darin, den nativen JSON-Serializer nicht zu verwenden und diese Überschreibung in der Register-Methode der WebApi-Konfiguration auszuführen:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);
Ray Suelzer
quelle
1
Während der Wechsel zu List für mich funktioniert hat, hat das Hinzufügen eines parameterlosen Konstruktors auch für mich funktioniert und ich konnte weiterhin IEnumerable <Widget>
Mike Cheel
8

Die Lösung ist einfach.

Fügen Sie nach der LINQ-Abfrage .ToList () (oder bei Bedarf ToDictionary) hinzu.

Das Laden wird eifriger als das langsame Laden der Daten

om471987
quelle
1
Das Ändern des Aktionsrückgabetyps in IENumerableund das Hinzufügen .TiList()zur Rückgabe hat bei mir funktioniert.
Ricardo Souza
4

** Dieser Fehler tritt auf, wenn von der Client-Seite aus die Anforderungs-Web-API / wcf / ... aufgerufen wird. Als Nebeneffekt müssen Sie jedoch abhängige Beziehungen durch das Schlüsselwort include einschließen. ** **.

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

Wenn Sie mit EF arbeiten, fügen Sie neben dem folgenden Code auch Global.asax hinzu

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

Vergessen Sie nicht zu importieren

using System.Data.Entity;

Dann können Sie Ihre eigenen EF-Modelle zurückgeben

Lucas Roselli
quelle
3

Wenn Sie die Web-API mit Entity Framework verwenden, kann eine Lösung fehlschlagen, um die Antwort in der Web-API mit Json zu serialisieren

Grundsätzlich müssen Sie ein Modell erstellen, das jedem EF-Modell entspricht. Dadurch werden Abhängigkeiten zwischen Klassen beseitigt und eine einfache Serialisierung ermöglicht.

Code: (entnommen aus dem Link, auf den verwiesen wird)

Erstellen Sie ein UserModel

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

Ändere meine Methode 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;
    }
}
Tung Nguyen
quelle
2

Standardentität 6 verwendet XML , um in Ihrem Projekt die Datei "Global.asax" zu finden und die folgende Zeile hinzuzufügen:

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

Diese Zeile entfernt den XML-Formatierer.

Roberth Solís
quelle
Hallo, Web-API serialisiert die Antwort in XML und JSON. Wenn Sie den Header Content-Type: application / json hinzufügen, ist die Antwort in JSON. Sie müssen diesen Header definieren. Im Browser können Sie ihn immer als XML-Format
anzeigen
1

Wenn Sie dieses Problem jedoch bei anderen Entitäten / Klassen festgestellt haben, müssen Sie für jede Klasse ein neues DTO erstellen. Wenn Sie viele davon haben, können Sie ein Problem finden. Ich denke auch, dass Sie ein DTO nur zur Lösung dieses Problems erstellen ist nicht der beste Weg ...

Hast du das versucht?

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

Grüße

Julito Avellaneda
quelle
1

hmmm, Folgendes kann helfen.

Ich habe die gleiche Ausnahme erhalten und in meinem Fall zuerst die eigentliche Poco-Entität übergeben, die für den Entitätscode erstellt wurde. Da es eine Beziehung zu anderen Entitäten enthält, habe ich gerade die viewmapper / dto-Entität darüber erstellt, um zurückzukehren.

Es funktioniert jetzt gut.

Poco Entity:

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;}
}
aamir sajjad
quelle
0

Ihre Frage ist meiner ziemlich ähnlich. Sie dürfen keine Daten direkt aus der Datenbank zurückgeben. Dazu müssen Sie ein Modell erstellen und Daten zuordnen, die angezeigt werden sollen.

In meinem Beispiel gibt es Daten zu Benutzern, die Json nicht serialisieren konnte. Ich hatte ein Benutzermodell erstellt und in meiner API gebe ich stattdessen Benutzermodell Benutzer aus Datenbank zurück.

Die Logik zum Konvertieren oder Zuordnen von Daten zwischen User und UserModel muss in der API enthalten sein.

Fehler beim Serialisieren der Antwort in der Web-API mit Json

CampDev
quelle
0

Dies war der spezifische Fehler, den ich von meinem Odata-Web-API-Aufruf erhalten habe:

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

Ich fand schließlich heraus, dass meine dbContext-Klasse einen schlecht formatierten Tabellennamen hatte , der in onModelCreating zugewiesen wurde. Also starb der SqlClient auf der Suche nach einer Tabelle, die in meiner Datenbank nicht vorhanden war !!

bkwdesign
quelle