Search code examples
c#web-servicesasp.net-web-api2asp.net-web-api-routing

Error when send POST to a function with defined route - Web API 2


I have this function in my Web Service that add a 'addlocalidade' in my table TBLocalidade in SQL Server.

[HttpPost]
[Route("api/insertlocalidade")]
[ResponseType(typeof(TBLocalidade))]
public async Task<IHttpActionResult> insertlocalidade([FromBody] TBLocalidade addlocalidade)
{
    objapi.Configuration.LazyLoadingEnabled = false;
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    objapi.TBLocalidade.Add(addlocalidade);
    await objapi.SaveChangesAsync();

    return CreatedAtRoute("DefaultApi", new { id = addlocalidade.idLocalidade }, addlocalidade);
}

If I remove the route, it works perfectly, but when I add this route: [Route("api/insertlocalidade")], it doesn't work good, I tested it with httpRequester, it was possible to add the value in database, but it return this error message:

{"Message":"An error has occurred.","ExceptionMessage":"UrlHelper.Link must not return null.","ExceptionType":"System.InvalidOperationException","StackTrace":" em System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.Execute()\r\n em System.Web.Http.Results.CreatedAtRouteNegotiatedContentResult1.ExecuteAsync(CancellationToken cancellationToken)\r\n em System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()\r\n--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---\r\n em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n em System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()\r\n--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---\r\n em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n em System.Web.Http.Controllers.AuthenticationFilterResult.d__0.MoveNext()\r\n--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---\r\n em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n em System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()"}

Anyone can please help me to solve this error?


Solution

  • That is because there is not enough information for the UrlHelper to generate the link using convention based routing.

    Assuming a web api config like this ...

    public static class WebApiConfig {
        public static void Register(HttpConfiguration config) {
            // Attribute routing.
            config.MapHttpAttributeRoutes();
    
            // Convention-based routing.
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
    

    You would need to provide the controller name when generating the created at response using that route.

    return CreatedAtRoute("DefaultApi", new { controller = "localidade", id = addlocalidade.idLocalidade }, addlocalidade);
    

    However since you are using an attribute routing then, assuming the following get action in the controller ...

    //GET api/localidade/5
    [HttpGet]
    [Route("api/localidade/{id:int}")]
    [ResponseType(typeof(TBLocalidade))]
    public async Task<IHttpActionResult> getlocalidade(int id) { ... }
    

    You have to add a route name to the route attribute which is used by the UrlHelper for generating links.

    //GET api/localidade/5
    [HttpGet]
    [Route("api/localidade/{id:int}", Name="GetLocalidade")] // <-- NOTE THE CHANGE
    [ResponseType(typeof(TBLocalidade))]
    public async Task<IHttpActionResult> getlocalidade(int id) { ... }
    

    and use it in the CreatedAtRoute in order to generate the link properly

    return CreatedAtRoute("GetLocalidade", new { id = addlocalidade.idLocalidade }, addlocalidade);