2

I may have the verbiage all wrong here, so forgive and correct me if I'm using the wrong words. I'm from the world of traditional ASP.Net web applications, where I could simply add an ApiController to my web application project and hit the ground running. However, that doesn't seem to be the case with the ASP.Net Core web application I'm working with now.

I created a web application project:

ASP.NET Core Web Application

Chose type of Web Application:

Type

Then I added my controller to the root directory:

Controller Type

Wrote a minuscule chunk of code for it:

[Route("[controller]")]
[ApiController]
public class ModulesController : ControllerBase {
    [HttpPost]
    [Route("Modules/Execute")]
    public void Execute([FromBody] string key) => ModuleManager.Instance.TryExecute(key);
}

Then tried to call it with AJAX:

$.ajax(
    {
        contentType: "application/json",
        data: JSON.stringify({ executionKey: executionKey }),
        dataType: "jsond",
        type: "POST",
        url: "/Modules/Execute",
        failure: function (msg) {
            alert("failure");
        },
        success: function (msg) {
            alert("success");
        }
    });

Annnnnd I get a 404 error saying it can't be found.

Dev Tools Error

Now, I've tried several other things, like:

  • Changing to get.
  • Removing the Route from the controller.
  • Adding controller route mapping to Startup.cs:

^

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

And several other failed attempts along the way. I'm obviously missing something fundemental with this new setup, and I can't figure out what it is.


How do I call my API controller from my ASP.NET Core web page?

NOTE: I've tried to manually hit it as a GET to see if maybe it was a path issue, and couldn't hit it that way either, no matter how many different combinations I tried.

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44
  • `Modules` controller you have has a method which returns void. Such methods are exposed as endpoints. You need to create action methods in Controller. – Chetan Aug 13 '20 at 00:05

2 Answers2

3

The called URL

"/Modules/Execute"

does not match the routes on the controller.

[Route("[controller]")] //<- Prefixes all Actions on this controller with controller name
[ApiController]
public class ModulesController : ControllerBase {
    
    [HttpPost]
    [Route("Modules/Execute")] //<- This route resolves to: POST Modules/Modules/Execute
    public void Execute([FromBody] string key) => ModuleManager.Instance.TryExecute(key);
}

So either update the client to call the correct URL or update the controller routes to the desired URL.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • It sounds like `[Route("[controller]")]` is probably not doing what they want and thus unnecessary and should be removed? – Brad Aug 13 '20 at 00:20
  • 1
    @Brad actually that is usually the advised approach on setting the route on your controller. The action route should be `[Route("Execute")]`, which when coupled with the route on the controller resolves to the desired URL `Modules/Execute` – Nkosi Aug 13 '20 at 00:23
  • OP did mention that they tried removing the `[Route]` attribute from the controller. There is more than 1 issue. @Brad, [Route] on the controller acts as a [RoutePrefix] attribute, which is present in the .NET Framework version of Web API – CoolBots Aug 13 '20 at 00:24
  • This is the initial problem, and I confirmed it by adjusting the AJAX to point to `/Modules/Modules/Execute`, which is odd because I'm sure I tried that. Maybe didn't start it with `/`? Not sure, but @CoolBots is correct that I have more than one issue, and their answer addresses that. Do you mind me marking their answer as the accepted answer to my question to assist future readers? I leave the decision to you as you were the first to answer, and technically solved my problem. :) – Hazel へいぜる Aug 13 '20 at 00:28
  • 1
    @Taco not a problem at all. They obviously went into more detail. – Nkosi Aug 13 '20 at 00:30
2

Several issues:

  1. Make sure you're mapping controllers (you mentioned you tried it, but it has to be there, in Startup.cs):
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();  // if you need it; there by default
                endpoints.MapControllers();
            });
  1. Your route is incorrect - the routes are cumulative, so if you're specifying [Route] on your Controller class, it acts as a [RoutePrefix] in the older ASP.NET frameworks; change the route on your method:
    [HttpPost]
    [Route("Execute")] //<- This route resolves to: POST Modules/Execute
    public void Execute([FromBody] string key) => ModuleManager.Instance.TryExecute(key);

Alternatively, you can remove the [Route] attribute from the controller; again, you mentioned you tried it, but probably without the rest of the issues being fixed at the same time.

  1. Your ajax call sends in a JSON object, but your function is expecting a string. Change the call, or (better idea) introduce a Model that contains a key.

Any of these 3 issues present will cause a 404.

As an aside, consider returning IActionResult instead of void: https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-3.1

CoolBots
  • 4,770
  • 2
  • 16
  • 30