ASP.NET Core 2.1 Angular 6.0 SPA шаблон - страница бритвы (cshtml) для индекса вместо статической страницы

Я пытаюсь перенести мой ASP.NET Core 2.0 Angular 5 приложение с webpack настроить на ASP.NET Core 2.1 Angular 6 с Angular-Cli,

Краткий вопрос:

Как я могу заставить директивы разбора бритвенных страниц от cshtml с Microsoft.AspNetCore.SpaServices.Extensions?

Я не хочу использовать index.html от Angular.json, но index.cshtml,

Длинное описание:

Я начал новый проект ASP.NET Core из шаблона Angular. Есть немало вещей, которые просто волшебным образом работают.

  1. Есть index.html файл внутри ClientApp/src папка, которая автоматически обслуживается при запуске приложения.
  2. Когда приложение запускается, до </body> тег от index.html (из первого пункта) вставлено несколько скриптов: inline.bundle.js, polyfills.bundle.js, vendor.bundle.js, main.bundle.js а также styles.bundle.css до </head> тег.

Я не уверен, кто вставил эти скрипты, но я хочу вставить их на страницу Razor (cshtml).

Я пытался использовать код из моего старого проекта:

<!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>

И указатели опций индекса в Angular.json к этому index.cshtml:

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

Проблема в том, что контент (все теги @) не обрабатывается ASP.NET Core, но выводит прямой контент:

<!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>
...

но это должно быть:

<!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>

Я хочу напечатать некоторые переменные (из appsettings.json) в конце HTML-страницы. Поскольку я уже использую ASP.NET Core, страница Razor кажется хорошим решением.

Я также пытаюсь:
чтобы добавить новый RazorPage, обрабатывается контент C# (директивы @), но никто не вставляет скрипты Angular.

Ответ для AndyCunningham:

ng build --prod пишет эти файлы:

<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, Как написать это на страницу бритвы.

3 ответа

Я основываю этот ответ на своем опыте с расширениями React SPA, но он должен быть полезен и для Angular, так как он использует те же ClientApp/index.html механизм промежуточного программного обеспечения, и то же самоеIApplicationBuilder.UseSpa точка входа.

Проблема в том, что когда вы используете app.UseSpa(...)Реализация этого расширения по умолчанию настраивает промежуточное ПО, которое прослушивает ВСЕ запросы интерфейса и отправляет их в index.html.

Я построил быстрый пример того, как мы обходим это для наших проектов: https://github.com/andycmaj/aspnet_spa_without_indexhtml/pull/1/files должен показать вам, что нужно изменить, чтобы игнорировать index.html и использовать вместо бритвы.

По сути, я повторно реализовал то, что UseSpa делает, но не подключая промежуточное программное обеспечение, которое перехватывает и fwds к index.html.

Обратите внимание, что Home Просмотр бритвы все еще должен делать более важные вещи, которые делал index.html. Самое главное, это должно включатьbundle.js обслуживается промежуточным ПО статического контента SPA.

Это и старый вопрос, но я надеюсь, что ответ поможет кому-то

Что ж, сложно сделать так, чтобы веб-пакет вставлял тег скриптов в ваш index.cshtml, но вы можете включить теги в index.cshtml, например:

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

тогда вы можете маршрутизировать ваш MVC как

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

});

Обратите внимание, что все маршруты, которые не соответствуют {controller}{action=Index}/{id?}, Попадают в "spa-fallback", в котором говорится, что если файл не имеет.css или.map или.js или.sockjs, то ваш Главная /Index. Необходимо, чтобы "регулярные выражения" для.NET обслуживали файлы сценариев.

Последний шаг - это настройка вашего angular.json для поддержки имени скриптов с помощью outputHashing: все

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

Наконец, мы можем проверить, является ли URL-адрес действительным или нет (иначе любой URL-сервер индексной страницы), который вы можете использовать в startup.cs, например:

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

ПРИМЕЧАНИЕ: я поместил href скриптов в абсолютный путь, например, src="/runtime.js", хорошо в пакете json у нас может быть несколько скриптов, таких как

"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",
    ...
  },

Если мы используем --serve-path=fr-FR, href скрипта должен использовать этот serve-путь, например, src="/fr-FR/runtime.js"

Вы на правильном пути, вам все еще нужно все, что у вас есть в вашем _layout.cshtml но вы не изменяете Angular index.html. Вместо вашего Home/Index.cshtml или же _layout.cshtml будет включать в себя <app-root> элемент, а также все ваши угловые сценарии. Скорее всего, вы захотите отключить хэши в сгенерированных угловых файлах и использовать ASP.NET для аннулирования вашего JS.

Эта ссылка объясняет это в деталях, но у меня все еще есть небольшие проблемы с ним в Angular 6 + ASP.NET Core 2.1: добавление проекта Angular 5 CLI в проект ASP.Net Core 2.0

Другие вопросы по тегам