web-dev-qa-db-ja.com

自己参照ループが検出されました-Web Apiからブラウザーにデータを取得しています

Entity Frameworkを使用していますが、ブラウザーに親データと子データを取得する際に問題があります。私のクラスは次のとおりです。

 public class Question
 {
    public int QuestionId { get; set; }
    public string Title { get; set; }
    public virtual ICollection<Answer> Answers { get; set; }
}

public class Answer
{
    public int AnswerId { get; set; }
    public string Text { get; set; }
    public int QuestionId { get; set; }
    public virtual Question Question { get; set; }
}

次のコードを使用して、質問と回答のデータを返します。

    public IList<Question> GetQuestions(int subTopicId, int questionStatusId)
    {
        var questions = _questionsRepository.GetAll()
            .Where(a => a.SubTopicId == subTopicId &&
                   (questionStatusId == 99 ||
                    a.QuestionStatusId == questionStatusId))
            .Include(a => a.Answers)
            .ToList();
        return questions; 
    }

C#側ではこれは機能しているように見えますが、回答オブジェクトには質問への参照があります。 WebAPIを使用してブラウザにデータを取得すると、次のメッセージが表示されます。

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

タイプ「Models.Core.Question」のプロパティ「question」の自己参照ループが検出されました。

これは、質問に回答があり、回答に質問への参照があるためですか?私が見たすべての場所は、子供の親への参照を持つことを示唆しているので、私は何をすべきかわかりません。誰かが私にこれに関するいくつかのアドバイスを与えることができます。

78
user1943020

これは、質問に回答があり、回答に質問への参照があるためですか?

はい。シリアル化できません。

編集:Tallmarisの答えとOttOのコメントを参照してください。より簡単で、グローバルに設定できます。

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Re‌​ferenceLoopHandling = ReferenceLoopHandling.Ignore;

旧回答:

EFオブジェクトQuestionを独自の中間体またはDataTransferObjectに投影します。その後、このDtoを正常にシリアル化できます。

public class QuestionDto
{
    public QuestionDto()
    {
        this.Answers = new List<Answer>();
    } 
    public int QuestionId { get; set; }
    ...
    ...
    public string Title { get; set; }
    public List<Answer> Answers { get; set; }
}

何かのようなもの:

public IList<QuestionDto> GetQuestions(int subTopicId, int questionStatusId)
{
    var questions = _questionsRepository.GetAll()
        .Where(a => a.SubTopicId == subTopicId &&
               (questionStatusId == 99 ||
                a.QuestionStatusId == questionStatusId))
        .Include(a => a.Answers)
        .ToList();

    var dto = questions.Select(x => new QuestionDto { Title = x.Title ... } );

    return dto; 
}
69
Sam Leach

OWINを使用している場合は、これ以上GlobalSettingsを使用しないでください。 IAppBuilder UseWebApi関数(または使用しているサービスプラットフォーム)に渡されるHttpConfigurationオブジェクトのこの同じ設定を変更する必要があります。

このように見えるでしょう。

    public void Configuration(IAppBuilder app)
    {      
       //auth config, service registration, etc      
       var config = new HttpConfiguration();
       config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
       //other config settings, dependency injection/resolver settings, etc
       app.UseWebApi(config);
}
21
Bon

ASP.NET Coreでは、修正は次のとおりです。

services
.AddMvc()
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
21
Mohsen Afshin

DNX/MVC 6/ASP.NET vNext blah blahを使用している場合、HttpConfigurationでさえ欠落しています。 Startup.csファイルで次のコードを使用してフォーマッターを構成する必要があります。

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().Configure<MvcOptions>(option => 
        {
            //Clear all existing output formatters
            option.OutputFormatters.Clear();
            var jsonOutputFormatter = new JsonOutputFormatter();
            //Set ReferenceLoopHandling
            jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            //Insert above jsonOutputFormatter as the first formatter, you can insert other formatters.
            option.OutputFormatters.Insert(0, jsonOutputFormatter);
        });
    }
5
Stewart Hou

ASP.NET Core Web-API(.NET Core 2.0):

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.Configure<MvcJsonOptions>(config =>
    {
        config.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
    });
}
5

これを使用して:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore

うまくいかなかった。代わりに、テストするためにモデルクラスの新しい単純化されたバージョンを作成しましたが、正常に戻りました。この記事では、EFでうまく機能したが、シリアライズ可能ではなかった私のモデルで抱えていた問題のいくつかについて説明します。

http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-4

2
Mike

.Net Framework 4.5を使用する新しいAsp.Net Webアプリケーションの場合:

Web API:Go_App_Start-> WebApiConfig.cs:

次のようになります。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // ReferenceLoopHandling.Ignore will solve the Self referencing loop detected error
        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

        //Will serve json as default instead of XML
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
1
Ogglas

ReferenceLoopHandling.Ignoreは機能しませんでした。私がやり遂げることができる唯一の方法は、コードを介して不要な親へのリンクを削除し、私がしたものを保持することでした。

parent.Child.Parent = null;
1
Rob Sedgwick

ASP.NET Core 2.2では、上記の回答の構成はどれも機能しませんでした。

仮想ナビゲーションプロパティにJsonIgnore属性を追加しました。

public class Question
{
    public int QuestionId { get; set; }
    public string Title { get; set; }
    [JsonIgnore]
    public virtual ICollection<Answer> Answers { get; set; }
}
0
chakeda

遅延読み込みのため、このエラーが発生しています。したがって、私の提案は、プロパティから仮想キーを削除することです。 APIを使用している場合、遅延読み込みはAPIの健全性に適していません。

構成ファイルに余分な行を追加する必要はありません。

public class Question
 {
    public int QuestionId { get; set; }
    public string Title { get; set; }
    public ICollection<Answer> Answers { get; set; }
}

public class Answer
{
    public int AnswerId { get; set; }
    public string Text { get; set; }
    public int QuestionId { get; set; }
    public Question Question { get; set; }
}
0

エンティティdb = new Entities()

db.Configuration.ProxyCreationEnabled = false;

db.Configuration.LazyLoadingEnabled = false;

0
Imran

このエラーは、既存のデータベースのedmx(概念モデルを定義するXMLファイル)を生成したときに発生し、親テーブルと子テーブルの両方へのナビゲーションプロパティがあったことがわかりました。子にナビゲートしたいだけなので、親オブジェクトへのすべてのナビゲーションリンクを削除し、問題は解決しました。

0
Zymotik

この問題を簡単に回避するために、新しい子コレクションを動的に作成できます。

public IList<Question> GetQuestions(int subTopicId, int questionStatusId)
    {
        var questions = _questionsRepository.GetAll()
            .Where(a => a.SubTopicId == subTopicId &&
                   (questionStatusId == 99 ||
                    a.QuestionStatusId == questionStatusId))
            .Include(a => a.Answers).Select(b=> new { 
               b.QuestionId,
               b.Title
               Answers = b.Answers.Select(c=> new {
                   c.AnswerId,
                   c.Text,
                   c.QuestionId }))
            .ToList();
        return questions; 
    }
0
spadelives