Home > OS >  POSTing from jQuery Ajax to WebAPI 2.1 controller not working - No HTTP resource was found that matc
POSTing from jQuery Ajax to WebAPI 2.1 controller not working - No HTTP resource was found that matc

Time:07-25

I can't find an answer here to this one (been asked before, but this is specific to MVC5 WebAPI2.1 and jQuery), but in Postman, I'm getting

{ "Message": "No HTTP resource was found that matches the request URI 'https://localhost:44371/api/reportdiscrepancy'.", "MessageDetail": "No action was found on the controller 'ReportProblem' that matches the request." }

error message - which is there (I have other controllers that use GET, but this one is using POST is the only difference and they work just fine). My controller (note: this inherits from ApiController, NOT Controller) - and the code worked fine when it was an ASMX :

  [Route("api/reportdiscrepancy")]
    [HttpPost]
    public async Task<IHttpActionResult> ReportDiscrepancy(string lid, string ProblemTypes, string ProblemTypeOther)
    {     
        string retval = string.Empty;
        lid = AppCore.Validation.StripToGUID(lid);
        ProblemTypes = AppCore.Validation.StripToDigitInCSVFromStr(ProblemTypes);
        ProblemTypeOther = AppCore.Validation.StripAllCharsForMetaTag(StripHtml(ProblemTypeOther));
        var session = HttpContext.Current.Session;

        if (lid.Length == 36 && ProblemTypes.Length > 0 | ProblemTypeOther.Length > 0)
        {
            if (IsGUID(lid))
            {
                if (session != null)
                {
                    if (session.SessionID != null)
                    {
                        if (session.SessionID.Length > 0)
                        {
                            var dr = new Discrepancy
                            {
                                lid = lid,
                                SessionId = session.SessionID,
                                IPAddress = Ops.Site.GetUserIP(HttpContext.Current),
                                UserId = "anonymous"
                            };
                            if (User != null)
                            {
                                if (User.Identity != null)
                                {
                                    if (User.Identity.IsAuthenticated)
                                    {
                                        dr.UserId = User.Identity.GetUserId();
                                    }
                                }
                            }
                            dr.ProblemTypeIds = ProblemTypes;
                            dr.ProblemTypeOther = ProblemTypeOther;
                            dr.idx = await DiscrepancyReportData.InsertDiscrepancyAsync(dr);
                            if (dr.idx > 0)
                            {
                                retval = "success";
                            }
                        }
                    }
                }
            }
        }


        return Ok(retval);
    }

The jquery/javascript:

    $("#btnSendReport").bind('click', function (e) {
    var parElem = $(this).parent().parent().parent();
    var listID = parElem.find("#hidLID").val();
    var problemTypes = $.map(parElem.find('option:selected'), function (e) { return e.value; }).join(',');
    var problemTypeOther = parElem.find("#txtProblemTypeOther").val();

    var obj = {};
    obj.lid = listID;
    obj.ProblemTypes = problemTypes;
    obj.ProblemTypeOther = problemTypeOther;

    try {
        $.ajax({
            type: "POST",
            url: "../../api/reportdiscrepancy/",
            data: JSON.stringify(obj),     //not sure if this is necessary w/webAPI           
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (data) {
                var result = data; //not doing anything here
            },
            error: function (err) {
                console.log(err);
            }

        });
    } catch (err) {
        console.log(err);
    }

});

Anyone have any ideas? There are no examples with WebAPI 2.1 showing a jQuery post (I don't want to use GET because of query string limits and I'm not using a FORM or BODY, so those answers won't work either). The more I look into this, I get many answers, but all very specific to special cases. I would like to just see one working example of POSTing and OBJECT (not a string or anything simple) from JQuery (3.x or higher) to an MVC5 (other versions are different) and NOT Core (totally different) and WebAPI 2.x . How to properly decorate the controller for a jquery post (not a querystring, not a form). Any ideas?

CodePudding user response:

fix the action route by adding ~. The route will start from root

 [Route("~/api/reportdiscrepancy")]

fix ajax url to start from root too. also remove stringify and contentType: "application/json; charset=utf-8", since I am not sure that your ancient framework supports it

$.ajax({
            type: "POST",
            url: "/api/reportdiscrepancy",
            data: obj,         
            dataType: "json",

but I would create a special class for an action too

public class ViewModel
{
public string Lid {get; set;}
public string ProblemTypes {get; set; }
public string ProblemTypeOther {get; set;}
}

 [Route("~/api/reportdiscrepancy")]
public async Task<IHttpActionResult> ReportDiscrepancy(ViewModel model)
{
.....
}

CodePudding user response:

On the client side - I made the changes Serge recommended.

   $("#btnSendReport").bind('click', function (e) {
    var parElem = $(this).parent().parent().parent();
    var listID = parElem.find("#hidLID").val();
    var problemTypes = $.map(parElem.find('option:selected'), function (e) { return e.value; }).join(',');
    var problemTypeOther = parElem.find("#txtProblemTypeOther").val();
    if (problemTypeOther === null) { problemTypeOther = '' };

    var obj = {};
    obj.lid = listID;
    obj.ProblemTypes = problemTypes;
    obj.ProblemTypeOther = problemTypeOther;

    try {
        $.ajax({
            type: "POST",
            url: "../../api/reportdiscrepancy/",
            data: obj,
            dataType: "json",
            success: function (data) {
                var result = data; 
            },
            error: function (err) {
                console.log(err);
            }

        });
    } catch (err) {
        console.log(err);
    }

});

In the api controller, the only change required was the inputs to an object (webapi 2.x does automatic conversion - didn't know this)

      [Route("api/reportdiscrepancy")]
    [HttpPost]
    public async Task<IHttpActionResult> ReportDiscrepancy(DiscrepancyPost dp)
    {
        string retval = string.Empty;
        dp.lid = AppCore.Validation.StripToGUID(dp.lid);
        dp.ProblemTypes = AppCore.Validation.StripToDigitInCSVFromStr(dp.ProblemTypes);
        dp.ProblemTypeOther = AppCore.Validation.StripAllCharsForMetaTag(StripHtml(dp.ProblemTypeOther.xToStr()));
        var session = HttpContext.Current.Session;

        try
        {
            if (dp.lid.Length == 36 && dp.ProblemTypes.Length > 0 | dp.ProblemTypeOther.Length > 0)
            {
                if (IsGUID(dp.lid))
                {
                    if (session != null)
                    {
                        if (session.SessionID != null)
                        {
                            if (session.SessionID.Length > 0)
                            {
                                var dr = new Discrepancy
                                {
                                    lid = dp.lid,
                                    SessionId = session.SessionID,
                                    IPAddress = Ops.Site.GetUserIP(HttpContext.Current),
                                    UserId = "anonymous"
                                };
                                if (User != null)
                                {
                                    if (User.Identity != null)
                                    {
                                        if (User.Identity.IsAuthenticated)
                                        {
                                            dr.UserId = User.Identity.GetUserId();
                                        }
                                    }
                                }
                                dr.ProblemTypeIds = dp.ProblemTypes;
                                dr.ProblemTypeOther = dp.ProblemTypeOther;
                                dr.idx = await DiscrepancyReportData.InsertDiscrepancyAsync(dr);
                                if (dr.idx > 0)
                                {
                                    retval = "success";
                                }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception)
        {
            //TODO logging
        }
        return Ok(retval);
    }

and the class:

 public class DiscrepancyPost
{
    public string lid { get; set; }
    public string ProblemTypes { get; set; }
    public string ProblemTypeOther { get; set; }
}

Works like a charm. So the problem was in the controller signature (fixed that first and got it to work in Postman perfectly), then in the jQuery side.

  • Related