.Net Core 3 和 EF Core 3 包含问题 (JsonException)
Posted
技术标签:
【中文标题】.Net Core 3 和 EF Core 3 包含问题 (JsonException)【英文标题】:.Net Core 3 and EF Core 3 Include Problem (JsonException) 【发布时间】:2020-02-01 02:36:05 【问题描述】:我正在尝试使用 .NET Core 3 和 EF Core 开发应用程序。我遇到了一个我找不到解决方案的错误。我无法在“.Net Core 3”上做一个可以用 php eloquent 简单创建的结构。
型号;
public NDEntityContext(DbContextOptions<NDEntityContext> options)
: base(options)
public DbSet<User> Users get; set;
public DbSet<Order> Orders get; set;
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<User>(entity =>
entity.Property(u => u.CreatedAt)
.HasDefaultValueSql("DATEADD(HOUR, +3, GETUTCDATE())");
entity.HasMany(u => u.Orders)
.WithOne(o => o.User);
);
modelBuilder.Entity<Order>(entity =>
entity.Property(o => o.CreatedAt)
.HasDefaultValueSql("DATEADD(HOUR, +3, GETUTCDATE())");
entity.HasOne(o => o.User)
.WithMany(u => u.Orders)
.HasForeignKey(o => o.UserId)
.HasConstraintName("Fk_Order_User");
);
public class User : EntityBase
public int UserId get; set;
public string FirstName get; set;
public string LastName get; set;
public string FullName get; set;
public int Type get; set;
public string Email get; set;
public string Phone get; set;
public string Password get; set;
public string Gender get; set;
[IgnoreDataMember]
public string HomePhone get; set;
[IgnoreDataMember]
public string WorkPhone get; set;
public DateTime? BirthDate get; set;
public string SmsConfCode get; set;
public bool IsActive get; set;
public bool IsOutOfService get; set;
public ICollection<Order> Orders get; set;
public class Order : EntityBase
public int OrderId get; set;
public int UserId get; set;
public User User get; set;
public decimal Price get; set;
用户控制器:
[Route("api")]
[ApiController]
public class UserController : ControllerBase
private readonly NDEntityContext _context;
private readonly ILogger<UserController> _logger;
public UserController(ILogger<UserController> logger, NDEntityContext context)
_logger = logger;
_context = context;
[HttpGet("users")]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
_logger.LogInformation("API Users Get");
return await _context.Users.ToListAsync();
[HttpGet("user/id:int")]
public async Task<ActionResult<User>> GetUser(int id)
_logger.LogInformation("API User Get");
return await _context.Users.Include(u => u.Orders).FirstOrDefaultAsync(e => e.UserId == id);
启动ConfigureServices
;
services.AddControllersWithViews().AddNewtonsoftJson(opt => opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
services.AddDbContext<NDEntityContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
services.AddSwaggerGen(c =>
c.SwaggerDoc("v1", new OpenApiInfo Title = "ND API", Version = "v1" );
);
localhost/api/users/
;
[
"userId": 1,
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe",
"type": 1,
"email": "jhondoe@test.com",
"phone": "01234567890",
"password": "123456789",
"gender": "Man",
"homePhone": "123456789",
"workPhone": "987654321",
"birthDate": null,
"smsConfCode": null,
"isActive": true,
"isOutOfService": false,
"orders": null,
"createdAt": "2019-10-01T21:47:54.2966667",
"updatedAt": null,
"deletedAt": null
]
localhost/api/user/1/
;
System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: application/json
Accept-Encoding: gzip, deflate, br
Accept-Language: tr,en;q=0.9
Connection: close
Cookie: .AspNet.Consent=yes
Host: localhost:44352
Referer: https://localhost:44352/swagger/index.html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
sec-fetch-mode: cors
sec-fetch-site: same-origin
当我删除.Include(u => u.Orders)
代码时,我可以像localhost/api/users/
一样获得成功的响应。我在使用 Include 时看到此错误
我想得到这个回复;
"userId": 0,
"firstName": "string",
"lastName": "string",
"fullName": "string",
"type": 0,
"email": "string",
"phone": "string",
"password": "string",
"gender": "string",
"birthDate": "2019-10-02T18:24:44.272Z",
"smsConfCode": "string",
"isActive": true,
"isOutOfService": true,
"orders": [
"orderId": 0,
"userId": 0,
"price": 0,
"createdAt": "2019-10-02T18:24:44.272Z",
"updatedAt": "2019-10-02T18:24:44.272Z",
"deletedAt": "2019-10-02T18:24:44.272Z"
],
"createdAt": "2019-10-02T18:24:44.272Z",
"updatedAt": "2019-10-02T18:24:44.272Z",
"deletedAt": "2019-10-02T18:24:44.272Z"
【问题讨论】:
映射到新的模型类以在控制器中使用将是更简洁的解决方案,并且可以避免循环引用,Automapper 可以用于映射而无需编写太多代码。 【参考方案1】:对于 .NET Core 3,NewtonJson 刚刚发布了一个新补丁。安装包Microsoft.AspNetCore.Mvc.NewtonsoftJson
后问题就解决了。
【讨论】:
您还需要做什么吗?我安装了软件包,但仍然有同样的问题 .NET Core 3 自带微软的 System.Text.Json 用于序列化和反序列化。在不更改服务注册的情况下添加 Newtonsoft 包不会做任何事情,并且表明对“市场上”的不同 JSON 序列化程序缺乏理解。现在 .Net Core 5 已经发布(在提出问题时当然不可用)有一个新的 System.Text.Json 处理程序应该可以解决这个问题docs.microsoft.com/en-us/dotnet/api/…【参考方案2】:在我的情况下,仅添加 NewtonSoft 包不起作用。我还必须修改Startup.cs
文件中的ConfigurationService
方法,如以下答案https://***.com/a/58084628/6026570 中所述
【讨论】:
【参考方案3】:您的 OnModelCreating 方法缺少外键约束的定义。 以下应该有效:
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<User>().Property(u => u.CreatedAt).HasDefaultValueSql("DATEADD(HOUR, +3, GETUTCDATE())");
modelBuilder.Entity<Order>(entity =>
entity.Property(o => o.CreatedAt)
.HasDefaultValueSql("DATEADD(HOUR, +3, GETUTCDATE())");
entity.HasOne(o => o.User)
.WithMany(u => u.Orders)
.HasForeignKey(o => o.UserId)
.HasConstraintName("Fk_Order_User);
);
这定义了一个订单连接到一个用户,但一个用户可以有多个订单。
【讨论】:
我试过你的样品。但问题仍在继续。错误是我采取的 JsonException。:(【参考方案4】:我遇到了同样的问题,它通过删除“反向导航属性”得到解决,即从 Order 实体类中删除“public User User get; set; ”,使其如下所示:
public class Order : EntityBase
public int OrderId get; set;
public int UserId get; set;
public decimal Price get; set;
【讨论】:
这确实可行,但时间会到,您必须包含该属性,这将使您返回此处参考序列化对象的解决方案。以上是关于.Net Core 3 和 EF Core 3 包含问题 (JsonException)的主要内容,如果未能解决你的问题,请参考以下文章
从 .NET Core 2.2 迁移到 3.1 后,EF Core 随机抓取 API 请求上的用户表