15

我正在尝试将我的ASP.NET Core 2.0 Angular 5应用程序与webpacksetup 迁移到ASP.NET Core 2.1 Angular 6with Angular-Cli

简短的问题:

如何从cshtmlwith强制解析 razor pages 指令Microsoft.AspNetCore.SpaServices.Extensions

我不想使用index.htmlfrom Angular.json,但是index.cshtml.

详细描述:

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

  1. 文件夹内有一个index.html文件,该文件ClientApp/src在应用程序启动时自动提供。
  2. 当应用程序运行时,在标签</body>之前index.html(从第一点开始)插入几个脚本:、、、inline.bundle.js和标签之前。polyfills.bundle.jsvendor.bundle.jsmain.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>

并将索引选项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. 如何将此写入剃须刀页面。

4

3 回答 3

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 静态内容中间件提供服务。

于 2018-10-06T04:47:01.033 回答
5

it's and old question, but I hope the answer help someone

Well, is difficut make that webpack insert the scripts tag in you index.cshtml, but you can include the tags in the index.cshtml like

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

then you can router your mvc like

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

});

See that all the routes that not correcponding with {controller}{action=Index}/{id?} fall in "spa-fallback" that say that if the file not have .css or .map or .js or .sockjs serve your Home/Index. It's necesary the "regex" for .NET serve the script files necesarys.

The last step is configure your angular.json to maintaine the name of the scripts using 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"
}

At last we can check if an url is valid or not (else any url server the index page) you can use in startup.cs some like

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: I put the href of the scripts in absolute path, e.g src="/runtime.js", well in package json we can have several scripts like

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

If we use --serve-path=fr-FR, the href of script must use this serve-path, e.g. src="/fr-FR/runtime.js"

于 2018-07-29T15:18:39.833 回答
-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

于 2018-06-21T16:41:54.180 回答