Think_Twice
Think_Twice

Reputation: 323

Controller with HttpGet(...) gives error 404

I am struggling to understand why I'm getting a Error 404 error when I use [HttpGet("/add-brand")] but without [HttpGet("/add-brand")] it works fine?

Here is my Controller:

public class BrandController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        [HttpGet("/add-brand")]
        public async Task<IActionResult> AddBrand()
        {
            return View();
        }
    }

It works if the path is /brand/addbrand (without [HttpGet("/add-brand")]) but I would like to use [HttpGet("/add-brand")] instead.

What am I doing wrong?

EDIT: Here is my Startup.cs Configure method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });
        }

Upvotes: 0

Views: 1671

Answers (3)

poke
poke

Reputation: 387775

The route is: localhost:5001/brand/add-brand

So you expect the action to be callable within the /brand that’s coming from your BrandController. But that’s not how attribute routing works.

By default, ASP.NET Core uses conventional routing for controllers. The default template it uses is /{controller}/{action}. That is why accessing /brand/addbrand works if you don’t use attribute-based routing.

But as soon you specify the route via an attribute (either [Route(…)] or a method-specific attribute like [HttpGet(…)]) you are basically disabling the convention based routing. So that action’s route will only be determined by the route attributes. And since you only have the single [HttpGet("/add-brand")], the actual route for your action will be https://localhost:5001/add-brand without an additional path segment for the controller.

You can put that back in if you like using [HttpGet("/{controller}/add-brand")]. An alternative would be to add a separate [Route("{controller}")] on the controller which will then cause all action routes to be concatenated to this. Note that this will disable conventional routing for all routes though, requiring you to specify it for every action.

Upvotes: 2

VMoosky
VMoosky

Reputation: 16

When you try /brand/addbrand (without [HttpGet("/add-brand")]):

MVC used routing template "{controller}/{action} It matches brand with BrandController and addbrand with your action name

I'm curious why '/' is needed in [HttpGet("/add-brand")]. If you try [HttpGet("add-brand")] it should work fine.

Upvotes: 0

Xavier
Xavier

Reputation: 1430

Camilo is correct, you don't need the leading / in the route string, the /brand/ is implied by the controller.

public class BrandController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpGet("add-brand")]
    public async Task<IActionResult> AddBrand()
    {
        return View();
    }
}

Upvotes: 0

Related Questions