Home > other >  Web Api Ignoring Route Attribute
Web Api Ignoring Route Attribute

Time:11-27

I am working on a Web API project and when I run it and try to use the route for a controller, it doesn't work and instead, it throws me a 404 error. Why is the Web API ignoring the route attribute?

I'll leave the code below:

[ApiController]
[Route("api/[controller]")]

public class Controller3 : ControllerBase
{
    private readonly IServiceContract3 _interest;
    public Controller3(IServiceContract3 interest)
    {
        _interest = interest;
    }

    [HttpGet]
    [Route("[action]")]
    [Route("api/Interest/GetInterests")]
    public IEnumerable<Interest> GetEmployees()
    {
        return _interest.GetInterests();
    }

    [HttpPost]
    [Route("[action]")]
    [Route("api/Interest/AddInterest")]
    public IActionResult AddInterest(Interest interest)
    {
        _interest.AddInterest(interest);
        return Ok();
    }

    [HttpPost]
    [Route("[action]")]
    [Route("api/Interest/UpdateInterest")]
    public IActionResult UpdateInterest(Interest interest)
    {
        _interest.UpdateInterest(interest);
        return Ok();
    }

    [HttpDelete]
    [Route("[action]")]
    [Route("api/Interest/DeleteInterest")]
    public IActionResult DeleteInterest(int id)
    {
        var existingInterest = _interest.GetInterest(id);
        if (existingInterest != null)
        {
            _interest.DeleteInterest(existingInterest.Id);
            return Ok();
        }
        return NotFound($"Employee Not Found with ID : {existingInterest.Id}");
    }

    [HttpGet]
    [Route("GetInterest")]
    public Interest GetInterest(int id)
    {
        return _interest.GetInterest(id);
    }

}

And for my Startup.cs

    public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddDbContextPool<DatabaseContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DB")));
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DatabaseContext context)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        context.Database.Migrate();

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

How can I fix the routing? Every time I try to do it in my browser like https://localhost:44316/api/Interest/GetInterests I get a 404 error instead. Why is this happening?

CodePudding user response:

you have to fix your route by making api a root. Replace "api" by "~/api". IMHO you should remove [action] from actions and add it to a controller. Also fix a controller name

    [ApiController]
    [Route("~/api/[controller]/[action]")]
    public class  InterestController : ControllerBase

    [HttpGet("~/api/Interest/GetInterests")]
    public IEnumerable<Interest> GetEmployees()
     ....

   
    [HttpPost("~/api/Interest/AddInterest")]
    public IActionResult AddInterest(Interest interest)
    ...

    
    [HttpPost("~/api/Interest/UpdateInterest")]
    public IActionResult UpdateInterest(Interest interest)
     ...

    
    [HttpDelete("~/api/Interest/DeleteInterest/{id}")]
    public IActionResult DeleteInterest(int id)
    ....

    [HttpGet("~/api/Interest/GetInterest/{id}")]
    public Interest GetInterest(int id)

CodePudding user response:

Typically controllers for a webapi are defined as so:

[ApiController]
[Route("api/[controller]")]
public sealed class InterestController : ControllerBase
{
    private readonly IServiceContract3 _interest;

    public InterestController(IServiceContract3 interest)
    {
        _interest = interest;
    }

    [HttpGet, Route("GetInterests")]
    public IActionResult GetEmployees()
    {
        // this is located at: GET api/Interest/GetInterests
        return Ok(_interest.GetInterests());
    }


    [HttpPost, Route("AddInterest")]
    public IActionResult AddInterest([FromBody] Interest interest)
    {
        // this is located at: POST api/Interest/AddInterest
    }

    [HttpPost, Route("UpdateInterest")]
    public IActionResult UpdateInterest([FromBody] Interest interest)
    {
        // this is located at: POST api/Interest/UpdateInterest
    }

    [HttpDelete, Route("DeleteInterest/{id}")]
    public IActionResult DeleteInterest([FromRoute] int id)
    {
        // this is located at: DELETE api/Interest/DeleteInterest/{id}
    }

    [HttpGet, Route("GetInterest/{id}")]
    public IActionResult GetInterest([FromRoute] int id)
    {
        // this is located at: GET api/Interest/GetInterest/{id}
        return Ok(_interest.GetInterest(id));
    }
}

First, you want to name your controller a relevant name that will carry throughout the rest of your controller. So, this this case, I changed Controller3 to InterestController. Since the route of the controller is "/api/[Controller]", it will translate to "api/Interest".

Next, remove the [Action] attributes. You do not need them in this scenario.

Then, make sure your routes are correct. If you are passing an ID, define your ID in the route using {id} and setting the [FromRoute] attribute for clarity. Also, use [FromBody] to define parameters that will be coming from the body. A lot of these are "default" (meaning you don't need to add them), but it helps with clarity.

Finally, if you are using the IActionResult pattern, then stick with that through your controller. Don't mix/match return types across endpoints because it's confusing for maintenance.

One final thing: Your controller endpoint names are slightly redundant. For example, you could do this:

    [HttpGet, Route("")]
    public IActionResult GetEmployees()
    {
        // this is located at: GET api/Interest
        return Ok(_interest.GetInterests());
    }


    [HttpPut, Route("")]
    public IActionResult AddInterest([FromBody] Interest interest)
    {
        // this is located at: PUT api/Interest/
    }

    [HttpPost, Route("")]
    public IActionResult UpdateInterest([FromBody] Interest interest)
    {
        // this is located at: POST api/Interest/
    }

    [HttpDelete, Route("{id}")]
    public IActionResult DeleteInterest([FromRoute] int id)
    {
        // this is located at: DELETE api/Interest/{id}
    }

    [HttpGet, Route("{id}")]
    public IActionResult GetInterest([FromRoute] int id)
    {
        // this is located at: GET api/Interest/{id}
        return Ok(_interest.GetInterest(id));
    }

i.e.: Use the "HTTP Verb" to your advantage to segregate actions.

  • Related