十三、在 ASP.NET Core 应用中集成 Vue.js

现在,是时候让 Vue.js 应用与 REST API 对话了。 在本章中,你将集成 Vue.js 前端应用和 ASP.NET Core 5 后端应用通过安装一个 NuGet 包和添加一些代码。 您还将在后端添加一个 CORS 策略,以允许来自其他域的 web 应用发送请求到您的后端。

我们将涵盖以下议题:

  • ASP.NET Core Web API 和 Vue.js 应用一起作为一个单元
  • 跨源资源共享CORS
  • 在 ASP 中启用 CORS 策略.NET Core

技术要求

以下是你完成本章所需要的东西:

完成的代码回购可以在这里找到:https://github.com/PacktPublishing/ASP.NET-Core-and-Vue.js/tree/master/Chapter13/

放 ASP.NET Core Web API 和 Vue.js 应用一起作为一个单元

我们在本节将要做的集成并不需要 Vue.js 向 ASP 发送请求.NET Core,但将给我们一些优势。 我们的目标是在一个应用项目中托管后端和前端项目。 作为回报,应用可以作为单个单元发布或构建。

有官方的 web 应用项目模板。 你可以在。net 5 中称它们为样板,用 ASP 构建 Angular 应用.NET Core Web API 和一个带有 ASP. NET 的 React 应用.NET CoreWeb API。 你可在以下连结查阅这两个项目模板:

上面的样板是一个方便的 ASP 的起点.NET Core 应用使用 React 或 Angular。 该项目可以从 GitHub 或 Azure DevOps 这样的 Git 存储库中,作为一个单独的应用从本地机器快速发送到 Azure app Service。

不幸的是,没有官方的 Vue.js 与 ASP.NET Core Web API 样板。 然而,我们可以转换我们的 ASP。 通过在Startup.cs中添加一些额外的代码,更新Travel.WebApi.csproj,并安装一个 NuGet 项目,将 NET Core API 和 Vue.js 应用整合到一个项目中。 你兴奋吗? 让我们开始:

  1. The first step is to install VueCliMiddleware in the Travel.WebApi project. The NuGet package is only needed in the src | presentation | Travel.WebApi project, so there's no need to install it in other projects.

    VueCliMiddleware将允许我们在 ASP 上构建 Vue.js SPA。 使用 Quasar CLI 或 Vue CLI 的 NET MVC 核心。 在此链接查看 nuGet 包及其 GitHub 存储库:https://www.nuget.org/packages/VueCliMiddlewarehttps://github.com/EEParker/aspnetcore-vueclimiddleware

  2. 下一步是更新Travel.WebApi.csproj文件。 我们将在文件中最后一个ItemGroup下面添加一些代码,它是:

    <ItemGroup> <Folder Include="Extensions\" /> </ItemGroup>

  3. We are going to add the following code to the </ItemGroup> closing tag. So make some space, hitting the Enter key several times, and then write the following code:

    <!-- Below is for Single Page Application. --> <!-- Please wait for compilation to finish before going to https://localhost:5001 --> <PropertyGroup> <!-- Typescript/Javascript Client Configuration --> <SpaRoot>..\vue-app\</SpaRoot> <DefaultItemExcludes>$(DefaultItemExcludes); $(SpaRoot)node_modules\**</DefaultItemExcludes> <!-- Set this to true if you enable server-side prerendering --> <BuildServerSideRenderer>false </BuildServerSideRenderer> <IsPackable>false</IsPackable> </PropertyGroup>

    新添加的代码告诉应用 SPA 的目录在vue-app中。

    还添加以下代码:

    <ItemGroup> <!-- Don't publish the SPA source files, but do show them in the project files list --> <Content Remove="$(SpaRoot)**" /> <None Remove="$(SpaRoot)**" /> <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" /> </ItemGroup> <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists( '$(SpaRoot)node_modules') "> <!-- Ensure Node.js is installed --> <Exec Command="node --version" ContinueOnError="true"> <Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> </Exec> <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." /> <Exec WorkingDirectory="$(SpaRoot)" Command= "npm install" /> </Target>

    上述代码将Spa Root文件夹(即vue-app)添加到项目中。

  4. Then add the final block of code we need in Travel.WebApi.csproj, like so:

    <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish"> <!-- As part of publishing, ensure the JS resources are freshly built in production mode --> <Exec WorkingDirectory="$(SpaRoot)" Command= "npm install" /> <Exec WorkingDirectory="$(SpaRoot)" Command= "npm run build" /> <!-- Include the newly-built files in the publish output --> <ItemGroup> <DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" /> <DistFiles Include="$(SpaRoot) node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" /> <ResolvedFileToPublish Include="@(DistFiles ->'%(FullPath)')" Exclude=" @(ResolvedFileToPublish)"> <RelativePath>%(DistFiles.Identity) </RelativePath> <CopyToPublishDirectory>PreserveNewest </CopyToPublishDirectory> <ExcludeFromSingleFile>true </ExcludeFromSingleFile> </ResolvedFileToPublish> </ItemGroup> </Target>

    添加的代码是为了在 vae .jsroot目录中运行npm run build,其中包括在发布输出中新建的文件。

    这就是所有的csproj文件。 现在让我们进行下一步。

  5. Now go to Startup.cs and update the ConfigureServices method. Add the following code at the end of the services:

    services.AddSpaStaticFiles(configuration => { configuration.RootPath = "../vue-app/dist"; });

    上述代码应在services.AddTransient IConfigureOptions以下。 代码在应用中添加 SPA 静态文件服务。

  6. Next, we update the middleware block, which is the Configure method. Add the following code under the if (env.IsDeveloper()) block:

    app.UseStaticFiles(); if (!env.IsDevelopment()) { app.UseSpaStaticFiles(); }

    我们正在中间件管道中添加UseSpaStaticFiles

  7. Now let's add UseSpa, another middleware, like so:

    app.UseSpa(spa => { spa.Options.SourcePath = "../vue-app"; if (env.IsDevelopment()) { spa.UseVueCli(npmScript: "serve"); } });

    该代码将源代码路径添加到UseSpa,并在生产环境中运行Vue CLI serve

    如果你的 ide 不能帮助你,你可能需要手动导入VueCliMiddlewareSpaServices:

    using Microsoft.AspNetCore.SpaServices; using VueCliMiddleware;

    前面的代码是创建 Vue CLI 代理映射所需的名称空间。 Travel.WebApivue-apppresentation目录下,如下截图所示:

    Figure 13.1 – The presentation directory

    图 13.1 -演示目录

    你在图 13.1中看到的两个文件夹也是你在 Visual Studio Code 中看到的:

    Figure 13.2 – VS Code folder arrangement

    图 13.2 - VS Code 文件夹布局

    图 13.2 中的 VS Code 文件夹排列也显示出Travel.WebApivue-app在目录中处于同一级别。 然而,在 ide 中是不同的,如 JetBrains’Rider, Visual Studio for Mac, Visual Studio 2019,如下截图所示:

    Figure 13.3 – Vue.js files and folders in the Travel.WebApi directory

    图 13.3 - Travel 中的 Vue.js 文件和文件夹 WebApi 目录

    ide 足够智能,知道 SPA 文件夹和文件,并将它们暴露在解决方案资源管理器的界面中。

  8. Now let's run the application by hitting your IDE debug button or running the dotnet run command inside the Travel.WebApi project. Then go to https://localhost:5001 to see the Vue.js app as shown in the following screenshot:

    Figure 13.4 – Vue.js running on port 5001

    图 13.4 - Vue.js 运行在端口 5001 上

    接受来自浏览器的任何弹出窗口,该窗口告诉您本地主机的 SSL 证书。 localhost:5001代理 Vue.js CLI 的8080端口。 开始编辑你的代码库中的欢迎旅行消息,你会发现热模块替换仍然很快。 您可以在保存任何更改后立即看到更改。

  9. 现在看看 Swagger 的 UI,看看它也在同一个端口上运行:

Figure 13.5 – Swagger UI on port 5001

图 13.5 - 5001 端口上的 Swagger UI

图 13.5 显示 Swagger UI 仍然在端口5001上工作。

现在我们可以将应用作为单个单元发送。 如果您有另一个位于另一个域的 SPA,并且希望向您的 ASP 发送请求,该怎么办? NET Core?

现在还不可能,这就是我们将在本章下一节讨论的问题。

介绍跨源资源共享或 CORS

在我们讨论 CORS 策略和跨源资源共享之前,尝试向WeatherForecast端点的版本 2 发送一个 POST 请求。 看看你是否仍然可以使用 Postman 检索WeatherForecast控制器的一些 JSON 响应,如下截图所示:

Figure 13.6 – Sending a POST request to WeatherForecast using Postman

图 13.6 -使用邮差向天气预报发送 POST 请求

图 13.6表示端点仍然正常工作,但在另一个 SPA 中不起作用。

我创建了一个运行在端口3000上的 React 应用,看看它是否可以从WeatherForecast控制器获取 JSON 对象。 请求中不需要认证,但是 React 应用在控制台中记录错误; 见图 13.7

Figure 13.7 – Blocked by CORS policy

图 13.7 - CORS 策略阻止

图 13.7 中的错误表示从localhost:3000访问端点XMLHttpRequest已被 CORS 策略阻塞。 No Access-Control-Allow-Origin头出现在请求的资源上。 如果你想亲自看看,你可以运行从 GitHub repo 的第 13 章中获得的 React 应用。 通过运行npm installnpm run start来使用react-app文件夹,这将在localhost 3000上打开浏览器。

这里发生了什么? 我们如何解决这个问题?

CORS代表跨源资源共享。 这是一个很好的安全概念。 如果客户端应用和 api 都来自同一个服务器,就像传统 web 一样,发送 HTTP 请求就会成功。 服务器处理请求是因为请求试图访问同一服务器上的资源。

然而,有时甚至局部宿主也被认为是不同的起源。 如果源端不相同,以3000端口为例,React 从3000端口向服务器发送请求以获取资源,但浏览器会拒绝 React 的请求。

因为我们正在构建 RESTful api,所以我们希望允许这种访问,因为 Web api 需要被不同的浏览器应用使用。 我明确地说浏览器应用是因为 CORS 限制不应用于移动应用,所以移动应用不需要发送飞行前请求。 预飞行请求是浏览器发送给资源服务器的一个快速、小的请求。 飞行前请求检查 CORS 协议是否被理解,服务器是否有处理方法和头的策略。

现在我们知道了 CORS 是什么,让我们在下一节中更新后端以启用 CORS 策略配置。

在 ASP 中启用 CORS 策略.NET Core

本节的目标是使用带有 CORS 策略的接口,并配置以允许任何 spa 向我们的 ASP 发送请求.NET Core Web api。

因此,让我们进入Travel.WebApi项目的Startup.cs文件,通过在AddSpaStaticFiles方法下添加以下代码来更新ConfigureServices方法:

services.AddCors();

services.AddCors方法将是我们在ConfigureServices内部调用的最后一个方法。 此服务是用于设置 CORS 服务的扩展方法。

这里还没有结束; 我们仍然需要更新我们的中间件。 因此,转到Configure方法,并在app.UseSpaStaticFiles下添加以下代码:

app.UseCors(b =>
  {
      b.AllowAnyOrigin();
      b.AllowAnyHeader();
      b.AllowAnyMethod();
 });

UseCors方法将 CORS 中间件添加到 web 应用的管道中。 从现在开始,这个中间件将允许在我们的应用中跨域请求。

现在让我们尝试一下,看看我们是否可以直接从不同的端口发送请求。

您可以通过在其根文件夹中运行npm run start来运行 React 应用。 你应该会看到如下截图所示的结果:

Figure 13.8 – React from port 3000 getting a 200 OK response

图 13.8 -从 3000 端口收到一个 200 OK 响应

图 13.8 显示了我们的 CORS 策略配置正在工作,并且它没有阻塞来自localhost:3000的 React 请求。

重要的

您可以在https://auth0.com/docs/applications/set-up-cors了解更多关于 CORS 政策的信息。

让我们来总结一下所学到的内容。

总结

你已经看完了这一章; 你已经学习了如何在 ASP 中包含 Vue.js 应用.NET Core Web API 项目来运行并将它们作为一个整体发布。 您也知道跨源资源共享CORS的工作原理。 简而言之,它是浏览器的一个安全特性,可以阻止来自不同域或来源的请求。 您已经学习了如何在 ASP 中启用和配置 CORS 策略.NET Core 允许来自其他域或源的传入请求。

在下一章中,我们将开始向 ASP 发送 GET 请求.NET Core Web API,并使用 Vuex 来管理我们的 Vue.js 应用的状态。这将是一个重要的章节,所以先休息一下,40 到 60 分钟后再回来。