国外网站开发文献,wordpress iis7伪静态,郑州做网站_郑州免费建站,wordpress自动加标签本文要点#xff1a;可以把多个 Angular 应用程序集成到 ASP.NET 网站中把 Angular 代码打包成 Web 组件是引导 Angular 应用程序的好方法可以把用 Angular 编写的 Web 组件轻松地集成到 ASP.NET 视图中把 Angular 解决方案构造成 Angular 应用程序的集合以实现更好的代码重用… 本文要点可以把多个 Angular 应用程序集成到 ASP.NET 网站中把 Angular 代码打包成 Web 组件是引导 Angular 应用程序的好方法可以把用 Angular 编写的 Web 组件轻松地集成到 ASP.NET 视图中把 Angular 解决方案构造成 Angular 应用程序的集合以实现更好的代码重用ASP.NET 结合使用 Angular 是创建 web 应用程序的强大平台本文是我们的.NET 教育系列文章的一部分这个系列探索了该技术的优势设法做到不仅有助于传统的.NET 开发人员而且有助于所有需要把健壮、高性能和经济的解决方案推向市场的技术人员。随着.NET Core 3.0 的发布微软拥有了通用、模块化、跨平台和开源平台的下一个重要版本.NET Core 最初发布于 2016 年。创建.NET Core 的最初目的是为了下一代的 ASP.NET 解决方案但是现在其驱动并成为很多其他场景的基础这些场景包括物联网、云和下一代移动解决方案。.NET Core 3.0 版添加了大量经常需要功能如对 WinForms、WPF 和 Entity Framework 6 的支持。挑战开始使用 Angular 和 ASP.NET Core 的最简单的方法是使用微软提供的 Visual Studio 模板。该模板可以让我们迅速启动并运行但有一个很大的限制——Angular 接管了 UI把 ASP.NET 保留在后台并提供 API。如果我们希望.NET 服务某些页面而 Angular 服务其他页面那么我们需要在 ASP.NET Core 和 Angular 中都复制外观和菜单结构。或者我们可以让单个 Angular 应用程序服务整个 UI但接下来我们必须在 Angular SPA 中实现所有的页面包括琐碎的静态内容如 Contact As、Licensing 等等。我想要的设置是一个充当门户的 ASP.NET 站点然后把 Angular 工件嵌入 ASP.NET 页面。一般来说有两种架构设计模式。在第一种设计模式下我有一个带路由的 Angular 应用程序想嵌入到 ASP.NET 视图中其中具有 Angular 提供的子菜单和提供顶层菜单的 ASP.NET 站点。在第二种设计模式下我有 Angular 组件这些组件不一定是成熟的 Angular 应用程序但是仍然需要把它们嵌入 ASP.NET 视图。例如假设我想在一个 ASP.NET 视图中嵌入一个组件以显示当前时间。在 Angular 中开发这么一个组件很容易但把它嵌入 MVC 视图就比较难。最后我希望实现尽可能多的代码重用我希望能够在 Angular 应用程序中重用组件并能够把相同的组件嵌入 ASP.NET 视图。本文演示了如何引导 ASP.NET 和 Angular 项目以适应这些架构设计模式。如果要看最终的代码请参考 GitHub 上的 Multi App Demo 存储库。总结一下这就是我们要构建的一个 ASP.NET Core web 网站该网站作为门户具有菜单结构其中每个菜单都打开一个 MVC 视图。能够在网站中托管一个或更多 Angular SPA能够在 ASP.NET 视图中重用这些 SPA 的某些组件实现概述我们将使用.NET Core在撰写本文时版本号为 3.0创建一个 ASP.NET MVC 网站我们将使用 Angular CLI 创建一个 Angular 项目并集成开发工作流、产品构建、发布等该项目到 ASP.NET 项目中。我们将把 Angular 项目作为 Web 组件也称为自定义元素也叫 Angular 元素进行引导。我们将使用 Angular CLI 生成应用程序。这些应用程序将引用根 Angular 项目的可重用组件。我们将使用指向同一域的 iframes在 ASP.NET 视图中嵌入 Angular 应用程序。IFrames 将使用 JavaScript 根据内容调整大小并且我们将把 iframed Angular 应用程序和 ASP.NET 路由集成在一起因此把书签放入路由过的 Angular 视图是可行的。为了在 ASP.NET 视图中托管 Angular 组件我们将把这些组件打包成 Web 组件。创建 ASP.NET Core MVC 项目我用的是 Visual Studio 2019 社区版可以从微软那里免费下载。从 2019 版开始用于选择模板的向导和以前的版本有所不同但无论使用哪个版本步骤基本上是一样的。转到创建一个新的项目。选择 ASP.NET Core Web Application。为项目选择名字和位置我称之为我的 MultiAppDemo。选择 ASP.NET Core在我的情况下是 3.0 版。选择 ASP.NET Model-View-Controller为了简单起见选择 No Authentication这样VS 不会为这个演练生成不相关的工件。在 Solution Explorer 中我们的项目视图应如下所示由于我们使用了 ASP.NET MVC 模板而不是 SPA 模板因此我们需要添加 Microsoft.AspNetCore.SpaServices.Extensions NuGet 包。为了安装这个包请打开软件包管理器控制台Package Manager Console并运行以下语句复制代码Install-Package Microsoft.AspNetCore.SpaServices.Extensions创建 Angular 项目请确保以下软件都已安装全部是免费的Visual Studio CodeNode.jsAngular CLI。为了安装这个请转到命令提示符并执行以下命令复制代码npm install -g angular/cli我在使用 Angular v8。用更早的版本也可以只要可以访问 createCustomElement API 就行。 Angular v7 中也有这些功能。为了创建一个 Angular 解决方案以在我们的 ASP.NET MVC 项目中使用请打开命令提示符转到包含用于 MVC 项目的项目文件扩展名.csproj所在的文件夹。到达之后通过命令提示符执行以下命令以创建 Angular 项目复制代码ng new Apps路由选择 N样式选 CSS。把目录改为 Apps并输入以下内容包括结尾的点复制代码code .现在在 Visual Studio Code 中应该有我们已经打开的 Angular 项目了。引导 Angular 元素这里的想法是把这个根项目做为可重用组件的存储库其他 Angular 应用程序我们稍后创建它们可以把这些可重用组件作为普通 Angular 组件使用并作为 Web 组件提供给 MVC 视图也称为 Angular 元素。那么什么是 web component在 webcomponents.org 中是这么定义的Web 组件是一组 web 平台 API这些 API 允许我们创建新的自定义、可重用、封装的 HTML 标记以用于 web 页面和 web 应用程序。Angular 提供一种方法通过被称为 Angular 元素的 API 把 Angular 组件打包成 web 组件。例如如果我们创建一个显示当前时间的 Angular 组件 并引导该组件作为 Angular 元素当前时间那么我们接着可以在纯 HTML 页面中包含这个标签。在 Angular 官方网站上有更多相关信息。在 VS Code 中打开我们的 Angular 项目。打开一个终端窗口输入一个命令以生成时钟组件并把该组件添加到 app.module.ts 中复制代码ng g c current-time现在我们应该在 src/app 下有一个名为 current-time 的文件夹包含一些组成我们的时钟组件的文件。把 app/current-time/current-time.component.html 改成具有以下标记复制代码p{{ time }}/p把 app/current-time/current-time.component.ts 改成具有以下代码复制代码import { Component, OnInit, OnDestroy } from angular/core;Component({selector: app-current-time,templateUrl: ./current-time.component.html,styleUrls: [./current-time.component.css]})export class CurrentTimeComponent implements OnInit, OnDestroy {timer: any;time: stringconstructor() { }ngOnInit() {var setTime () {var today new Date();this.time (0 today.getHours()).slice(-2) : (0 today.getMinutes()).slice(-2) : (0 today.getSeconds()).slice(-2);};setTime();this.timer setInterval(setTime, 500);}ngOnDestroy(){if (this.timer){clearTimeout(this.timer);}}}这个实现相当简单。我们有个每半秒钟触发一次的计时器。该计时器用一个代表当前时间的字符串更新时间属性并且 HTML 模板绑定到该字符串。把以下样式粘贴到我们的 app/current-time/current-time.component.css复制代码p {background-color: darkslategray;color: lightgreen;font-weight: bold;display: inline-block;padding: 7px;border: 4px solid black;border-radius: 5px;font-family: monospace;}现在保存所有修改后的文件让我们把这个时钟组件作为 web 组件引导在 Visual Studio Code 中打开一个新的终端窗口添加 Angular 元素库和 polyfills。在终端窗口输入以下命令实现这个操作复制代码ng add angular/elements转到 src/app/app.module.ts如果那里还没有那么在 app.module.ts 的顶部添加以下导入语句复制代码import { createCustomElement } from angular/elements;从 angular/core 给导入添加 Injector复制代码import { NgModule, Injector } from angular/core;用 bootstrap: [AppComponent] 替换 entryComponents: [ClockComponent]最后给 AppModule 类添加构造函数和 ngDoBootstrap。复制代码constructor(private injector: Injector) {}ngDoBootstrap(){ customElements.define(current-time, createCustomElement(CurrentTimeComponent, {injector: this.injector}));}现在我们还需要做一件事情稍后当我们在一个不同的 Angular 应用程序中导入 CurrentTimeComponents 时就会用到。我们需要从这个模块导出该组件。在 providers 上方添加导出属性就可以实现复制代码exports: [CurrentTimeComponent],我们的整个 app.module.ts 应如下所示:复制代码import { BrowserModule } from angular/platform-browser;import { NgModule, Injector } from angular/core;import { AppComponent } from ./app.component;import { createCustomElement } from angular/elements;import { CurrentTimeComponent } from ./current-time/current-time.component;NgModule({declarations: [AppComponent,CurrentTimeComponent],imports: [BrowserModule],exports: [CurrentTimeComponent],providers: [],entryComponents: [CurrentTimeComponent]})export class AppModule {constructor(private injector: Injector) {}ngDoBootstrap(){customElements.define(current-time, createCustomElement(CurrentTimeComponent,{injector: this.injector}));}}现在我们来测试一下我们的解决方案是否有用。转到 src\index.html用替换。在终端窗口输入 ng serve --open 以运行该项目。现在我们应该在浏览器窗口看到当前时间。在 ASP.NET 项目中使用 Web 组件接下来要让我们的当前时间组件在 ASP.NET MVC Core 项目中可用。在 Visual Studio 中打开 ASP.NET 就可以了。在 Views/Shares/_Layout.cshtml 中的结束标签前粘贴以下代码复制代码environment includeDevelopmentscript typetext/javascript srchttp://localhost:4200/runtime.js/scriptscript typetext/javascript srchttp://localhost:4200/polyfills.js/scriptscript typetext/javascript srchttp://localhost:4200/styles.js/scriptscript typetext/javascript srchttp://localhost:4200/scripts.js/scriptscript typetext/javascript srchttp://localhost:4200/vendor.js/scriptscript typetext/javascript srchttp://localhost:4200/main.js/script/environmentenvironment excludeDevelopmentscript asp-src-include~/Apps/dist/core/runtime-es2015.*.js typemodule/scriptscript asp-src-include~/Apps/dist/core/polyfills-es2015.*.js typemodule/scriptscript asp-src-include~/Apps/dist/core/runtime-es5.*.js nomodule/scriptscript asp-src-include~/Apps/dist/core/polyfills-es5.*.js nomodule/scriptscript asp-src-include~/Apps/dist/core/scripts.*.js/scriptscript asp-src-include~/Apps/dist/core/main-es2015.*.js typemodule/scriptscript asp-src-include~/Apps/dist/core/main-es5.*.js nomodule/script/environment前面的代码段显示了两个块一个用于开发一个用于非开发。当我们在开发时我们托管 web 组件的 Angular 项目将运行于从 VS Code 启动的 4200 端口。当我们投入生产时该 Angular 项目将被编译到 wwwroot/apps/core 文件夹并带有附加哈希值命名的 javascript 文件。为了正确地引用这些文件我们需要使用 asp-src-include 标记助手。接下来在 _Layout.cshtml 中在结束标记后面直接添加。测试我们的开发配置是否有用转到打开 Angular 项目的 VS Code在终端提示符中输入该命令复制代码ng serve --liveReloadfalse转到打开 ASP.NET 项目的 Visual Studio点击 F5 键运行该项目。我们的 ASP.NET 站点应该打开并且我们应该看到在每个页面上显示的当前时间组件。创建 Angular 应用程序Web 组件很棒也许是 web UI 的未来但是就今天来说Angular 项目作为单个页面应用程序Single Page Applications简称 SPAs引导仍有自己的生存空间。Angular 是围绕着模块的概念设计的它的一些特性特别是路由是与模块而不是组件保持一致的。在混合 Angular 和 ASP.NET 开发时我的目标是在 MVC 视图中托管 Angular 应用程序。我希望 ASP.NET MVC 提供顶层菜单结构SPA 提供它们自己的菜单和路由结构这些都驻留在更大的 MVC 应用程序中 。此外我希望实现代码重用这些代码可以在解决方案中的多个 SPAs 中共享也可以作为 web 组件包含在非 Angular 页面中。第一步是在 Angular 中创建一个新的应用程序。最简单的实现方法是使用 Angular CLI命令行接口。如果还没有这个在 VS Code 中打开 Angular 项目并启动一个新的终端窗口。在终端窗口执行该命令复制代码ng g application App1 --routingtrue这将在配置了路由模块的 Apps\projects\App1 下生成新的 Angular 应用程序。让我们生成两个组件并设置路由这样我们可以路由到某处去。从终端窗口执行以下命令复制代码ng g c Page1 --projectApp1ng g c Page2 --projectApp1现在我们应该在 Apps/Projects/App1/src/app 下看到两个新的组件文件夹 page1 和 page2。现在让我们来为这些组件设置路由。把 Apps/Projects/App1/src/app 下的 app.component.html 改成具有这个标记复制代码h2App1/h2a routerLink/page1 routerLinkActiveactivePage1/aa routerLink/page2 routerLinkActiveactivePage2/arouter-outlet/router-outlet并用以下代码更新 Apps/projects/App1/src/app 下的 app-routing.module.ts复制代码import { NgModule } from angular/core;import { Routes, RouterModule } from angular/router;import { Page1Component } from ./page1/page1.component;import { Page2Component } from ./page2/page2.component;const routes: Routes [{path: , redirectTo: page1, pathMatch: full},{path: page1, component: Page1Component},{path: page2, component: Page2Component}];NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule]})export class AppRoutingModule { }这只是标准的路由代码。关于 Angular 路由的评论请访问该页面。现在让我们来测试我们的新应用程序是否配置得正确。打开一个新的终端窗口输入以下命令复制代码ng serve App1 --port 4201 --open我们的浏览器窗口应该打开我们应该能看到类似以下的内容请注意现在我们在用端口 4201和我们用于根 Angular 项目的不同。我们创建的每个应用程序都将需要开发环境中一个不同的端口服务于它但是在非开发环境中所有的应用程序、ASP.NET 和 Angular 都将运行于同一个端口上。现在该演示的一个目标是实现代码重用。让我们在 App1 中重用来自基础项目的 Angular 组件。为了实现这个目标要在 App1 的主模块中包含 CurrentTimeComponent 的导入。转到 Apps/projects/App1/src/app 下的 app.modules.ts添加以下导入语句复制代码import { CurrentTimeComponent } from ../../../../src/app/current-time/current-time.component;这里正在发生的事是我们从根项目中导入 CurrentTimeComponent。或者我们可以从根项目中导入整个 AppModule。接下来把 CurrentTimeComponent 添加到声明列表中复制代码 declarations: [ AppComponent, Page1Component, Page2Component,CurrentTimeComponent],现在转到 App1 中的 app.component.html并为当前时间添加标签就添加在路由器出口的正下方。复制代码h2App1/h2a routerLink/page1 routerLinkActiveactivePage1/aa routerLink/page2 routerLinkActiveactivePage2/arouter-outlet/router-outletapp-current-time/app-current-time请注意我们为这个组件使用了 Angular 标签app-current-time而不是 web 组件标签名current-time。原因是我们把该组件作为 Angular 组件包含在内了。App1 完全不知道这个 Angular 组件在其他地方用作 web 组件。保存所有的文件并检查浏览器。我们的 App1 页面现在应该显示当前时间组件。把 App1 作为 SPA 集成到 ASP.NET MVC在这个演练中我们要做的最后一件事是把 App1 作为单页面应用程序合并到 ASP.NET MVC 应用程序 。我们希望有以下特性该 SPA 应该嵌入 MVC 视图之一。其应该可以深度链接到一个 SPA 中的页面。应该支持实时重新加载。首先让我们在主控制器上Home Controller上设置一个名为 App1 的常规 MVC 视图。在我们的 MVC 项目中转到 Controllers/HomeController.cs并添加以下代码复制代码[Route(app1/{*url})]public IActionResult App1(string url){return View(App1, url);}这个在路由Route属性中的{*url}构造告诉 ASP.NET 捕获在 url 变量中 /app1/ 段右侧的一切内容。然后将其传到 Angular 应用程序。现在右键单击 View() 令牌然后选择添加视图。调用视图 App1并点击 Add 按钮。这应该在 Views/Home 中创建一个名为 App1.cshtml 的文件。确保该文件有以下标记复制代码{ViewData[Title] App1;}This is the view for App1.转到 Shared/_Layout.cshtml并给该视图添加一个链接就添加在到隐私Privacy视图链接的下方。最简单的方法是复制这个隐私链接标记并用“App1”这个词替换“Privacy”这个词。复制代码ul classnavbar-nav flex-grow-1li classnav-itema classnav-link text-dark asp-area asp-controllerHomeasp-actionIndexHome/a/lili classnav-itema classnav-link text-dark asp-area asp-controllerHomeasp-actionPrivacyPrivacy/a/lili classnav-itema classnav-link text-dark asp-area asp-controllerHomeasp-actionApp1App1/a/li/ul在 _Layout.cshtml 中时让我们多做一个更改。让我们web 组件周围添加一些标记以直观地指明这是一个 web 组件而不是 Angular 组件。添加和注释就可以做到复制代码div classcontainerpartial name_CookieConsentPartial /main rolemain classpb-3RenderBody()/mainhr /This is a web componentbr /current-time/current-time/div接下来我们来测试一下这个应用程序。点击 F5 键确保可以通过 App1 链接跳转到 App1 视图。下一步是把 App1 应用程序嵌入 App1 MVC 视图。我们准备使用一个 iframe它指向在同一个域的 URL。使用 iframe 的好处是可以把 App1 封装在其自身的容器中但也带来两个挑战iframe 需要动态地随其内容的变化而调整其大小。在用户在 Angular 应用程序中跳转时顶部窗口的地址栏必须改变。我们将使用 JavaScript 来解决这两个挑战。因为 iframe 指向同一个域所以这是唯一可行的方法从而避免了跨域限制。但是在我们这么做之前我们仍然需要在.NET 代码中做更多的修改。首先我们在 Startup 中配置 App1。打开 Startup.cs并把以下代码添加到配置Configure方法中复制代码app.Map(/apps/app1, builder {builder.UseSpa(spa {if (env.IsDevelopment()){spa.UseProxyToSpaDevelopmentServer($http://localhost:4201/);}else{var staticPath Path.Combine(Directory.GetCurrentDirectory(), $wwwroot/Apps/dist/app1);var fileOptions new StaticFileOptions{ FileProvider new PhysicalFileProvider(staticPath) };builder.UseSpaStaticFiles(options: fileOptions);spa.Options.DefaultPageStaticFileOptions fileOptions;}});});该段代码告诉.NET 核心运行时把应用程序映射到 /apps/app1 路径以代理到开发中的端口 4201并期望在非开发环境中的 wwwroot/apps/app1 可用编译后的文件。但是我们不希望 /apps/app1 的用户使用我们的应用程序。我们希望我们的应用程序在用户转到 App1 视图时可用App1 视图可以是 /home/app1 或只是 /app1 URL。这里是我们打算使用 iframe 的地方。打开 App1.cshtml并添加以下标记复制代码iframe src/apps/app1/Model classapp-container frameborder0 scrollingno/iframe请注意 Model 构造。它被映射到组件中的{*url}我们把路径的一部分从顶部窗口传到 App1 右侧的 iframe因此路由在 Angular 应用程序内部进行。现在我们可以测试这个应用程序了。转到 VS Code并从一个可用的终端窗口执行以下 serve 命令ng serve App1 --port 4201 --servePath / --baseHref /apps/app1/ --publicHosthttp://localhost:4201该命令在 4201 端口启动 App1。由于我们知道准备从 apps/app1 给它提供服务因此它设置了基础 HREF并且它指示 Angular 使用 localhost:4201 而不是使用相对的 URL 进行实时重载。转到 Visual Studio并点击 F5 键。在 ASP.NET 站点出现在浏览器窗口后转到 App1 菜单。如果看到和下面类似的屏幕那就意味着该应用程序已经正确地连接上了。尽管 App1 Angular 应用程序确实出现在 App1 视图中但是没有内容。如果点击 Page 1 和 Page 2 的链接可以看到在 Angluar 组件中跳转是正常工作的但是在浏览器顶部的地址栏没有反映出跳转的当前状态。让我们来解决这两个问题。为了在启动时以及 iframe 的内容有变化时调整 iframe 的大小我们将使用名为 iFrame Resizer 的 JavaScript 组件iFrame Resizer 是由 David Bradshaw 创建的。为了让该组件工作我们需要执行这三个步骤。在 _Layout.cshtml 中把以下脚本标签粘贴到指向 site.js 的脚本标签的正上方复制代码script srchttps://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.1.1/iframeResizer.min.js/script给位于 wwwroot/js 的 site.js 添加以下代码行。复制代码$(.app-container).iFrameResize({ heightCalculationMethod: documentElementOffset });接着转到 VS Code并在结束标签的上方给位于 Apps/projects/App1/src 的 Index.html 添加以下脚本标签复制代码script srchttps://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.1.1/iframeResizer.contentWindow.min.js/script保存所有的文件我们来重新测试一下这个应用程序。App1 现在应该如下所示请注意内容不再消失了。iFrame Resizer 的这一点做得很不错在 iframe 初始加载后它将不断调整 iframe 的大小以适合内容。现在我们来解决这个问题当点击 Angular 路由器链接时地址栏没有更新。因为 App1 在 iframe 中运行因此地址栏没有更新。iframe 的地址在改变但是我们看不到原因是我们看到的地址栏是用于顶部浏览器窗口的。请记住我们已经有代码可以捕捉 /app1 URL 段右侧的路径并存入{*ulr}变量再把它传给 iframe。我们需要添加的代码是另一个方式当路由在 Angular 应用程序中进行时我们希望把变化传播到顶层地址栏。我们需要把代码添加到 App1 应用程序中的路由模块中来实现。打开 Apps/projects/App1/src/app 中的 app-routing.module.ts。在 AppRouting Module 的构造函数中添加以下代码复制代码constructor(private route:Router){var topHref window.top.location.href ! window.location.href ?window.top.location.href.substring(0,window.top.location.href.indexOf(/app1) 5) :null;this.route.events.subscribe(e {if(e instanceof NavigationEnd){if (topHref){window.top.history.replaceState(window.top.history.state,window.top.document.title, topHref e.url);}}});}该代码通过比较顶部窗口的 HREF 和当前窗口的 HREF 来确定应用程序是否在 iframe 中运行。如果应用程序在 iframe 中运行那么代码把顶部窗口的 HREF 保存在一个局部变量中但是去掉了指向 /app1 段右侧的 HREF 部分。然后代码进入 NavigationEnd 事件并把路由过的 URL 追加到顶部窗口的 HREF 的后面。我们还将需要给导入添加 Router 和 NavigationEnd。整个 app-routing.module.ts 应该如下所示复制代码import { NgModule } from angular/core;import { Routes, RouterModule, Router, NavigationEnd } from angular/router;import { Page1Component } from ./page1/page1.component;import { Page2Component } from ./page2/page2.component;const routes: Routes [{path: , redirectTo: page1, pathMatch: full},{path: page1, component: Page1Component},{path: page2, component: Page2Component}];NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]})export class AppRoutingModule {constructor(private route:Router){var topHref window.top.location.href ! window.location.href ?window.top.location.href.substring(0,window.top.location.href.indexOf(/app1) 5) :null;this.route.events.subscribe(e {if(e instanceof NavigationEnd){if (topHref){window.top.history.replaceState(window.top.history.state,window.top.document.title, topHref e.url);}}});}}为了测试该应用程序请从 Visual Studio 启动它。点击 Page 1 或 Page 2 的链接。观察到顶部 URL 现在在变化。我们还可以复制修改过的 URL并把它粘贴到一个独立的窗口App1 将路由到顶部 URL 中指定的组件。调整发布Publish设置还有最后一件事要做。我们需要修改项目文件以将 Angular 构建任务纳入发布过程。为此转到 ASP.NET 项目右键单击项目文件选择 Edit .csproj。项目文件应该与如下所示的类似复制代码Project SdkMicrosoft.NET.Sdk.WebPropertyGroupTargetFrameworknetcoreapp3.0/TargetFrameworkTypeScriptToolsVersion3.3/TypeScriptToolsVersionSpaRootApps\/SpaRoot/PropertyGroupPropertyGroup Condition$(Configuration)|$(Platform)Debug|AnyCPUWarningLevel0/WarningLevel/PropertyGroupItemGroupContent Remove$(SpaRoot)** /None Remove$(SpaRoot)** /None Include$(SpaRoot)** Exclude$(SpaRoot)node_modules\** //ItemGroupItemGroupPackageReference IncludeMicrosoft.AspNetCore.SpaServices.Extensions Version3.0.0 //ItemGroupTarget NamePublishApps AfterTargetsComputeFilesToPublishExec WorkingDirectory$(SpaRoot) Commandnpm install /Exec WorkingDirectory$(SpaRoot) Commandnpm run build -- --prod --outputPath./dist/core /Exec WorkingDirectory$(SpaRoot) Commandnpm run build App1 -- --prod --base-href/apps/app1/ --outputPath./dist/app1 /ItemGroupDistFiles Include$(SpaRoot)dist\** /ResolvedFileToPublish Include(DistFiles-%(FullPath)) Exclude(ResolvedFileToPublish)RelativePathwwwroot\%(DistFiles.Identity)/RelativePathCopyToPublishDirectoryPreserveNewest/CopyToPublishDirectory/ResolvedFileToPublish/ItemGroup/Target/Project这里有个有趣的部分就是 Target 标签。我们指示构建过程运行 npm 安装然后构建两个 Angular 项目接着复制 dist 文件夹输出到 ASP.NET 站点的 wwwroot 文件夹。为了测试我们的发布配置是否有用在 Visual Studio 中右键单击 ASP.NET 项目名称。转到 Publish。在选择Pick一个发布目标下选择文件夹Folder。点击发布Publish按钮。在这个过程的最后我们应该看到在 Output 窗口中发布的新文件的文件夹的整个路径。为了测试发布的站点在命令窗口打开发布文件夹。输入dotnet .dll转到到我们的浏览器打开 http://localhost:5000结论我们创建了一个 ASP.NET 站点把两个 Angular 项目与它集成在一起并把 Angular 工件嵌入 MVC 视图。如果我们想试用这个解决方案建议从 GitHub 中克隆项目。尝试添加 App2并从不同的 MVC 视图中为它提供服务或者尝试创建更多的 web 组件。作者介绍30 年来Evgueni Tsygankov 一直在编写软件从 80 年代的 Commodore 64 一直到如今的云计算。目前他在 Effita 领导其中的一支开发团队Effita 是总部在密苏里州圣路易斯的一家软件公司。在空闲的时候Evgueni 把时间用于陪伴他的两个孩子以及打冰球和踢足球。