У меня есть простое действие контроллера ASP.NET Core 2.2, которое возвращает неполный JSON даже при отправке запроса из POSTMAN.
Код работает нормально, пока я не включу свойство навигации для связанной сущности «Книги». Результаты правильно возвращаются из метода ToList () объекта IQueryable, как я вижу при отладке. Но по какой-то причине при запуске ReadAsStringAsync () возвращается только часть ожидаемого результата JSON.
Ниже приведен код для API:
[HttpPost]
[Route("api/TestEntity/ListTest")]
public async Task<ActionResult<IEnumerable<TestEntityPerson>>> ListTest()
{
var query = _context.Persons
.Include(p => p.Books)
.AsQueryable().Take(5);
var results = await Task.FromResult(Json(query.ToList()));
return results;
}
И результат, который я получаю (который является только частью ожидаемого результата) в клиенте:
[{"$type":"Identica.My.Bonus.Entities.TestEntityPerson, Identica.My.Bonus","name":"Susan","balance":240749.08345506949,"age":56,"books":[{"$type":"Identica.My.Bonus.Entities.TestEntityBook, Identica.My.Bonus","title":"SRWZLSRKQNYKPY","author":"VEJZP","price":13.334878714911119,"personId":"f24dbe36-1f99-4a59-3cb7-08d6c4048ace"
Какие-нибудь указатели на то, что я мог бы попытаться решить эту проблему? Я не смог найти подходящих вопросов о переполнении стека.
РЕДАКТИРОВАТЬ: Это происходит только в том случае, если на связанном объекте есть навигационное свойство, указывающее назад на исходный объект. Когда я удалил это свойство, проблема исчезла.
А это код клиента:
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Press any key to run query...");
Console.Read();
MediaTypeWithQualityHeaderValue mediaTypeJson = new MediaTypeWithQualityHeaderValue("application/json");
List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter> {
new JsonMediaTypeFormatter {
SerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects
}
}
};
using (HttpClient httpClient = new HttpClient() { BaseAddress = new Uri("https://localhost:44359/") })
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(mediaTypeJson);
Expression<Func<TestEntityPerson, bool>> expressionFilter =
t => (t.Balance > 240000 || t.Age < 25) &&
(t.Books == null || t.Books.Any(b => b.Price < 7 || b.Title.StartsWith('A')));
var filterNode = expressionFilter.ToExpressionNode();
Expression<Func<IQueryable<TestEntityPerson>, IOrderedQueryable<TestEntityPerson>>> expressionOrderBy = t => t.OrderByDescending(x => x.Balance);
var orderByNode = expressionOrderBy.ToExpressionNode();
Pagination pagination = new Pagination() { Start = 0, Limit = 10 };
QueryOptionsNodes queryOptions = new QueryOptionsNodes()
{
FilterExpressionNode = filterNode,
SortingExpressionNode = orderByNode,
Pagination = pagination
};
try
{
Console.WriteLine("Sending request...");
var response = await httpClient.PostAsync("api/TestEntity/List", queryOptions, formatters[0], mediaTypeJson, CancellationToken.None);
response.EnsureSuccessStatusCode();
Console.WriteLine("Reading Response request...");
var result = await response.Content.ReadAsAsync<IEnumerable<TestEntityPerson>>(formatters, CancellationToken.None);
ShowEntities(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
Console.ReadLine();
}
private static void ShowEntities(IEnumerable<TestEntityPerson> testEntities)
{
foreach (var entity in testEntities)
{
Console.WriteLine("{0}) {1} Age = {2} Balance = {3}", entity.Id, entity.Name, entity.Age, entity.Balance);
if (entity.Books != null)
{
Console.WriteLine("Books:");
foreach (var book in entity.Books)
{
Console.WriteLine("-- {0}) {1} Price = {2}", book.Id, book.Title, book.Price);
}
}
Console.WriteLine();
}
}
}