简体   繁体   中英

Pass complex parameter to Web API service via javascript

I'm making an ASP.NET Web API web service, and an HTML/javascript page to test it. The issue I'm having is with passing a complex data parameter and having it come through properly in the web API controller.

I know there are numerous similar questions and I've read them and tried the solutions and haven't solved it. I have also read some JQuery documentation.

Here's my controller:

public class TitleEstimateController : ApiController
{
    public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
    {
            // All the values in "query" are null or zero
            // Do some stuff with query if there were anything to do
    }
}

public class EstimateQuery
{
    // Various fields
}

The route mapping in WebApiConfig.cs:

config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{query}"
            );

And the javascript:

var uri = 'api/titleEstimate/';
var query = {
            "username": $("#user").val(),
            // other fields
        };

      $.getJSON(uri,query)
          .done(function (data) {
              $('#product').text("OK");
          })
          .fail(function (jqXHR, textStatus, err) {
            $('#product').text('Error: ' + err);
          });

Currently I'm getting a 404. I tried $.getJSON(uri + '/' + query) but that didn't work either. Before I was passing this object I was calling it successfully so I think the routing is generally OK. I tried a type converter, but that didn't help, still a 404. Does anyone see what I'm missing/doing wrong?

Answer

You are using the wrong uri . You need api/titleEstimate/getTitleEstimate . That explains and will resolve your 404.

Answer to Follow Up Question

Everything else you're doing almost works. After you resolve the 404, you'll find that you aren't receiving the value FromUri , and you'll have a follow up question. So, you need to change your route config to this:

config.Routes.MapHttpRoute(
    name: "Default",
    routeTemplate: "api/{controller}/{action}"
);

Then you'll not only resolve your 404 but also receive the FromUri value that you're sending as query string parameters.

Demo

Here is a fiddle for evidence , which is calling into this controller , which is hosted LIVE here . The only thing I changed in the working version are the uri to resolve the 404 and the route config to make sure you receive the FromUri value. That's all.

HTML

<label>Username:
    <input id="user" />
</label>
<button id="submit">Submit</button>
<button id="submit-fail">Submit Fail</button>
<div id="product"></div>

JavaScript

This will succeed.

Note, we only need domain because we doing cross-site scripting here for the demo purpose.

var domain = "https://cors-webapi.azurewebsites.net";

$("#submit").click(function () {

    var uri = domain + '/api/titleEstimate/getTitleEstimate';

    var query = {
        "username": $("#user").val(),
        // other fields
    };

    $.getJSON(uri, query)
        .done(function (data) {
        $('#product').text(data);
    })
        .fail(function (jqXHR, textStatus, err) {
        $('#product').text('Error: ' + err);
    });
});

This will 404.

$("#submit-fail").click(function () {

    var uri = domain + '/api/titleEstimate';

    var query = {
        "username": $("#user").val(),
        // other fields
    };

    $.getJSON(uri, query)
        .done(function (data) {
        $('#product').text(data);
    })
        .fail(function (jqXHR, textStatus, err) {
        $('#product').text('Error: ' + err);
    });
});

Controller

public class TitleEstimateController : ApiController
{
    public class EstimateQuery
    {
        public string username { get; set; }
    }

    public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
    {
        // All the values in "query" are null or zero
        // Do some stuff with query if there were anything to do
        if(query != null && query.username != null)
        {
            return Ok(query.username);
        }
        else
        {
            return Ok("Add a username!");
        }
    }        
}

You can read more details about WebApi routing here . From reading it you can probably come up with an alternative solution within your route config. There are also lots of terrific examples in this blog post .

For complex objects, I usually send them in the message body rather than the URL.

Would you have any objection to an approach similar to the answer of this question? How to pass json POST data to Web API method as object

It seems like the more straightforward/natural approach.

Something like (untested, but should be close):

[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
   [HttpGet]
    public IHttpActionResult GetTitleEstimate([FromBody] EstimateQuery query)
    {
        // All the values in "query" are null or zero
        // Do some stuff with query if there were anything to do
     }
}

public class EstimateQuery
{
    public string QueryName{ get; set; }
    public string Whatever{ get; set; }
}

$(function () {
   var query = {QueryName:"My Query",Whatever:"Blah"};
   $.ajax({
       type: "GET",
       data :JSON.stringify(query),
       url: "api/titleEstimate",
       contentType: "application/json"
   })
      .done(function (data) {
          $('#product').text("OK");
      })
      .fail(function (jqXHR, textStatus, err) {
        $('#product').text('Error: ' + err);
      });
});

First, I would try to use the attribute routing feature of web.api like this:

[RoutePrefix("api/titleestimate")]
public class TitleEstimateController : ApiController
{
    [HttpGet]
    public IHttpActionResult GetTitleEstimate([FromUri] EstimateQuery query)
    {
            // All the values in "query" are null or zero
            // Do some stuff with query if there were anything to do
    }
}

It would also be helpful to see the request in your dev tools. I disagree with Colin that you should make this a POST, because HTTP POST is supposed to be used to create new items. You are trying to get information so HTTP GET makes sense.

I think Web.Api assumes methods are GETs by default, but declarating it with the HttpGet attribute will for sure take care of that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM