0
votes

I'm trying to build a test web API controller, just for the purpose of understanding web API. I'm wrote the following web API controller:

[Route("api/books")]
public class BookController : Controller
{

    public IEnumerable<Book> Get()
    {
        List<Book> books = new List<Models.Book>();
        books.Add(new Book { Title = "Test Title 1", Author = "Test Author 1", ISBN = "Test ISBN 1" });
        books.Add(new Book { Title = "Test Title 2", Author = "Test Author 2", ISBN = "Test ISBN 2" });

        return books;
    }

    [HttpGet("{id}")]
    public Book Get(int id)
    {
        return new Book { Title = "Test Title 1", Author= "Test Author 1", ISBN="Test ISBN 1", PublishingDate = DateTime.Today.AddYears(-90).AddDays(-73) };
    }


    //[HttpPost]
    //public IActionResult Post([FromBody]Book book)
    //{
    //    string str = "Post request received";

    //    return new JsonResult(str);
    //}


    [HttpPost]
    public IActionResult Post([FromBody]Book book)
    {            
        //return CreatedAtRoute("abi/books", new { controller = "Book", id = 1  }, book);
        //return CreatedAtRoute("Get", new { controller = "Book", id = 1  }, book);
        //return CreatedAtRoute("Get", book);
        //return CreatedAtRoute("abi/books", book);
        return CreatedAtRoute("abi/books/1", book);
    }
}

The Get and Get(id) methods work fine. The commented port method also works fine. In the other post method, I'm trying to use the CreatedAtRoute method. When I call this action using the postman tool, it returns 500 internal server error. I tried several alternatives for the method parameters (as you can see in the comment return statements) but non of them worked.

This is the detailed error that I get:

System.InvalidOperationException: No route matches the supplied values.

at Microsoft.AspNetCore.Mvc.CreatedAtRouteResult.OnFormatting(ActionContext context)

at Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)

at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__32.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__31.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__29.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__23.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__18.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()

--- End of stack trace from previous location where exception was thrown ---

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.d__6.MoveNext()

Any help is highly appreciated

1
This is most probably a typo as you have abi/books/1 instead of api/books/1. So the error is accurate as there is no route that starts with abiNkosi
I believe there are better ways to state your suggestion. Anyway, I could not delete the question. There's an error when I try to delete stating that questions that have answers cannot be deleteduser2931442

1 Answers

4
votes

The problem seems to be a misspelling in your HTTP POST return statement (abi should be api). Fixing that should do it. Also, it might be better to specify a route name for your HTTP GET method (i.e., GetBook). And in your HTTP POST return statement, pass in the route name along with the route value and object. Also, you should wrap your book object in an ObjectResult before you return it in you HTTP GET method.

// GET /api/books/{id}
[HttpGet("{id}", Name = "GetBook")]
public IActionResult Get(int id)
{
    var book = new Book { 
        Title = "Test Title 1", 
        Author = "Test Author 1", 
        ISBN="Test ISBN 1", 
        PublishingDate = DateTime.Today.AddYears(-90).AddDays(-73) 
    };
    return new ObjectResult(book);
}

// POST api/books
[HttpPost]
public IActionResult Post([FromBody] Book book)
{
    if (book == null)
    {
        return BadRequest();
    }

    // code to add book to database
    //_context.Books.Add(book);
    //_context.Books.SaveChanges();

    return CreatedAtRoute(
        routeName: "GetBook",
        routeValues: new { id = 1 },
        value: book);
}