Yanıtı Web API'sinde Json ile seri hale getiremedi


109

ASP.NET MVC 5 Web Api ile çalışıyorum. Tüm kullanıcılarıma danışmak istiyorum.

Yazdım api/usersve şunu alıyorum:

"'ObjectContent`1' türü, 'application / json; charset = utf-8' içerik türü için yanıt gövdesini serileştiremedi"

WebApiConfig'te şu satırları zaten ekledim:

HttpConfiguration config = new HttpConfiguration();
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

Ama yine de çalışmıyor.

Dönüş verileri için fonksiyonum şudur:

public IEnumerable<User> GetAll()
{
    using (Database db = new Database())
    {
        return db.Users.ToList();
    }
}

Tüketiciye aktarmaya çalıştığınız değer nesnesi neye benziyor?
mckeejm

Çok teşekkürler! Sadece fyi - Sanırım şunu okumalı: using (Database db = new Database ()) {List <UserModel> listOfUsers = new List <UserModel> (); foreach (db.Users'daki var kullanıcı) {UserModel userModel = new UserModel (); userModel.FirstName = user.FirstName; userModel.LastName = user.LastName; listOfUsers.Add (userModel); } IEnumerable <UserModel> users = listOfUsers; geri dönen kullanıcılar; } .. sonuçların hepsi aynı değerleri döndürdüğü için.
Jared Whittington

Yanıtlar:


76

Verileri Web Api'den (veya bu konuyla ilgili başka bir web hizmetinden) tüketiciye geri döndürmek söz konusu olduğunda, bir veritabanından gelen varlıkları geri vermemenizi şiddetle tavsiye ederim. Veritabanının değil, verilerin neye benzediğini kontrol ettiğiniz Modelleri kullanmak çok daha güvenilir ve sürdürülebilirdir. Bu şekilde, WebApiConfig konsolundaki biçimlendiricilerle çok fazla uğraşmanıza gerek kalmaz. Özellik olarak alt Modellere sahip bir UserModel oluşturabilir ve dönüş nesnelerindeki referans döngülerinden kurtulabilirsiniz. Bu, serileştiriciyi çok daha mutlu kılar.

Ayrıca, genellikle istekte yalnızca "Kabul Ediyor" başlığını belirtiyorsanız, biçimlendiricileri veya desteklenen ortam türlerini kaldırmanız gerekmez. Bu şeylerle uğraşmak bazen işleri daha kafa karıştırıcı hale getirebilir.

Misal:

public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
    // Other properties here that do not reference another UserModel class.
}

Modellere atıfta bulunduğunuzda, ne yaptığımı söylemek ister misiniz? Return IEnumerable of Users Model olan.
CampDev

5
Bir Varlığı iade ediyorsunuz. Bir varlık, DB'deki benzersiz bir id ile alınabilen bir nesneyi ifade eder. Veritabanınızdan tüm Kullanıcı varlıklarını iade ediyorsunuz. "UserModel" adında yeni bir sınıf oluşturmanızı ve veritabanından aldığınız her bir Kullanıcı varlığı için, açığa çıkarmak istediğiniz gerekli bilgilerle doldurulmuş yeni bir veri modeli sınıfı örneği oluşturmanızı öneriyorum. User varlıklarının tersine UserModel nesnelerinin IEnumerable'ını döndürür. Model Özelliklerinin UserModel sınıfının örneklerine başvurmadığından emin olun. Sizi bu soruna sokan da budur.
jensendp

3
ncampuzano doğru, otomatik olarak oluşturulan varlıkları döndürmek istemezsiniz. Veritabanına erişim için saklı yordamları kullanıyorsanız, ayırma daha net olacaktır. Bir C # değer nesnesi oluşturmanız ve IDataReader'dan değer nesnesine eşlenmiş değerler oluşturmanız gerekir. EF'yi kullandığınız için, sizin için oluşturulan sınıflar vardır, ancak bunlar değerli nesnelerin yaptığından daha fazlasını bilen özel EF sınıflarıdır. İstemcinize yalnızca "aptal" değer nesnelerini iade etmelisiniz.
mckeejm

1
@Donny Denetleyicinizde varlıkları DB'den geri döndüren bir DBContext veya Depo kullanıyorsanız, nesneleri denetleyicideki modellere (örneğin bir DTO) eşleyebilirsiniz ... ancak ben denetleyici modeli / DTO döndüren bir hizmeti çağırır. AutoMapper'a göz atın - haritalamayı işlemek için harika bir araç.
ben

1
@NH. Kesinlikle yukarıda belirtilen saçmalıkları kullanabilirsiniz, ancak her şeyin bir yeri vardır. Veri Katmanına erişim tarafından sağlanan "varlıklar" genellikle Veri Katmanında kalmalıdır. Bu verileri uygulamanın İş Katmanı içinde kullanmak isteyen herhangi bir şey, tipik olarak "varlıkları" da dönüştürülmüş bir biçimde (Etki Alanı Nesneleri) kullanacaktır. Ve sonra kullanıcıya döndürülen ve kullanıcıdan girilen veriler de tipik olarak başka bir form (Modeller) olacaktır. Bu tür bir dönüşümü her yerde yapmanın sıkıcı olabileceği kabul edildi, ancak AutoMapper gibi araçların gerçekten işe yaradığı yer burasıdır.
jensendp

147

EF ile çalışıyorsanız, aşağıdaki kodu Global.asax'a eklemenin yanı sıra

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

İçe aktarmayı unutma

using System.Data.Entity;

Ardından kendi EF Modellerinizi iade edebilirsiniz

Bu kadar basit!


EF için yardımcı olsa bile, çözüm EF'e özgü değildir ve diğer tür modellerle de çalışır. Global.asax'ta kullanılması gerekli görünmüyor. Kontrolörler için mi tasarlandı?
Matthieu

16
Bu kodun ne yaptığı ve etkileri hakkında bazı açıklamalar memnuniyetle karşılanacaktır.
Jacob

1
Teşekkürler benzer bir sorunla karşı karşıyaydım, bu cevap sorunu çözmeme yardımcı oldu.
RK_Aus

Benim için çalışıyor. System.Data.Entity kullanarak eklemeye gerek yok; global.asax'a. Teşekkür ederim.
Dr MAF

İşe yarıyor. Global.asax üzerine basit kod ekleyin, hepsi bu, System.Data.Entity kullanarak içe aktarmaya gerek yok;
Vahap Ramphul

52

Doğru cevap vermek, gitmenin bir yoludur, ancak tek bir yapılandırma ayarıyla düzeltebilmeniz aşırı bir durumdur.

Dbcontext yapıcısında kullanmak daha iyidir

public DbContext() // dbcontext constructor
            : base("name=ConnectionStringNameFromWebConfig")
{
     this.Configuration.LazyLoadingEnabled = false;
     this.Configuration.ProxyCreationEnabled = false;
}

Asp.Net Web API Hatası: 'ObjectContent`1' türü, içerik türü 'application / xml için yanıt gövdesini serileştiremedi; karakter kümesi = UTF-8'


Modeli veritabanından güncellersek kodunuz kaldırılacaktır.
Bimal Das

1
.Tt dosyalarını kaldırarak kolayca ayırabilir ve ayrık bağlama sahip olabilirsiniz. Modeli her oluşturduğunuzda, yerine yeni bir sınıf ekleyin. @Brimal: Bunu youtube.com/watch?v=yex0Z6qwe7A
Md. Alim Ul Karim

1
Üzerine yazmayı önlemek için, edmx özelliklerinden geç yüklemeyi devre dışı bırakabilirsiniz. Benim için çalıştı.
Francisco G

@FranciscoG işe yarıyor, ancak edmx'i kaldırıp yeniden oluşturursak kaybolur.
Md. Alim Ul Karim

1
@BimalDas bunu youtube.com/… deneyin . Bu kaldırılmayacak
Md Alim Ul Karim.

37

Bu kodu global.asaxaşağıya ekleyin Application_Start:

Dan güncelleyin .Ignoreiçin .Serialize. Çalışması gerekir.

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

1
Harika çalışıyor, teşekkürler !, Çalışması için Xml Formatter'ı neden kaldırmamız gerektiğini daha iyi açıklayabilir misiniz?
Jav_1

Json serileştiriciyi eklemeye gerek yok (en azından benim durumumda) ancak Xml biçimlendirmesini kaldırmak gerekiyordu. Ben tahmin xml serialiser anonim türleri tefrika edemez ve onu kaldırarak sonucu json olarak tefrika edilir. Tahminim doğruysa, MIME türü "application / json" sorulduğunda denetleyiciden veri alınabilir.
LosManos

11
public class UserController : ApiController
{

   Database db = new Database();

   // construction
   public UserController()
   {
      // Add the following code
      // problem will be solved
      db.Configuration.ProxyCreationEnabled = false;
   }

   public IEnumerable<User> GetAll()
    {
            return db.Users.ToList();
    }
}

Vay canına, benim için çalıştı. Ama neden? ProxyCreationEnabled özelliği ne yapar?
jacktric

benimle çalıştı ama bu kod ne? ayrıca tüm alt sınıfların null ile alındığını da not ettim !!
Waleed A. Elgalil

10

Bu kodu beğenmedim:

foreach(var user in db.Users)

Alternatif olarak, benim için işe yarayan böyle bir şey yapılabilir:

var listOfUsers = db.Users.Select(r => new UserModel
                         {
                             userModel.FirstName = r.FirstName;
                             userModel.LastName = r.LastName;

                         });

return listOfUsers.ToList();

Ancak, Lucas Roselli'nin çözümünü kullandım.

Güncelleme: Anonim bir nesne döndürerek basitleştirilmiştir:

var listOfUsers = db.Users.Select(r => new 
                         {
                             FirstName = r.FirstName;
                             LastName = r.LastName;
                         });

return listOfUsers.ToList();

10

Bu kodu kullanarak WebApiConfig.cs dosyasına çözdüm

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

çok teşekkürler. bunun güvenliğe ne yaptığını bilmiyorum.
Arun Prasad ES

6

Aynı hatayı oluşturan şu senaryo da var:

Geri dönüşün bir List<dynamic>web api yöntemi olması durumunda

Misal:

public HttpResponseMessage Get()
{
    var item = new List<dynamic> { new TestClass { Name = "Ale", Age = 30 } };

    return Request.CreateResponse(HttpStatusCode.OK, item);
}

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Dolayısıyla, bu senaryo için, dönüş sınıfında (tümü) [KnownTypeAttribute] 'u şu şekilde kullanın:

[KnownTypeAttribute(typeof(TestClass))]
public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Bu benim için çalışıyor!


Dinamik sütunlarla linq pivot kullanıyorsanız ne olur?
codegrid

[KnownTypeAttribute (typeof (TestClass))] sorunumu çözdü
Guillaume Raymond

6

Bunu dosya Application_Start()yönteminize eklemek Global.asaxsorunu çözmelidir

protected void Application_Start()
{
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
        .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    GlobalConfiguration.Configuration.Formatters
        .Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); 
// ...
}

YÖNTEM 2: [Önerilmez]
EntityFramework ile çalışıyorsanız, DbContext sınıfı yapıcınızda proxy'yi devre dışı bırakabilirsiniz. NOT: modeli güncellerseniz bu kod kaldırılacaktır.

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.ProxyCreationEnabled = false;
  }
}

1
Teşekkürler Suman. Ben de aynı sorunu yaşıyordum. Web API'mi test ediyordum ve bu sorunla uğraşıyordum. çözümünüz sorunu çözer. çok teşekkürler.
TarakPrajapati

4

Kişisel favorim: Aşağıdaki kodu bölümüne eklemeniz yeterli App_Start/WebApiConfig.cs. Bu, varsayılan olarak XML yerine json döndürür ve ayrıca sahip olduğunuz hatayı önler. Global.asaxKaldırmak için düzenlemeye gerek yok XmlFormattervb.

'ObjectContent`1' türü, içerik türü 'application / xml için yanıt gövdesini serileştiremedi; karakter kümesi = UTF-8

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

2

AutoMapper'ı kullanın ...

public IEnumerable<User> GetAll()
    {
        using (Database db = new Database())
        {
            var users = AutoMapper.Mapper.DynamicMap<List<User>>(db.Users);
            return users;
        }
    }

2

Aşağıdaki ad alanını kullanın:

using System.Web.OData;

Onun yerine :

using System.Web.Http.OData;

Benim için çalıştı


2

Aşağıdaki satırı ekleyin

this.Configuration.ProxyCreationEnabled = false;

ProxyCreationEnabledOlarak kullanmanın iki yolu false.

  1. İç ekleyin DBContextOluşturucu

    public ProductEntities() : base("name=ProductEntities")
    {
        this.Configuration.ProxyCreationEnabled = false;
    }

VEYA

  1. GetYöntemin içindeki satırı ekleyin

    public IEnumerable<Brand_Details> Get()
    {
        using (ProductEntities obj = new ProductEntities())
        {
            this.Configuration.ProxyCreationEnabled = false;
            return obj.Brand_Details.ToList();
        }
    }

2

Benim için çalışan çözüm:

  1. Serileştirilecek her özelliğin [DataContract]sınıf ve [DataMember]öznitelikleri için kullanın . Bu, Json sonucunu almak için yeterlidir (örneğin, kemancıdan).

  2. Xml serileştirme almak için Global.asaxbu kodu yazın:

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

  3. Bu makaleyi okuyun, serileştirmeyi anlamama yardımcı oldu: https://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

1

Jensendp'in cevabına eklemek için:

Varlığı, kullanıcı tarafından oluşturulan bir modele aktarır ve bu varlıktaki değerleri yeni oluşturduğunuz modeldeki değerleri ayarlamak için kullanırdım. Örneğin:

public class UserInformation {
   public string Name { get; set; }
   public int Age { get; set; }

   public UserInformation(UserEntity user) {
      this.Name = user.name;
      this.Age = user.age;
   }
}

Ardından iade türünüzü şu şekilde değiştirin: IEnumerable<UserInformation>


1
sizin için çeviriyi halletmenin daha zarif yolları var, böylece her özelliği korumak zorunda kalmazsınız .. AutoMapper ve ValueInjecter dikkate değer 2 tanesi
Sonic Soul

1

Bu benim hatam

Temel olarak bir satır ekliyorum ki

  • entities.Configuration.ProxyCreationEnabled = false;

UsersController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using UserDataAccess;

namespace SBPMS.Controllers
{
    public class UsersController : ApiController
    {


        public IEnumerable<User> Get() {
            using (SBPMSystemEntities entities = new SBPMSystemEntities()) {
                entities.Configuration.ProxyCreationEnabled = false;
                return entities.Users.ToList();
            }
        }
        public User Get(int id) {
            using (SBPMSystemEntities entities = new SBPMSystemEntities()) {
                entities.Configuration.ProxyCreationEnabled = false;
                return entities.Users.FirstOrDefault(e => e.user_ID == id);
            }
        }
    }
}

İşte çıktım:


1

Sınıf için [Serializable] kullanın:

Misal:

[Serializable]
public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
}

Benim için çalıştı!


1
Bu şekilde ifade edersek, bu yazıyı daha önce cevaplayan herkesin aptal olduğu neredeyse düşünülebilirdi;)… Öyle olduğundan ciddi şüpheliyim, bu yüzden bu çözüm 2015'te soru sorulduğunda muhtemelen uygulanabilir olmadığı anlamına geliyor ... Bu sözdizimi hakkında kendim pek bir şey bilmiyorum, ancak ya nispeten yeni olduğu ya da belirli kullanım durumlarında onu kullanılamaz hale getiren bazı dezavantajları olabileceğini hissediyorum. Çözümünüzün bu soruya ulaşan gelecekteki okuyucular için faydalı olabileceğini düşünüyorum, ancak sınırlamalarını netleştirmeniz kesinlikle yardımcı olacaktır.
jwatkins

1

App_Start Klasöründe bulunan WebApiConfig.cs içinde Serializer Formatter'ı tanımlamanız gerekecektir.

Config.Formatters.Remove (config.Formatters.XmlFormatter) ekleme; // size JSON Formatında veri sağlayacak

Config.Formatters.Remove (config.Formatters.JsonFormatter) ekleme; // size XML Biçiminde veri sağlayacak


Madalyayı hak ediyorsun.
TheKrogrammer

1

Aşağıdaki satırları global.asax içine koyun:

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

İthalat

using System.Data.Entity;

0

Bu hatayı aldığım başka bir durum, veritabanı sorgumun boş bir değer döndürdüğü, ancak kullanıcı / görünüm modeli türümün null yapılamaz olarak ayarlandığı zamandı. Örneğin, benim UserModel alanı değiştirdikten intiçin int?çözüldü.


0

Bu, Response-Type herkese açık olmadığında da olur! Bana tür oluşturmak için Visual Studio kullandığım için dahili bir sınıf döndürdüm.

internal class --> public class

0

Yukarıdaki tüm bu cevaplar doğru olsa da, InnerException> ExceptionMessage'ı kontrol etmek isteyebilir .

Böyle bir şey söylüyorsa ObjectContext örneği atıldı ve artık bağlantı gerektiren işlemler için kullanılamaz. " Bu, EF'nin varsayılan davranışı nedeniyle bir sorun olabilir.

DbContext yapıcınızda LazyLoadingEnabled = false atayarak hile yapacak.

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.LazyLoadingEnabled = false;
  }
}

EF'nin EagerLoading ve LazyLoading davranışı hakkında daha ayrıntılı okuma için bu MSDN Makalesine bakın .


0

Benim durumumda benzer bir hata mesajı aldım:

'ObjectContent`1' türü, içerik türü 'application / xml için yanıt gövdesini serileştiremedi; karakter kümesi = UTF-8' .

Ama daha derine indiğimde sorun şuydu:

'SomeSubRootType: //schemas.datacontract.org/2004/07/WhatEverService' veri sözleşmesi adıyla 'name.SomeSubRootType' yazın. DataContractSerializer kullanıyorsanız veya bilinen türler listesine statik olarak bilinmeyen türler ekliyorsanız bir DataContractResolver kullanmayı düşünün - örneğin, KnownTypeAttribute özniteliğini kullanarak veya bunları serileştiriciye geçirilen bilinen türler listesine ekleyerek.

Ekleyerek çözdüğüm yol KnownType.

[KnownType(typeof(SomeSubRootType))]
public partial class SomeRootStructureType

Bu, bu cevaptan esinlenerek çözüldü .

Referans: https://msdn.microsoft.com/en-us/library/ms730167(v=vs.100).aspx


0

Visual Studio 2017 veya 2019 bu konuda tamamen düşüncesizdir çünkü Visual Studio çıktının json biçiminde olmasını gerektirirken, Visual Studio'nun varsayılan biçimi " XmlFormat" (config.Formatters.XmlFormatter) şeklindedir .

Visual Studio, geliştiricilere bu kadar sorun yaşatmak yerine bunu otomatik olarak yapmalıdır.

Bu sorunu düzeltmek için WebApiConfig.cs dosyasına gidin ve

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

Register (HttpConfiguration config) yönteminde " config.MapHttpAttributeRoutes (); " sonra . Bu, projenizin json çıktısı üretmesine izin verecektir.


0

Benim durumumda veritabanını yeniden oluşturmayı çözdüm. Bir modelde bazı değişiklikler yaptım ve Paket Yöneticisi Konsolunda Güncelleme-Veritabanını başlatırken aşağıdaki Hatayı aldım:

"ALTER TABLE deyimi, FOREIGN KEY kısıtlaması" FK_dbo.Activities_dbo.Projects_ProjectId "ile çakıştı. Çakışma" TrackEmAllContext-20190530144302 "veritabanında," dbo.Projects "tablosunda, 'Id' sütununda meydana geldi."


0

Durumda: WebApiConfig.cs veya Global.asax.cs'ye kod eklemek işinize yaramazsa:

.ToList();

.ToList () işlevi ekleyin.

Her çözümü denedim ama aşağıdakiler benim için çalıştı:

var allShops = context.shops.Where(s => s.city_id == id)**.ToList()**;
return allShops;

Umut ediyorum bu yardım eder.


0

benim durumumda, sanal anahtar kelimeyi navigasyon özelliklerimden önce kaldırdığımda düzeltildi, yani referans tabloları. bu yüzden değiştim

public virtual MembershipType MembershipType { get; set; }

için:

public MembershipType MembershipType { get; set; }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.