web-dev-qa-db-ja.com

コンテンツタイプの応答本文のシリアル化に失敗しました

ControllersとApiControllersの両方を使用するMVC4アプリケーションを構築しています。デフォルトのWeb APIルートを変更して、アクション名を含めました。ベンチマークのリストを取得しようとすると、次のエラーメッセージが表示されます。

'ObjectContent`1タイプは、コンテンツタイプ' application/json;の応答本文のシリアル化に失敗しました。 charset = utf-8 '

InnerExceptionは次のとおりです(その場合、JSONを返します。XMLでも同じです):

"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Error getting value from 'IdentityEqualityComparer' on 'NHibernate.Proxy.DefaultLazyInitializer'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": " at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value) at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value) at System.Net.Http.Formatting.JsonMediaTypeFormatter.<>c__DisplayClassd.<WriteToStreamAsync>b__c() at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Common Language Runtime detected an invalid program.",
"ExceptionType": "System.InvalidProgramException",
"StackTrace": " at GetIdentityEqualityComparer(Object ) at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
}

これは私が実行するコードです:

// GET api/benchmark/getincomplete
        [HttpGet]
        public IList<Benchmark> GetIncomplete()
        {
            var s = HibernateModule.CurrentSession;
            var benchList = s.QueryOver<Benchmark>()
                                .Where(b => !b.Completed)
                                .Where(b => !b.Deleted)
                                .OrderBy(b => b.Id).Asc
                                .List<Benchmark>();

            return benchList;
        }

そして、これがベンチマークモデルです。

public class Benchmark
    {
        public virtual int Id { get; set; }
        [Required]
        [DataType(DataType.Date)]
        public virtual DateTime Date { get; set; }
        [Required, ScriptIgnore]
        public virtual IList<TestResult> Results { get; set; }
        [Required]
        public virtual IList<TestCase> TestCases { get; set; }
        [AllowHtml]
        public virtual string Description { get; set; }
        public virtual Device Device { get; set; }        
        public virtual bool Published { get; set; }
        [Display(Name = "Deleted"), ScriptIgnore]
        public virtual bool Deleted { get; set; }
        public virtual bool Completed { get; set; }

        public Benchmark() 
        {
            Results = new List<TestResult>();
            TestCases = new List<TestCase>();
            Published = false;
            Deleted = false;
            Completed = false;
        }
    }

問題がどこにあるのか、私にはよくわかりません。それはNHibernateプロキシ(私はFluent NHibernateを使用しています)ですか?奇妙なことに、ApiControllerを使用せず、手動でJSONを返す場合、これは完全に機能します。

更新:

以下の答えに従って、これはApplication_Start()に追加しなければならなかったコードです:

HttpConfiguration config = GlobalConfiguration.Configuration;
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
16
Astaar

NHibernateフレームワークの IdentityEqualityCompairer には[SerializableAttribute]アノテーション。

ここでの回答のコメントから引用 Web APIがデシリアライズされないのに、JSON.Netがデシリアライズされるのはなぜですか? JSON.NETの構成は、WebApiの使用とスタンドアロンの使用で少し異なるようです。

Json.NETシリアライザーはデフォルトでIgnoreSerializableAttributeをtrueに設定します。 WebAPIでは、これをfalseに設定します。

したがって、[SerializableAttribute]オフ(コード内にないため)この回答を使用して、デフォルトのWebApi JSON.NET設定を変更して無視することができます here

((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;

また、おそらく考慮してください応答で送信される結果にDTOを使用する-これにより、ネットワーク経由で送信されるオブジェクトを完全に制御できます。

7
Mark Jones

これにより、JSONエラーが修正されます。XMLで頑張ってください。これを、Registerメソッドの下のWebApiConfigクラスに追加します。

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

更新:

これに対する2つの解決策を見つけました。最初に実装するのが最も簡単なのは、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
 }

もう1つのオプションは、ネイティブJSONシリアライザーを使用しないことです。私が投稿した最初のメソッドはまだ機能します。

9
Ray Suelzer

うーん、以下が役立つかもしれません。

同じ例外が発生し、私の場合、最初にエンティティコード用に作成された実際のpocoエンティティを渡していました。 IList Locationsなどのナビゲーションプロパティが含まれているため、返すためにその上に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;}
}
3
aamir sajjad