我正在尝试使用Entity Framework Core和ASP.NET Core制作Web API
我有一个用户配置文件表(称为featUsers)和一个方案表(称为“方案”)。首先,我想基于一个字段查找一个用户,然后返回与该用户关联的方案列表。
返回所有方案都可以:
// GET: api/Scenarios
[HttpGet]
public async Task<ActionResult<IEnumerable<Scenario>>> Getscenarios()
{
return await _context.scenarios.ToListAsync();
}
修改它以测试具有特定外键的搜索和返回方案也可以正常工作:
// GET: api/Scenarios
[HttpGet]
public async Task<ActionResult<IEnumerable<Scenario>>> Getscenarios()
{
return await _context.scenarios.Where(scenario => scenario.FeatUserId == 1).ToListAsync();
}
但是当我进一步修改它以首先找到用户概要文件,然后使用该概要文件查找场景时,事情就倒了。该函数的外观如下:
// GET: api/Scenarios
[HttpGet]
public async Task<ActionResult<IEnumerable<Scenario>>> Getscenarios()
{
//Find the profile, with specific Identity ID
var featProfile = _context.featUsers.FirstOrDefault(u => u.IdentityId == "44fc0698-9f99-46dd-bfac-db1781fd8b01");
//Debug
Console.WriteLine(featProfile.FeatUserId);
//Return all the scenarios which are related to that profile above
return await _context.scenarios.Where(scenario => scenario.FeatUserId == featProfile.FeatUserId).ToListAsync();
}
当我用Postman查询此端点时(Console.WriteLine正确地向终端写入了“ 1”,这是预期的,但是)这是我在Postman中得到的响应:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected with type 'DAF_FEAT.Models.Scenario'. Path '[0].featUser.scenarios'.
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable 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.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.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, IEnumerable 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, Type objectType)
at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.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__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
at IdentityServer4.Hosting.MutualTlsTokenEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Cache-Control: no-cache
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate
Host: localhost:5001
User-Agent: PostmanRuntime/7.15.0
Postman-Token: c3ba03bb-8f2f-433a-998a-e13cd361f888
为完整起见,模型如下:
public class FeatUser
{
public int FeatUserId { get; set; }
public string Role { get; set; }
public string OrganisationName { get; set; }
public string PhoneNumber { get; set; }
public string IdentityId { get; set; }
public List<Scenario> Scenarios { get; set; }
}
public class Scenario
{
public int ScenarioId { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public bool Active { get; set; }
public int FeatUserId { get; set; }
public FeatUser FeatUser { get; set; }
}
也许我要解决所有这些错误,并且应该通过做类似以下的事情来利用导航属性:
return (await _context.featUsers.Include(u => u.Scenarios).FirstOrDefaultAsync(u => u.IdentityId == userId)).Scenarios.ToList();
答案 0 :(得分:0)
正如DavidG在其评论中建议的那样,您不应在api中返回EF模型。您应该为模型创建DTO(数据传输对象),然后返回它们。您的DTO不应具有自引用循环(FeatUser包含场景,然后Scenario包含FeatUser)。因此,在您的示例中,您的DTO如下所示:
public class FeatUserDto
{
public int FeatUserId { get; set; }
public string Role { get; set; }
public string OrganisationName { get; set; }
public string PhoneNumber { get; set; }
public string IdentityId { get; set; }
public List<ScenarioDto> Scenarios { get; set; }
}
public class ScenarioDto
{
public int ScenarioId { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
public bool Active { get; set; }
}
请注意,ScenarioDto如何不包含指向FeatUserDto的链接,以避免自引用循环。
现在剩下的是将模型映射到DTO。 Automapper可以帮上忙。