Search code examples
asp.net-web-apiwebformsvs-web-site-project

Calling Web API from an aspx page is always resulting in Not Found error


I have a web site project ( the one that has an App_Code folder) which I have upgraded to .Net 4.5, and installed NuGet package for Web API 2.2 into the solution in VS 2013.

Under the root folder, there is a folder 'Vendors'. From a page under this folder, I am using jQuery to call a PUT Web API method inside a controller class 'AppsProcureWebApiController' under App_Code folder.

Using the url: 'api/AppsProcureWebApi' in ajax call from jQuery always results in a 'Not Found error'. Not Found Error But if I hard-code the url as url:'http://localhost/appsprocure/api/AppsProcureWebApi' in same jQuery ajax call then it works and executes the code within the Web API method.

Question: Do I need to use some special routing configuration in global.asax to make it work with orginal url, Or there is something else I need to do? (code being used for configuring routing in global.asax is mentioned below).

jQuery for calling Web API from /Vendors/EditProduct.aspx page

function SaveProdDesc() {
            var data = {
                productId: $find("<%= radcomBoxProducts.ClientID%>").get_value(),
                productDescription: $("#<%= txtProdDesc.ClientID%>").val(),
                originalProductDescription: $("#<%= hfOrigProdDesc.ClientID%>").val()
            }
            $.ajax({
                url: 'api/AppsProcureWebApi',
                type: 'PUT',
                data: JSON.stringify(data),
                contentType: "application/json",
                dataType:"json",
                success: function (data) {
                    alert(data);
                },
                error: function (x, y, z) {
                    alert(x + '\n' + y + '\n' + z);
                }
            });
        }

Routing defined in Global.asax

    void Application_Start(object sender, EventArgs e)
    {
      //below code to make Web API work in Webforms
          RouteTable.Routes.MapHttpRoute( name: "DefaultApi", 
               routeTemplate: "api/{controller}/{id}", 
               defaults: new { id = System.Web.Http.RouteParameter.Optional });
}

Web API controller class under App_Code is as below.

    public class AppsProcureWebApiController : ApiController
{
    //OTHER METHODS ARE OMITTED TO SAVE SPACE

    [HttpPut]
    [Authorize]
    public int Put(ProductDesc p)
    {
        string prodDesc = p.ProductDescription;
        return ApplicationDataAccess.UpdateProductDescription(p.ProductId, ref prodDesc, p.OriginalProductDescription);
    }

}

public class ProductDesc
{
    public long ProductId { get; set; }
    public string ProductDescription { get; set; }
    public string OriginalProductDescription { get; set; }
}

Solution

  • I found the answer after a lot of trying. This will be very useful in cases when using jQuery from an aspx page to call Web API in webforms asp.net projects, since in such projects the pages will exist under different folders.

    Only a simple change is needed so the Web API can be called seamlessly from an aspx page under folder 'Vendors' using the url: 'api/AppsProcureWebApi'.

    This simple change is of adding vendors to the routing configuration. If you let the original rule be there then make sure you name this new routing rule differently i.e. something other than DefaultApi. I have named this new rule as Rule1Api in code below.

    So api/{controller}/{id} becomes vendors/api/{controller}/{id} in routing configuration as in code below. But do not change the url mentioned in jQuery call, which means let it be url: api/AppsProcureWebApi since vendors will be automatically prepended to the url mentioned in jQuery call.

    void Application_Start(object sender, EventArgs e)
    {
          //below code to make Web API work in Webforms
              RouteTable.Routes.MapHttpRoute( name: "Rule1Api", 
                   routeTemplate: "vendors/api/{controller}/{id}", 
                   defaults: new { id = System.Web.Http.RouteParameter.Optional });
    }