日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

深入研究 Angular 和 ASP.NET Core 3.0

發(fā)布時間:2023/12/4 asp.net 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入研究 Angular 和 ASP.NET Core 3.0 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文要點:

  • 可以把多個 Angular 應(yīng)用程序集成到 ASP.NET 網(wǎng)站中

  • 把 Angular 代碼打包成 Web 組件是引導(dǎo) Angular 應(yīng)用程序的好方法

  • 可以把用 Angular 編寫的 Web 組件輕松地集成到 ASP.NET 視圖中

  • 把 Angular 解決方案構(gòu)造成 Angular 應(yīng)用程序的集合以實現(xiàn)更好的代碼重用

  • ASP.NET 結(jié)合使用 Angular 是創(chuàng)建 web 應(yīng)用程序的強大平臺

本文是我們的.NET 教育系列文章的一部分,這個系列探索了該技術(shù)的優(yōu)勢,設(shè)法做到不僅有助于傳統(tǒng)的.NET 開發(fā)人員,而且有助于所有需要把健壯、高性能和經(jīng)濟的解決方案推向市場的技術(shù)人員。

隨著.NET Core 3.0 的發(fā)布,微軟擁有了通用、模塊化、跨平臺和開源平臺的下一個重要版本,.NET Core 最初發(fā)布于 2016 年。創(chuàng)建.NET Core 的最初目的是為了下一代的 ASP.NET 解決方案,但是現(xiàn)在,其驅(qū)動并成為很多其他場景的基礎(chǔ),這些場景包括物聯(lián)網(wǎng)、云和下一代移動解決方案。.NET Core 3.0 版添加了大量經(jīng)常需要功能,如對 WinForms、WPF 和 Entity Framework 6 的支持。

挑戰(zhàn)

開始使用 Angular 和 ASP.NET Core 的最簡單的方法是,使用微軟提供的 Visual Studio 模板。該模板可以讓我們迅速啟動并運行,但有一個很大的限制——Angular 接管了 UI,把 ASP.NET 保留在后臺,并提供 API。如果我們希望.NET 服務(wù)某些頁面而 Angular 服務(wù)其他頁面,那么,我們需要在 ASP.NET Core 和 Angular 中都復(fù)制外觀和菜單結(jié)構(gòu)。或者,我們可以讓單個 Angular 應(yīng)用程序服務(wù)整個 UI,但接下來,我們必須在 Angular SPA 中實現(xiàn)所有的頁面,包括瑣碎的靜態(tài)內(nèi)容,如 Contact As、Licensing 等等。

我想要的設(shè)置是一個充當(dāng)門戶的 ASP.NET 站點,然后把 Angular 工件嵌入 ASP.NET 頁面。一般來說,有兩種架構(gòu)設(shè)計模式。在第一種設(shè)計模式下,我有一個帶路由的 Angular 應(yīng)用程序,想嵌入到 ASP.NET 視圖中,其中具有 Angular 提供的子菜單和提供頂層菜單的 ASP.NET 站點。在第二種設(shè)計模式下,我有 Angular 組件,這些組件不一定是成熟的 Angular 應(yīng)用程序,但是,仍然需要把它們嵌入 ASP.NET 視圖。例如,假設(shè)我想在一個 ASP.NET 視圖中嵌入一個組件,以顯示當(dāng)前時間。在 Angular 中開發(fā)這么一個組件很容易,但把它嵌入 MVC 視圖就比較難。最后,我希望實現(xiàn)盡可能多的代碼重用,我希望能夠在 Angular 應(yīng)用程序中重用組件,并能夠把相同的組件嵌入 ASP.NET 視圖。本文演示了如何引導(dǎo) ASP.NET 和 Angular 項目以適應(yīng)這些架構(gòu)設(shè)計模式。如果要看最終的代碼,請參考 GitHub 上的?Multi App Demo?存儲庫。

總結(jié)一下,這就是我們要構(gòu)建的:

  • 一個 ASP.NET Core web 網(wǎng)站,該網(wǎng)站作為門戶,具有菜單結(jié)構(gòu),其中每個菜單都打開一個 MVC 視圖。

  • 能夠在網(wǎng)站中托管一個或更多 Angular SPA

  • 能夠在 ASP.NET 視圖中重用這些 SPA 的某些組件

實現(xiàn)概述

  • 我們將使用.NET Core(在撰寫本文時,版本號為 3.0)創(chuàng)建一個 ASP.NET MVC 網(wǎng)站

  • 我們將使用 Angular CLI 創(chuàng)建一個 Angular 項目,并集成(開發(fā)工作流、產(chǎn)品構(gòu)建、發(fā)布等)該項目到 ASP.NET 項目中。

  • 我們將把 Angular 項目作為 Web 組件(也稱為自定義元素,也叫 Angular 元素)進行引導(dǎo)。

  • 我們將使用 Angular CLI 生成應(yīng)用程序。這些應(yīng)用程序?qū)⒁酶?Angular 項目的可重用組件。

  • 我們將使用指向同一域的 iframes,在 ASP.NET 視圖中嵌入 Angular 應(yīng)用程序。

  • IFrames 將使用 JavaScript 根據(jù)內(nèi)容調(diào)整大小,并且,我們將把 iframed Angular 應(yīng)用程序和 ASP.NET 路由集成在一起,因此,把書簽放入路由過的 Angular 視圖是可行的。

  • 為了在 ASP.NET 視圖中托管 Angular 組件,我們將把這些組件打包成 Web 組件。

創(chuàng)建 ASP.NET Core MVC 項目

我用的是 Visual Studio 2019 社區(qū)版,可以從微軟那里免費下載。從 2019 版開始,用于選擇模板的向?qū)Ш鸵郧暗陌姹居兴煌?#xff0c;但無論使用哪個版本,步驟基本上是一樣的。

  • 轉(zhuǎn)到創(chuàng)建一個新的項目。

  • 選擇 ASP.NET Core Web Application。

  • 為項目選擇名字和位置(我稱之為我的 MultiAppDemo)。

  • 選擇 ASP.NET Core(在我的情況下,是 3.0 版)。

  • 選擇 ASP.NET Model-View-Controller(為了簡單起見,選擇 No Authentication,這樣,VS 不會為這個演練生成不相關(guān)的工件)。

在 Solution Explorer 中,我們的項目視圖應(yīng)如下所示:

由于我們使用了 ASP.NET MVC 模板而不是 SPA 模板,因此,我們需要添加 Microsoft.AspNetCore.SpaServices.Extensions NuGet 包。為了安裝這個包,請打開軟件包管理器控制臺(Package Manager Console)并運行以下語句:

復(fù)制代碼

Install-Package Microsoft.AspNetCore.SpaServices.Extensions

創(chuàng)建 Angular 項目

請確保以下軟件都已安裝(全部是免費的):

  • Visual Studio Code

  • Node.js

  • Angular CLI。為了安裝這個,請轉(zhuǎn)到命令提示符并執(zhí)行以下命令:

復(fù)制代碼

npm install -g @angular/cli

我在使用 Angular v8。用更早的版本也可以,只要可以訪問 createCustomElement API 就行。 Angular v7 中也有這些功能。

為了創(chuàng)建一個 Angular 解決方案以在我們的 ASP.NET MVC 項目中使用,請打開命令提示符,轉(zhuǎn)到包含用于 MVC 項目的項目文件(擴展名.csproj)所在的文件夾。到達之后,通過命令提示符執(zhí)行以下命令以創(chuàng)建 Angular 項目:

復(fù)制代碼

ng new Apps

路由選擇 N,樣式選 CSS。

把目錄改為 Apps,并輸入以下內(nèi)容(包括結(jié)尾的點):

復(fù)制代碼

code .

現(xiàn)在,在 Visual Studio Code 中應(yīng)該有我們已經(jīng)打開的 Angular 項目了。

引導(dǎo) Angular 元素

這里的想法是,把這個根項目做為可重用組件的存儲庫,其他 Angular 應(yīng)用程序(我們稍后創(chuàng)建它們)可以把這些可重用組件作為普通 Angular 組件使用,并作為 Web 組件提供給 MVC 視圖(也稱為 Angular 元素)。

那么,什么是 web component?在?webcomponents.org?中,是這么定義的:

Web 組件是一組 web 平臺 API,這些 API 允許我們創(chuàng)建新的自定義、可重用、封裝的 HTML 標(biāo)記以用于 web 頁面和 web 應(yīng)用程序。

Angular 提供一種方法,通過被稱為 Angular 元素的 API 把 Angular 組件打包成 web 組件。例如,如果我們創(chuàng)建一個顯示當(dāng)前時間的 Angular 組件, 并引導(dǎo)該組件作為 Angular 元素當(dāng)前時間,那么,我們接著可以在純 HTML 頁面中包含這個標(biāo)簽。在?Angular 官方網(wǎng)站上有更多相關(guān)信息。

在 VS Code 中打開我們的 Angular 項目。打開一個終端窗口,輸入一個命令以生成時鐘組件,并把該組件添加到 app.module.ts 中:

復(fù)制代碼

ng g c current-time

現(xiàn)在,我們應(yīng)該在 src/app 下有一個名為 current-time 的文件夾,包含一些組成我們的時鐘組件的文件。把 app/current-time/current-time.component.html 改成具有以下標(biāo)記:

復(fù)制代碼

<p>{{ time }}</p>


把 app/current-time/current-time.component.ts 改成具有以下代碼:

復(fù)制代碼

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: string

constructor() { }

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);

}

}

}

這個實現(xiàn)相當(dāng)簡單。我們有個每半秒鐘觸發(fā)一次的計時器。該計時器用一個代表當(dāng)前時間的字符串更新時間屬性,并且 HTML 模板綁定到該字符串。

把以下樣式粘貼到我們的 app/current-time/current-time.component.css

復(fù)制代碼

p {

background-color: darkslategray;

color: lightgreen;

font-weight: bold;

display: inline-block;

padding: 7px;

border: 4px solid black;

border-radius: 5px;

font-family: monospace;

}

現(xiàn)在,保存所有修改后的文件,讓我們把這個時鐘組件作為 web 組件引導(dǎo):

  • 在 Visual Studio Code 中打開一個新的終端窗口

  • 添加 Angular 元素庫和 polyfills。在終端窗口輸入以下命令實現(xiàn)這個操作:

復(fù)制代碼

ng add @angular/elements

  • 轉(zhuǎn)到 src/app/app.module.ts

  • 如果那里還沒有,那么在 app.module.ts 的頂部添加以下導(dǎo)入語句:

復(fù)制代碼

import { createCustomElement } from '@angular/elements';

  • 從 @angular/core 給導(dǎo)入添加 Injector:

復(fù)制代碼

import { NgModule, Injector } from '@angular/core';

  • 用 bootstrap: [AppComponent] 替換 entryComponents: [ClockComponent]

  • 最后,給 AppModule 類添加構(gòu)造函數(shù)和 ngDoBootstrap。

復(fù)制代碼

constructor(private injector: Injector) {

}

ngDoBootstrap(){

customElements.define('current-time', createCustomElement(CurrentTimeComponent,

{injector: this.injector}));

}

現(xiàn)在我們還需要做一件事情,稍后當(dāng)我們在一個不同的 Angular 應(yīng)用程序中導(dǎo)入 CurrentTimeComponents 時就會用到。我們需要從這個模塊導(dǎo)出該組件。在 providers 上方添加導(dǎo)出屬性就可以實現(xiàn):

復(fù)制代碼

exports: [

CurrentTimeComponent

],

我們的整個 app.module.ts 應(yīng)如下所示:

復(fù)制代碼

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}));

}

}

現(xiàn)在,我們來測試一下我們的解決方案是否有用。轉(zhuǎn)到 src\index.html,用替換。在終端窗口輸入 ng serve --open 以運行該項目。現(xiàn)在,我們應(yīng)該在瀏覽器窗口看到當(dāng)前時間。

在 ASP.NET 項目中使用 Web 組件

接下來,要讓我們的當(dāng)前時間組件在 ASP.NET MVC Core 項目中可用。在 Visual Studio 中打開 ASP.NET 就可以了。在 Views/Shares/_Layout.cshtml 中的結(jié)束標(biāo)簽前粘貼以下代碼:

復(fù)制代碼

<environment include="Development">

<script type="text/javascript" src="http://localhost:4200/runtime.js"></script>

<script?type="text/javascript" src="http://localhost:4200/polyfills.js"></script>

<script?type="text/javascript" src="http://localhost:4200/styles.js"></script>

<script type="text/javascript" src="http://localhost:4200/scripts.js"></script>

<script?type="text/javascript" src="http://localhost:4200/vendor.js"></script>

<script?type="text/javascript" src="http://localhost:4200/main.js"></script>

</environment>

<environment exclude="Development">

<script?asp-src-include="~/Apps/dist/core/runtime-es2015.*.js" type="module"></script>

<script?asp-src-include="~/Apps/dist/core/polyfills-es2015.*.js" type="module"></script>

<script?asp-src-include="~/Apps/dist/core/runtime-es5.*.js" nomodule></script>

<script?asp-src-include="~/Apps/dist/core/polyfills-es5.*.js" nomodule></script>

<script asp-src-include="~/Apps/dist/core/scripts.*.js"></script>

<script asp-src-include="~/Apps/dist/core/main-es2015.*.js" type="module"></script>

<script?asp-src-include="~/Apps/dist/core/main-es5.*.js" nomodule></script>

</environment>

前面的代碼段顯示了兩個塊,一個用于開發(fā),一個用于非開發(fā)。當(dāng)我們在開發(fā)時,我們托管 web 組件的 Angular 項目將運行于從 VS Code 啟動的 4200 端口。當(dāng)我們投入生產(chǎn)時,該 Angular 項目將被編譯到 wwwroot/apps/core 文件夾,并帶有附加哈希值命名的 javascript 文件。為了正確地引用這些文件,我們需要使用 asp-src-include 標(biāo)記助手。

接下來,在 _Layout.cshtml 中,在結(jié)束標(biāo)記后面直接添加。

測試我們的開發(fā)配置是否有用:

  • 轉(zhuǎn)到打開 Angular 項目的 VS Code,在終端提示符中輸入該命令:

復(fù)制代碼

ng serve --liveReload=false

  • 轉(zhuǎn)到打開 ASP.NET 項目的 Visual Studio,點擊 F5 鍵運行該項目。我們的 ASP.NET 站點應(yīng)該打開,并且,我們應(yīng)該看到在每個頁面上顯示的當(dāng)前時間組件。

創(chuàng)建 Angular 應(yīng)用程序

Web 組件很棒,也許是 web UI 的未來,但是,就今天來說,Angular 項目作為單個頁面應(yīng)用程序(Single Page Applications,簡稱 SPAs)引導(dǎo)仍有自己的生存空間。

Angular 是圍繞著模塊的概念設(shè)計的,它的一些特性,特別是路由,是與模塊而不是組件保持一致的。在混合 Angular 和 ASP.NET 開發(fā)時,我的目標(biāo)是在 MVC 視圖中托管 Angular 應(yīng)用程序。我希望 ASP.NET MVC 提供頂層菜單結(jié)構(gòu),SPA 提供它們自己的菜單和路由結(jié)構(gòu),這些都駐留在更大的 MVC 應(yīng)用程序中 。此外,我希望實現(xiàn)代碼重用,這些代碼可以在解決方案中的多個 SPAs 中共享,也可以作為 web 組件包含在非 Angular 頁面中。

第一步是在 Angular 中創(chuàng)建一個新的應(yīng)用程序。最簡單的實現(xiàn)方法是使用 Angular CLI(命令行接口)。如果還沒有這個,在 VS Code 中打開 Angular 項目,并啟動一個新的終端窗口。在終端窗口,執(zhí)行該命令:

復(fù)制代碼

ng g application App1 --routing=true

這將在配置了路由模塊的 Apps\projects\App1 下生成新的 Angular 應(yīng)用程序。讓我們生成兩個組件,并設(shè)置路由,這樣我們可以路由到某處去。從終端窗口執(zhí)行以下命令:

復(fù)制代碼

ng g c Page1 --project=App1


ng g c Page2 --project=App1

現(xiàn)在,我們應(yīng)該在 Apps/Projects/App1/src/app 下看到兩個新的組件文件夾 page1 和 page2。

現(xiàn)在,讓我們來為這些組件設(shè)置路由。把 Apps/Projects/App1/src/app 下的 app.component.html 改成具有這個標(biāo)記:

復(fù)制代碼

<h2>App1</h2>

<a routerLink="/page1" routerLinkActive="active">Page1</a>

<a routerLink="/page2" routerLinkActive="active">Page2</a>

<router-outlet></router-outlet>

并用以下代碼更新 Apps/projects/App1/src/app 下的 app-routing.module.ts:

復(fù)制代碼

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 { }

這只是標(biāo)準(zhǔn)的路由代碼。關(guān)于 Angular 路由的評論,請訪問該頁面。

現(xiàn)在,讓我們來測試我們的新應(yīng)用程序是否配置得正確。打開一個新的終端窗口,輸入以下命令:

復(fù)制代碼

ng serve App1 --port 4201 --open

我們的瀏覽器窗口應(yīng)該打開,我們應(yīng)該能看到類似以下的內(nèi)容:

請注意,現(xiàn)在我們在用端口 4201,和我們用于根 Angular 項目的不同。我們創(chuàng)建的每個應(yīng)用程序都將需要開發(fā)環(huán)境中一個不同的端口服務(wù)于它,但是,在非開發(fā)環(huán)境中,所有的應(yīng)用程序、ASP.NET 和 Angular 都將運行于同一個端口上。

現(xiàn)在,該演示的一個目標(biāo)是實現(xiàn)代碼重用。讓我們在 App1 中重用來自基礎(chǔ)項目的 Angular 組件。為了實現(xiàn)這個目標(biāo),要在 App1 的主模塊中包含 CurrentTimeComponent 的導(dǎo)入。

轉(zhuǎn)到 Apps/projects/App1/src/app 下的 app.modules.ts,添加以下導(dǎo)入語句:

復(fù)制代碼

import { CurrentTimeComponent } from '../../../../src/app/current-time/current-time.component';

這里正在發(fā)生的事是,我們從根項目中導(dǎo)入 CurrentTimeComponent。或者,我們可以從根項目中導(dǎo)入整個 AppModule。

接下來,把 CurrentTimeComponent 添加到聲明列表中:

復(fù)制代碼

declarations: [

AppComponent,

Page1Component,

Page2Component,

CurrentTimeComponent

],

現(xiàn)在,轉(zhuǎn)到 App1 中的 app.component.html,并為當(dāng)前時間添加標(biāo)簽,就添加在路由器出口的正下方。

復(fù)制代碼

<h2>App1</h2>

<a routerLink="/page1" routerLinkActive="active">Page1</a>

<a routerLink="/page2" routerLinkActive="active">Page2</a>

<router-outlet></router-outlet>

<app-current-time></app-current-time>

請注意,我們?yōu)檫@個組件使用了 Angular 標(biāo)簽(app-current-time),而不是 web 組件標(biāo)簽名(current-time)。原因是,我們把該組件作為 Angular 組件包含在內(nèi)了。App1 完全不知道這個 Angular 組件在其他地方用作 web 組件。

保存所有的文件并檢查瀏覽器。我們的 App1 頁面現(xiàn)在應(yīng)該顯示當(dāng)前時間組件。

把 App1 作為 SPA 集成到 ASP.NET MVC

在這個演練中,我們要做的最后一件事是,把 App1 作為單頁面應(yīng)用程序合并到 ASP.NET MVC 應(yīng)用程序 。我們希望有以下特性:

  • 該 SPA 應(yīng)該嵌入 MVC 視圖之一。

  • 其應(yīng)該可以深度鏈接到一個 SPA 中的頁面。

  • 應(yīng)該支持實時重新加載。

首先,讓我們在主控制器上(Home Controller)上設(shè)置一個名為 App1 的常規(guī) MVC 視圖。

在我們的 MVC 項目中,轉(zhuǎn)到 Controllers/HomeController.cs,并添加以下代碼:

復(fù)制代碼

[Route("app1/{*url}")]

public IActionResult App1(string url)

{

return View("App1", url);

}

這個在路由(Route)屬性中的{*url}構(gòu)造告訴 ASP.NET 捕獲在 url 變量中 /app1/ 段右側(cè)的一切內(nèi)容。然后,將其傳到 Angular 應(yīng)用程序。
現(xiàn)在,右鍵單擊 View() 令牌,然后選擇添加視圖。調(diào)用視圖 App1,并點擊 Add 按鈕。這應(yīng)該在 Views/Home 中創(chuàng)建一個名為 App1.cshtml 的文件。確保該文件有以下標(biāo)記:

復(fù)制代碼

@{

ViewData["Title"] = "App1";

}

This is the view for App1.

轉(zhuǎn)到 Shared/_Layout.cshtml,并給該視圖添加一個鏈接,就添加在到隱私(Privacy)視圖鏈接的下方。最簡單的方法是,復(fù)制這個隱私鏈接標(biāo)記,并用“App1”這個詞替換“Privacy”這個詞。

復(fù)制代碼

<ul class="navbar-nav flex-grow-1">

<li class="nav-item">

<a class="nav-link text-dark" asp-area="" asp-controller="Home"

asp-action="Index">Home</a>

</li>

<li class="nav-item">

<a class="nav-link text-dark" asp-area="" asp-controller="Home"

asp-action="Privacy">Privacy</a>

</li>

<li class="nav-item">

<a class="nav-link text-dark" asp-area="" asp-controller="Home"

asp-action="App1">App1</a>

</li>

</ul>

在 _Layout.cshtml 中時,讓我們多做一個更改。讓我們web 組件周圍添加一些標(biāo)記,以直觀地指明這是一個 web 組件而不是 Angular 組件。添加


和注釋就可以做到:

復(fù)制代碼

<div class="container">

<partial name="_CookieConsentPartial" />

<main role="main" class="pb-3">

@RenderBody()

</main>

<hr />

This is a web component<br />

<current-time></current-time>

</div>

接下來,我們來測試一下這個應(yīng)用程序。點擊 F5 鍵,確保可以通過 App1 鏈接跳轉(zhuǎn)到 App1 視圖。

下一步是把 App1 應(yīng)用程序嵌入 App1 MVC 視圖。我們準(zhǔn)備使用一個 iframe,它指向在同一個域的 URL。使用 iframe 的好處是可以把 App1 封裝在其自身的容器中,但也帶來兩個挑戰(zhàn):

  • iframe 需要動態(tài)地隨其內(nèi)容的變化而調(diào)整其大小。

  • 在用戶在 Angular 應(yīng)用程序中跳轉(zhuǎn)時,頂部窗口的地址欄必須改變。

我們將使用 JavaScript 來解決這兩個挑戰(zhàn)。因為 iframe 指向同一個域,所以,這是唯一可行的方法,從而避免了跨域限制。

但是,在我們這么做之前,我們?nèi)匀恍枰?NET 代碼中做更多的修改。

首先,我們在 Startup 中配置 App1。打開 Startup.cs,并把以下代碼添加到配置(Configure)方法中:

復(fù)制代碼

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 核心運行時,把應(yīng)用程序映射到 /apps/app1 路徑,以代理到開發(fā)中的端口 4201,并期望在非開發(fā)環(huán)境中的 wwwroot/apps/app1 可用編譯后的文件。

但是,我們不希望 /apps/app1 的用戶使用我們的應(yīng)用程序。我們希望我們的應(yīng)用程序在用戶轉(zhuǎn)到 App1 視圖時可用,App1 視圖可以是 /home/app1 或只是 /app1 URL。

這里是我們打算使用 iframe 的地方。打開 App1.cshtml,并添加以下標(biāo)記:

復(fù)制代碼

<iframe src="/apps/app1/@Model" class="app-container" frameborder="0" scrolling="no"></iframe>

請注意 @Model 構(gòu)造。它被映射到組件中的{*url},我們把路徑的一部分從頂部窗口傳到 App1 右側(cè)的 iframe,因此,路由在 Angular 應(yīng)用程序內(nèi)部進行。

現(xiàn)在,我們可以測試這個應(yīng)用程序了。轉(zhuǎn)到 VS Code,并從一個可用的終端窗口執(zhí)行以下 serve 命令:

ng serve App1 --port 4201 --servePath / --baseHref /apps/app1/ --publicHosthttp://localhost:4201

該命令在 4201 端口啟動 App1。由于我們知道準(zhǔn)備從 apps/app1 給它提供服務(wù),因此,它設(shè)置了基礎(chǔ) HREF,并且,它指示 Angular 使用 localhost:4201 而不是使用相對的 URL 進行實時重載。

轉(zhuǎn)到 Visual Studio,并點擊 F5 鍵。在 ASP.NET 站點出現(xiàn)在瀏覽器窗口后,轉(zhuǎn)到 App1 菜單。如果看到和下面類似的屏幕,那就意味著該應(yīng)用程序已經(jīng)正確地連接上了。

盡管 App1 Angular 應(yīng)用程序確實出現(xiàn)在 App1 視圖中,但是沒有內(nèi)容。如果點擊 Page 1 和 Page 2 的鏈接,可以看到在 Angluar 組件中跳轉(zhuǎn)是正常工作的,但是,在瀏覽器頂部的地址欄沒有反映出跳轉(zhuǎn)的當(dāng)前狀態(tài)。讓我們來解決這兩個問題。

為了在啟動時以及 iframe 的內(nèi)容有變化時調(diào)整 iframe 的大小,我們將使用名為 iFrame Resizer 的 JavaScript 組件,iFrame Resizer 是由?David Bradshaw?創(chuàng)建的。

為了讓該組件工作,我們需要執(zhí)行這三個步驟。

在 _Layout.cshtml 中,把以下腳本標(biāo)簽粘貼到指向 site.js 的腳本標(biāo)簽的正上方

復(fù)制代碼

<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.1.1/iframeResizer.min.js">

</script>

給位于 wwwroot/js 的 site.js 添加以下代碼行。

復(fù)制代碼

$('.app-container').iFrameResize({ heightCalculationMethod: 'documentElementOffset' });

接著,轉(zhuǎn)到 VS Code,并在結(jié)束標(biāo)簽的上方給位于 Apps/projects/App1/src 的 Index.html 添加以下腳本標(biāo)簽:

復(fù)制代碼

<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.1.1/iframeResizer.contentWindow.min.js">

</script>

保存所有的文件,我們來重新測試一下這個應(yīng)用程序。App1 現(xiàn)在應(yīng)該如下所示:

請注意,內(nèi)容不再消失了。iFrame Resizer 的這一點做得很不錯,在 iframe 初始加載后,它將不斷調(diào)整 iframe 的大小以適合內(nèi)容。

現(xiàn)在,我們來解決這個問題:當(dāng)點擊 Angular 路由器鏈接時,地址欄沒有更新。因為 App1 在 iframe 中運行,因此,地址欄沒有更新。iframe 的地址在改變,但是,我們看不到,原因是,我們看到的地址欄是用于頂部瀏覽器窗口的。

請記住,我們已經(jīng)有代碼可以捕捉 /app1 URL 段右側(cè)的路徑,并存入{*ulr}變量,再把它傳給 iframe。我們需要添加的代碼是另一個方式,當(dāng)路由在 Angular 應(yīng)用程序中進行時,我們希望把變化傳播到頂層地址欄。

我們需要把代碼添加到 App1 應(yīng)用程序中的路由模塊中來實現(xiàn)。

打開 Apps/projects/App1/src/app 中的 app-routing.module.ts。在 AppRouting Module 的構(gòu)造函數(shù)中添加以下代碼:

復(fù)制代碼

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 和當(dāng)前窗口的 HREF 來確定應(yīng)用程序是否在 iframe 中運行。如果應(yīng)用程序在 iframe 中運行,那么,代碼把頂部窗口的 HREF 保存在一個局部變量中,但是去掉了指向 /app1 段右側(cè)的 HREF 部分。然后,代碼進入 NavigationEnd 事件,并把路由過的 URL 追加到頂部窗口的 HREF 的后面。

我們還將需要給導(dǎo)入添加 Router 和 NavigationEnd。整個 app-routing.module.ts 應(yīng)該如下所示:

復(fù)制代碼

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);

}

}

});

}

}

為了測試該應(yīng)用程序,請從 Visual Studio 啟動它。點擊 Page 1 或 Page 2 的鏈接。觀察到頂部 URL 現(xiàn)在在變化。我們還可以復(fù)制修改過的 URL,并把它粘貼到一個獨立的窗口,App1 將路由到頂部 URL 中指定的組件。

調(diào)整發(fā)布(Publish)設(shè)置

還有最后一件事要做。我們需要修改項目文件,以將 Angular 構(gòu)建任務(wù)納入發(fā)布過程。為此,轉(zhuǎn)到 ASP.NET 項目,右鍵單擊項目文件,選擇 Edit?.csproj。項目文件應(yīng)該與如下所示的類似:

復(fù)制代碼

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>

<TargetFramework>netcoreapp3.0</TargetFramework>

<TypeScriptToolsVersion>3.3</TypeScriptToolsVersion>

<SpaRoot>Apps\</SpaRoot>

</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

<WarningLevel>0</WarningLevel>

</PropertyGroup>

<ItemGroup>

<Content Remove="$(SpaRoot)**" />

<None Remove="$(SpaRoot)**" />

<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />

</ItemGroup>

<ItemGroup>

<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.0.0" />

</ItemGroup>

<Target Name="PublishApps" AfterTargets="ComputeFilesToPublish">

<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />

<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod --outputPath=./dist/core" />

<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build App1 -- --prod --base-href=/apps/app1/ --outputPath=./dist/app1" />

<ItemGroup>

<DistFiles Include="$(SpaRoot)dist\**" />

<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">

<RelativePath>wwwroot\%(DistFiles.Identity)</RelativePath>

<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>

</ResolvedFileToPublish>

</ItemGroup>

</Target>

</Project>

這里有個有趣的部分,就是 Target 標(biāo)簽。我們指示構(gòu)建過程運行 npm 安裝,然后構(gòu)建兩個 Angular 項目,接著,復(fù)制 dist 文件夾輸出到 ASP.NET 站點的 wwwroot 文件夾。

為了測試我們的發(fā)布配置是否有用:

  • 在 Visual Studio 中右鍵單擊 ASP.NET 項目名稱。

  • 轉(zhuǎn)到 Publish。

  • 在選擇(Pick)一個發(fā)布目標(biāo)下,選擇文件夾(Folder)。

  • 點擊發(fā)布(Publish)按鈕。

在這個過程的最后,我們應(yīng)該看到在 Output 窗口中發(fā)布的新文件的文件夾的整個路徑。為了測試發(fā)布的站點:

  • 在命令窗口打開發(fā)布文件夾。

  • 輸入:dotnet?

    .dll
  • 轉(zhuǎn)到到我們的瀏覽器,打開 http://localhost:5000

結(jié)論

我們創(chuàng)建了一個 ASP.NET 站點,把兩個 Angular 項目與它集成在一起,并把 Angular 工件嵌入 MVC 視圖。如果我們想試用這個解決方案,建議從 GitHub 中克隆項目。嘗試添加 App2,并從不同的 MVC 視圖中為它提供服務(wù),或者嘗試創(chuàng)建更多的 web 組件。

作者介紹

30 年來,Evgueni Tsygankov 一直在編寫軟件,從 80 年代的 Commodore 64 一直到如今的云計算。目前,他在 Effita 領(lǐng)導(dǎo)其中的一支開發(fā)團隊,Effita 是總部在密蘇里州圣路易斯的一家軟件公司。在空閑的時候,Evgueni 把時間用于陪伴他的兩個孩子以及打冰球和踢足球。

總結(jié)

以上是生活随笔為你收集整理的深入研究 Angular 和 ASP.NET Core 3.0的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。