Search code examples
c#asp.net-coreasp.net-core-routing

ASP.NET Core 2.2 - CreatedAtRoute method failure for complex routes


I have this AuthController which I want to use CreatedAtRoute method to run an action in UsersController to return inserted user but it gives this error:

InvalidOperationException: No route matches the supplied values.

The AuthController is shown here. The user registers and after successful registration the GetUser action of UsersController gets called:

[Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private readonly IConfiguration _config;
        private readonly ITokenService _tokenService;
        private readonly IMapper _mapper;
        private readonly UserManager<User> _userManager;
        private readonly IUserService _userService;
        private readonly SignInManager<User> _signInManager;
        private readonly ILogger _logger;

        public AuthController(IConfiguration config,
           ITokenService tokenService,
           IMapper mapper,
           UserManager<User> userManager,
           SignInManager<User> signInManager,
           IUserService userService,
           ILogger<AuthController> logger)
        {
            _tokenService = tokenService;
            _userManager = userManager;
            _signInManager = signInManager;
            _mapper = mapper;
            _config = config;
            _userService = userService;
            _logger = logger;
        }
        [AllowAnonymous]
        [HttpPost("register")]
        public async Task<IActionResult> Register([FromBody]UserForRegisterDto userForRegisterDto)
        {
            _logger.LogInformation(LoggingEvents.InsertItem, "Registering user {UserName}", userForRegisterDto.UserName);
            var userToCreate = _mapper.Map<User>(userForRegisterDto);

            var result = await _userManager.CreateAsync(userToCreate,"1234567a" /*userForRegisterDto.Password*/);

            var userToReturn = _mapper.Map<UserForLoginReturnDto>(userToCreate);

            if (result.Succeeded)
            {
                _logger.LogInformation(LoggingEvents.InsertItem, "Registering user {UserName}", userForRegisterDto.UserName);
                return CreatedAtRoute("GetUser",
                    new { controller = "Users", id = userToCreate.Id }, userToReturn);
            }
            _logger.LogError(LoggingEvents.InsertItem, "Registering user failed: {UserName}", userForRegisterDto.UserName);
            return BadRequest(result.Errors);
        }
}

And the UsersController is as below:

[Route("api/users/{userId}/users")]
    [ApiController]
    public class UsersController : ControllerBase
    {
        private readonly IUserService _userService;
        private readonly IMapper _mapper;
        private readonly UserManager<User> _userManager;
        public UsersController(IUserService userService,
            UserManager<User> userManager,
            IMapper mapper)
        {
            _userService = userService;
            _userManager = userManager;
            _mapper = mapper;
        }


        [Authorize(Roles = "Admin, Manager, User")]
        [HttpGet("{id}", Name = "GetUser")]
        public async Task<IActionResult> GetUser(int id)
        {
            var isCurrentUser = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value) == id;

            var user = await _userService.GetUser(id, isCurrentUser);

            var userToReturn = _mapper.Map<UserForLoginReturnDto>(user);

            return Ok(userToReturn);
        }
}

How can I address UsersController in CreatedAtRoute method?


Solution

  • This is a routing issue. You are missing a value for the target route

    return CreatedAtRoute("GetUser", new { id = userToCreate.Id, userId = {some value here} }, userToReturn);