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. Есть немало вещей, которые просто волшебным образом работают.
- Есть
index.html
файл внутриClientApp/src
папка, которая автоматически обслуживается при запуске приложения. - Когда приложение запускается, до
</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