Ril*_*n42 10 c# routing angular-routing angular
如何修复路由?我有一个带有Angular前端的C#项目.如果我去ac #View哪个调用Angular组件,一切都会中断.如果我调用Angular视图(直接从URL),一切正常.
C#路由到ac#视图
xxx/Home/index 这只是一个调用Angular组件的View(抛出一堆500个错误)手动路由到Angular
/anything到url(xxx/Home/Index/anything),Angular路由接管并且所有内容都加载正常.索引方法调用
public class HomeController : Controller
{
public IActionResult Index()
{
return View("IndexAng");
}
}
Run Code Online (Sandbox Code Playgroud)
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>
}
Run Code Online (Sandbox Code Playgroud)
从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" });
});
}
Run Code Online (Sandbox Code Playgroud)
尝试导航到main-client.js的屏幕截图
首先,一个小说明:我遇到了完全相同的问题,但使用的是 ASP.NET MVC 5。因此,我不能保证 100% 相同的解决方案能够正常工作。
但是,我相当确定我将要描述的技术是合理的,并且至少可以以最小的努力进行调整。
回到问题的根源:为了让 ASP.NET MVC(简称 MVC)和 Angular 2+ 愉快地共存,他们必须知道服务器的路由处理责任将在哪里结束以及从哪里开始客户端。
我们还必须了解 MVC 在收到路由请求时如何简化地址。
我提倡的解决方案是创建一个名为 的控制器,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 });
}
}
Run Code Online (Sandbox Code Playgroud)
非常基本的东西:我们只需要确保默认Index操作不直接为任何应用程序提供服务。
然后,我们需要确保MVC路由正常工作:
/TheApp/...并/AnotherSPA/作为根路由(因为我们喜欢简短的助记符 URL)一些路线及其行为方式:
https://server:port应重定向到https://server:port/TheApphttps://server:port/TheApp应通过TheApp中的操作来服务NgControllerhttps://server:port/AnotherSPA应通过AnotherSPA中的操作来服务NgControllerhttps://server:port/TheApp/some/token/and/subroute/for/angular/deep/linkingTheApp应该由 中的操作提供服务,
NgController并且之后的所有内容TheApp都应保持原样并直接进入 Angular Router我选择的配置是这样的(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), "$");
}
Run Code Online (Sandbox Code Playgroud)
现在,MVC 路由和控制器对于重定向部分和“do-not-mess-with-everything-after-the-app-name”部分来说很好并且可测试。;)
现在,我们必须设置托管 Angular 应用程序所需的唯一 MVC 视图。我们需要“Ng”控制器的单个“Ui”视图。视图中唯一真正重要的部分是<base>html 文档头部的标签。我亲自将该dist文件夹复制到 MVC 站点内的一个static文件夹中,只是为了澄清命名。“static”文件夹旨在包含所有(您猜对了)静态内容。我认为 MVCContent默认情况下会创建一个文件夹,但我从来不喜欢这个名字。
MVCroot
|-static
|-ng
|-TheApp (this is the dist folder for TheApp)
|-AnotherSPA (this is the dist folder for AnotherSPA)
Run Code Online (Sandbox Code Playgroud)
我还将每个 js 文件打包到一个名为 SPA 的文件中,但这不是必需的。
我不喜欢局部,只是因为我不需要布局,所以我把所有东西放在一起。
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>
Run Code Online (Sandbox Code Playgroud)
AAAAAnd...我们已经完成了 MVC 方面的工作。
在客户端,我们只需要确保 Angular 使用适当的默认值来管理路由(不要启用哈希选项)。
一切都应该正常进行。
希望能帮助到你。
| 归档时间: |
|
| 查看次数: |
447 次 |
| 最近记录: |