-1

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>
Andrew Corrigan
  • 1,017
  • 6
  • 23
  • Have you tried changing the attribute on the controller from `[RoutePrefix]` to `[Route]`? Also, I think you should remove forward and trailing `/` from that attribute. – Dandry Jan 28 '22 at 13:21
  • Not related to your problem, but why on earth are you mixing VB and C# in the same project?! – DavidG Jan 28 '22 at 13:33
  • @DavidG - I inherited the code base; it was that way before I started the job. – Andrew Corrigan Jan 28 '22 at 13:37
  • @Dandry just attempted that, same outcome unfortunately – Andrew Corrigan Jan 28 '22 at 13:47
  • 1
    Is your API project running at the root of a site (eg: `https://localhost:42`), or is it configured as an application within another site (eg: `http://localhost/yourapi/``)? – Richard Deeming Jan 28 '22 at 14:11
  • Also, I can't see anything in your `Global.asax` code which would enable attribute routing. I'd expect to see a call to `MapHttpAttributeRoutes` somewhere. – Richard Deeming Jan 28 '22 at 14:13
  • @AndrewCorrigan Give the `root` in your URL: `'~/Utilities/LaptopTrolleyBooking/LaptopApi/GetLaptopBookings'` – Rahul Sharma Jan 28 '22 at 14:48

1 Answers1

0

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();
            }
        });
    }
Andrew Corrigan
  • 1,017
  • 6
  • 23