ASP.NET 5 + Angular 2路由(模板页面不重载)

时间:2016-01-06 08:23:28

标签: asp.net angular asp.net-core angular2-routing

Angular 2 beta默认使用html5路由。 但是,当您转到某个组件并且路径发生变化(例如http://localhost:5000/aboutus)和时,您将重新加载/刷新该页面,则不会加载任何内容。

post 中也出现了此问题。 大多数答案都表示,如果我们要在角度2中进行HTML5路由,那么应该在服务器端处理这个路由问题。更多讨论 here

我不确定如何使用asp.net服务器环境来处理这个问题。

任何有角度的2开发者也使用asp.net并遇到这个问题?

PS。我正在使用ASP.NET 5.我的Angular 2路由正在使用MVC路由。

11 个答案:

答案 0 :(得分:18)

您遇到的问题与客户端上的Angular路由和MVC服务器端路由之间的区别有关。您实际上收到404 Page Not Found错误,因为服务器没有针对该路由的Controller和Action。我怀疑你没有处理错误,这就是为什么看起来没有任何反应。

当您重新加载http://localhost:5000/aboutus或者您尝试直接从快捷方式链接到该URL或通过在地址栏中键入(深层链接)时,它会向服务器发送请求。 ASP.NET MVC将尝试解决该路由,在您的情况下,它将尝试加载aboutusController并运行Index操作。当然,这不是你想要的,因为你的aboutus路线是Angular组件。

您应该做的是为ASP.NET MVC路由器创建一种方法,将Angular应解析的URL传递回客户端。

Startup.cs文件的Configure()方法中,添加" spa-fallback"到现有路线的路线:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    // when the user types in a link handled by client side routing to the address bar 
    // or refreshes the page, that triggers the server routing. The server should pass 
    // that onto the client, so Angular can handle the route
    routes.MapRoute(
        name: "spa-fallback",
        template: "{*url}",
        defaults: new { controller = "Home", action = "Index" }
    );
});

通过创建指向最终加载Angular应用程序的Controller和View的catch-all路由,这将允许将服务器无法处理的URL传递到客户端以进行正确的路由。

答案 1 :(得分:8)

Startup.cs中将此添加到Configure方法。这必须早于其他app陈述。

app.Use(async (context, next) => {
    await next();

    if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) {
        context.Request.Path = "/index.html"; // Put your Angular root page here 
        await next();
    }
});

答案 2 :(得分:6)

我最喜欢的解决方案是将以下代码添加到Global.asax.cs,它可以非常顺利和可靠地解决问题:

     private const string RootUrl = "~/Home/Index";
     // You can replace "~Home/Index" with whatever holds your app selector (<my-app></my-app>)
     // such as RootUrl="index.html" or any controller action or browsable route

     protected void Application_BeginRequest(Object sender, EventArgs e)
        {
            // Gets incoming request path
            var path = Request.Url.AbsolutePath;

            // To allow access to api via url during testing (if you're using api controllers) - you may want to remove this in production unless you wish to grant direct access to api calls from client...
            var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
            // To allow access to my .net MVCController for login
            var isAccount = path.StartsWith("/account", StringComparison.InvariantCultureIgnoreCase);
            if (isApi || isAccount)
            {
                return;
            }

            // Redirects to the RootUrl you specified above if the server can't find anything else
            if (!System.IO.File.Exists(Context.Server.MapPath(path)))
                Context.RewritePath(RootUrl);
        }

答案 3 :(得分:5)

您需要在ASP.NET MVC中使用此路由

app.UseMvc(routes =>
{
     routes.MapRoute("Default", "{*url}",  new { @controller = "App", @action = "Index" });
});

然后,您需要使用basePath选项设置SystemJS

答案 4 :(得分:2)

您正在寻找的功能是URL重写。有两种可能的方法来处理它。经典的方法是让IIS完成工作,如下所述:

https://stackoverflow.com/a/25955654/3207433

如果你不想依赖IIS,你可以在ASP.NET 5中间件中处理它,如我在这里的回答所示:

https://stackoverflow.com/a/34882405/3207433

答案 5 :(得分:2)

我没有运气好

<div class="wrapper">
  <div class="item"><h3>1.1</h3><p>1.2</p></div>
  <div class="item"><p>2.1</p><p>2.2</p><p>2.3</p><p>2.4</p><p>2.5</p></div>
  <div class="item"><h2>3.1</h2></div>
  <div class="item"><h2>4.1</h2><p>4.2</p><p>4.3</p><p>4.4</p></div>
  <div class="item"><p>5.1</p><p>5.2</p><p>5.3</p><p>5.4</p></div>
  <div class="item"><h2>6.1</h2><p>6.2</p></div>
  <div class="item"><h2>7.1</h2><p>7.2</p><p>7.3</p></div>
  <div class="item"><p>8.1</p><p>8.2</p></div>

</div>

上班。我仍然可以通过任何客户端路线获得404.

  

<强>更新
  弄清楚为什么全能路由不起作用:我定义了一个属性路由( routes.MapRoute("Default", "{*url}", new { @controller = "App", @action = "RedirectIndex" }); ),而普通路由可以直接访问它没有触发的后备路由。删除属性路由使其工作。

另一个似乎与catch-all路由处理程序一样简单的解决方案就是创建一个自定义处理程序,该处理程序在[Route("api/RedirectIndex")]中的中间件管道末尾触发:

Configure()

如果没有其他处理程序接收请求,这基本上会成为简单地将index.html发送到现有URL请求的全能路由。

即使与IIS Rewrite rules结合使用也很有效(在这种情况下,上述情况不会被解雇。

撰写关于此主题的博客文章:

答案 6 :(得分:1)

以下是解决此问题的另外两个选项。您可以将哈希位置策略添加到您的应用模块。

import { LocationStrategy, HashLocationStrategy } from '@angular/common';

@NgModule({
imports: [.... ],
declarations: [...],
bootstrap: [AppComponent],
providers: [
{
  provide: LocationStrategy,
  useClass: HashLocationStrategy
}
]
})
export class AppModule { }

此选项仅适用于Home ASP控制器上的Angular2应用程序部分

您的第二个选择是向ASP控制器添加与Angular 2应用程序路由匹配的路由并返回“索引”视图

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

    [ActionName("Angular-Route1")]
    public IActionResult AngularRoute1()
    {
        return View("Index");
    }

    public IActionResult Route2()
    {
        return View("Index");
    }
}

答案 7 :(得分:0)

您使用过:

指令:组件中的[RouterOutlet,RouterLink]。

答案 8 :(得分:0)

应用@ ZOXEXIVO的解决方案,然后在_Layout.cshtml中添加:

<head>
    <base href="/"/>
    .....
</had>

答案 9 :(得分:0)

您可以同时使用路由 当你从角度路由中调用Home / Index时。

Home/Index.cshtml
<my-app></my-app>

app.routing.ts
    const routes: Routes = [
        { path: '', redirectTo: '/Home/Index', pathMatch: 'full' },
        { path: 'Home/Index', component: DashboardComponent }
    ]

所以,当URL为Home / Index时  将加载活动网址的组件,以便加载仪表板组件。

答案 10 :(得分:0)

上面选择的解决方案对我不起作用我在跟踪了所有评论后得到了404.我在MVC5应用程序中使用了angular5应用程序。我使用默认索引登录页面作为angular5的开头。我的角度应用程序位于名为mvcroot / ClientApp /的文件夹中,但在ng build中,它通过使用“outDir”更改.angular-cli.json文件中的一个设置将分布式文件放入mvcroot / Dist /中:“../Dist”

这个解决方案确实有效。

这样,只有Dist目录中的路由才会被覆盖。现在,您可以每次都点击刷新,并且在保持正确的组件的同时重新加载angular5应用程序的确切路线。一定要把捕获全部放在第一位。另外,如果在angular5中使用令牌身份验证,请将令牌保存到window.localStorage(或angular5应用程序之外的其他一些机制),因为点击刷新会清除您可能将令牌存储在全局变量中的所有内存。这使用户不必在刷新时再次登录。

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Catch All",
                "dist/{*url}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional });

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }


            );