Json을 사용하여 Web API에서 응답을 직렬화하지 못했습니다.


109

ASP.NET MVC 5 Web Api로 작업하고 있습니다. 모든 사용자에게 문의하고 싶습니다.

나는 이것을 썼고 api/users나는 이것을 받았다.

" 'ObjectContent`1'유형이 'application / json; charset = utf-8'컨텐츠 유형에 대한 응답 본문을 직렬화하지 못했습니다."

WebApiConfig에서 이미 다음 줄을 추가했습니다.

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

하지만 여전히 작동하지 않습니다.

반환 데이터에 대한 내 기능은 다음과 같습니다.

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

소비자에게 전달하려는 값 개체는 어떻게 생겼습니까?
mckeejm 2014

정말 고마워! 그냥 fyi-읽어야한다고 생각합니다. using (Database db = new Database ()) {List <UserModel> listOfUsers = new List <UserModel> (); foreach (var user in db.Users) {UserModel userModel = new UserModel (); userModel.FirstName = user.FirstName; userModel.LastName = user.LastName; listOfUsers.Add (userModel); } IEnumerable <UserModel> 사용자 = listOfUsers; 반환 사용자; } .. 결과가 모두 동일한 값을 반환했기 때문입니다.
Jared Whittington

답변:


76

Web Api (또는 해당 문제에 대한 다른 웹 서비스)에서 소비자에게 데이터를 반환하는 경우 데이터베이스에서 가져온 엔터티를 다시 전달하지 않는 것이 좋습니다. 데이터베이스가 아닌 데이터의 모양을 제어 할 수있는 모델을 사용하는 것이 훨씬 더 안정적이고 유지 관리가 쉽습니다. 이렇게하면 WebApiConfig에서 포맷터를 너무 많이 다룰 필요가 없습니다. 속성으로 자식 모델이있는 UserModel을 만들고 반환 개체에서 참조 루프를 제거 할 수 있습니다. 이것은 serializer를 훨씬 더 행복하게 만듭니다.

또한 요청에 "Accepts"헤더 만 지정하는 경우 일반적으로 포맷터 또는 지원되는 미디어 유형을 제거 할 필요가 없습니다. 그 물건을 가지고 노는 것은 때때로 일을 더 혼란스럽게 만들 수 있습니다.

예:

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

모델을 언급 할 때 내가하는 일을 말하고 싶습니까? 모델 인 사용자의 IEnumerable을 반환합니다.
CampDev 2014

5
엔티티를 반환합니다. 엔티티는 고유 한 ID로 검색 할 수있는 DB의 개체를 의미합니다. 데이터베이스에서 모든 사용자 엔터티를 반환합니다. "UserModel"이라는 새 클래스를 만들고 데이터베이스에서 가져온 각 User 엔터티에 대해 노출하려는 필수 정보로 채워진 데이터 모델 클래스의 새 인스턴스를 만드는 것이 좋습니다. User 엔터티가 아닌 UserModel 개체의 IEnumerable을 반환합니다. 모델 속성이 UserModel 클래스의 인스턴스를 참조하지 않는지 확인하십시오. 그것이 당신을이 문제에 빠지게하는 것입니다.
jensendp 2014

3
ncampuzano가 정확합니다. 자동 생성 된 엔티티를 반환하고 싶지 않습니다. 데이터베이스 액세스에 저장 프로 시저를 사용하는 경우 분리가 더 명확 해집니다. C # 값 개체를 생성하고 IDataReader의 값을 값 개체에 매핑해야합니다. EF를 사용하고 있기 때문에 생성되는 클래스가 있지만 값 개체보다 더 많은 것을 알고있는 특수 EF 클래스입니다. 클라이언트에 "dumb"값 개체 만 반환해야합니다.
mckeejm 2014

1
@Donny DB에서 엔티티를 다시 반환하는 컨트롤러에서 DBContext 또는 Repository를 사용하는 경우 컨트롤러의 모델 (예 : DTO)에 개체를 매핑 할 수 있지만 컨트롤러는 모델 / DTO를 반환하는 서비스를 호출합니다. AutoMapper-매핑 처리를위한 훌륭한 도구를 확인하십시오.
ben

1
@NH. 앞서 말한 헛소리를 절대적으로 사용할 수 있지만 모든 것이 그 자리에 있습니다. 데이터 영역에 대한 액세스로 제공되는 "항목"은 일반적으로 데이터 영역에 있어야합니다. 응용 프로그램의 비즈니스 계층 내에서이 데이터를 사용하려는 모든 것은 일반적으로 변환 된 형식 (도메인 개체)의 "엔티티"도 사용합니다. 그리고 사용자에게 반환되고 입력되는 데이터는 일반적으로 다른 형식 (모델)이됩니다. 모든 곳에서 이러한 유형의 변환을 수행하는 것은 지루할 수 있지만 AutoMapper와 같은 도구가 실제로 유용한 곳입니다.
jensendp

147

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 모델을 반환 할 수 있습니다.

그렇게 간단합니다!


EF에 도움이 되더라도 솔루션은 EF에만 국한되지 않으며 다른 종류의 모델에서도 작동합니다. Global.asax에서는 사용이 필요하지 않은 것 같습니다. 컨트롤러 용입니까?
Matthieu

16
이 코드가하는 일과 그 의미에 대한 몇 가지 설명을 환영합니다.
야곱

1
비슷한 문제에 직면 해 주셔서 감사합니다.이 답변은 문제를 해결하는 데 도움이되었습니다.
RK_Aus

그것은 나를 위해 작동합니다. System.Data.Entity를 사용하여 추가 할 필요가 없습니다. global.asax에. 감사합니다.
Dr. MAF

효과가있다. Global.asax에 위의 간단한 코드를 추가하면 System.Data.Entity를 사용하여 가져올 필요가 없습니다.
Hemant Ramphul

52

정답이 주어지면 한 가지 방법이지만 하나의 구성 설정으로 수정할 수 있다면 과잉입니다.

dbcontext 생성자에서 사용하는 것이 더 좋습니다.

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

Asp.Net Web API 오류 : 'ObjectContent`1'유형이 'application / xml'콘텐츠 유형에 대한 응답 본문을 직렬화하지 못했습니다. charset = utf-8 '


데이터베이스에서 모델을 업데이트하면 코드가 제거됩니다.
Bimal Das

1
.tt 파일을 제거하여 쉽게 분리 할 수 ​​있으며 컨텍스트가 분리되어 있습니다. 모델을 생성 할 때마다 그 자리에 새 클래스를 추가하십시오. @Brimal : You can follow this youtube.com/watch?v=yex0Z6qwe7A
Md. Alim Ul Karim

1
덮어 쓰기를 방지하기 위해 edmx 속성에서 지연로드를 비활성화 할 수 있습니다. 그것은 나를 위해 일했습니다.
Francisco G

@FranciscoG 작동하지만 edmx를 제거하고 재생성하면 손실됩니다.
. 메릴랜드 Alim에 UL 카림

1
@BimalDas이 youtube.com/…을 사용 해보세요 . 그것은 제거하지 않습니다
메릴랜드를 Alim에 UL 카림.

37

이 코드를 global.asax아래에 추가하십시오 Application_Start.

에서 .Ignore로 업데이트하십시오 .Serialize. 작동해야합니다.

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

1
감사합니다!, Xml Formatter를 제거해야하는 이유를 더 잘 설명해 주시겠습니까?
Jav_1

(적어도 제 경우에는) json serialiser를 추가 할 필요가 없지만 Xml 형식을 제거해야했습니다. 내가 생각 하는 XML 시리얼 라이저는 익명의 유형에는 직렬화 할 수없는 그것을 제거하여 결과를 JSON으로 직렬화됩니다. 내 추측이 맞으면 MIME 유형 "application / json"을 요청하여 컨트롤러에서 데이터를 가져올 수 있습니다.
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();
    }
}

와우, 저에게 효과적이었습니다. 그런데 왜? ProxyCreationEnabled 속성의 기능은 무엇입니까?
jacktric

나와 함께 일했지만이 코드는 무엇입니까? 나는 또한 모든 하위 클래스가 null !!
Waleed A. Elgalil

10

이 코드가 마음에 들지 않습니다.

foreach(var user in db.Users)

대안으로 다음과 같이 할 수 있습니다.

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

                         });

return listOfUsers.ToList();

그러나 결국 Lucas Roselli의 솔루션을 사용하게되었습니다.

업데이트 : 익명 객체를 반환하여 단순화 :

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

return listOfUsers.ToList();

10

이 코드를 사용하여 WebApiConfig.cs 파일에 해결했습니다.

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

감사합니다. 이것이 보안에 어떤 영향을 미치는지 모르겠습니다.
Arun Prasad ES

6

동일한 오류를 생성하는 다음 시나리오도 있습니다.

반환이 List<dynamic>웹 API 메서드 인 경우

예:

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; }
}

따라서이 시나리오의 경우 다음과 같이 반환 클래스 (모두)에서 [KnownTypeAttribute]를 사용합니다.

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

이것은 나를 위해 작동합니다!


동적 열과 함께 linq 피벗을 사용하는 경우 어떻게해야합니까?
codegrid

[KnownTypeAttribute (대해서 typeof (TestClass에가))] 내 문제 해결
기욤 레이몬드

6

파일 Application_Start()방법에 이것을 추가 Global.asax하면 문제가 해결됩니다.

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

방법 2 : [권장되지 않음]
EntityFramework로 작업하는 경우 DbContext 클래스 생성자에서 프록시를 비활성화 할 수 있습니다. 참고 : 모델을 업데이트하면이 코드가 제거됩니다.

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

1
고마워요 수만. 나는 같은 문제를 겪고 있었다. 내 웹 API를 테스트 중이 었고이 문제가 발생했습니다. 솔루션이 문제를 해결합니다. 감사합니다.
TarakPrajapati

4

개인적으로 가장 좋아하는 것 : 아래 코드를 App_Start/WebApiConfig.cs. 이렇게하면 기본적으로 XML 대신 json이 반환되고 발생한 오류도 방지됩니다. Global.asax제거 하기 위해 편집 할 필요가 없습니다 XmlFormatter.

'ObjectContent`1'유형이 'application / xml'컨텐츠 유형에 대한 응답 본문을 직렬화하지 못했습니다. charset = utf-8

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

2

AutoMapper 사용 ...

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

2

다음 네임 스페이스를 사용하십시오.

using System.Web.OData;

대신에 :

using System.Web.Http.OData;

그것은 나를 위해 일했습니다


2

아래 줄 추가

this.Configuration.ProxyCreationEnabled = false;

두 가지 방법 ProxyCreationEnabled으로 false.

  1. DBContext생성자 내부에 추가

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

또는

  1. Get메서드 내부에 줄 추가

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

2

나를 위해 일한 솔루션 :

  1. 직렬화 할 각 속성의 [DataContract]클래스 및 [DataMember]특성에 사용 합니다 . 이것은 Json 결과를 얻기에 충분합니다 (예 : 피들러에서).

  2. xml 직렬화를 얻으려면 Global.asax다음 코드를 작성하십시오.

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

  3. 이 기사를 읽으면 직렬화를 이해하는 데 도움이되었습니다 : https://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

1

jensendp의 답변에 추가하려면 :

사용자가 만든 모델에 엔터티를 전달하고 해당 엔터티의 값을 사용하여 새로 만든 모델의 값을 설정합니다. 예를 들면 :

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;
   }
}

그런 다음 반품 유형을 다음으로 변경하십시오. IEnumerable<UserInformation>


1
.. AutoMapper 및 ValueInjecter 2 주목할만한 것들 당신이 모든 재산을 유지하지 않아도 당신을 위해 번역을 처리하는 더 우아한 방법이있다
소닉 소울

1

이것은 내 실수입니다

기본적으로 한 줄을 추가합니다.

  • entity.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);
            }
        }
    }
}

내 결과는 다음과 같습니다.


1

클래스에 [Serializable] 사용 :

예:

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

그것은 나를 위해 일했습니다!


1
이렇게 말하면 이전에이 게시물에 답변 한 모든 사람이 멍청하다고 생각할 수 있습니다.)… 음, 진지하게 의심이 듭니다. 2015 년에 질문을 받았을 때이 솔루션이 적용되지 않았 음을 의미합니다. 나는 그 구문에 대해 많이 알지 못하지만 상대적으로 새롭거나 특정 사용 사례에서 사용할 수 없게 만드는 몇 가지 단점이있을 수 있다는 느낌이 있습니다. 귀하의 솔루션이이 질문에 도달하는 미래의 독자들에게 유용 할 수 있다고 생각하지만, 그 한계를 명확히한다면 확실히 도움이 될 것입니다.
jwatkins 19.07.22

1

App_Start 폴더에서 사용할 수있는 WebApiConfig.cs 내에서 Serializer Formatter를 정의해야합니다.

config.Formatters.Remove (config.Formatters.XmlFormatter); 추가 // JSON 형식으로 데이터를 제공합니다.

config.Formatters.Remove (config.Formatters.JsonFormatter); 추가 // XML 형식으로 데이터를 제공합니다.


당신은 메달을받을 자격이 있습니다.
TheKrogrammer

1

global.asax에 다음 줄을 넣으십시오.

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

수입

using System.Data.Entity;

0

이 오류가 발생한 또 다른 경우는 데이터베이스 쿼리가 null 값을 반환했지만 사용자 / 뷰 모델 유형이 nullable이 아닌 것으로 설정된 경우입니다. 예를 들어, 내 UserModel 필드를 int에서 int?해결로 변경했습니다.


0

이는 Response-Type이 공개되지 않은 경우에도 발생합니다! Visual Studio를 사용하여 형식을 생성 할 때 내부 클래스를 반환했습니다.

internal class --> public class

0

위의 모든 답변이 정확하지만 InnerException> ExceptionMessage 를 확인하는 것이 좋습니다.

" ObjectContext 인스턴스가 삭제되어 더 이상 연결이 필요한 작업에 사용할 수 없습니다. " 와 같은 내용이 표시되면 . 이는 EF의 기본 동작으로 인해 문제가 될 수 있습니다.

DbContext 생성자에서 LazyLoadingEnabled = false 를 할당 하면 트릭을 수행 할 수 있습니다.

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

EF의 EagerLoading 및 LazyLoading 동작에 대한 자세한 내용은이 MSDN 문서를 참조하십시오 .


0

제 경우에는 비슷한 오류 메시지가 있습니다.

'ObjectContent`1'유형이 'application / xml'컨텐츠 유형에 대한 응답 본문을 직렬화하지 못했습니다. charset = utf-8 '입니다.

그러나 더 깊이 파고들 때 문제는 다음과 같습니다.

데이터 계약 이름이 'SomeSubRootType : //schemas.datacontract.org/2004/07/WhatEverService'인 'name.SomeSubRootType'을 입력해야합니다. DataContractSerializer를 사용하는 경우 DataContractResolver를 사용하거나 알려진 형식 목록에 정적으로 알려지지 않은 형식을 추가하는 경우 (예 : KnownTypeAttribute 특성을 사용하거나 serializer에 전달 된 알려진 형식 목록에 추가하는 방법) DataContractResolver를 사용하는 것이 좋습니다.

내가 KnownType.

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

이것은이 답변 에서 영감을 받아 해결되었습니다 .

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


0

Visual Studio 2017 또는 2019는 Visual Studio 자체가 출력이 json 형식 이어야 하는 반면 Visual Studio의 기본 형식은 " XmlFormat"(config.Formatters.XmlFormatter)이므로 전혀 생각하지 않습니다 .

Visual Studio는 개발자에게 많은 문제를주지 않고이 작업을 자동으로 수행해야합니다.

이 문제를 해결하려면 WebApiConfig.cs 파일 로 이동하여

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

Register (HttpConfiguration config) 메서드 에서 " config.MapHttpAttributeRoutes (); " 뒤에 있습니다. 이렇게하면 프로젝트에서 json 출력을 생성 할 수 있습니다.


0

제 경우에는 데이터베이스 재생성을 해결했습니다. 모델을 변경하고 패키지 관리자 콘솔에서 Update-Database를 시작하면 다음 오류가 발생합니다.

"ALTER TABLE 문이 FOREIGN KEY 제약 조건"FK_dbo.Activities_dbo.Projects_ProjectId "와 충돌했습니다. 충돌은"TrackEmAllContext-20190530144302 "데이터베이스,"dbo.Projects "테이블, 'Id'열에서 발생했습니다."


0

경우 : WebApiConfig.cs 또는 Global.asax.cs에 코드를 추가 해도 작동하지 않는 경우 :

.ToList();

.ToList () 함수를 추가합니다.

나는 모든 솔루션을 시도했지만 다음은 나를 위해 일했습니다.

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

도움이되기를 바랍니다.


0

제 경우에는 내비게이션 속성 앞에 가상 키워드를 제거했을 때 수정되었습니다. 참조 테이블을 의미합니다. 그래서 나는 변했다

public virtual MembershipType MembershipType { get; set; }

에:

public MembershipType MembershipType { get; set; }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.