nie udało się serializować odpowiedzi w internetowym interfejsie API

86

Pracowałem na internetowym API ASP.NET MVC, mam ten błąd:

Typowi „ObjectContent” 1 nie udało się serializować treści odpowiedzi dla typu zawartości „application / xml”; charset = utf-8 '.

Mój kontroler to:

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

dlaczego otrzymuję ten błąd?

Tamal kanti Dey
źródło
6
Wyjątek, który widzisz, jest wyjątkiem ogólnym, który może być spowodowany wieloma czynnikami. Sprawdź InnerExceptionwłaściwość wyjątku serializacji, aby dowiedzieć się, co dokładnie spowodowało niepowodzenie serializacji.
Nazwa wyświetlana
Czy możesz udostępnić kod swojego typu pracownika? Może to być spowodowane tym, że typ pracownika nie daje się serializować ...
Maggie Ying
Spójrz także na ten stackoverflow.com/questions/8173524/ ...
sttaq

Odpowiedzi:

121

Dla mnie był to problem z odniesieniami cyklicznymi.

Zaakceptowana odpowiedź nie zadziałała, ponieważ zmieniała tylko zachowanie programu formatującego JSON, ale otrzymywałem XML, gdy dzwoniłem do usługi z przeglądarki.

Aby to naprawić, wyłączyłem XML i wymusiłem zwracanie tylko JSON.

W pliku Global.asax umieść następujące wiersze u góry metody Application_Start:

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

Teraz zostaną zwrócone tylko wyniki JSON. Jeśli potrzebujesz wyników XML, musisz znaleźć inne rozwiązanie.

Zane
źródło
pracował dla mnie. ale rzecz w tym, że używam POSTMAN. to rozszerzenie do Chrome. kiedy wysyłam dane za pomocą POSTMAN, działa dobrze. ale kiedy używam restsharp, daje mi ten błąd. w każdym razie twoje rozwiązanie rozwiązało mój problem
ArgeKumandan,
Ta odpowiedź nie dostarcza rozwiązania do używania xml i o to właśnie prosił.
szczery
Działa dla mnie, gdy przełączyłem się na json z xml.
Sike12
Właściwie ta odpowiedź dociera do źródła problemu. Pierwszym otrzymanym błędem był cykliczny błąd odwołania (próba zwrócenia JSON z kontrolera MVC). Kiedy przełączyłem się na kontroler dziedziczony po API, zacząłem otrzymywać ten błąd. Kiedy dodałem powyższy kod do Global.asax, błąd zniknął.
Matthew Pitts
43

w pliku global.asax, w metodzie Application_start () dodaj następujący wiersz:

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

Mam nadzieję, że ci to pomoże!

Julito Avellaneda
źródło
3
Co to jest application_start i gdzie można go znaleźć? A gdzie dokładnie należy umieścić tę linię?
Ciaran Gallagher
4
Przepraszam, ale jakie jest znaczenie tego stwierdzenia?
Blaise
5
Linia dodany do Global.asax„s Application_Start, ale bez zmian.
ser
8
To nadal nie działa dla mnie. Jednak dodałem kolejną linię po jednej w tej odpowiedzi i zadziałało: GlobalConfiguration.Configuration.Formatters.Remove (GlobalConfiguration.Configuration.Formatters.XmlFormatter); Poniżej utworzyłem pełniejszą odpowiedź
Zane
2
Ta odpowiedź nie powinna zostać zaakceptowana, ponieważ faktycznie usuwa XmlSerializer zamiast rozwiązywania problemu cyklicznego odwołania z XmlSerializer.
Believe2014
29

Mam ten sam problem. I rozwiązałem to. Domyślnego konstruktora umieściłem w klasie DTO.

Dawny:

public class User
{
    public User()
    {
    }
}

Mam nadzieję, że to zadziała!

taynguyen
źródło
Dzięki za sugestię, pomogło mi to w odpowiedzi xml, ale czy ktoś wie, dlaczego potrzebuje domyślnego konstruktora? Mamy już dane ...
Ilya Chernomordik
Myślę, że gdy obiekt jest serializowany z odpowiedzi, najpierw został wywołany konstruktor w celu utworzenia instancji obiektu, a następnie metoda set służy do ustawiania danych na instancję obiektu. To moje przypuszczenie.
taynguyen
Właściwie to powinna być wybrana odpowiedź, ponieważ nie przyjmuje żadnych założeń dotyczących typów zwrotów, których potrzebujesz. To zadziała zarówno dla XML, jak i JSON. Dzięki za opublikowanie tego.
Allen Underwood
22

Umieść to w konstruktorze. Mam nadzieję, że to rozwiąże problem:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }
Sadjad Khazaie
źródło
Doskonałe rozwiązanie. Muszę włożyć to do konstruktora i zadziałało.
InsParbo
To zadziałało dla mnie w połączeniu z ustawieniami GlobalConfiguration. Ale dlaczego to działa? Jakieś wyjaśnienie, jak to rozwiązuje problem? Na czym właściwie polegał problem?
Ciaran Gallagher
Aby zrozumieć, czym są proxy encji: msdn.microsoft.com/en-us/library/jj592886(v=vs.113).aspx Aby zrozumieć, czym jest ProxyCreationEnabled: stackoverflow.com/questions/7111109/…
Sadjad Khazaie
16

Znalazłem dwa rozwiązania tego problemu. Pierwszym i najłatwiejszym do zaimplementowania jest zmiana dowolnego IEnumerables, ICollections na typ List. Interfejs WebAPI może serializować te obiekty, ale nie może serializować typów interfejsów.

public class Store
{

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

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

Inną opcją jest nieużywanie natywnego serializatora JSON i uruchomienie tego zastąpienia w metodzie Register w WebApi Config:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);
Ray Suelzer
źródło
1
Podczas zmiany na List zadziałało dla mnie dodanie konstruktora bez parametrów i mogłem nadal zwracać IEnumerable <Widget>
Mike Cheel
8

Rozwiązanie jest proste.

Po zapytaniu LINQ dodaj .ToList () (lub ToDictionary w razie potrzeby).

Będzie ładować chętniej niż leniwie ładowanie danych

om471987
źródło
1
Zmiana typu powrotu akcji na IENumerablei dodanie .TiList()do zwrotu zadziałało.
Ricardo Souza
5

** ten błąd występuje podczas wywoływania z żądania internetowego interfejsu API / wcf / ... ze strony klienta, ale jako efekt uboczny, będziesz musiał dołączyć zależne relacje przez słowo kluczowe include. **

public CustomerPortalContext()
            : base("Name=CustomerPortalContext")
        {
            base.Configuration.ProxyCreationEnabled = false;
        }
Mohamed Abdo
źródło
4

Jeśli pracujesz z EF, oprócz dodania poniższego kodu na Global.asax

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

Nie zapomnij zaimportować

using System.Data.Entity;

Następnie możesz zwrócić własne modele EF

Lucas Roselli
źródło
3

Jeśli używasz interfejsu API sieci Web z Entity Framework, rozwiązanie może zakończyć się niepowodzeniem serializacji odpowiedzi w interfejsie API sieci Web z Json

Zasadniczo musisz utworzyć model odpowiadający każdemu modelowi EF, usuwa to zależności między klasami i umożliwia łatwą serializację.

Kod: (pobrany z odnośnika)

Utwórz model użytkownika

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

Zmień moją metodę 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
źródło
2

Domyślna jednostka 6 używa XML do apis, w swoim projekcie znajdź plik „Global.asax” File i dodaj ten wiersz:

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

Ta linia usuwa XML Formatter.

Roberth Solís
źródło
Witaj, Web API serializuje odpowiedź w XML i JSON, jeśli dodasz nagłówek Content-Type: application / json, odpowiedź jest w formacie JSON, musisz zdefiniować ten nagłówek, w przeglądarce zawsze możesz zobaczyć go jako format XML
Roberth Solís
1

ale jeśli znalazłeś ten problem z innymi bytami / klasami, musisz stworzyć nowe DTO dla każdej klasy, a jeśli masz ich dużo, możesz znaleźć problem, również myślę, że tworzymy DTO tylko do rozwiązania tego problemu nie jest najlepszym sposobem ...

Próbowałeś tego?

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

pozdrowienia

Julito Avellaneda
źródło
1

hmmm, Poniższe mogą pomóc.

Otrzymałem ten sam wyjątek, aw moim przypadku najpierw przekazywałem rzeczywistą jednostkę poco utworzoną dla kodu jednostki. Ponieważ zawiera on relacje z innymi bytami, właśnie utworzyłem na nim byty viewmapper / dto, aby powracały.

Teraz działa dobrze.

Podmiot 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;}
}
aamir sajjad
źródło
0

Twoje pytanie jest dość podobne do mojego. Nie możesz zwracać danych bezpośrednio z bazy danych. W tym celu musisz utworzyć Model i skojarzyć dane, które chcesz pokazać.

W moim przykładzie są dane o użytkowniku, których Json nie mógł serializować, utworzyłem userModel iw moim API zwracam userModel zamiast User z bazy danych.

Logika konwertowania lub kojarzenia danych między użytkownikiem a modelem użytkownika musi znajdować się w interfejsie API.

Nie udało się serializować odpowiedzi w internetowym interfejsie API za pomocą Json

CampDev
źródło
0

To był konkretny błąd, który otrzymałem z mojego wywołania internetowego interfejsu API odata:

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

W końcu zorientowałem się, że moja klasa dbContext miała źle sformatowaną nazwę tabeli, która została przypisana w onModelCreating .. więc SqlClient umierał, szukając tabeli, której nie było w mojej bazie danych !!

bkwdesign
źródło