[SOLVED] API Controller not being found – ASP.NET

Issue

Bit of background:

I’m adding a feature to one of our clunky old systems to keep it ticking over until such time as the new version of the system is at a level where this feature could be brought to a level where it can support this feature.

The system is a combination of C# and VB (yes, I know, I’m slowly phasing the VB out). Essentially, I’m adding this simple API Controller (there will be one or two more methods once finished, this is just me getting the first bit working):

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;


[RoutePrefix("/Utilities/LaptopTrolleyBooking/LaptopAPI/")]
public class LaptopBookingsController : ApiController
{
    [Route("GetLaptopBookings"), HttpGet]
    public async Task<HttpResponseMessage> GetLaptopBookings()
    {
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["NGConnectionString"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = "FR_TT_GetUpcomingLaptopBookingsForJson";
                command.CommandType = CommandType.StoredProcedure;

                var result = await command.ExecuteScalarAsync();
                var response = Request.CreateResponse(HttpStatusCode.OK);
                response.Content = new StringContent(result.ToString(), Encoding.UTF8, "application/json");
                return response;
            }
        }
    }
}

However, when I attempt to call it from this javascript block:

$(document).ready(function () {
    init();

    function createElement(tag) {
        return $('<' + tag + '>');
    }

    function createElement(tag, className) {
        return $('<' + tag + '>').addClass(className);
    }

    function init() {
        var headerElem = createElement('div', 'panHeader')
            .text('Laptop Trolley Bookings');

        $('.content')
            .append(headerElem);

        GetBookings();

        function GetBookings() {
            $.ajax({
                url: '/Utilities/LaptopTrolleyBooking/LaptopApi/GetLaptopBookings',
                method: 'get',
                contentType: 'json',
                dataType: 'json',
                success: function (response) {
                    debugger;
                },
                error: function () {
                    debugger;
                }
            });
        }
    }
});

I’m receiving an error 404. Have I done something obviously wrong here, or am I missing some setting somewhere?

If it helps, here’s the Global.asax

<%@ Application Language="VB" %>

<script runat="server">

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Code that runs on application startup

        ' License Aspose.Words & Aspose.PDF
        Dim licenseWords As New Aspose.Words.License()
        licenseWords.SetLicense("Aspose.Total.lic")
        Dim licensePDF As New Aspose.Pdf.License()
        licensePDF.SetLicense("Aspose.Total.lic")
        Dim licenseOCR As New Aspose.OCR.License()
        licenseOCR.SetLicense("Aspose.Total.lic")
        Dim licenseBarCode As New Aspose.BarCode.License()
        licenseBarCode.SetLicense("Aspose.Total.lic")
        Dim licenseBarCodeRecognition As New Aspose.BarCodeRecognition.License()
        licenseBarCodeRecognition.SetLicense("Aspose.Total.lic")
        Dim licenceCells As New Aspose.Cells.License()
        licenceCells.SetLicense("Aspose.Total.lic")



    End Sub

    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
        ' Code that runs on application shutdown
    End Sub

    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
        ' Code that runs when an unhandled error occurs
    End Sub

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Get session data
    End Sub

    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
        ' Code that runs when a session ends. 
        ' Note: The Session_End event is raised only when the sessionstate mode
        ' is set to InProc in the Web.config file. If session mode is set to StateServer 
        ' or SQLServer, the event is not raised.
    End Sub

</script>

Solution

After much research and further experimentation, I’ve found the issue. In essence, the codebase was so old that it just doesn’t support having an API controller within the web project. To get around this I created a WebService, as such:

using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web.Script.Serialization;
using System.Web.Script.Services;
using System.Web.Services;

[WebService(Namespace = "mySillyUrl")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class LaptopBookingController : WebService
{
    public LaptopBookingController()
    {
    }

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = true)]
    public void CancelLaptopBooking(int RSBH_ISN)
    {
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["NGConnectionString"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = connection.CreateCommand())
            {
                List<LaptopBooking> bookings = new List<LaptopBooking>();
                command.CommandText = "FR_TT_CancelLaptopBooking";
                command.Parameters.AddWithValue("RSBH_ISN", RSBH_ISN);
                command.CommandType = CommandType.StoredProcedure;

                var unused = command.ExecuteScalar();
            }
        }
    }

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public void GetLaptopBookings()
    {
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["NGConnectionString"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = connection.CreateCommand())
            {
                List<LaptopBooking> bookings = new List<LaptopBooking>();
                command.CommandText = "FR_TT_GetUpcomingLaptopBookingsForJson";
                command.CommandType = CommandType.StoredProcedure;

                var result = command.ExecuteScalar();
                var jArr = JArray.Parse(result.ToString());

                foreach (JObject jObj in jArr)
                {
                    bookings.Add(new LaptopBooking(jObj));
                }
                JavaScriptSerializer serializer = new JavaScriptSerializer();
                Context.Response.Write(serializer.Serialize(bookings));
            }
        }
    }
}

Then, from the javascript, the call was as simple as:

    function GetBookings() {
        $.ajax({
            url: '/Utilities/LaptopTrolleyBooking/LaptopBookingController.asmx/GetLaptopBookings',
            method: 'POST',
            //contentType: "application/json; charset=utf-8",
            //dataType: "json",
            data: '{ }',
            success: function (response) {
                //debugger;
                bookings = JSON.parse(response);

                ShowBookings();
            }
        });
    }

Answered By – Andrew Corrigan

Answer Checked By – Pedro (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *