Použití služeb JavaScriptu k vytváření aplikací s jedním stránkou v ASP.NET Core
Jediná stránková aplikace (SPA) je oblíbeným typem webové aplikace z důvodu svého vlastního prostředí pro práci s uživateli. integrace architektur a knihoven SPA na straně klienta, jako je například Angular nebo React, s architekturami na straně serveru, jako je například ASP.NET Core, mohou být obtížné. Služba JavaScript Services byla vyvinuta za účelem snížení tření v procesu integrace. Umožňuje bezproblémovou operaci mezi různými serverovými a technologickými zásobníky pro klienty.
Upozornění
funkce popsané v tomto článku jsou zastaralé od ASP.NET Core 3,0. v balíčku Microsoft. AspNetCore. SpaServices. extensions NuGet je k dispozici jednodušší mechanismus pro integraci rozhraní SPA. Další informace najdete v tématech [oznámení] obsoleting Microsoft. AspNetCore. SpaServices a Microsoft. AspNetCore. NodeServices.
Co je JavaScript Services
Služba JavaScript Services je kolekce technologií na straně klienta pro ASP.NET Core. jeho cílem je umístit ASP.NET Core jako preferovanou platformu na straně serveru vývojářů pro sestavování jednostránkové.
služby javascriptu se skládají ze dvou různých NuGet balíčků:
- Microsoft. AspNetCore. NodeServices (NodeServices)
- Microsoft. AspNetCore. SpaServices (SpaServices)
Tyto balíčky jsou užitečné v následujících scénářích:
- Spuštění JavaScriptu na serveru
- Použití architektury nebo knihovny SPA
- Sestavení prostředků na straně klienta pomocí webpacku
Většina zaměření v tomto článku je umístěna na používání balíčku SpaServices.
Co je SpaServices
SpaServices byl vytvořen tak, aby bylo možné umístit ASP.NET Core jako preferovanou platformu na straně serveru vývojářů pro stavební jednostránkové. SpaServices se nevyžaduje k vývoji jednostránkové s ASP.NET Core a nezamkne vývojáře do konkrétního klientského rozhraní.
SpaServices poskytuje užitečnou infrastrukturu, jako je:
- Předběžné vykreslování na straně serveru
- Middleware pro vývoj pro Webpack
- Výměna horkého modulu
- Helpdesky směrování
Souhrnně tyto komponenty infrastruktury rozšiřují pracovní postup vývoje i prostředí za běhu. Komponenty lze jednotlivě přijmout.
Předpoklady pro použití SpaServices
Pokud chcete pracovat s SpaServices, nainstalujte následující:
Node.js (verze 6 nebo novější) s npm
Chcete-li ověřit, zda jsou tyto součásti nainstalovány a lze je najít, spusťte následující příkaz z příkazového řádku:
node -v && npm -vPokud nasazujete na web Azure, není nutná žádná akce —Node.js je nainstalována a k dispozici v prostředích serveru.
-
.NET Core SDK verze 2.0 nebo novější
- v případě Windows s využitím Visual Studio 2017 se sada SDK nainstaluje tak, že vyberete úlohu vývoje pro různé platformy .net Core .
balíček Microsoft. AspNetCore. SpaServices NuGet
Předběžné vykreslování na straně serveru
Univerzální (označovaná také jako isomorphic) aplikace je JavaScriptová aplikace schopná běžet na serveru i v klientovi. Angular, React a další oblíbená rozhraní poskytují univerzální platformu pro tento styl vývoje aplikace. Nápad je nejprve vykreslovat komponenty architektury na serveru přes Node.js a poté delegovat další provádění na klienta.
ASP.NET Core pomocníků značek , které poskytuje SpaServices, zjednoduší implementaci předvykreslování na straně serveru vyvoláním funkcí javascriptu na serveru.
Požadavky na předběžné vykreslování na straně serveru
Nainstalujte balíček npm s předvykreslováním ASPNET :
npm i -S aspnet-prerendering
Konfigurace předvykreslování na straně serveru
Pomocníky značek jsou v souboru _ViewImports. cshtml projektu Zjistitelnější prostřednictvím registrace oboru názvů:
@using SpaServicesSampleApp
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
@addTagHelper "*, Microsoft.AspNetCore.SpaServices"
Tyto značky pomocníka složitými rozhranímiy, které jsou v zobrazení k dispozici při přímé komunikaci s rozhraními API nízké úrovně pomocí syntaxe podobné HTML Razor .
<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
ASP-PreRender-pomocník značek modulu
asp-prerender-modulePomocník značek použitý v předchozím příkladu kódu spouští clientapp/dist/main-server.js na serveru přes Node.js. V zájmu srozumitelnosti je main-server.js soubor artefaktem úlohy TypeScript-to-JavaScript transpilation v procesu sestavení pro sadu Webpack . Webpack definuje alias vstupního bodu main-server pro. a přechod grafu závislostí pro tento alias začíná v souboru clientapp/boot-server. TS :
entry: { 'main-server': './ClientApp/boot-server.ts' },
v následujícím příkladu Angular soubor ClientApp/boot-server. ts používá createServerRenderer funkci a RenderResult typ aspnet-prerendering balíčku npm ke konfiguraci vykreslování serveru prostřednictvím Node.js. Označení HTML určené pro vykreslování na straně serveru je předáno volání funkce přeložit, které je zabaleno do silně typovaného Promise objektu JavaScriptu. PromiseHodnota významnosti objektu je, že asynchronně poskytuje kód HTML na stránce pro vložení do elementu zástupného prvku modelu DOM.
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
export default createServerRenderer(params => {
const providers = [
{ provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
{ provide: 'ORIGIN_URL', useValue: params.origin }
];
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
const appRef = moduleRef.injector.get(ApplicationRef);
const state = moduleRef.injector.get(PlatformState);
const zone = moduleRef.injector.get(NgZone);
return new Promise<RenderResult>((resolve, reject) => {
zone.onError.subscribe(errorInfo => reject(errorInfo));
appRef.isStable.first(isStable => isStable).subscribe(() => {
// Because 'onStable' fires before 'onError', we have to delay slightly before
// completing the request in case there's an error to report
setImmediate(() => {
resolve({
html: state.renderToString()
});
moduleRef.destroy();
});
});
});
});
});
ASP-PreRender-Pomocník s datovou značkou
Při spojení s asp-prerender-module pomocníkem značek asp-prerender-data lze pomoc pomocí značky použít k předání kontextových informací ze Razor zobrazení na straně serveru JavaScript. Například následující kód předává uživatelská data do main-server modulu:
<app asp-prerender-module="ClientApp/dist/main-server"
asp-prerender-data='new {
UserName = "John Doe"
}'>Loading...</app>
Přijatý UserName argument je serializován pomocí integrovaného serializátoru JSON a je uložen v params.data objektu. v následujícím příkladu Angular se data používají k sestavení vlastního pozdravu v rámci h1 elementu:
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
export default createServerRenderer(params => {
const providers = [
{ provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
{ provide: 'ORIGIN_URL', useValue: params.origin }
];
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
const appRef = moduleRef.injector.get(ApplicationRef);
const state = moduleRef.injector.get(PlatformState);
const zone = moduleRef.injector.get(NgZone);
return new Promise<RenderResult>((resolve, reject) => {
const result = `<h1>Hello, ${params.data.userName}</h1>`;
zone.onError.subscribe(errorInfo => reject(errorInfo));
appRef.isStable.first(isStable => isStable).subscribe(() => {
// Because 'onStable' fires before 'onError', we have to delay slightly before
// completing the request in case there's an error to report
setImmediate(() => {
resolve({
html: result
});
moduleRef.destroy();
});
});
});
});
});
Názvy vlastností předané v Pomocníkech značek jsou reprezentovány PascalCase Notation. Na rozdíl od jazyka JavaScript, kde jsou stejné názvy vlastností, které jsou reprezentovány s CamelCase. Výchozí konfigurace serializace JSON zodpovídá za tento rozdíl.
Pro rozšíření na předchozí příklad kódu mohou být data předána ze serveru do zobrazení tím, že se dobalí globals vlastnost poskytnutá resolve funkci:
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
export default createServerRenderer(params => {
const providers = [
{ provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
{ provide: 'ORIGIN_URL', useValue: params.origin }
];
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
const appRef = moduleRef.injector.get(ApplicationRef);
const state = moduleRef.injector.get(PlatformState);
const zone = moduleRef.injector.get(NgZone);
return new Promise<RenderResult>((resolve, reject) => {
const result = `<h1>Hello, ${params.data.userName}</h1>`;
zone.onError.subscribe(errorInfo => reject(errorInfo));
appRef.isStable.first(isStable => isStable).subscribe(() => {
// Because 'onStable' fires before 'onError', we have to delay slightly before
// completing the request in case there's an error to report
setImmediate(() => {
resolve({
html: result,
globals: {
postList: [
'Introduction to ASP.NET Core',
'Making apps with Angular and ASP.NET Core'
]
}
});
moduleRef.destroy();
});
});
});
});
});
postListPole definované uvnitř globals objektu je připojeno k globálnímu window objektu prohlížeče. Tato proměnná výtahem do globálního rozsahu eliminuje duplicity, zejména v případě, že se týká načítání stejných dat na serveru a znovu v klientovi.

Middleware pro vývoj pro Webpack
Middleware pro vývoj pro Webpack zavádí zjednodušený vývojový pracovní postup, který v sadě Webpack vytváří prostředky na vyžádání. Middleware automaticky zkompiluje a zachová prostředky na straně klienta při opětovném načtení stránky v prohlížeči. Alternativním přístupem je ruční vyvolání sady Webpack prostřednictvím skriptu sestavení npm projektu, když se změní závislost třetí strany nebo vlastní kód. V následujícím příkladu je zobrazen skript sestavení npm v souboru Package. JSON :
"build": "npm run build:vendor && npm run build:custom",
Požadavky na middleware pro vývoj pro Webpack
Instalace balíčku ASPNET-Webpack npm:
npm i -D aspnet-webpack
Konfigurace pro vývoj middlewaru pro Webpack
Middleware pro vývoj v sadě Webpack je zaregistrovaný do kanálu požadavků HTTP prostřednictvím následujícího kódu v metodě souboru Startup. cs Configure :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
// Call UseWebpackDevMiddleware before UseStaticFiles
app.UseStaticFiles();
UseWebpackDevMiddlewarePřed registrací statického souboru hostujícího prostřednictvím metody rozšíření je nutné volat metodu rozšíření UseStaticFiles . Z bezpečnostních důvodů Zaregistrujte middleware pouze v případě, že aplikace běží v režimu vývoje.
Vlastnost souboru webpack.config.js dává output.publicPath middlewaru pokyn, aby ve dist složce sledoval změny:
module.exports = (env) => {
output: {
filename: '[name].js',
publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
Výměna horkého modulu
Zamyslete se nad funkcí HMR ( Hot Module nahradilo ) sady Webpack jako vývoj middlewaru pro vývoj pro Webpack. HMR zavádí všechny stejné výhody, ale ještě více zjednodušuje pracovní postup vývoje díky automatické aktualizaci obsahu stránky po zkompilování změn. Nepleťte si to s aktualizací prohlížeče, což by vedlo ke konfliktu s aktuálním stavem v paměti a relacemi ladění zabezpečeného hesla. Mezi službou Webpack dev middleware a prohlížečem existuje živý odkaz, který znamená, že se do prohlížeče dostanou změny.
Požadavky na nahrazení horkého modulu
Nainstalujte balíček Webpack – Hot-middleware npm:
npm i -D webpack-hot-middleware
Konfigurace nahrazení horkého modulu
Komponenta HMR musí být zaregistrovaná do kanálu požadavků HTTP MVC v Configure metodě:
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
HotModuleReplacement = true
});
Stejně jako u rozhraní Webpack dev middleware UseWebpackDevMiddleware musí být metoda rozšíření volána před UseStaticFiles metodou rozšíření. Z bezpečnostních důvodů Zaregistrujte middleware pouze v případě, že aplikace běží v režimu vývoje.
webpack.config.js soubor musí definovat plugins pole, i když je ponecháno prázdné:
module.exports = (env) => {
plugins: [new CheckerPlugin()]
Po načtení aplikace v prohlížeči se na kartě konzola nástroje pro vývojáře zobrazí potvrzení aktivace HMR:

Helpdesky směrování
ve většině ASP.NET Core jednostránkové na straně klienta je často žádoucí směrování na straně klienta kromě směrování na straně serveru. Systémy směrování SPA a MVC můžou pracovat nezávisle bez rušivých zásahů. Existuje ale jeden hraniční případ s výzvami k identifikaci 404 odpovědí HTTP.
Vezměte v úvahu scénář, ve kterém se používá trasa s příponou /some/page . Předpokládat, že požadavek neodpovídá vzorové trase na straně serveru, ale jeho vzor odpovídá trase na straně klienta. Teď zvažte příchozí požadavek na , který obecně očekává, že na serveru najde /images/user-512.png soubor obrázku. Pokud požadovaná cesta k prostředku neodpovídá žádné trase na straně serveru ani statickému souboru, je nepravděpodobné, že by klientská aplikace obvykle vrátila stavový kód — HTTP 404.
Požadavky na pomocníky směrování
Nainstalujte balíček npm pro směrování na straně klienta. Použití Angular jako příkladu:
npm i -S @angular/router
Konfigurace pomocníků směrování
V metodě MapSpaFallbackRoute se používá rozšiřující metoda s názvem Configure :
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
Trasy se vyhodnocují v pořadí, ve kterém jsou nakonfigurované. V důsledku toho default se trasa v předchozím příkladu kódu použije jako první pro porovnávání vzorů.
Vytvoření nového projektu
Služby Jazyka JavaScript poskytují předem nakonfigurované šablony aplikací. SpaServices se v těchto šablonách používá ve spojení s různými rozhraními a knihovnami, jako jsou Angular, React a Redux.
Tyto šablony je možné nainstalovat prostřednictvím .NET Core CLI spuštěním následujícího příkazu:
dotnet new --install Microsoft.AspNetCore.SpaTemplates::*
Zobrazí se seznam dostupných šablon SPA:
| Šablony | Krátký název | Jazyk | Značky |
|---|---|---|---|
| MVC ASP.NET Core s Angular | Úhlové | [C#] | Web/MVC/SPA |
| MVC ASP.NET Core s React.js | react | [C#] | Web/MVC/SPA |
| MVC ASP.NET Core s React.js a Reduxem | reactredux | [C#] | Web/MVC/SPA |
Pokud chcete vytvořit nový projekt pomocí jedné ze šablon SPA, zahrnete krátký název šablony do příkazu dotnet new. Následující příkaz vytvoří novou Angular s ASP.NET Core MVC nakonfigurovanou pro stranu serveru:
dotnet new angular
Nastavení režimu konfigurace modulu runtime
Existují dva primární režimy konfigurace modulu runtime:
- Vývoj:
- Obsahuje zdrojové mapy pro usnadnění ladění.
- Optimalizuje výkon kódu na straně klienta.
- Production (Produkční):
- Vyloučí zdrojové mapy.
- Optimalizuje kód na straně klienta prostřednictvím sdružování a minifikace.
ASP.NET Core používá proměnnou prostředí s názvem ASPNETCORE_ENVIRONMENT k uložení režimu konfigurace. Další informace najdete v tématu Nastavení prostředí.
Spuštění s .NET Core CLI
Obnovte požadované NuGet a npm spuštěním následujícího příkazu v kořenovém adresáři projektu:
dotnet restore && npm i
Sestavte a spusťte aplikaci:
dotnet run
Aplikace se spustí na místním hostiteli podle režimu konfigurace modulu runtime. Když v prohlížeči http://localhost:5000 přejdete na , zobrazí se úvodní stránka.
Spuštění s Visual Studio 2017
Otevřete soubor .csproj vygenerovaný příkazem dotnet new. Požadované balíčky NuGet a npm se při otevření projektu automaticky obnoví. Tento proces obnovení může trvat až několik minut a po dokončení je aplikace připravená ke spuštění. Klikněte na zelené tlačítko spuštění nebo stiskněte a prohlížeč se otevře na Ctrl + F5 cílové stránce aplikace. Aplikace běží na místním hostiteli podle režimu konfigurace modulu runtime.
Otestování aplikace
Šablony SpaServices jsou předem nakonfigurované tak, aby spouštěl testy na straně klienta pomocí Karma a Jasmine. Jasmine je oblíbená rozhraní pro testování jednotek pro JavaScript, kdežto Karma je spouštěče testů pro tyto testy. Karma je nakonfigurovaný tak, aby pracoval s vývojový middleware Webpack tak, aby vývojář při každém provedení změn nebyl nutný k zastavení a spuštění testu. Ať už se jedná o kód spuštěný proti testovacímu případu, nebo samotný testovací případ, test se spustí automaticky.
Při použití Angular příkladu jsou v souboru CounterComponent counter.component.spec.ts dva testovací případy Jasmine:
it('should display a title', async(() => {
const titleText = fixture.nativeElement.querySelector('h1').textContent;
expect(titleText).toEqual('Counter');
}));
it('should start with count 0, then increments by 1 when clicked', async(() => {
const countElement = fixture.nativeElement.querySelector('strong');
expect(countElement.textContent).toEqual('0');
const incrementButton = fixture.nativeElement.querySelector('button');
incrementButton.click();
fixture.detectChanges();
expect(countElement.textContent).toEqual('1');
}));
Otevřete příkazový řádek v adresáři ClientApp. Spusťte následující příkaz:
npm test
Skript spustí spouštěč testů Karma, který načte nastavení definovaná v karma.conf.js souboru. Kromě jiných nastavení identifikuje karma.conf.js testovací soubory, které se budou provádět prostřednictvím svého files pole:
module.exports = function (config) {
config.set({
files: [
'../../wwwroot/dist/vendor.js',
'./boot-tests.ts'
],
Publikování aplikace
Další informace o GitHub v Azure najdete v tomto článku.
Kombinace vygenerovaných prostředků na straně klienta a publikovaných artefaktů ASP.NET Core do balíčku připraveného k nasazení může být těžkopádná. SpaServices naštěstí orchestruje celý proces publikování s vlastním cílem MSBuild názvem RunWebpack :
<Target Name="RunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec Command="npm install" />
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" />
<Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="wwwroot\dist\**; ClientApp\dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
Cíl MSBuild má následující zodpovědnosti:
- Obnovte balíčky npm.
- Vytvořte sestavení prostředků třetích stran na straně klienta v produkčním prostředí.
- Vytvořte sestavení vlastních prostředků na straně klienta na produkční úrovni.
- Zkopírujte prostředky vygenerované webpackem do složky publish.
Cíl MSBuild se vyvolá při spuštění:
dotnet publish -c Release