繁体   English   中英

使用jQuery在ASP.NET MVC 5应用程序中调用WebAPI服务

[英]Calling WebAPI Service in ASP.NET MVC 5 application, using jQuery

我正在尝试构建一个简单的WebApi服务,该服务将实时返回帖子的评论。 因此,该服务仅实现了Get方法,并且它是传递的Post ID的字符串的IEnumerable的简单返回:

 public class CommentApiController : ApiController
    {
        // GET api/<controller>
        public IEnumerable<string> Get(int id)
        {
            return new ApplicationDbContext().Posts.First(x => x.PostId == id).CommentId.Select(x => x.CommentText).ToList();
        }

        // POST api/<controller>
        public void Post([FromBody]string value)
        {
        }

        // PUT api/<controller>/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/<controller>/5
        public void Delete(int id)
        {
        }
    }

我也制作了WebApiConfig类,并指定了以下路由:

public static void Register(HttpConfiguration config)
{
    config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
    );
}

在我的Global.asax.cs文件中,我添加了该路由的参考:

protected void Application_Start()
{
      AreaRegistration.RegisterAllAreas();
      WebApiConfig.Register(GlobalConfiguration.Configuration);
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      BundleConfig.RegisterBundles(BundleTable.Bundles);
}

在简单的局部视图中,我试图每8秒调用一次此服务,以便帖子的评论可以自己显示,而无需刷新页面,从而检查其他用户是否在帖子中发表了评论。

@model List<StudentBookProject.Models.Post>

<table class="table table-striped">
    @foreach (var item in Model)
    {
        if (item.ImagePost != null)
        {
            <tr class="info">
                <td>@item.CurrentDate</td>
            </tr>
            <tr class="info">
                <td>
                    |@Html.ActionLink("Delete", "Delete", new { id = item.PostId }) |
                    @Html.ActionLink("Comment", "AddComment", new { id = item.PostId }, new { @class = "comment" }) |
                </td>
            </tr>
            <tr class="info">
                <td>
                    <img src="data:image/png;base64,@Convert.ToBase64String(item.ImagePost, 0, item.ImagePost.Length)" width="620" />
                </td>
            </tr>
            <tr>
                <td>
                    @Html.Partial("~/Views/Posts/ListComment.cshtml", item.CommentId)
                </td>
            </tr>
        }
        if (item.FilePost != null)
        {
            <tr class="info">
                <td>@item.CurrentDate</td>
            </tr>
            <tr class="info">
                <td>
                    | @Html.ActionLink("Delete", "Delete", new { id = item.PostId }) |
                    @Html.ActionLink("Comment", "AddComment", new { id = item.PostId }, new { @class = "comment" }) |
                </td>
            </tr>
            <tr class="info">
                <td>
                    File attachment
                </td>
            </tr>
        }
        if (item.TextPost != "")
        {
            <tr class="info">
                <td>@item.CurrentDate</td>
            </tr>
            <tr class="info">
                <td>
                    | @Html.ActionLink("Edit", "Edit", new { id = item.PostId }, new { @class = "lnkEdit" }) |
                    @Html.ActionLink("Delete", "Delete", new { id = item.PostId }) |
                    @Html.ActionLink("Comment", "AddComment", new { id = item.PostId }, new { @class = "comment" }) |
                </td>
            </tr>
            <tr class="info">
                <td>
                    @item.TextPost
                </td>
            </tr>
        }
    }
</table>

@{
    int i = 0;

    while (i < Model.Count())
    {
        if (Model[i].ImagePost != null || Model[i].TextPost != null || Model[i].FilePost != null)
        {
            <script>
                $(document).ready(function () {

                    var showAllComments = function () {                 
                        $.ajax({
                            url: "/api/CommentApi/" + "@Model[i].PostId.ToString()"        
                        }).done(function (data) {
                            var html = "";                              
                            for (item in data) {
                                html += '<div>' + data[item] + '</div>';
                            }
                            var divID = "@("quote" + Model[i].PostId.ToString())"

                            $('#' + divID).html(html);

                            setInterval(function () {   
                                showAllComments();                                          
                            }, 8000);                                                       

                        });
                    };
                })
            </script>
        }
        ++i;
    }
}

没有调用我的服务,至少没有以正确的方式调用它,导致仅在刷新页面后才会显示新评论。 我知道WebApi,尤其是在这种情况下,应该易于实现并且非常简单,但是我对这项技术是完全陌生的,我不知道我错过或错误实现了什么。 一直试图找到一些合适的教程来帮助我解决这个问题,但是还没有任何帮助。

我读过某个地方,应该为WebDAV在Web.config文件中添加一行,但这也没有帮助。

<handlers>
      <remove name="WebDAV"/>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

有人看到我没做过的事情以及可能出现的错误吗? 另外,有人知道一些不错的.NET WebApi教程吗?

PS当我直接使用以下方法从浏览器中调用WebApi Get方法时:... / api / CommentApi / id route服务被调用并返回传递的post id的注释,因此该服务还可以,我没有在其中调用它很好的代码...

首先,就像您自己说的那样,当您在浏览器中键入URL并按Enter键时,您会收到来自Web API的响应:这意味着Web API服务和服务器已正确配置。 因此,您的问题与配置无关:问题在于请求本身。

网址和方法

为了使请求生效,它必须是GET请求,正确的URL和正确的参数。

您的路由模板看起来像如下routeTemplate: "api/{controller}/{id}"带有可选的id 您的方法是一种get方法。 在这种方法中,可以从路由(模板中的{id}段)或查询字符串中恢复参数,即:

  • GET api/CommentApi/5
  • GET api/CommentApi?id=5

您可以使用任何一个URL。

返回的数据格式和Accept标头

Web API可以两种不同的格式(XML或JSON)返回数据。 如果未指定任何内容,则返回的数据将采用XML格式(这就是在浏览器中键入URL时得到的信息)。 如果您喜欢JSON(在这种情况下),则需要在请求中添加标头: Accept: application/json

注意:指定Content-Type没有意义,因为您无法在GET请求中发送有效载荷(主体中的数据)

用jQuery做到这一点

从Web API服务中的GET方法获取数据的最简单方法是使用jQuery .getJSON 如果您查看文档,您会发现此方法等效于

$.ajax({
  dataType: "json",
  url: url,
  data: data,
  success: success
});

而且,如果您阅读了.ajax()的文档,您将了解指定dataType: "json"等同于包含标头Accept:application/json ,该标头要求Web API返回JSON数据。 您还将了解默认方法是GET。 因此,您必须确保的唯一一件事就是URL看起来像预期的那样。 查看getJSON的签名: jQuery.getJSON( url [, data ] [, success ] )

它需要一个URL和可选的数据以及一个成功的回调。 我建议不要使用回调,因此让我们来看两个发出请求的可能选项:

  • $.getJSON('/api/CommentApi/'+id)会呈现类似/api/CommentApi/5的URL(未指定数据)
  • $.getJSON('/api/CommentApi',{id:5})会呈现类似/api/CommentApi?id=5的URL(指定为JavaScript对象的数据,其属性名称类似于操作的参数名称: id in this案件)

使用回应

我建议不要使用success回调,而应使用promise .done方法。 因此,无论用于调用的哪种语法,都必须像这样在.done推迟(就像您在原始代码中所做的那样):

$.getJSON('/api/CommentApi/'+id).done(function(response) {
    // use here the response
});

最终代码

因此,修改后的showAllComments方法将如下所示

请特别注意评论

var showAllComments = function () {
    $.getJSON("/api/CommentApi/" + "@Model[i].PostId.ToString()")
    .done(function (data) {
        // create empty jQuery div
        var $html = $('<div>'); 
        // Fill the empty div with inner divs with the returned data
        for (item in data) {
          // using .text() is safer: if you include special symbols
          // like < or > using .html() would break the HTML of the page
          $html.append($('<div>').text(data[item]));
        }
        // Transfer the inner divs to the container div
        var divID = "@("quote" + Model[i].PostId.ToString())";
        $('#' + divID).html($html.children());
        // recursive call to the same function, to keep refreshing
        // you can refer to it by name, don't need to call it in a closure
        // IMPORTANT: use setTimeout, not setInterval, as
        // setInterval would call the function every 8 seconds!!
        // So, in each execution of this method you'd bee asking to repeat
        // the query every 8 seconds, and would get plenty of requests!!
        // setTimeout calls it 8 seconds after getting each response,
        // only once!!
        setTimeout(showAllComments, 8000);                                        
    }).fail(function() {
        // in case the request fails, do also trigger it again in seconds!
        setTimeout(showAllComments, 8000);                                        
    });
};

您需要设置dataTypecontentType ,还需要在dataType传递id参数;

请尝试以下操作:

 $.ajax({
        url: "/api/CommentApi/Get",
        type: 'GET',
        data: { id: @Model[i].PostId },
        dataType: 'json',
        contentType: 'application/json',
        success: function (data) { 

                            var html = "";                              
                            for (item in data) {
                                html += '<div>' + data[item] + '</div>';
                            }
                            var divID = "@("quote" + Model[i].PostId.ToString())"

                            $('#' + divID).html(html);

                            setInterval(function () {   
                                showAllComments();                                          
                            }, 8000);                                                        }
    });

更新资料

好的,将其分解为一个更简单的工作示例,以下将起作用。

javascript

    var urlString = "http://localhost/api/CommentApi/Get";

    $.ajax({
        url: urlString,
        type: 'GET',
        data: { id : 1},
        dataType: 'json',
        contentType: 'application/json',
        success: function (data) { console.log(data); }
    });
</script>

让您的控制器仅按以下方式返回硬编码值:

// GET api/values
public IEnumerable<string> Get(int id)
{
    return new List<string>() { "one", "two" };
}

运行上面的命令,并测试将其输出到控制台。

首先,您好,您似乎没有调用该方法。 我找不到对“ showAllComments”函数的任何调用。 当我复制您的代码并在声明后才调用

 <script>
    $(document).ready(function () {

        var showAllComments = function () {
            // code
        };

        showAllComments();
    })
</script>

我看到调用了ApiController方法,为我更新了html。 确定要调用“ showAllComments”功能吗?

而且JotaBe的答案很好,应该可以。 并遵循JotaBe所写的setTimeout函数。 请参见功能说明。

http://www.w3schools.com/jsref/met_win_setinterval.asp http://www.w3schools.com/jsref/met_win_settimeout.asp

您是否查看了呼叫的路由以及真正的服务器响应是什么?

您可能希望将Route属性设置到操作上,然后看一下使用Postman快速调用它以查看响应。 我发现没有使用邮递员,这会使检查路由变得比所需困难得多。

示例项似乎只是将根称为/ api / comments / 1或api / comments /?id = 1,其中,从路由中获取的调用看起来是/ api / comments / get?id = 1,这与IIRC默认路由一样具有索引未获取或查看的操作。

稍后,我可以启动演示项目并测试正在发生的事情时,我将对其进行详细介绍。

编辑:如果您将属性添加到控制器/操作,您可以看到构造调用的方式更简单一些:

[RoutePrefix("api/Account")]
public class AccountController : BaseAPIController
{
       [Route("someroute")]
       [HttpGet]
       public int mymethod(int ID){return 1;}
}

在此示例中,您将调用get到/ api / account / soumeroute?id = 123123并获得1的返还。 HTTPGet只是一个帮助分离代码可读性的帮助(如果启用了XMLAPI文档,那么很高兴)

t您是否尝试添加以下内容:

dataType: 'json',
async: true,
type: 'GET', //EDIT: my mistake should be GET, thx JotaBe for pointing that

您的$ .ajax电话?

或尝试这种方式:

$.ajax({
                url: "/api/CommentApi/" + "@Model[i].PostId.ToString()",

                dataType: 'json',
                async: true,
                type: 'GET',
                error: function () {
                    alert('Error');
                }

            success: function (data) {
                alert('Success')
            }});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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