web-dev-qa-db-ja.com

.netコア:不完全なJSON応答

私はトレーニング用のシンプルなAPIを構築しようとしています。私のデータベースには、ユーザー(名、姓、メールパスワード、list<sports>)およびsports(名前、userID)。ユーザーを取得したいときはすべて問題ありません。オブジェクトにスポーツが含まれています。しかし、JSON応答は不完全であり、途中で「カット」されます。

[{"firstName":"Nicolas","lastName":"Bouhours","email":"[email protected]","password":"[email protected]","sports":[{"name":"Trail","userId":1

これは私のコントローラーです:

// GET: api/Users
[HttpGet]
public IEnumerable<User> GetUsers()
{
    var users = _context.Users.Include(u => u.Sports).ToList();
    return users;
}

そして私のモデル:

public class Sport : BaseEntity
{
    public string Name { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }
}

public class User : BaseEntity
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
    public String Email { get; set; }
    public String Password { get; set; }

    public List<Sport> Sports { get; set; }
}

public class SportAppContext : DbContext
{
    public SportAppContext(DbContextOptions<SportAppContext> options) : base(options)
    { }

    public DbSet<User> Users { get; set; }
    public DbSet<Sport> Sports { get; set; }
}

あなたが何か考えがあれば、私は本当に何が起こるか理解していません

15
Nicolas B

これが発生する可能性のある、もう1つのユニークなシナリオを追加するだけです。これは、DALがクエリ可能オブジェクトを返している場合にも発生する可能性があります。私のシナリオでは、DALからボックス化されたオブジェクトを返していましたが、linqクエリとして次のようなものがありました

_ ...
 RootLevelProp1 = "asd",
 RootLevelProp2 = "asd",
 Trades = b.Trades.OrderBy(c => c.Time).Select(c => new
                {
                    c.Direction,
                    c.Price,
                    c.ShareCount,
                    c.Time
                }) //<---- This was being returned as a queryable to the controller 
_

ルートオブジェクトの.ToListAsync()が呼び出されても、Tradesクエリは実行されませんでした。何が起こっていたかというと、コントローラーは結果を返しましたが、Tradesセクションまでしかありませんでした。Jsonは適切に終了されませんでした。その後、私が書いたいくつかのカスタムミドルウェアで例外が検出され、データリーダーが既に開いていることを訴えていることに気付きました。私の調査を深く掘り下げることなく、DIで何かを行う必要があり、それがコンテキストのライフサイクルをどのように処理していたかを想定しました。修正は、取引にToListを追加することでした。 DALからデータを渡すのは醜い方法ですが、これは楽しいプロジェクトです。

0
Adrian

私の場合、これはNewtonsoftを使用してコア3の問題を解決します: https://docs.Microsoft.com/en-us/aspnet/core/web-api/advanced/formatting?view=aspnetcore-3.0 #add-newtonsoftjson-based-json-format-support

ASP.NET Core 3.0以前では、デフォルトでは、Newtonsoft.Jsonパッケージを使用して実装されたJSONフォーマッターが使用されていました。 ASP.NET Core 3.0以降では、デフォルトのJSONフォーマッターはSystem.Text.Jsonに基づいています。 Newtonsoft.Jsonベースのフォーマッターと機能のサポートは、Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGetパッケージをインストールし、Startup.ConfigureServicesで構成することで利用できます。

    public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson();
}
0
Proteo5

選択した答えは私の場合も正しかった、私のJSON応答は私のJSON応答の参照ループによって切り捨てられており、ReferenceLoopHandling.Ignoreを設定すると実際に問題が解決しました。ただし、これはモデルで循環参照を維持するため、私の意見では最良の解決策ではありません。より良いソリューションは、モデル内の[JsonIgnore]属性を使用することです。

モデルの問題はここにあります:

public class Sport : BaseEntity
{
    public string Name { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }  //This is the cause of your circular reference
}

public class User : BaseEntity
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
    public String Email { get; set; }
    public String Password { get; set; }

    public List<Sport> Sports { get; set; }
}

ご覧のとおり、ユーザーナビゲーションプロパティは、この応答が切り捨てられる場所です。具体的には、json応答の各Sportに、応答の各スポーツエントリのすべてのユーザー情報が含まれるようにします。 Newtonsoftはこれが好きではありません。解決策は、この循環参照を引き起こすナビゲーションプロパティを単に[JsonIngore]することです。あなたのコードではこれは次のようになります:

public class Sport : BaseEntity
{
    public string Name { get; set; }

    public int UserId { get; set; }
    [JsonIgnore]
    public User User { get; set; }  //fixed
}

public class User : BaseEntity
{
    public String FirstName { get; set; }
    public String LastName { get; set; }
    public String Email { get; set; }
    public String Password { get; set; }

    public List<Sport> Sports { get; set; }
}
0
Kevin Bell