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

平台无关 Web 软件开发的有用技术

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (22投票s)

2016年9月14日

CPOL

19分钟阅读

viewsIcon

19143

downloadIcon

197

本文介绍了一系列 Web 技术。使用 ASP.NET Core 和 node.js 编写的跨操作系统服务器,以及 HTML/JavaScript/TypeScript 的单页客户端构建的可滚动表格示例。

 

 

 

 

引言

本文及其附带的示例演示了服务器端和客户端 Web 软件开发的多种实用技术。该示例呈现了一个简单的可滚动表格。当用户在滚动表格内容时,接近表格可见部分的任一端或开始时,会从服务器下载相应的相邻部分数据,并替换已变得不可见的表格部分。该示例工作原理如下。浏览器调用 Web 服务器并加载 index.html 文件以及相关的 JavaScript (JS) 和 CSS 文件,从而启动单页 Web 应用程序。此应用程序通过 WebSocket(首选选项)或 HTTP POST(如果浏览器不支持 WebSocket)与服务器进行密集通信以获取数据。在客户端应用程序中,JS Promise 构造用于 WebSocket 创建函数。使用闭包和对象增强技术创建函数调用链来操作 DOM 对象。两个数据提供程序组织数据供给给客户端。它们都扩展了相同的 JS 风格“基类”。数据提供程序由可滚动表格对象使用依赖注入机制。数据提供程序有两种实现:一种是使用 JS,另一种是使用 TypeScript (TS)。在后一种情况下,TS 文件会被转译为 JS,这是一种 “Web assembly 语言”

本文介绍了两种功能相同的基于不同技术的服务器。其中一种使用微软最近发布的 ASP.NET Core 平台,另一种则使用 node.js 开发。两种服务器都可以在不同的操作系统 (OS) 上运行,并在 Windows 10 和 Linux Ubuntu 16.04 下进行了测试。

上述技术将在下文进行更详细的讨论。

在这项工作中,我使用了其他作者的一些代码片段。我在文章和/或代码中附上了适当的引用。如果我无意中遗漏了某些引用,请原谅。

先决条件

如前所述,本文中的示例演示了服务器在不同操作系统上运行的能力。但如果您只想局限于 Windows,可以跳过下一段。

由于我们将使用的主要平台是 Windows 10,为了在 Linux 环境中运行我们的服务器,我们需要安装 Linux 虚拟机。为此选择了 Oracle VirtualBox(实际上只需要服务器环境)。VirtualBox 可以从 其网站 下载,安装指南可以在例如 这里 找到。安装虚拟机后,我们需要安装一个用于 Windows 和 Linux 之间文件交换的工具。WinSCP 可以完成这项工作(首字母缩写代表 Windows Secure Copy)。该应用程序可以从 其站点 安装。虽然 VirtualBox 的显示窗口可以用于输入命令,但 PuTTY 终端模拟器在这方面非常有用。它可以从 这里 下载。

node.js 和 .NET Core 的安装应在 Windows 和 Linux 操作系统上进行。Windows 版 node.js 可以从 这里 安装,Linux 版可以从 这里 安装。.NET Core(包括 ASP.NET Core)的安装可以从 微软专用网站 执行。可以使用仅包含 .NET Core Runtime 的命令行操作来运行本文中的示例,而无需任何开发工具。但是,为了调试示例并对其代码进行修改,Microsoft Visual Studio (VS) 2015 Update 3 和 .NET Core VS 工具将非常有用。为了方便 node.js 代码的调试,可以从 这里 安装 VS for node.js 工具。

如果您坚持不懈地成功安装了以上所有东西(在我看来,这在一位精通多平台和移动软件的专家和我的好朋友 Michael Molotsky 的帮助下才得以实现),那么您可以继续进行我们的示例。让我们从客户端开始。

客户端

客户端是一个单页 Web 应用程序。它位于 .\webclient 文件夹中(此处及以下,“.\" 或 “” 指代解压示例的解决方案根文件夹),并通过浏览器中的 index.html 文件激活。客户端是用 JS 编写的(本文中引用客户端 JS 指的是 ES5 标准的 JavaScript)。.\webclient\js\index.js 文件包含客户端应用程序的主要逻辑。.\webclient\js\scrollableTable.js 文件实现了可滚动表格。与数据提供程序相关的文件位于 .\webclient\js\dataProviders 文件夹中。示例演示了一些有用的 JS 技术,例如闭包、“类”继承模拟、Promise、ajax 通信等(所有这些功能都在许多知名的 JS 库中实现,但对我而言,自己开发它们的极简实现很有趣)。实现这些功能的文件的位置在 .\webclient\js\helpers 文件夹中。

closure.js 文件包含用于 DOM 元素操作的闭包。这些闭包允许使用基于 Object 增强的链(objectAugmentation.js 文件)。communication.js 文件负责与服务器通信。它支持通过 WebSocket(可用时)和 HTTP(GET 和 POST 方法)进行通信。给定 WebSocket 连接的实现说明了两种重要的范例:单例模式(singleton.js 文件)用于保存创建的 WebSocket 对象,以及 Promise 模式(promiseC.js 文件)。后者通过将异步回调封装在一个类似同步的包装器中,简化了异步回调的语法。大多数现代浏览器都支持 Promise,但并非全部。由于某些浏览器缺乏 Promise(并且因为该主题很有趣),本文开发了一个自定义的简化版 Promise 实现,即 promiseC.js 文件中的 PromiseC。它将在适当的章节中详细讨论。

可滚动表格与其数据提供程序分离,并通过依赖注入使用它们。客户端有两个数据提供程序,即本地的 DataProviderLocal 和从服务器提供数据的 DataProviderFromServer。两个提供程序都有一个共同的“基类”DataProvider。提供程序有两种实现方式:(a)使用 Douglas Crockford 的“继承”机制的 JS(inheritance.js 文件),以及(b)使用 TS 文件(.\webclient\ts 文件夹),然后将其转译为相应的 JS 文件。转译由 TS 编译器 tsc.exe 执行(通过命令文件 tsc.cmd 和 TS 项目文件 tsconfig.json 调用)。

在示例中,所有与服务器的交互均由客户端发起(没有异步通知)。工作场景如下:

  • 如果 utilities.js 文件中的常量 SERVER 设置为 true,则客户端尝试通过 WebSocket 连接服务器。如果 SERVER 设置为 false,则客户端根本不连接服务器,而是显示 dataProviderLocal.js 文件中本地数据提供程序生成的数据(这是测试模式);
  • 如果浏览器不支持 WebSocket,则尝试通过 HTTP 进行通信;
  • 发送给服务器的第一个请求是“about”请求,用于获取服务器来源(ASP.NET Core 或 node.js)的信息。客户端显示响应信息和通信方式(WebSocket 或 HTTP POST);
  • 然后客户端请求第一个数据块,并将响应放入可滚动表格;
  • 当用户在浏览器中滚动表格并接近当前显示数据块的末尾或开头时,客户端会根据用户的滚动方向向服务器请求下一个数据块;
  • 新接收的数据块会显示出来,替换掉表格可见区域之外的部分。

客户端和服务器之间的数据交换以 JSON 格式进行,允许双方使用标准的解析过程。index.html 文件定义了如下的可滚动表格:

<div>
  <div>
    <table class="tbl">
      <tr>
        <th>Column A</th>
        <th>Column B</th>
        <th>Column C</th>
        <th>Column D</th>
      </tr>
    </table>
  </div>
  <div class="scrollBox">
    <table class="tbl"></table>
  </div>
</div>

在上面的片段中,第一个 <table> 元素提供了可滚动表格的头部,其中包含 <th> 标签。位于 <div class="scrollBox"> 内的第二个表格实际上是可滚动的,并将动态填充。类 tblscrollBox 的样式(以及所有其他元素的样式)定义在 .\webclient\\css\styles.css 文件中。

注意:在滚动条样式定义中使用了 -webkit 厂商特定前缀以改善其外观。这个前缀被 Google Crome 和 Apple Safari “理解”。FireFox 和 Microsoft 浏览器不识别 -webkit,并以简单的标准方式呈现滚动条。

当文档就绪时,会调用 fillTable() 函数(.\webclient\js\index.js 文件):

// Scrollable Table Handling 

var fillTable = function() {

    var divScrollBox = allTags('div').byAttribute('class', 'scrollBox').result()[0];

    // Tables
    var tables = allTags('table').result();
    var tblHeader = tables[0];
    var tblData = tables[1];

    var maxData = 200;
    var tableRowLimit = 50;
    var vertScrollerLowerPosInPerCent = 0.9;
    var chunkLen = tableRowLimit / 5;
	
    var dataProvider = DataFactory.prototype.dataProviderFactory(
                           SERVER ? 'fromServer' : 'local',
                           maxData,
                           urlProvider,
                           function (about) { 
                               elementById('lblDataProviderAbout').setText(about); 
                           },
						   SERVER ? theSingleton.getInstance().getWebSocket() 
                                  : undefined);

    scrollableTable(tblData, tblHeader, tableRowLimit, vertScrollerLowerPosInPerCent, 
                    chunkLen, divScrollBox, dataProvider, 
                    function(relativePosHorz, relativePosVert) {
                        var scrollHorzText = '';
                        if (!isNaN(relativePosHorz)) {
                            scrollHorzText = 'Scrolled from the left: ' + 
                                             relativePosHorz.toFixed(2) *100 + '%, ';
                        }
                        elementById('lblScrolling')
                            .setText(scrollHorzText + 
                                     'Scrolled from the top: ' + 
                                     relativePosVert.toFixed(2) * 100 + '%')
                            .setStyle('color: #73AD21');
                    });
}

该函数获取可滚动表格使用的 DOM 元素,设置所需的配置参数,创建相应的数据提供程序,最后调用 scrollableTable() 函数,该函数将上述参数作为其参数,并另外接收一个用于滚动条位置更改事件的回调。

由于浏览器主要提供单线程执行模型,为了使 UI 响应迅速,Web 客户端通常异步执行耗时操作(例如通信相关操作)。这意味着需要使用回调。普通 JS 中的回调代码有时不易阅读。最好使用伪同步表示法,并清晰地表示回调的调用顺序,从而呈现异步函数。称为“Promise”的构造就完成了这项工作。

Promise

Promise 是一个有用的对象,用于处理异步函数调用。根据 Mozilla Development Network 的 定义,“Promise 代表一个尚未完成但预计在未来会完成的单个异步操作。Promise 代表一个在其创建时值不一定已知的代理。它允许您将处理程序与异步操作的最终成功值或失败原因关联起来。这使得异步方法可以像同步方法一样返回值:异步方法返回一个 Promise,而不是最终值,表示将来某个时候会有一个值。

我不得不承认,上述定义(以及我找到的其他一些定义)对我来说并不算很清晰。因此,我将提供我理解的 Promise 的描述。以下伪代码片段说明了 Promise 的功能:

当创建 Promise 对象时,Promise() 函数以一个名为 executor 的函数作为参数。executor 的参数是 Promise 对象本身的 resolve()reject() 函数。Promise 对象有一个 then() 函数,带有两个参数:onResolve()onReject() 函数。Executor 由 Promise“构造函数”调用。Executor 的调用会导致调用 resolve()reject() 函数。这通常是一个异步过程。例如,在我们的代码中,我们使用 Promise 来初始化 WebSocket 连接。因此,如果支持 WebSocket,那么我们的 executor 函数将创建一个 WebSocket 对象,设置其 onopen 事件的处理程序并返回。一段时间后,将调用 WebSocketonopen 处理程序。该处理程序反过来调用 Promiseresolve() 函数,并将某个参数(在本例中为 WebSocket 对象)传递给它。如果不支持 WebSocket,则会调用 reject() 函数,并将错误对象作为其参数。

调用 resolve()reject() 函数会启动 then() 函数的回调参数链的执行。resolve() 函数导致 onResolve 回调的执行,而 reject() 函数则导致 onReject 回调的执行。回调函数接收分别传递给 resolve()reject() 函数的参数。链中的每个后续回调都以前一个回调的结果作为参数。如果前一个回调正确返回,则在当前对中调用 onResolve 回调;如果发生异常,则激活 onReject 回调,并以错误对象作为其参数。

Promise 是相对较晚才流行起来的,而旧的浏览器(例如 Internet Explorer 11 和 Safari for Windows 5.1.7)并不原生支持 Promise。因此,我在 .\webclient\js\helpers\promiseC.js 文件中提供了一个自定义的简化版 Promise 实现,即 PromiseC() 函数。下面展示了该函数:

function PromiseC(executer) {
    var isResolved;
    var arg;
    var callbackPairs = [];

    var resolve = function (val) {
        isResolved = true;
        arg = val;
        invokeCallbacks();
    }

    var reject = function (err) {
        isResolved = false;
        arg = err;
        invokeCallbacks();
    }

    var invokeCallbacks = function () {
        if (callbackPairs.length > 0 && !(isResolved === undefined)) {
            callbackPairs.reverse();

            while (callbackPairs.length > 0) {
                var aCallbackPair = callbackPairs.pop();

                try {
                    arg = isResolved ? aCallbackPair.onResolveCallback(arg)
                                     : aCallbackPair.onRejectCallback(arg);
                    isResolved = true;
                }
                catch (err) {
                    arg = err;
                    isResolved = false;
                }
            }
        }
    }

    this.then = function (onResolveCallback, onRejectCallback) {
        callbackPairs.push({ 
                             onResolveCallback: onResolveCallback, 
                             onRejectCallback: onRejectCallback 
                           });
        invokeCallbacks();
        return this;
    }

    // Executer is called
    executer(resolve, reject);
}

这确实是一个简化的实现,因为标准的 Promise 除了 then() 之外还有更多方法,但它足以满足我们的示例。在此实现中,invokeCallbacks() 函数由 resolve() / reject() 调用,也由 then() 调用。实际的回调执行发生在调用 executor 并将(某些或全部)onResolve / onReject 回调添加到 callbackPairs 数组之后。

为了试验 Promise,我们在 communication.js 文件中为我们的 Promise 添加了两个 then() 函数(它们用 //TEST 注释标记)。当 WebSocket 支持时,Web 应用程序会在浏览器开发者工具控制台中记录以下输出:

the 1st "then()" - resolved, arg: [object WebSocket]
the 2nd "then()" - rejected, arg: Exception in the 1st "resolve()'!

如果不支持 WebSocket(或者通过取消注释 createWebSocket() 函数调用内部的 throw() 函数调用来模拟这种情况),则会在浏览器控制台中输出以下日志:

the 1st "then()" - rejected, arg: TEST to disable WebSocket
the 2nd "then()" - resolved, arg: result of 1st "reject()"

如果您的浏览器原生支持 Promise,则可以使用标准的 Promise 实现而不是我的。为此,在 communication.js 文件中,将行 var promise = new PromiseC(... 中的 PromiseC 替换为 Promise(删除字母“C”)。使用标准的 Promise 也会获得上述日志。

通信

如前所述,客户端和服务器之间的通信使用 WebSocket 或 HTTP 进行。前者是首选方式,因为它开箱即用地支持异步(推送)服务器发起的 PUSH 消息。尽管到目前为止我们在示例中还没有使用 PUSH 消息,但在实际应用中,这对于 Web 应用程序来说是非常常见的做法。如果浏览器不支持 WebSocket(如今这已很少见),则可以通过例如 HTTP 长轮询 技术实现 PUSH 消息的效果。不幸的是,长轮询不仅需要额外的代码,而且由于线程占用,还会影响服务器的扩展性。

注意:有一个常用的 SignalR 通信框架,它经过优化,可提供高生产力和可扩展性,它(除其他功能外)会自动选择最佳可用传输(无论是 WebSocket、HTTP 长轮询还是其他)。但目前 SignalR 主要在 Windows 环境中可用(在 Linux 上,它可以使用 Mono)。根据微软的说法,下一版 ASP.NET Core 的计划应包含 SignalR。因此,希望 SignalR 在 .NET Core 中的可用性指日可待。

服务器

本文开发了两种服务器。一种基于最近发布的 ASP.NET Core,另一种基于 node.js。两种服务器都展示了在最广泛使用的操作系统(如 Windows 和 Linux)之间的互操作性。服务器的实现相当简洁,没有太多辅助细节。

ASP.NET Core 服务器

2016 年 6 月底,微软最终发布了 .NET Core 平台的第一版,该平台可在所有主要操作系统上互操作。本文使用其 ASP.NET Core 子系统来开发服务器。该服务器本质上是一个普通的 ASP.NET Web API 服务器。因此,对于 ASP.NET 开发人员来说,学习过程简短而轻松。

该服务器是通过 VS2015 和 .NET Core 开发工具创建的。在 FILE -> New -> Project... 对话框中,选择 Templates -> Visual C# -> .NET Core,然后在右侧面板中选择 ASP.NET Core Web Application (.NET Core) 模板。然后,在 New ASP.NET Core Web Application (.NET Core) 对话框中,选择 Web API 模板。基本上就是这样:ASP.NET Core 服务器模板已创建。服务器所需的 DLL 应以类似方式使用 Class Library (.NET Core) 项目模板创建。

我们的服务器位于 .\AspNetCoreServer 文件夹中。它的主要部分是 RESTful Web API ServerApi 项目。ServerApi 提供整体 Web 服务基础结构和通过 HTTP 与客户端通信的标准机制(JsonController 类)。它还在其 Startup.Configure() 方法中通过调用 RequestProcessorLib.dllRequestProcessor 单例类的 RequestProcessor.Instance.ProcessRequest() 方法来启动 WebSocket 通信。InterfaceClientContextLib.dll 包含由 ClientContext 类型(ClientContextLib.dll)实现的 IClientContext 接口。这种设计允许开发人员将来拥有多个实现 IClientContext 接口的客户端上下文,为不同的客户端提供不同的模型和数据处理算法。ClientContextFactoryLib.dllClientContextFactory 类负责创建客户端上下文对象。

该服务器和客户端一起采用了模型-视图-控制器 (MVC) 模型。ClientContextLib.dll 中的内部类 ClientContext.TableRow 作为模型,JsonController 类构成了当前服务器实现中唯一的控制器,而 index.html 文件及其所有 JS/CSS 文件则代表视图。

服务器支持通过 WebSocket 和 HTTP 与客户端通信。后者以 ASP.NET Web API 应用程序的常规方式组织,即使用适当的控制器 JsonController 类。目前,它只有一个 PostJsonString() 方法,该方法负责接收 HTTP POST 请求并将其传递给一个重载的 RequestProcessor.Instance.ProcessRequest() 方法之一,以进行实际处理。第二个方法由 WebSocket 通信通道使用。两个方法都调用 ClientContext 类的同一个 ProcessText() 方法来生成响应字符串。

服务器监听请求的 IP 地址和端口是可配置的。配置文件 appsettings.json 中的 "ServerUrls" 部分包含这些 IP 地址的列表,并且 Program 类的静态方法 Urls() 读取此配置。

跨域资源共享 (CORS)

我们的服务器支持跨域资源共享 (CORS)。根据 Wiki,CORS “是一种允许从 Web 页面上的受限制资源(例如字体)请求来自与资源来源域不同的域的机制。...传统上,嵌入式 Web 字体和 AJAX (XMLHttpRequest) 请求仅限于访问与父 Web 页面相同的域(根据同源安全策略)。默认情况下,‘跨域’AJAX 请求是禁止的,因为它们能够执行高级请求(POST、PUT、DELETE 以及其他类型的 HTTP,以及指定自定义 HTTP 标头),这会带来许多跨站点脚本安全问题。” 为了解除此限制,会在 Startup 类中的 IApplicationBuilder app 对象中创建并添加相应的策略。

public void ConfigureServices(IServiceCollection services)
{
    ...

    // Add CORS
    services.AddCors(o => o.AddPolicy("CurrentCORSPolicy", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader();
    }));
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // Add CORS middleware before MVC
    app.UseCors("CurrentCORSPolicy");

    ...
}

node.js 服务器

基于 node.js 的服务器是使用 VS2015 和 node.js 开发工具创建的。在 VS2015 中,执行了以下操作:FILE -> New -> Project...,在 New Project 对话框的左侧面板中选择 Templates -> Other Languages -> JavaScript。然后,在右侧面板中选择 Blank Node.js Web Application 模板。模板被放置在名为 .\nodeScrollableTableServer 的文件夹中,解决方案名称相同。模板创建后,nodeScrollableTableServer.jsmessageProcessor.jsutilities.js 这三个 JS 文件被放入 .\nodeScrollableTableServer\nodeScrollableTableServer 文件夹,并通过右键菜单 -> Add -> Existing Item... 添加到项目中,然后删除了向导创建的 server.js 文件。通过右键菜单将 nodeScrollableTableServer.js 文件设置为 Node.js Startup File

WebSocket 已在 .\nodeScrollableTableServer\nodeScrollableTableServer 文件夹中本地安装,使用 node.js 的默认包管理器 npm(Node Package Manager)。

npm install websocket

(为方便起见,该命令被放入命令文件 installWebSocket.cmd 中,可以从那里运行)。

nodeScrollableTableServer.js 文件包含负责通过 WebSocket 和 HTTP 与客户端通信的函数,messageProcessor.js 文件提供解析客户端消息和生成响应的功能,而 utilities.js 文件包含几个方便常用的实用程序。服务器文件使用 modern node.js 版本(测试时使用版本 4.4.3)支持的 lambda 表达式。

CORS

上一章中描述的 CORS 问题在此服务器中也得到了解决。为此,以下对象包含在响应头中(nodeScrollableTableServer.js 文件):

{
    'access-control-allow-origin': '*',
    'access-control-allow-methods': 'GET',
    'access-control-allow-headers': 'content-type, accept'
}

运行示例

请将示例 zip 文件解压到下面称为 <Root Dir> 的文件夹中,并阅读 ReadMe.txt 文件。为了启动 Web 应用程序,我使用了 IIS Express Web 服务器。要配置它,请将 ReadMe.txt 中的 ScrollableTable 站点添加到 IIS Express 标准配置文件 ..\Documents\IISExpress\config\applicationhost.config 中,并将 <Root Dir> 替换为实际路径。通过以管理员身份运行 .\startIIS.cmd 文件来启动 IIS Express 下的 ScrollableTable 站点。

Windows 中的服务器

下一步是运行服务器。ASP.NET Core 服务器通过激活命令 .\aspNetCoreServer.cmd 文件启动:

dotnet run

从其主文件夹 .\AspNetCoreServer\src\ServerApi

或者,可以通过激活命令文件 .\nodeScrollableTableServer.cmd 来启动 node.js 服务器,该文件包含以下命令:

node nodeScrollableTableServer

服务器将监听所有可用 IP 地址上的 15011 端口。

这两个服务器不能同时运行,因为它们监听同一个端口。

然后您可以启动浏览器并在其中输入 IP 地址 https://:15111。应用程序将启动。

Linux 中的服务器

为了在 Linux 环境中安装我们的 ASP.NET Core 服务器,首先需要对其进行“发布”。发布操作会准备运行服务器所需的一整套资源。在发布之前,应更改配置文件 appsettings.json 中的 "ServerUrls" 部分,插入服务器的正确 IP 地址和端口。为了发布服务器,应从其主文件夹 .\AspNetCoreServer\src\ServerApi 执行以下命令(为方便起见,该命令已放入命令文件 .\publish_aspNetCoreServer.cmd):

dotnet publish -o publish -c Release

上述命令的输出是 .\AspNetCoreServer\src\ServerApi\publish 文件夹。此文件夹包含在 Linux 环境中运行我们的 ASP.NET Core 服务器所需的所有资源。

下一步是使用 WinSCP 应用程序将新创建的 publish 文件夹的内容复制到 Linux 文件夹 .\AspNetCoreServer。然后,从 Linux 文件夹内部运行命令:

dotnet ServerApi.dll

在 Linux 中启动我们的 ASP.NET Core 服务器。

我们的 node.js 服务器应首先使用 WinSCP 复制到 Linux 文件夹 .\nodeScrollableTableServer(只需复制 JS 文件和 node_modules 文件夹)。然后,可以使用与 Windows 中相同的命令 node nodeScrollableTableServer 来运行服务器。

客户端

为了实现正确的通信,需要将客户端 Web 应用程序中的服务器 IP 地址更改为与服务器 IP 地址匹配:在 .\index.js 文件中,在返回 urlProvider 对象的匿名函数中,将变量 host 的值 'localhost' 替换为实际服务器 IP 地址。

要使用 TS 中的数据提供程序测试 Web 应用程序,请转到 .\webclient\ts 文件夹并运行 tsc.cmd 文件,从而激活使用 tsconfig.json 配置文件工作的 TS 转译器 tsc.exe。生成的 JS 文件将放置在 <Root Dir>\webclient\js\dataProviders 文件夹中,替换其中的先前文件。然后刷新浏览器中的页面。

进一步研究

本文展示了一系列对“全栈”Web 开发人员有用的客户端和服务器技术。但是,一些与本文范围相关的重要主题被遗漏了。首先是与数据库的交互。确实,为了简化起见,服务器生成要显示在可滚动表格中的数据,而不是像实际情况那样从某个数据存储中获取。因此,与数据库的交互是进一步研究的明显方向(CodeProject 最近发表了几篇关于 ASP.NET Core 使用数据库的优秀文章)。如上所述,PUSH 消息对于某些 Web 应用程序至关重要。因此,演示使用 WebSocket 和 HTTP 长轮询实现它们将是很好的。

致谢

我想感谢我的朋友兼同事 Michael Molotsky,他在 VirtualBox 和 .NET Core for Linux 的安装方面提供了巨大帮助,并在本文范围内进行了有益的讨论。我感谢 Mark Hotykov 关于 JS Promise 的讨论。我非常感谢 Liron Levi 对我 Web 研究的支持以及他对这个主题提出的宝贵建议。

© . All rights reserved.