通过 javascript 将复杂参数传递给 Web API 服务

Posted

技术标签:

【中文标题】通过 javascript 将复杂参数传递给 Web API 服务【英文标题】:Pass complex parameter to Web API service via javascript 【发布时间】:2015-07-10 17:48:35 【问题描述】:

我正在制作一个 ASP.NET Web API Web 服务和一个 html/javascript 页面来测试它。我遇到的问题是传递一个复杂的数据参数并让它在 Web API 控制器中正确通过。

我知道有很多类似的问题,我已经阅读并尝试了解决方案,但都没有解决。我还阅读了一些 JQuery 文档。

这是我的控制器:

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

WebApiConfig.cs 中的路由映射:

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

还有 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);
          );

目前我收到的是 404。我尝试了$.getJSON(uri + '/' + query),但也没有用。在传递此对象之前,我已成功调用它,因此我认为路由通常没问题。我尝试了一个类型转换器,但没有帮助,仍然是 404。有没有人看到我错过了什么/做错了什么?

【问题讨论】:

服务器端有异常吗?你检查过“输出窗口”吗? 调试输出中没有任何内容。 除了uri 之外,您做的一切都很好。有关详细信息,请参阅以下答案。 【参考方案1】:

对于复杂的对象,我通常在消息体而不是 URL 中发送。

您对类似于这个问题的答案的方法有任何异议吗? How to pass json POST data to Web API method as object

这似乎是更直接/自然的方法。

类似的东西(未经测试,但应该接近):

[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);
      );
);

【讨论】:

谢谢,我用 'JSON.stringify(query)' 尝试了这个版本,但它仍然给我一个 404。因为它是一个 404 而不是 500 什么的,似乎有一些关于通过这个Web API 不喜欢的参数。它找不到要调用的控制器方法。 这个答案也不起作用,因为它的 uri 也不正确。【参考方案2】:

首先,我会尝试像这样使用 web.api 的属性路由功能:

[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
    

在您的开发工具中查看请求也会有所帮助。我不同意 Colin 的观点,即您应该将其设为 POST,因为 HTTP POST 应该用于创建新项目。您正在尝试获取信息,因此 HTTP GET 有意义。

我认为 Web.Api 默认假定方法是 GET,但使用 HttpGet 属性声明它肯定会解决这个问题。

【讨论】:

小细节,但不错。我会调整我的答案以做出改进。 我尝试添加这些,但似乎没有多大作用。我现在得到很多关于 PDB 文件的调试输出并跳过加载符号,但没有错误。这是 Chrome 的消息:GET http://localhost:47503/api/titleEstimate/?username=whatever…&StreetSuffix=Street&County=Boulder&IsPrimary=on&State=CO&Unit=&Zip=80303 404 (Not Found) 如果需要,我愿意使用 POST,但我同意,GET 在这里更有意义,它似乎应该可以工作。 我已经多次解决这些类型的错误。如果没有所有信息,很难说。例如,用户名是小写的,但所有其他人都以大写字母开头。我通常还会在我的控制器方法上放置一个 [Route("Blah")] 属性,然后您的代码应该保存 var uri = 'api/titleEstimate/blah';它以前也依赖于我的浏览器。 Chrome 似乎使用默认标头作为 application/json,而 Firefox 似乎默认使用 application/xml。查看标题,检查大小写并更明确地说明您的路线,看看是否有帮助。 你不需要HttpGet。没必要。【参考方案3】:

回答

您使用了错误的uri。你需要api/titleEstimate/getTitleEstimate。这解释了并将解决您的 404。

回答后续问题

你正在做的所有其他事情几乎都有效。解决 404 后,您会发现您没有收到值 FromUri,并且您将有一个后续问题。因此,您需要将路由配置更改为:

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

那么您不仅会解析 404,还会收到您作为查询字符串参数发送的 FromUri 值。

演示

这里是a fiddle for evidence,它正在调用this controller,它是is hosted LIVE here。我在工作版本中唯一更改的是 uri 来解析 404 和路由配置以确保您收到 FromUri 值。就是这样。

HTML

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

JavaScript

这会成功。

请注意,我们只需要domain,因为我们在这里进行跨站点脚本是为了演示目的。

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);
    );
);

这将是 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);
    );
);

控制器

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!");
        
            

您可以阅读更多详细信息about WebApi routing here。通过阅读它,您可能会在您的路线配置中提出替代解决方案。还有很多terrific examples in this blog post。

【讨论】:

非常感谢您抽出宝贵时间整理出如此详细的答案。我寄予厚望,但是当我运行小提琴并按下提交(有或没有值)时,我得到错误:未找到。所以我认为那里的路由仍然有问题。 @nasch 已修复 :-)。我使用的是旧的uri,当我更新小提琴时,我忘记将新版本设置为基础。也就是说,我使用的是/api/values/GetTitleEstimate 而不是/api/titleEstimate/GetTitleEstimate。链接的小提琴现在可以工作了,因为我已将最新版本设置为基础。 太棒了,现在可以使用了,谢谢!令我困惑的一件事是我无法将结果显示在网页上。我和你一样有这个:$('#product').text(data); 但它什么也没做。我可以使用该值记录或警告,这很好,但是 text() 调用不起作用。我尝试输入一个字符串文字值,将其移动到函数的开头,将其放入 document.ready() 中,没有效果。我敢肯定这是愚蠢的,但如果你有任何想法,我会很高兴听到它。 div 是这样的:&lt;div id="product"&gt;Information goes here&lt;/div&gt; 不客气。我不确定为什么不会为您显示结果。您已经尝试了我会尝试的大多数故障排除步骤。例如。日志、警报等。我可能会尝试使用另一个 div 和另一个 id。另外,创建一个复制错误的小提琴;这样您就可以准确地共享产生错误的代码。 好的,谢谢,如果我什么都没发生,我可能会提出另一个问题,但网页不是项目的关键部分。再次感谢您的帮助。

以上是关于通过 javascript 将复杂参数传递给 Web API 服务的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 HtmlDocument.InvokeScript 将对象作为参数传递给 javascript

如何将 JavaScript 变量作为参数传递给 JSF 操作方法?

将复杂参数传递给 [Theory]

JavaScript:将参数传递给回调函数

如何将复杂的 DevOps 管道模板参数传递给脚本

将参数传递给 JavaScript 文件