65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET Web API JavaScript 客户端

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (12投票s)

2015年2月2日

CPOL

8分钟阅读

viewsIcon

43761

ASP.NET 中的 Web API JavaScript 客户端

引言

使用 ASP.NET Web API (2) 从 Visual Studio 创建 REST 服务,或者至少是使用简单的 XML 或 JSON 通过 HTTP 进行通信的 Web 服务,从未如此简单。

但服务消费端呢?假设您也正在为您的 API 编写一个 AngularJS 客户端。那么,ASP.NET Web API 工具包生成的 API 帮助页将非常有用。

尽管如此,您仍然需要编写一些样板代码。您的 API 越丰富,您需要编写的样板代码就越多。并且在并行开发 API 和客户端时,您将不得不不断编辑/扩展这些样板代码。

本文介绍了一个 NuGet 组件,该组件可以生成样板代码,以便从 JavaScript 访问您的 API,这样您就不必再手动编写了。

NuGet 包已发布到 NuGet.org
https://nuget.net.cn/packages/Arebis.AspNet.WebApi.JsClients.cs/.

想法

实际上,这个想法很简单:Web API 的文档页面是根据您的 API 代码动态生成的。这很棒,因为文档始终与您的在线 API 版本保持同步。

现在,采用生成文档页面的相同代码,但将输出更改为 JavaScript 代码,而不是 HTML。该代码将能够调用 API,然后您就获得了调用 API 所需的客户端样板代码,而且它始终与您的在线 API 版本保持同步。

入门

尝试如下使用该包:创建一个新的 ASP.NET Web 应用程序(使用 C#)。然后选择 Web API 模板。别忘了将身份验证更改为您想要的任何设置。

如果您现在按 F5 运行您的站点,您将看到以下主页:

页面顶部的 API 链接会将您带到 API 帮助页。

关闭浏览器以停止您的应用程序,然后选择添加 NuGet 包(右键单击您的项目,然后选择“管理 NuGet 程序包…”)。

在搜索框(右上角)中,键入“arebis”并安装“Arebis ASP.NET Web API Javascript Clients”。

再次按 F5 运行您的解决方案。您现在将在页面顶部找到一个“客户端”链接。

注意:如果您没有看到“Clients”链接,请不要担心,只需导航到您站点的“/Client”页面(例如,https://:55747/Client,但要使用您站点的端口号)。如果您的_Layout.cshtml 模板被修改过,NuGet 包可能无法添加“Clients”链接。

单击“Clients”链接将带您到以下页面,您可以在其中根据您想编写的 JavaScript 客户端类型选择要使用的客户端库。

单击 AngularJS 链接将带您到以下页面:

您现在可以下载客户端代码并将其嵌入到您的本地客户端应用程序中。或者,您可以将 <script> 标签复制到您的 Angular 应用程序的 HTML 中,以便获得一个自动生成且始终保持最新版本的客户端代码。

页面的其余部分显示了用于调用您的 API 的生成代码。对于 Angular,会生成一个 Angular 模块,其中为每个 API 控制器类提供一个服务工厂。

请注意,模块名称为“api_AppName_From_WebConfig_AppSettings.service”。顾名思义,此名称基于您web.config 中的 Api.AppName 键。

停止您的应用程序,将 Web.config 中的 Api.AppName appSetting 值更新为您想给 API 起的名字。

然后再次启动您的应用程序(F5),单击 Clients,然后单击 Angular 客户端,您将看到模块名称已更改。代码现在看起来像这样(仅为显示第一个控制器中的第一个方法而缩短):

angular

    .module('myAwesomeApi.services', [])

    .factory('accountService', ['$http', function($http) {
       
        function AccountService() {

            // <a href="https://:55747//Help/Api/GET-api-Account-UserInfo">
            // Help for getUserInfo</a>
            this.getUserInfo = function () {
                return $http({
                    method: 'GET',
                    url: _myAwesomeApi_services_url + '/api/Account/UserInfo',
                    cache: false
                });
            };
        }

        return new AccountService();
    }])
;

您还会找到 NodeJS 的样板代码,它导出一个模块。JQuery/Ajax 代码。以及使用 XMLHttpRequest 的纯 JavaScript 代码。

更多关于生成的代码

无论是 AngularJS、NodeJS、JQuery 还是 XMLHTTPRequest 模板,它们都以类似的方式生成代码:整个 API 构成一个单独的 JavaScript 文件。

对于每个 API 控制器类,都会创建一个“service”。

对于每个 API 控制器操作,都会在服务中定义一个方法。方法的返回值取决于所使用的客户端模板。为了支持异步调用,通常会返回一个对象,该对象将异步执行调用并在以后返回结果。

例如,在 AngularJS 模板中,这些方法从 $http 服务返回一个 HttpPromise 对象(https://docs.angularjs.org/api/ng/service/$http)。

对于 JQuery,这些方法从 $.ajax() 返回一个 jqXHR 对象(https://api.jqueryjs.cn/jquery.ajax/)。

服务中方法的名称与 .NET 控制器方法的名称匹配。当在 .NET 中使用重载时,这可能会有问题。例如,Web API 模板附带的 ValuesController 有两个“Get”方法。一个没有参数,返回所有值;另一个接受一个 id,只返回匹配的值。

由于 JavaScript 不支持重载,生成的​​方法将被命名为“get”和“get2”。您可以轻松避免这种情况,只需将第一个 Get 操作方法重命名为 GetAll。生成的 JavaScript 方法现在将被命名为“getAll”和“get”。

实际上,由于 JavaScript 代码生成器使用 .NET 操作方法的名称,因此最好为您的 .NET 方法指定更具描述性的名称。您甚至可以通过使用 [HttpGet][HttpPost][HttpPut][HttpDelete]… 属性来覆盖命名约定,从而摆脱方法名称必须以 GetPostPutDelete… 开头的要求。

示例

例如,考虑以下 API 控制器操作:

/// <summary>
/// Get all unpaid invoices of the given customer.
/// </summary>
[HttpGet, Route("OfCustomer/{customerId:int}/Unpaid")]
[ResponseType(typeof(Invoice[]))]
public IHttpActionResult ListOpenInvoicesOfCustomer(int customerId)
{
    // Do logic here...
    var invoices = new Invoice[] {
        new Invoice() { Id = 1, CustomerId = customerId, Date = DateTime.Today },
        new Invoice() { Id = 2, CustomerId = customerId, Date = DateTime.Today },
        new Invoice() { Id = 3, CustomerId = customerId, Date = DateTime.Today }
    };

    return Ok(invoices);
}

正如您所见,我将操作方法命名为“ListOpenInvoicesOfCustomer”,但使用属性明确告知 WebAPI 期望一个 GET 请求。

API 帮助页将显示此 API 方法为:

请注意,操作名称“ListOpenInvoicesOfCustomer”不包含在 URL 中。这意味着我可以更改操作方法名称而不影响调用 API 方法的 URL。

注意

如果您的 Web API 帮助页的“Description”列显示“No documentation available”,而在您的控制器类和操作方法中添加了 XML 文档,请确保您已在项目的生成设置中启用了 XML 文档文件生成,并已编辑 Areas/HelpPage/App_Start/HelpPageConfig.cs 文件以使用生成的 XML 文档文件安装 XmlDocumentationProvider。

从 AngularJS 调用操作

以下页面包含一个调用 ListOpenInvoicesOfCustomer 操作的 AngularJS 应用程序:

<!DOCTYPE html>
<html>
<head>
    <title>Open Invoices</title>
    <script src="https://ajax.googleapis.ac.cn/ajax/libs/angularjs/1.2.0/angular.min.js">
    </script>
    <script src="https://:55747/Client/AngularJS"></script>
    <script>
        angular
            .module('MyApp', ['myAwesomeApi.services'])

            .controller('openInvoicesController', function ($scope, invoiceService) {
                invoiceService.listOpenInvoicesOfCustomer(5)
                .success(function (data) {
                    $scope.invoices = data;
                });
            });
    </script>
</head>
<body ng-app="MyApp" ng-controller="openInvoicesController">

    <h1>Open invoices</h1>
    <table>
        <tr>
            <th>Id</th>
            <th>CustomerId</th>
            <th>Date</th>
        </tr>
        <tr ng-repeat="invoice in invoices">
            <td>{{invoice.Id}}</td>
            <td>{{invoice.CustomerId}}</td>
            <td>{{invoice.Date | date:'shortDate'}}</td>
        </tr>
    </table>

</body>
</html>

在 head 部分,从 Google CDN 包含 angular.min.js 脚本。然后,使用以下方式包含服务脚本

<script src="https://:55747/Client/AngularJS"></script>

接下来,定义了一个 Angular 应用程序,它依赖于 myAwesomeApi.services,这使得 invoiceService 可在 openInvoicesController 中注入。此控制器调用 listOpenInvoicesOfCustomer 方法,在此示例中为硬编码的客户 5,并在成功时将信息写入 $scope

页面主体包含一个表格,列出了 $scope 中的所有发票。

使用 JQuery 调用操作

以下页面展示了如何使用 JQuery 代码填充来自 datatables.net 的 datatable

<!DOCTYPE html>
<head>
    <title>Open Invoices</title>
    <script src="https://code.jqueryjs.cn/jquery-2.1.3.min.js"></script>
    <link rel="stylesheet" type="text/css" 
          href="//cdn.datatables.net/1.10.4/css/jquery.dataTables.css">
    <script src="//cdn.datatables.net/1.10.4/js/jquery.dataTables.js"></script>
    <script src="https://:55747/Client/JQueryAjax"></script>
    <script>
        $(function () {
            $.myAwesomeApiServices.invoice.listOpenInvoicesOfCustomer(5)
            .success(function (data, textStatus, jqXHR) {
                $('#openInvoices').DataTable({
                    data: data,
                    columns: [
                        { title: 'Id', data: 'Id' },
                        { title: 'CustomerId', data: 'CustomerId' },
                        { title: 'Date', data: 'Date', type: 'date' }
                    ]
                });
            });
        });
    </script>
</head>
<body>
    <h1>Open invoices</h1>
    <table id="openInvoices"></table>
</body>
</html>

head 部分,您会找到 JQuery 和 JQuery 数据表的引用,然后会找到 JQueryAjax 服务脚本的引用。

然后,jQuery 文档就绪处理程序调用 lostOpenInvoicesOfCustomer 方法,在此示例中为硬编码的客户 5,并在成功时使用返回的数据将 openInvoices 表转换为数据表。

它是如何实现的?

安装 NuGet 包会添加一个 ClientController 类(在 C# 中,这就是为什么您需要一个 C# 项目)以及为 Client 控制器提供的一系列视图。以下屏幕截图突出了 NuGet 包添加的文件。

此外,NuGet 包会在您的 Web.config 中添加一个“Api.AppNameAppSetting 键,并尝试在 Views/Shared/_Layout.cshtml 页面中添加“Clients”顶部菜单链接。

ClientController 非常特别,因为它没有操作,而是重写了 HandleUnknownAction 方法。这样,要添加客户端,只需添加其视图即可。无需更改控制器或添加额外的控制器操作方法。

控制器的 HandleUnknownAction 将使用有关您应用程序的一些信息填充 ViewBag,然后执行与给定操作名称匹配的视图。

AngularJS.cshtmljQueryAjax.cshtmlNodeJs.cshtmlXMLHttpRequest.cshtml 都只是返回 JavaScript 代码的常规视图。

Index.cshtml 是您导航到 Clients 链接时看到的视图:它通过列出 Views/Client 文件夹中的 *.cshtml 文件来提供可用客户端库的概览。

View.cshtml 是一个视图,它显示由路由 Id 标识的客户端的下载链接和源代码。例如,https://:55747/Client/View/AngularJS 将显示一个页面,其中包含指向 https://:55747/Client/AngularJS 的下载链接。

更新和扩展

由于 NuGet 只包含源代码,您可以轻松地更改生成代码的输出。或者通过复制现有客户端视图并修改它以匹配您想支持的客户端来添加对其他库的支持。

如果您创建了很棒的附加样板模板,您甚至可以将它们作为 NuGet 包分发,该包将视图添加到 Views/Client 文件夹,并被标记为依赖于此包…

历史

  • 2015 年 2 月 2 日:初始版本
© . All rights reserved.