web-dev-qa-db-fra.com

ASP.NET Core 2.1 Angular Modèle 6.0 SPA - page de rasoir (cshtml) pour index à la place de page statique

J'essaie de migrer mon application ASP.NET Core 2.0 Angular 5 avec webpack setup vers ASP.NET Core 2.1 Angular 6 avec Angular-Cli.

Petite question:

Comment forcer l'analyse des directives de pages de rasoir de cshtml avec Microsoft.AspNetCore.SpaServices.Extensions?

Je ne veux pas utiliser index.html à partir de Angular.json, mais index.cshtml.

Description longue:

J'ai démarré un nouveau projet ASP.NET Core à partir de Angular template . Il y a pas mal de choses qui fonctionnent comme par magie.

  1. Il existe un fichier index.html dans le dossier ClientApp/src qui est automatiquement servi au démarrage de l'application.
  2. Lors de l'exécution de l'application, plusieurs scripts sont insérés avant la balise </body> de index.html (du premier point): inline.bundle.js, polyfills.bundle.js, vendor.bundle.js, main.bundle.js et styles.bundle.css avant la balise </head>.

Je ne sais pas qui a inséré ces scripts, mais je souhaite les insérer dans la page Razor (cshtml).

J'ai essayé d'utiliser le code de mon ancien projet:

<!DOCTYPE html>
<html>
<head>
    <base href="/" />
    <title>@ViewData["Title"]</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
@{string googleAnalyticsId = Html.Raw(ViewData["GoogleAnalyticsId"]).ToString();}
@if (!string.IsNullOrEmpty(googleAnalyticsId))
{
    <script>
        (function(i, s, o, g, r, a, m)
        {
           ...
        })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');

        ga('create', '@googleAnalyticsId', 'auto');
    </script>
}
<script>
    @Html.Raw(ViewData["TransferData"])
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/0.8.2/css/flag-icon.min.css" async defer />
<script src="https://apis.google.com/js/platform.js" async defer></script>
<app>
    <!-- loading layout replaced by app after startupp -->
    <div class="page-loading">
        <div class="bar">
            <i class="sphere"></i>
        </div>
    </div>
</app>
</body>
</html>

Et les options d'index de points dans Angular.json à ceci index.cshtml:

  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
        "options": {
            "outputPath": "wwwroot/dist",
            "index": "Views/Home/Index.cshtml",   //<----- here

Le problème est que le contenu (tous les tags @) n'est pas traité par ASP.NET Core, mais qu'il génère du contenu direct:

<!DOCTYPE html>
<html>
<head>
    <base href="/" />
    <title>@ViewData["Title"]</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
@{string googleAnalyticsId = Html.Raw(ViewData["GoogleAnalyticsId"]).ToString();}
@if (!string.IsNullOrEmpty(googleAnalyticsId))
{
    <script>
...

mais ce devrait être:

<!DOCTYPE html>
<html>
<head>
    <base href="/" />
    <title>Test title</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
    <script>

Je veux imprimer des variables (à partir de appsettings.json) vers la page HTML finale. Depuis que j'utilise déjà ASP.NET Core, la page Razor semble une bonne solution.

J'essaie aussi:
pour ajouter un nouveau RazorPage, le contenu en C # (directives @) est traité, mais personne n’insère les scripts Angular.

Réponse pour AndyCunningham answer:

ng build --prod écrit ces fichiers:

<script type="text/javascript" src="runtime.b38c91f828237d6db7f0.js"></script><script type="text/javascript" src="polyfills.2fc3e5708eb8f0eafa68.js"></script><script type="text/javascript" src="main.16911708c355ee56ac06.js"></script> 

à index.html. Comment écrire ceci sur une page de rasoir.

5
Makla

c'est une vieille question, mais j'espère que la réponse aidera quelqu'un

Eh bien, il est difficile de faire en sorte que Webpack insère la balise scripts dans votre index.cshtml, mais vous pouvez inclure les balises dans le fichier index.cshtml comme ceci:

@{
    ViewData["title"] = "I'am from cshtml";
}
<app-root>Loading...</app-root>
<script type="text/javascript" src="/runtime.js"></script>
<script type="text/javascript" src="/polyfills.js"></script>
<script type="text/javascript" src="/styles.js"></script>
<script type="text/javascript" src="/vendor.js"></script>
<script type="text/javascript" src="/main.js"></script>

alors vous pouvez router votre MVC comme

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller}/{action=Index}/{id?}");

    routes.MapRoute(
        name: "spa-fallback",
        template: "{*url:regex(^((?!.css|.map|.js|sockjs).)*$)}",
        defaults: new { controller = "Home", action = "Index" });

});

Voir que toutes les routes qui ne correspondent pas avec {controller} {action = Index}/{id?} Entrent dans "spa-fallback" qui dit que si le fichier ne contient pas de fichier .css ou .map ou .js ou .sockjs Accueil/Index. C'est necesary le "regex" pour .NET servir les fichiers de script necesarys.

La dernière étape consiste à configurer votre fichier angular.json pour conserver le nom des scripts à l’aide de outputHashing: all

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "ClientApp": {
      ...
      "architect": {
        "build": {
            ...
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all", //<--add this line
                  ...
            },
            ....
  },
  "defaultProject": "ClientApp"
}

Enfin, nous pouvons vérifier si une URL est valide ou non (sinon, la page d'index du serveur d'URL), vous pouvez utiliser dans startup.cs comme

app.Use(async (context, next) =>
{
    string path = context.Request.Path.Value.Substring(1);
    bool encontrado = path.EndsWith(".js") || path.EndsWith(".css") || path.EndsWith(".map") || path.StartsWith("sockjs");
    if (!encontrado)
    {
        ..use your code to check the url...
    }
    if (encontrado)
        await next.Invoke(); //<--continue
    else
    {   //send to an error404 page
        context.Response.ContentType = "text/html";
        await context.Response.SendFileAsync(Path.Combine(env.WebRootPath, "error404.html"));
    }
});

NOTE: Je mets le href des scripts dans le chemin absolu, par exemple src = "/ runtime.js", ainsi dans le paquet json, nous pouvons avoir plusieurs scripts comme

"scripts": {
    "ng": "ng",
    "start": "ng serve --base-href=/ --serve-path=/",
    "start:fr": "ng serve --base-href=/fr-FR/ --configuration=fr --serve-path=/fr-FR",
    "build": "ng build",
    ...
  },

Si nous utilisons --serve-path = fr-FR, le href du script doit utiliser ce serveur, par exemple. src = "/ fr-FR/runtime.js" 

3
Eliseo

Je fonde cette réponse sur mon expérience des extensions React SPA, mais elle devrait également être utile pour Angular, car elle utilise le même mécanisme intermédiaire de code ClientApp/index.html et le même IApplicationBuilder.UseSpa entrypoint .

Le problème est que lorsque vous utilisez app.UseSpa(...), l’implémentation par défaut de cette extension configuresest un middleware qui écoute TOUTES les demandes d’UI et les renvoie à index.html .

J'ai construit un exemple rapide de la façon dont nous abordons ce problème pour nos projets: https://github.com/andycmaj/aspnet_spa_without_indexhtml/pull/1/files devrait vous montrer ce qui doit être changé pour ignorer l'index .html et utilisez plutôt une vue rasoir.

Fondamentalement, j'ai ré-implémenté ce que UseSpa fait, mais sans attacher le middleware qui intercepte et fwds à index.html.

Notez que la vue du rasoir Home doit encore effectuer les tâches les plus importantes d’index.html. Plus important encore, il doit inclure bundle.js servi par le middleware de contenu statique SPA.

1
AndyCunningham