Having trouble getting a controller in a Razor Class Library to work, What am I missing?

399 Views Asked by At

I am having a terrible time getting a REST API controller that is located in an external assembly (in other words, a Razor Class Library) to work. Whenever I make a call to the API via JavaScript, I get a 404 error.

In the Razor Class Library (RCL) I put the controller in its own Area in this structure:

RCL project layout

The LookupController is decorated with Route attributes:

namespace Case.Coding.Areas.CaseCoding.Controllers
{
    [Route("CaseCoding/[controller]")]
    [ApiController]
    public class LookupsController : ControllerBase
    {
        [HttpPost]
        [Route("External")]
        public async Task<IActionResult> ExternalAsync()
        {
            return Ok("This is a value. Hoo boy.");
        }
    }
}

In the calling project I put a button on the Index page like this:

<button id="ClickHere" onclick="GetApiResult();">Click Here</button>
<div id="ClickResult"></div>

And the GetApiResult function looks like this:

function GetApiResult() {
    var container = $('#ClickResult');
    
    $.ajax({
        url: '/CaseCoding/Lookups/External',
        method: 'POST',
        contentType: 'application/json'
    })
        .done(function (result, statusText, xhr) {
            var isUndefined = typeof result === 'undefined';
    
            if (isUndefined || result.length == 0) {
                container.append('<p class="pat-comment err">Nothing returned.</p>');
            }
            else {
                container.append(result);
            }
        })
        .fail(function (xhr, statusText, err) {
            container.append('<p class="pat-comment err">' + err + '</p>');
        });
    }

I thought the URL to the controller might be different and tried several combinations. Nothing worked, so I thought I might explore the routes attached to the calling project to find out, and found some code (courtesy of https://www.meziantou.net/list-all-routes-in-an-asp-net-core-application.htm) that allowed me to explore them:

if (app.Environment.IsDevelopment())
{
    app.MapGet("/debug/routes", (IEnumerable<EndpointDataSource> endpointSources) =>
        string.Join("\n", endpointSources.SelectMany(source => source.Endpoints)));
}

Placed right before the app.Run() statement, this code let me see what I want, but the results flummoxed me. I found the controller in the routes, but the EndPoint was no URL. When navigating to /debug/routes I got this list:

/Error
/Index
/Index
/Privacy
/Page1
Case.Coding.Areas.CaseCoding.Controllers.LookupsController.ExternalAsync (Case.Coding)
HTTP: GET /debug/routes

There the API is listed out (2nd from bottom), but why isn't it a URL? Does anyone have any idea what is happening here, and (more importantly) how to make my controller route be recognized as a URL so I can call it from JavaScript?

1

There are 1 best solutions below

0
On

I didn't reproduce your issue, I can only show you how I did in my side.

I created a new .net 6 MVC project, and I created a web API project in the same solution. Then I create the same Area and the same folder and the same Controller.

enter image description here

Then I right click on the MVC project to add reference. Then choose the web api project.

enter image description here

This will make the MVC project csproj file be modified.

enter image description here

Since I created the MVC project first, so I don't need to change the startup project, pressing F5 to run the MVC project, then hitting the URL https://localhost:7089/CaseCoding/Lookups/External. Here I changed the POST request to GET for easier to test.

enter image description here

After making sure the URL, then I write an ajax request in the index.cshtml in MVC project.

<div>
    <button id="btn">send</button>
</div>

@section Scripts{
    <script>
        $("#btn").click(function () {
            alert(1);
            $.ajax({
                url: "https://localhost:7089/CaseCoding/Lookups/External",
                type:"get",
                success:function(data){
                    alert(data);
                }
            })
        })

    </script>
}

enter image description here