草庐IT

c# View 调用 Angular 组件中断,但直接调用 Angular 工作正常

coder 2024-06-03 原文

如何修复我的路由?我有一个带有 Angular 前端的 C# 项目。如果我转到调用 Angular 组件的 c# View ,一切都会中断。如果我调用 Angular View (直接从 URL),一切正常。

C# 路由到 C# View

  • 如果我在 startup.cs 中正确路由,我会去: xxx/Home/index 这只是一个调用 Angular 组件的 View (它会抛出一堆 500 错误)

手动路由到 Angular

  • 如果我手动将 /anything 添加到 url (xxx/Home/Index/anything),Angular 路由将接管一切并正常加载。

索引方法调用

public class HomeController : Controller
{
public IActionResult Index()
{
    return View("IndexAng");
}
}

IndexAng.cshtml

@{
    ViewData["Title"] = "Home Page";
}

@*<script src="https://npmcdn.com/tether@1.2.4/dist/js/tether.min.js"></script>*@
@*<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>*@
<h3>Loading Ang App root:</h3>
<app-root></app-root>
<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}

调用c#路由时出错:

从Startup.cs配置方法

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApplicationDbContext identityContext,
                    UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
        {

#if DEBUG
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
                {
                    HotModuleReplacement = true
                });
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
#else
            app.UseExceptionHandler("/Home/Error");
#endif
            app.UseStaticFiles();
            //app.UseSession();
            app.UseAuthentication();
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");

                routes.MapSpaFallbackRoute(
                    name: "spa-fallback",
                    defaults: new { controller = "Home", action = "Index" });
            });

        }

尝试导航到 main-client.js 的屏幕截图

最佳答案

首先,注意一点:我遇到了完全相同的问题,但使用的是 ASP.NET MVC 5。 因此,我不能 100% 保证完全相同的解决方案会奏效。

但是,我相当确定我要描述的技术是可靠的,并且 至少可以通过最小的努力进行调整。

归根结底:为了拥有ASP.NET MVC(简称MVC) 和 Angular 2+ 愉快地共存,他们必须知道路由处理在哪里 服务器的责任将结束,而客户端的责任将开始。

我们还必须了解 MVC 如何在提供路由时简化地址 请求。

我提倡的解决方案是创建一个 Controller ,称为 NgController , 它将为所有单页应用程序(从现在开始,SPA)提供服务 您的安装。

NgController 的草图这是:

public class NgController : Controller
{
    private boolean Authenticated()
    {
        // returns true if the user is authenticated. This system can
        // (and probably should) be integrated or replaced with
        // one of the ASP.NET Core authentication modules.
        return true;
    }

    public ActionResult Index()
    {
        if (!Authenticated())
            return RedirectToAction("Login", "Authentication", new { ReturnUrl = HttpContext?.Request?.Path });

        // Index does not serve directly the app: redirect to default one
        return RedirectToAction("TheApp");
    }

    // One action for each SPA in your installment
    public ActionResult TheApp() => UiSinglePageApp("TheApp");
    public ActionResult AnotherSPA() => UiSinglePageApp("AnotherSPA");

    // The implementation of every SPA action is reusable
    private ActionResult UiSinglePageApp(string appName)
    {
        if (!Authenticated())
            return RedirectToAction("Login", "Authentication", new { ReturnUrl = HttpContext?.Request?.Path });

        return View("Ui", new SinglePageAppModel { AppName = appName });
    }
}

真正基本的东西:我们只需要确保默认 Index操作不直接提供给任何应用程序。

然后,我们需要确保 MVC 路由正常工作:

  1. 要去 map /TheApp/.../AnotherSPA/作为根路由(因为我们喜欢简短的助记 URL)
  2. 不会干扰将由 Angular 处理的路由部分。

一些路线以及它们应该如何表现:

  • https://server:port 的 URL应该重定向到 https://server:port/TheApp
  • https://server:port/TheApp应由 TheApp 提供服务NgController 中的操作
  • https://server:port/AnotherSPA应由 AnotherSPA 提供服务NgController 中的操作
  • https://server:port/TheApp/some/token/and/subroute/for/angular/deep/linking应由 TheApp NgController 中的操作以及 TheApp 之后的所有内容应保持原样并直行 到 Angular 路由器

我选择的配置是这样的(MVC 5,需要对 MVC Core 2 进行一些调整):

public static void RegisterRoutes(RouteCollection routes)
{
    // the Ng controller is published directly onto the root,
    // the * before id makes sure that everything after the action name
    // is kept as-is
    routes.MapRoute("Ng",
        "{action}/{*id}",
        new {controller = "Ng", id = UrlParameter.Optional},
        new {action = GetUiConstraint()}
    );

    // this route allows the mapping of the default site route
    routes.MapRoute(
        "Default",
        "{controller}/{action}/{*id}",
        new { controller = "Ng", action = "Index", id = UrlParameter.Optional }
    );
}

/// <summary> The Ui constraint is to be used as a constraint for the Ng route.
/// It is an expression of the form "^(app1)|(app2)$", with one branch for
/// each possible SPA. </summary>
/// <returns></returns>
public static string GetUiConstraint()
{
    // If you don't need this level of indirection, just
    // swap this function with the result.
    // return "^(TheApp)|(AnotherSPA)$";

    var uiActions = new ReflectedControllerDescriptor(typeof(NgController))
        .GetCanonicalActions()
        .Select(x => x.ActionName.ToLowerInvariant())
        .Where(x => x != "index")
        .Select(x => "(" + x + ")");

    return string.Concat("^", string.Join("|", uiActions), "$");
}

现在 MVC 路由和 Controller 可以正常运行,并且可以测试重定向部分 以及“不要乱用应用程序名称后的所有内容”部分。 ;)

我们现在必须设置托管 Angular 应用程序所需的唯一 MVC View 。 “Ng” Controller 需要一个“Ui” View 。唯一真正重要的一点 View 的 <base>标记在 html 文档的头部。 我亲自复制了dist文件夹到 static MVC 站点内的文件夹, 只是为了澄清命名。 “静态”文件夹旨在包含所有 (你猜对了)静态内容。我认为 MVC 创建了一个 Content文件夹,由 默认,但我从来不喜欢那个名字。

MVCroot
 |-static
   |-ng
     |-TheApp (this is the dist folder for TheApp)
     |-AnotherSPA (this is the dist folder for AnotherSPA)

我也把每个js文件打包成一个文件,名字和SPA一样,但是没必要。
而且我不喜欢 partials,只是因为我不需要布局,所以我把所有东西放在一起。
YMMV.

Ui.cshtml

@{
    Layout = null;
    var baseUrl = Url.Content("/") + Model.AppName;
    var appName = Model.AppName.ToLowerInvariant();
}
<!DOCTYPE html>
<html style="min-height: 100%;">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" type="image/x-icon" href="~/static/favicon.ico">

    <title>My marvelous application</title>

    @Url.CssImportContent("static/ng/{appName}/css/main.css")

    <!-- This is the CRUCIAL bit.  -->
    <base href="@baseUrl">
</head>

<body>
    <app-root>Loading...</app-root>
    @Url.ScriptImportContent($"~static/ng/{appName}/main.js")
</body>

</html>

AAAAAnd... 我们完成了 MVC 方面的工作。

在客户端,我们只需要确保 Angular 管理路由 使用适当的默认值(不要启用散列选项)。

一切都应该正常工作。

希望对您有所帮助。

关于c# View 调用 Angular 组件中断,但直接调用 Angular 工作正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52449672/

有关c# View 调用 Angular 组件中断,但直接调用 Angular 工作正常的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  5. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  6. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  7. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  10. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

随机推荐