Utiliser le modèle de projet Angular avec ASP.NET CoreUse the Angular project template with ASP.NET Core

Note

Cette documentation ne concerne pas le modèle de projet Angular inclus dans ASP.NET Core 2.0.This documentation isn't about the Angular project template included in ASP.NET Core 2.0. Elle traite du nouveau modèle Angular que vous pouvez mettre à jour manuellement.It's about the newer Angular template to which you can update manually. Par défaut, le modèle est inclus dans ASP.NET Core 2.1.The template is included in ASP.NET Core 2.1 by default.

Le modèle de projet Angular mis à jour fournit un point de départ pratique pour les applications ASP.NET Core utilisant Angular et la CLI Angular pour implémenter une interface utilisateur (IU) côté client enrichie.The updated Angular project template provides a convenient starting point for ASP.NET Core apps using Angular and the Angular CLI to implement a rich, client-side user interface (UI).

Le modèle est équivalent à la création d’un projet ASP.NET Core en tant que back-end d’API et d’un projet CLI Angular en tant qu’interface utilisateur.The template is equivalent to creating an ASP.NET Core project to act as an API backend and an Angular CLI project to act as a UI. Le modèle offre l’avantage d’héberger les deux types de projets dans un projet d’application unique.The template offers the convenience of hosting both project types in a single app project. Par conséquent, le projet d’application peut être généré et publié sous la forme d’une unité unique.Consequently, the app project can be built and published as a single unit.

Créer une applicationCreate a new app

Si vous utilisez ASP.NET Core 2.0, vérifiez que vous avez installé le modèle de projet Angular mis à jour.If using ASP.NET Core 2.0, ensure you've installed the updated Angular project template. Si vous avez ASP.NET Core 2.1, vous n’avez pas besoin de l’installer.If you have ASP.NET Core 2.1, there's no need to install it.

Créez un projet à partir d’une invite de commandes à l’aide de la commande dotnet new angular dans un répertoire vide.Create a new project from a command prompt using the command dotnet new angular in an empty directory. Par exemple, les commandes suivantes créent l’application dans un répertoire my-new-app et basculent vers ce répertoire :For example, the following commands create the app in a my-new-app directory and switch to that directory:

dotnet new angular -o my-new-app
cd my-new-app

Exécutez l’application à partir de Visual Studio ou de CLI .NET Core :Run the app from either Visual Studio or the .NET Core CLI:

Ouvrez le fichier .csproj généré, puis exécutez l’application normalement à partir de là.Open the generated .csproj file, and run the app as normal from there.

Le processus de génération restaure les dépendances npm à la première exécution, ce qui peut prendre plusieurs minutes.The build process restores npm dependencies on the first run, which can take several minutes. Les générations suivantes sont beaucoup plus rapides.Subsequent builds are much faster.

Le modèle de projet crée une application ASP.NET Core et une application Angular.The project template creates an ASP.NET Core app and an Angular app. L’application ASP.NET Core est destinée à être utilisée pour tous les aspects liés au serveur, tels que l’accès aux données et l’autorisation.The ASP.NET Core app is intended to be used for data access, authorization, and other server-side concerns. L’application Angular, qui réside dans le sous-répertoire ClientApp, est destinée à être utilisée pour tout ce qui touche l’interface utilisateur.The Angular app, residing in the ClientApp subdirectory, is intended to be used for all UI concerns.

Ajouter des pages, des images, des styles, des modules, etc.Add pages, images, styles, modules, etc.

Le répertoire ClientApp contient une application CLI Angular standard.The ClientApp directory contains a standard Angular CLI app. Pour plus d’informations, consultez la documentation Angular officielle.See the official Angular documentation for more information.

Il existe de légères différences entre l’application Angular créée par ce modèle et celle créée par la CLI Angular (via ng new) ; toutefois, les fonctionnalités de l’application sont identiques.There are slight differences between the Angular app created by this template and the one created by Angular CLI itself (via ng new); however, the app's capabilities are unchanged. L’application créée par le modèle contient une mise en page basée sur Bootstrap et un exemple de routage de base.The app created by the template contains a Bootstrap-based layout and a basic routing example.

Exécuter des commandes ngRun ng commands

Dans une invite de commandes, basculez vers le sous-répertoire ClientApp :In a command prompt, switch to the ClientApp subdirectory:

cd ClientApp

Si l’outil ng est installé de manière globale, vous pouvez exécuter n’importe laquelle de ses commandes.If you have the ng tool installed globally, you can run any of its commands. Par exemple, vous pouvez exécuter ng lint, ng test ou toute autre commande CLI Angular.For example, you can run ng lint, ng test, or any of the other Angular CLI commands. Mais il est inutile d’exécuter ng serve, car votre application ASP.NET Core se charge de traiter les parties côté serveur et côté client de votre application.There's no need to run ng serve though, because your ASP.NET Core app deals with serving both server-side and client-side parts of your app. En interne, elle utilise ng serve dans le développement.Internally, it uses ng serve in development.

Si l’outil ng n’est pas installé, exécutez npm run ng à la place.If you don't have the ng tool installed, run npm run ng instead. Par exemple, vous pouvez exécuter npm run ng lint ou npm run ng test.For example, you can run npm run ng lint or npm run ng test.

Installer des packages npmInstall npm packages

Pour installer des packages npm tiers, utilisez une invite de commandes dans le sous-répertoire ClientApp.To install third-party npm packages, use a command prompt in the ClientApp subdirectory. Exemple :For example:

cd ClientApp
npm install --save <package_name>

Publier et déployerPublish and deploy

Pendant le développement, l’application s’exécute en mode optimisé pour des raisons pratiques.In development, the app runs in a mode optimized for developer convenience. Par exemple, les bundles JavaScript incluent des mappages de sources (ce qui vous permet de voir votre code TypeScript d’origine pendant le débogage).For example, JavaScript bundles include source maps (so that when debugging, you can see your original TypeScript code). L’application se recompile et se recharge automatiquement en cas de modification des fichiers TypeScript, HTML et CSS sur le disque.The app watches for TypeScript, HTML, and CSS file changes on disk and automatically recompiles and reloads when it sees those files change.

Dans un environnement de production, fournissez une version de votre application qui est optimisée pour les performances.In production, serve a version of your app that's optimized for performance. Ce comportement est configuré pour se produire automatiquement.This is configured to happen automatically. Quand vous publiez, la configuration de build émet une build compilée AoT (Ahead-of-Time) réduite de votre code côté client.When you publish, the build configuration emits a minified, ahead-of-time (AoT) compiled build of your client-side code. Contrairement à la build de développement, la build de production ne requiert pas que Node.js soit installé sur le serveur (sauf si vous avez activé le préaffichage côté serveur).Unlike the development build, the production build doesn't require Node.js to be installed on the server (unless you have enabled server-side prerendering).

Vous pouvez utiliser des méthodes d’hébergement et de déploiement ASP.NET Core standard.You can use standard ASP.NET Core hosting and deployment methods.

Exécuter « ng serve » indépendammentRun "ng serve" independently

Le projet est configuré pour démarrer sa propre instance du serveur CLI Angular en arrière-plan quand l’application ASP.NET Core démarre en mode de développement.The project is configured to start its own instance of the Angular CLI server in the background when the ASP.NET Core app starts in development mode. Ainsi, vous n’êtes pas obligé d’exécuter un serveur distinct manuellement.This is convenient because you don't have to run a separate server manually.

Cette configuration par défaut présente un inconvénient.There's a drawback to this default setup. Chaque fois que vous modifiez votre code C# et que votre application ASP.NET Core doit redémarrer, le serveur CLI Angular redémarre.Each time you modify your C# code and your ASP.NET Core app needs to restart, the Angular CLI server restarts. Environ 10 secondes sont requises pour démarrer la sauvegarde.Around 10 seconds is required to start back up. Si vous apportez des modifications fréquentes au code C# et que vous ne souhaitez pas attendre que la CLI Angular redémarre, exécutez le serveur CLI Angular en externe, indépendamment du processus ASP.NET Core.If you're making frequent C# code edits and don't want to wait for Angular CLI to restart, run the Angular CLI server externally, independently of the ASP.NET Core process. Pour ce faire :To do so:

  1. Dans une invite de commandes, basculez vers le sous-répertoire ClientApp et lancez le serveur de développement CLI Angular :In a command prompt, switch to the ClientApp subdirectory, and launch the Angular CLI development server:

    cd ClientApp
    npm start
    

    Important

    Utilisez npm start pour lancer le serveur de développement CLI Angular, et non ng serve, de sorte que la configuration dans package.json soit respectée.Use npm start to launch the Angular CLI development server, not ng serve, so that the configuration in package.json is respected. Pour transmettre des paramètres supplémentaires au serveur CLI Angular, ajoutez-les à la ligne scripts pertinente dans votre fichier package.json.To pass additional parameters to the Angular CLI server, add them to the relevant scripts line in your package.json file.

  2. Modifiez votre application ASP.NET Core afin qu’elle utilise l’instance CLI Angular externe au lieu de lancer une instance propre.Modify your ASP.NET Core app to use the external Angular CLI instance instead of launching one of its own. Dans votre classe Startup, remplacez l’appel spa.UseAngularCliServer par ce qui suit :In your Startup class, replace the spa.UseAngularCliServer invocation with the following:

    spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
    

Quand vous démarrez votre application ASP.NET Core, elle ne lance pas un serveur CLI Angular.When you start your ASP.NET Core app, it won't launch an Angular CLI server. L’instance que vous avez démarrée manuellement est utilisée à la place.The instance you started manually is used instead. Cela lui permet de démarrer et de redémarrer plus rapidement.This enables it to start and restart faster. Elle n’attend plus que votre CLI Angular regénère votre application cliente à chaque fois.It's no longer waiting for Angular CLI to rebuild your client app each time.

Rendu côté serveurServer-side rendering

En tant que fonctionnalité de performances, vous pouvez choisir de préafficher votre application Angular sur le serveur et de l’exécuter sur le client.As a performance feature, you can choose to pre-render your Angular app on the server as well as running it on the client. Cela signifie que les navigateurs reçoivent le balisage HTML qui représente l’interface utilisateur initiale de votre application, qu’ils affichent avant même de télécharger et d’exécuter vos bundles JavaScript.This means that browsers receive HTML markup representing your app's initial UI, so they display it even before downloading and executing your JavaScript bundles. La plupart de cette implémentation provient d’une fonctionnalité Angular appelée Angular Universal.Most of the implementation of this comes from an Angular feature called Angular Universal.

Conseil

L’activation du rendu côté serveur (SSR) présente un nombre de complications supplémentaires à la fois au cours du développement et du déploiement.Enabling server-side rendering (SSR) introduces a number of extra complications both during development and deployment. Lisez les inconvénients du SSR pour déterminer si le SSR est adapté à vos besoins.Read drawbacks of SSR to determine if SSR is a good fit for your requirements.

Pour activer le SSR, vous devez effectuer un certain nombre d’ajouts à votre projet.To enable SSR, you need to make a number of additions to your project.

Dans la classe Démarrer, après la ligne qui configure spa.Options.SourcePath et avant l’appel à UseAngularCliServer ou UseProxyToSpaDevelopmentServer, ajoutez ce qui suit :In the Startup class, after the line that configures spa.Options.SourcePath, and before the call to UseAngularCliServer or UseProxyToSpaDevelopmentServer, add the following:

app.UseSpa(spa =>
{
    spa.Options.SourcePath = "ClientApp";

    spa.UseSpaPrerendering(options =>
    {
        options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.bundle.js";
        options.BootModuleBuilder = env.IsDevelopment()
            ? new AngularCliBuilder(npmScript: "build:ssr")
            : null;
        options.ExcludeUrls = new[] { "/sockjs-node" };
    });

    if (env.IsDevelopment())
    {
        spa.UseAngularCliServer(npmScript: "start");
    }
});

En mode de développement, ce code tente de générer le bundle SSR en exécutant le script build:ssr, qui est défini dans ClientApp\package.json.In development mode, this code attempts to build the SSR bundle by running the script build:ssr, which is defined in ClientApp\package.json. Cette opération génère une application Angular nommée ssr, qui n’est pas encore définie.This builds an Angular app named ssr, which isn't yet defined.

À la fin du tableau apps dans ClientApp/.angular-cli.json, définissez une application supplémentaire nommée ssr.At the end of the apps array in ClientApp/.angular-cli.json, define an extra app with name ssr. Utilisez les options suivantes :Use the following options:

{
  "name": "ssr",
  "root": "src",
  "outDir": "dist-server",
  "assets": [
    "assets"
  ],
  "main": "main.server.ts",
  "tsconfig": "tsconfig.server.json",
  "prefix": "app",
  "scripts": [],
  "environmentSource": "environments/environment.ts",
  "environments": {
    "dev": "environments/environment.ts",
    "prod": "environments/environment.prod.ts"
  },
  "platform": "server"
}

Cette nouvelle configuration d’application SSR requiert deux fichiers supplémentaires : tsconfig.server.json et main.server.ts.This new SSR-enabled app configuration requires two further files: tsconfig.server.json and main.server.ts. Le fichier tsconfig.server.json spécifie les options de compilation TypeScript.The tsconfig.server.json file specifies TypeScript compilation options. Le fichier main.server.ts sert de point d’entrée du code pendant le rendu côté serveur.The main.server.ts file serves as the code entry point during SSR.

Ajoutez un nouveau fichier appelé tsconfig.server.json à l’intérieur de ClientApp/src (avec le fichier tsconfig.app.json existant), qui contient les éléments suivants :Add a new file called tsconfig.server.json inside ClientApp/src (alongside the existing tsconfig.app.json), containing the following:

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
      "baseUrl": "./",
      "module": "commonjs"
    },
    "angularCompilerOptions": {
      "entryModule": "app/app.server.module#AppServerModule"
    }
}

Ce fichier configure le compilateur AoT d’Angular pour rechercher un module appelé app.server.module.This file configures Angular's AoT compiler to look for a module called app.server.module. Ajoutez ceci en créant un nouveau fichier dans ClientApp/src/app/app.server.module.ts (avec l’élément app.module.ts existant) qui contient les éléments suivants :Add this by creating a new file at ClientApp/src/app/app.server.module.ts (alongside the existing app.module.ts) containing the following:

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
import { AppComponent } from './app.component';
import { AppModule } from './app.module';

@NgModule({
    imports: [AppModule, ServerModule, ModuleMapLoaderModule],
    bootstrap: [AppComponent]
})
export class AppServerModule { }

Ce module hérite de votre app.module côté client et définit quels modules Angular supplémentaires sont disponibles au cours du SSR.This module inherits from your client-side app.module and defines which extra Angular modules are available during SSR.

N’oubliez pas que la nouvelle entrée ssr dans .angular-cli.json faisait référence à un fichier de point d’entrée appelé main.server.ts.Recall that the new ssr entry in .angular-cli.json referenced an entry point file called main.server.ts. Vous n’avez pas encore ajouté ce fichier et il est maintenant temps de le faire.You haven't yet added that file, and now is time to do so. Créez un nouveau fichier dans ClientApp/src/main.server.ts (avec l’élément main.ts existant), qui contient les éléments suivants :Create a new file at ClientApp/src/main.server.ts (alongside the existing main.ts), containing the following:

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModule, renderModuleFactory } from '@angular/platform-server';
import { APP_BASE_HREF } from '@angular/common';
import { enableProdMode } from '@angular/core';
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { createServerRenderer } from 'aspnet-prerendering';
export { AppServerModule } from './app/app.server.module';

enableProdMode();

export default createServerRenderer(params => {
  const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;
 
  const options = {
    document: params.data.originalHtml,
    url: params.url,
    extraProviders: [
      provideModuleMap(LAZY_MODULE_MAP),
      { provide: APP_BASE_HREF, useValue: params.baseUrl },
      { provide: 'BASE_URL', useValue: params.origin + params.baseUrl }
    ]
  };

  const renderPromise = AppServerModuleNgFactory
    ? /* AoT */ renderModuleFactory(AppServerModuleNgFactory, options)
    : /* dev */ renderModule(AppServerModule, options);
    
  return renderPromise.then(html => ({ html }));
});

ASP.NET Core exécute le code de ce fichier pour chaque requête lorsqu’il exécute l’intergiciel UseSpaPrerendering (middleware) que vous avez ajouté à la classe Démarrer.This file's code is what ASP.NET Core executes for each request when it runs the UseSpaPrerendering middleware that you added to the Startup class. Il gère la réception de params à partir du code .NET (par exemple, l’URL demandée) et les appels aux API SSR Angular pour obtenir le code HTML résultant.It deals with receiving params from the .NET code (such as the URL being requested), and making calls to Angular SSR APIs to get the resulting HTML.

À proprement parler, cela suffit pour activer SSR en mode de développement.Strictly-speaking, this is sufficient to enable SSR in development mode. Il est primordial d’effectuer une modification finale afin que votre application fonctionne correctement lors de sa publication.It's essential to make one final change so that your app works correctly when published. Dans le fichier .csproj principal de votre application, définissez la propriété  BuildServerSideRenderer sur true :In your app's main .csproj file, set the BuildServerSideRenderer property value to true:

<!-- Set this to true if you enable server-side prerendering -->
<BuildServerSideRenderer>true</BuildServerSideRenderer>

Cela configure le processus de génération pour exécuter build:ssr lors de la publication et déployer les fichiers SSR sur le serveur.This configures the build process to run build:ssr during publishing and deploy the SSR files to the server. Si vous n’activez pas cette option, SSR échoue en production.If you don't enable this, SSR fails in production.

Lorsque votre application s’exécute en mode de développement ou de production, le code Angular est préaffiché au format HTML sur le serveur.When your app runs in either development or production mode, the Angular code pre-renders as HTML on the server. Le code côté client s’exécute normalement.The client-side code executes as normal.

Transmettre des données à partir du code .NET dans le code TypeScriptPass data from .NET code into TypeScript code

Au cours du rendu côté serveur (SSR), vous pouvez souhaiter transmettre des données par requête à partir de votre application ASP.NET Core dans votre application Angular.During SSR, you might want to pass per-request data from your ASP.NET Core app into your Angular app. Par exemple, vous pouvez transmettre des informations sur le cookie ou un élément lu dans une base de données.For example, you could pass cookie information or something read from a database. Pour ce faire, modifiez votre classe Démarrer.To do this, edit your Startup class. Dans le rappel pour UseSpaPrerendering, définissez une valeur pour options.SupplyData telle que la suivante :In the callback for UseSpaPrerendering, set a value for options.SupplyData such as the following:

options.SupplyData = (context, data) =>
{
    // Creates a new value called isHttpsRequest that's passed to TypeScript code
    data["isHttpsRequest"] = context.Request.IsHttps;
};

Le rappel SupplyData vous permet de transmettre des données sérialisables JSON, arbitraires, par requête (par exemple, chaînes, valeurs booléennes ou nombres).The SupplyData callback lets you pass arbitrary, per-request, JSON-serializable data (for example, strings, booleans, or numbers). Votre code main.server.ts les reçoit en tant que params.data.Your main.server.ts code receives this as params.data. Ainsi, l’exemple de code précédent transmet une valeur booléenne en tant que params.data.isHttpsRequest dans le rappel createServerRenderer.For example, the preceding code sample passes a boolean value as params.data.isHttpsRequest into the createServerRenderer callback. Vous pouvez transmettre ceci à d’autres parties de votre application prises en charge par Angular.You can pass this to other parts of your app in any way supported by Angular. Par exemple, consultez la façon dont main.server.ts transmet la valeur BASE_URL à un composant dont le constructeur est déclaré pour le recevoir.For example, see how main.server.ts passes the BASE_URL value to any component whose constructor is declared to receive it.

Inconvénients du SSRDrawbacks of SSR

Toutes les applications ne bénéficient pas du rendu côté serveur (SSR).Not all apps benefit from SSR. Le principal avantage concerne les performances.The primary benefit is perceived performance. Les visiteurs consultant votre application via une connexion réseau lente ou sur des appareils mobiles lents voient l’interface utilisateur initiale rapidement, même si l’extraction ou l’analyse des bundles JavaScript prend du temps.Visitors reaching your app over a slow network connection or on slow mobile devices see the initial UI quickly, even if it takes a while to fetch or parse the JavaScript bundles. Toutefois, de nombreuses applications monopage sont principalement utilisées via des réseaux d’entreprise internes rapides sur des ordinateurs rapides où l’application s’affiche presque instantanément.However, many SPAs are mainly used over fast, internal company networks on fast computers where the app appears almost instantly.

En même temps, il existe des inconvénients importants concernant l’activation du SSR.At the same time, there are significant drawbacks to enabling SSR. Il ajoute une complexité au processus de développement.It adds complexity to your development process. Votre code doit s’exécuter dans deux environnements différents : côté client et côté serveur (dans un environnement Node.js appelé à partir d’ASP.NET Core).Your code must run in two different environments: client-side and server-side (in a Node.js environment invoked from ASP.NET Core). Voici quelques éléments à prendre en compte :Here are some things to bear in mind:

  • Le SSR requiert une installation Node.js sur vos serveurs de production.SSR requires a Node.js installation on your production servers. C’est automatiquement le cas pour certains scénarios de déploiement, comme Azure App Services, mais pas pour d’autres, comme Azure Service Fabric.This is automatically the case for some deployment scenarios, such as Azure App Services, but not for others, such as Azure Service Fabric.

  • L’activation de l’indicateur de génération BuildServerSideRenderer entraîne votre répertoire node_modules à publier.Enabling the BuildServerSideRenderer build flag causes your node_modules directory to publish. Ce dossier contient plus de 20 000 fichiers, ce qui allonge le temps de déploiement.This folder contains 20,000+ files, which increases deployment time.

  • Pour exécuter votre code dans un environnement Node.js, il ne peut pas s’appuyer sur l’existence d’API JavaScript spécifiques à un navigateur comme window ou localStorage.To run your code in a Node.js environment, it can't rely on the existence of browser-specific JavaScript APIs such as window or localStorage. Si votre code (ou une bibliothèque tierce que vous référencez) tente d’utiliser ces API, vous obtiendrez une erreur au cours du SSR.If your code (or some third-party library you reference) tries to use these APIs, you'll get an error during SSR. Par exemple, n’utilisez pas jQuery, car il fait référence à des API spécifiques au navigateur dans de nombreux endroits.For example, don't use jQuery because it references browser-specific APIs in many places. Pour éviter les erreurs, vous devez éviter le SSR ou éviter les bibliothèques ou les API spécifiques au navigateur.To prevent errors, you must either avoid SSR or avoid browser-specific APIs or libraries. Vous pouvez encapsuler tous les appels à ces API dans des vérifications pour vous assurer qu’ils ne sont pas appelés au cours du SSR.You can wrap any calls to such APIs in checks to ensure they aren't invoked during SSR. Par exemple, utilisez une vérification telle que la suivante dans le code JavaScript ou TypeScript :For example, use a check such as the following in JavaScript or TypeScript code:

    if (typeof window !== 'undefined') {
        // Call browser-specific APIs here
    }