无论我尝试什么,CreatedAtAction 都会抛出 InvalidOperationExceptions

问题描述 投票:0回答:3

我正在尝试创建一个 .net core 5 API。我的控制器中有以下代码。

[HttpGet]
public async Task<IActionResult> GetAll()
{
    return Ok(await _repository.GetAllUsersAsync());
}

// GET api/<ReelTypes>/5
[Route("GetUserByIdAsync")]
[HttpGet("{id}", Name ="GetUserByIdAsync")]
public async Task<ActionResult<AppUser>> GetUserByIdAsync(Guid id)
{
    var appUser = await _repository.GetUserByIdAsync(id);
    if(appUser == null)
    {
        return NoContent();
    }
    return Ok(appUser);
}

[HttpPost]  
[Route("CreateAsync")]  
public async Task<IActionResult> CreateAsync([FromBody] AppUser model)  
{  
    var checkExists = await _userManager.FindByNameAsync(model.UserName);  
    if (checkExists != null)
    { 
        return StatusCode(StatusCodes.Status409Conflict, 
            new _ResponseBody { Title = "Duplicate Record", 
                    Body = "Record already exists" });  
    }
    AppUser user = new AppUser()  
    {  
        Email = model.Email,  
        SecurityStamp = Guid.NewGuid().ToString(),  
        UserName = model.UserName  
    };  
    var result = await _userManager.CreateAsync(user, model.PasswordHash);  
    if (!result.Succeeded)
        return StatusCode(StatusCodes.Status500InternalServerError, 
            new _ResponseBody { Title = "Not Created", 
                    Body = "Unable to create record" });  

    return CreatedAtAction("GetUserByIdAsync", new { id = user.Id }, user);
} 

我真的很努力遵循完整的规范,并且我知道当我使用 API 创建对象时,响应需要包含新对象的 URI 和新对象。为此,我尝试使用

CreatedAtAction
函数,但无论我做什么,我都会得到以下结果:

System.InvalidOperationException: No route matches the supplied values.
   at Microsoft.AspNetCore.Mvc.CreatedAtActionResult.OnFormatting(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncCore(ActionContext context, ObjectResult result, Type objectType, Object value)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)
   at Microsoft.AspNetCore.Mvc.ObjectResult.ExecuteResultAsync(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultAsync(IActionResult result)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
--- End of stack trace from previous location ---
   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 ---
   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.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

我尝试使用

GetName
作为第一个参数,但最终像现在一样对其进行了硬编码。所以我需要知道的是我是个白痴(明显的答案是肯定的)还是这个函数有问题?问题是我的
GetById
有一个
Guid
作为参数吗?我正在使用其中一个身份表吗?我必须使用版本控制吗?

我已经浏览了这里和其他地方关于这个问题的每一篇文章,所以我不只是发布这第一件事。如果它很明显,我很抱歉我只是错过了它。

编辑:我尝试使用

nameof
函数作为第一个参数。我还尝试用
[ActionName("GetUserByIdAsync")]
装饰目标动作。

c# .net asynchronous .net-core
3个回答
0
投票

更换

return CreatedAtAction("GetUserByIdAsync", new { id = user.Id }, user);

return GetUserByIdAsync(user.Id );

0
投票

异常消息准确地告诉您问题是什么:

没有路线与提供的值匹配。

如果您阅读了

CreatedAtAction(string actionName, object value)
的文档:

actionName:用于生成 URL 的操作的 name

然后,如果您阅读了

HttpGetAttribute.Name
的文档:

获取路线名称。路线名称可用于使用特定路线生成链接,而不是依赖于基于给定的一组路线值来选择路线。

所以问题是你在用

Name
装饰控制器方法时没有指定
HttpGet
。换句话说,您需要做的就是:

// GET api/<ReelTypes>/5
[HttpGet("{id}", Name = "GetUserByIdAsync")]
public async Task<ActionResult<AppUser>> GetUserByIdAsync(Guid id)

-1
投票

我发现我必须为 Get Action 指定参数的数据类型,重新添加 ActionName 装饰,然后将其更改回使用 nameof。所以我的代码现在看起来像:

        [HttpGet]
        public async Task<IActionResult> GetAll()
        {
            return Ok(await _repository.GetAllUsersAsync());
        }

        // GET api/<ReelTypes>/5
        [HttpGet("{id:Guid}", Name ="GetUserByIdAsync")]
        [ActionName("GetUserByIdAsync")]
        public async Task<ActionResult<AppUser>> GetUserByIdAsync([FromRoute] Guid id)
        {
            var appUser = await _repository.GetUserByIdAsync(id);
            if(appUser == null)
            {
                return NoContent();
            }
            return Ok(appUser);
        }
  
        [HttpPost]  
        [Route("CreateAsync")]  
        public async Task<IActionResult> CreateAsync([FromBody] AppUser model)  
        {  
            var checkExists = await _userManager.FindByNameAsync(model.UserName);  
            if (checkExists != null)
            { 
                return StatusCode(StatusCodes.Status409Conflict, 
                    new _ResponseBody { Title = "Duplicate Record", 
                            Body = "Record already exists" });  
            }
            AppUser user = new AppUser()  
            {  
                Email = model.Email,  
                SecurityStamp = Guid.NewGuid().ToString(),  
                UserName = model.UserName  
            };  
            var result = await _userManager.CreateAsync(user, model.PasswordHash);  
            if (!result.Succeeded)
                return StatusCode(StatusCodes.Status500InternalServerError, 
                    new _ResponseBody { Title = "Not Created", 
                            Body = "Unable to create record" });  
  
            return CreatedAtAction(nameof(GetUserByIdAsync), new { id = user.Id }, user);
        }  

所以这三个更改之一似乎解决了我的问题。我怀疑我现在已经指定了参数类型(Guid),但我也想知道装饰的顺序是否重要。我第一次添加 [ActionName] 装饰时,我将它放在 [HttpGet...] 装饰上方。

感谢所有试图帮助我的人。我希望这可以帮助其他人解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.