如何正确处理 ASP.Net Core 3 Web API 中的多个端点
How to handle multiple endpoints in ASP.Net Core 3 Web API properly
我有 2 种方法来处理 HTTP GET 请求,第一种用于 int
类型输入,另一种用于 string
类型输入。
//GET : api/Fighters/5
[HttpGet("{id}")]
public async Task<ActionResult<Fighter>> GetFighter(int id)
{
var fighter = await _context.Fighters.FindAsync(id);
if (fighter == null)
{
return NotFound();
}
return fighter;
}
// GET: api/Fighters/Alex
[Route("api/Fighters/{name}")]
[HttpGet("{name}")]
public async Task<ActionResult<IEnumerable<Fighter>>> GetFighter (string name)
{
return await _context.Fighters.Where(f => f.Name == name).ToListAsync();
}
当我发送 HTTP GET 时出现此异常(在 Postman 中):
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches:
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext httpContext, CandidateState[] candidateState)
at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.Select(HttpContext httpContext, CandidateState[] candidateState)
at Microsoft.AspNetCore.Routing.Matching.DfaMatcher.MatchAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.Matching.DataSourceDependentMatcher.MatchAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
GET api/fighters/1
显然会导致错误,因为“1
”可能是 int
或 string
所以我通过结合两种方法解决了我的问题:
// GET: api/Fighters/5
// GET: api/Fighters/Alex
[HttpGet("{idOrName}")]
public async Task<ActionResult<IEnumerable<Fighter>>> GetFighter(string idOrName)
{
if (Int32.TryParse(idOrName, out int id))
{
return await _context.Fighters.Where(f => f.Id == id).ToListAsync();
}
else
{
return await _context.Fighters.Where(f => f.Name == idOrName).ToListAsync();
}
}
这可行,但感觉根本不对。处理这个问题的正确方法是什么?
您可以使用 route constraint
[HttpGet("{id:int}")]
public async Task<ActionResult<Fighter>> GetFighter(int id)
[HttpGet("{name}")]
public async Task<ActionResult<IEnumerable<Fighter>>> GetFighter (string name)
我在 Core 3.0 中遇到了这个问题。我终于找到解决方案是在操作上放置一个路由属性——例如[Route("NodeInfo")]
。那修好了
请遵循 .Net Core 3.1 或更高版本的解决方案Version:Use [Route("RouteName")]
[HttpPost]
[Route("CreateUserRole")]
// [Authorize(Roles = "admin")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateUserRole([FromBody] AssignUserRole assignUserRole)
{
try
{
_logger.LogInfo("Attempted submission attempted");
if (assignUserRole == null)
{
_logger.LogWarn("Empty request submitted");
return BadRequest(ModelState);
}
if (!ModelState.IsValid)
{
_logger.LogWarn("User data was incomplete");
return BadRequest(ModelState);
}
var User = _Mapper.Map<Users>(assignUserRole);
_UserRoleRepository.AssignRoleUser(assignUserRole);
_logger.LogInfo("User Role created");
Audit_logs audit = new Audit_logs()
{
uid = User.id,
action = "Create User Role",
log = $"{assignUserRole.rolename} Role has created",
datetime = DateTime.Now
};
await _audit_Logs.Create(audit);
return Created("Create User Role", new { assignUserRole });
}
catch (Exception ex)
{
return InternalError($"{ex.Message}-{ex.InnerException}");
}
}
我有 2 种方法来处理 HTTP GET 请求,第一种用于 int
类型输入,另一种用于 string
类型输入。
//GET : api/Fighters/5
[HttpGet("{id}")]
public async Task<ActionResult<Fighter>> GetFighter(int id)
{
var fighter = await _context.Fighters.FindAsync(id);
if (fighter == null)
{
return NotFound();
}
return fighter;
}
// GET: api/Fighters/Alex
[Route("api/Fighters/{name}")]
[HttpGet("{name}")]
public async Task<ActionResult<IEnumerable<Fighter>>> GetFighter (string name)
{
return await _context.Fighters.Where(f => f.Name == name).ToListAsync();
}
当我发送 HTTP GET 时出现此异常(在 Postman 中):
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches:
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
FighterGameService.Controllers.FightersController.GetFighter (FighterGameService)
at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext httpContext, CandidateState[] candidateState)
at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.Select(HttpContext httpContext, CandidateState[] candidateState)
at Microsoft.AspNetCore.Routing.Matching.DfaMatcher.MatchAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.Matching.DataSourceDependentMatcher.MatchAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
GET api/fighters/1
显然会导致错误,因为“1
”可能是 int
或 string
所以我通过结合两种方法解决了我的问题:
// GET: api/Fighters/5
// GET: api/Fighters/Alex
[HttpGet("{idOrName}")]
public async Task<ActionResult<IEnumerable<Fighter>>> GetFighter(string idOrName)
{
if (Int32.TryParse(idOrName, out int id))
{
return await _context.Fighters.Where(f => f.Id == id).ToListAsync();
}
else
{
return await _context.Fighters.Where(f => f.Name == idOrName).ToListAsync();
}
}
这可行,但感觉根本不对。处理这个问题的正确方法是什么?
您可以使用 route constraint
[HttpGet("{id:int}")]
public async Task<ActionResult<Fighter>> GetFighter(int id)
[HttpGet("{name}")]
public async Task<ActionResult<IEnumerable<Fighter>>> GetFighter (string name)
我在 Core 3.0 中遇到了这个问题。我终于找到解决方案是在操作上放置一个路由属性——例如[Route("NodeInfo")]
。那修好了
请遵循 .Net Core 3.1 或更高版本的解决方案Version:Use [Route("RouteName")]
[HttpPost]
[Route("CreateUserRole")]
// [Authorize(Roles = "admin")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> CreateUserRole([FromBody] AssignUserRole assignUserRole)
{
try
{
_logger.LogInfo("Attempted submission attempted");
if (assignUserRole == null)
{
_logger.LogWarn("Empty request submitted");
return BadRequest(ModelState);
}
if (!ModelState.IsValid)
{
_logger.LogWarn("User data was incomplete");
return BadRequest(ModelState);
}
var User = _Mapper.Map<Users>(assignUserRole);
_UserRoleRepository.AssignRoleUser(assignUserRole);
_logger.LogInfo("User Role created");
Audit_logs audit = new Audit_logs()
{
uid = User.id,
action = "Create User Role",
log = $"{assignUserRole.rolename} Role has created",
datetime = DateTime.Now
};
await _audit_Logs.Create(audit);
return Created("Create User Role", new { assignUserRole });
}
catch (Exception ex)
{
return InternalError($"{ex.Message}-{ex.InnerException}");
}
}