ASP.NET Core 2.1 Angular 6.0 SPA模板 - 用于索引而非静态页面的razor页面(cshtml)

Mak*_*kla 11 asp.net-core angular-cli angular asp-net-core-spa-services angular-cli-v6

我想我的迁移ASP.NET Core 2.0 Angular 5与应用程序webpack安装到ASP.NET Core 2.1 Angular 6使用Angular-Cli.

简短的问题:

如何强制从解析剃刀页的指令cshtmlMicrosoft.AspNetCore.SpaServices.Extensions

我不希望使用index.htmlAngular.json,但index.cshtml.

详细描述:

我从Angular模板开始了一个新的ASP.NET Core项目.有很多东西可以神奇地起作用.

  1. index.html文件ClientApp/src夹内有一个文件,在应用程序启动时会自动提供.
  2. 当应用程序运行时,才</body>从标签index.html几个脚本插入(从第一个点)inline.bundle.js,polyfills.bundle.js,vendor.bundle.js,main.bundle.jsstyles.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>
Run Code Online (Sandbox Code Playgroud)

并将索引选项Angular.json指向此index.cshtml:

  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
        "options": {
            "outputPath": "wwwroot/dist",
            "index": "Views/Home/Index.cshtml",   //<----- here
Run Code Online (Sandbox Code Playgroud)

问题是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>
...
Run Code Online (Sandbox Code Playgroud)

但它应该是:

<!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>
Run Code Online (Sandbox Code Playgroud)

我想打印一些变量(从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> 
Run Code Online (Sandbox Code Playgroud)

index.html.如何将此写入剃刀页面.

小智 6

我的这个答案基于我对 React SPA 扩展的经验,但它也应该对 Angular 有帮助,因为它使用相同的ClientApp/index.html中间件机制和相同的IApplicationBuilder.UseSpa入口点。

问题是,当您使用时app.UseSpa(...),此扩展的默认实现配置 了一个中间件,用于侦听所有 UI 请求并将它们转发到 index.html

我已经建立了一个快速示例,说明我们如何为我们的项目解决这个问题:https : //github.com/andycmaj/aspnet_spa_without_indexhtml/pull/1/files应该向您展示为了忽略 index.html 并使用而需要更改的内容取而代之的是剃刀视图。

基本上,我重新实现了什么UseSpa,但没有附加拦截和转发到 index.html 的中间件。

请注意,Homerazor 视图仍然需要执行 index.html 所做的更重要的事情。最重要的是,它需要包含bundle.js由 SPA 静态内容中间件提供服务。


Eli*_*seo 5

这是一个老问题,但我希望答案对某人有所帮助

好吧,是不是很困难让 webpack 在你的 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>
Run Code Online (Sandbox Code Playgroud)

然后你可以像路由器一样路由你的 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" });

});
Run Code Online (Sandbox Code Playgroud)

看到所有与 {controller}{action=Index}/{id?} 不一致的路由都属于“spa-fallback”,表示如果文件没有 .css 或 .map 或 .js 或 .sockjs 为您提供服务主页/索引。.NET 的“正则表达式”必须为脚本文件提供服务。

最后一步是配置您的 angular.json 以使用 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"
}
Run Code Online (Sandbox Code Playgroud)

最后我们可以检查一个 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"));
    }
});
Run Code Online (Sandbox Code Playgroud)

注意:我将脚本的 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",
    ...
  },
Run Code Online (Sandbox Code Playgroud)

如果我们使用--serve-path=fr-FR,脚本的href必须使用这个serve-path,例如src="/fr-FR/runtime.js"


小智 -1

你走在正确的道路上,你仍然需要你拥有的一切_layout.cshtml,但你没有修改 Angular index.html。相反,您的Home/Index.cshtmlor_layout.cshtml将包含该<app-root>元素以及所有角度脚本。您可能希望禁用生成的角度文件中的哈希值并使用 ASP.NET 使您的 JS 无效。

此链接详细解释了这一点,但我在 Angular 6 + ASP.NET Core 2.1 中仍然遇到一些小问题: Add Angular 5 CLI project to ASP.Net Core 2.0 project