如何在 ASP.NET MVC 中定义 Angular 路由
How to define Angular Routing in ASP.NET MVC
我对在 Asp.Net MVC 应用程序中使用 Angular 的路由有点困惑。
为了理解我的问题,我将显示我的应用程序的当前代码:
Index.cshtml:
<head>
...
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-collapse collapse glyphicons pull-right">
<ul class="nav navbar-nav">
<li ng-class="{active:isActive == '/test1'}">
<a href="#/test1">Test1</a>
</li>
<li ng-class="{active:isActive == '/test2'}">
<a href="#/test2">Test2</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
<div ng-view></div>
</div>
@Scripts.Render("~/bundles/angular")
@Scripts.Render("~/bundles/app")
</body>
家庭控制器 (ASP.NET):
namespace Tests.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return PartialView();
}
public ActionResult Test1()
{
return PartialView();
}
public ActionResult Test2()
{
return PartialView();
}
}
}
我的Angular模块:
angular
.module('Tests', [
'ngRoute'
])
.config(config)
.run(['$rootScope', '$route', '$location', function($rootScope, $route, $location) {
$rootScope.$on('$routeChangeSuccess', function(event, currRoute, prevRoute) {
$rootScope.title = $route.current.title;
});
var path = function() {
return $location.path();
};
$rootScope.$watch(path, function(newPath, oldPath) {
$rootScope.isActive = newPath;
});
}]);
config.$inject = ['$routeProvider'];
function config($routeProvider) {
$routeProvider
.when('/test1', {
templateUrl: '/Home/Test1',
isActive: 'test1'
})
.when('/test2', {
templateUrl: '/Home/Test2',
isActive: 'test2'
})
.otherwise({
redirectTo: '/'
});
}
输出URL如下所示:localhost/Home/Index#/test1
问题:
我需要在 HomeController 中定义 Actions 吗?为什么?我以为我只需要 ActionResult 索引,因为我使用 PartialView()... 我怎样才能实现以下 URL: localhost/test1
当我点击 Menu Test1?
在我看来,您似乎在尝试让 MVC 将模板 URL 解析为部分网址。如果是这样,那么您不能对 MVC 路由和 Angular 路由使用相同的路由。
将其分解为步骤
1) 您是否需要 MVC 来解析模板路由(即动态生成的模板)如果需要,请制作一个模板控制器,并将每个模板构建为模板控制器上的部分操作。如果您不需要动态模板,只需将您的模板作为静态 HTML 存储在诸如 /Content/Templates 之类的文件夹中 - 这样可以避免 MVC 管道。
2) 如果 1) 正确,您应该有一个工作示例,但带有 # 路由。要使 HTML5 条路由正常工作,您需要从 MVC 管道中排除这些路由 - routes.IgnoreRoute("/Index/*"); in RouteConfig.cs 可能有效 - 我没试过。
除了@Andiih 在他的回答中所说的。 Angular
路由库旨在处理您的 Angular
路由 E.G.在 (找不到更好的术语) 前端 控制器之间。
您似乎以您期望 2 工作的方式混合了 Angular
和 ASP.NET MVC
路由。你的基本路线是 localhost/Home/Index#
从那一点开始 Angular
将它自己的(子)路线附加到基本 URL
,导致你看到的输出 URL
。
尽管根据需要在 MVC
和 Angular
路由和控制器之间跳转可能是可行的,但这将是一个比我假设您要实现的目标更复杂的场景。而且我过去从来不需要达到那种程度。
总结当前会发生什么:
如果您必须离开 Index.cshtml
"Root" 页面,您实际上会离开当前的 Angular
应用..或导航 到 不同的应用程序...根据解决方案结构,您甚至可以为每个单独的页面使用不同的 JavaScript MV* 框架...但这太疯狂了。
...但我怀疑这是你现阶段想要的,所以为了简单起见,我们坚持假设你只有一个 ASP.Net MVC Route
/ 页面,你只是想在 Angular
以某种方式从后端 .NET
服务向 Angular
路由或页面提供数据。
因此,您似乎可能会遗漏 link 每个框架在您当前拥有的堆栈中所扮演的角色。 (我会尽力澄清)
例如:
如果您查看(非常通用的)整体解决方案结构,可能如下所示。
- css
- bootstrap.css // all 3rd party css here
- libs
- angular.js // all 3rd party js libs here
- angular-ui-router.js
- controllers
- RootController.cs // This is your HomeController.
// It's effectively used to "deliver" the root view which is
// your core/base page for lack of a better term
- views
- RootView.cshtml // see code RootView.cshtml below,
// this defines your app "layout"
// as well as where you deliver your bundles,
// make use of server side auth, etc..
- webapi
- test1Api.cs // access to test1 data or serverside process
- test2Api.cs // etc..
- app
- pages
- home
- test1
- test1Ctrl.js
- test1View.html
- test1.css
- test2
- test2Ctrl.js
- test2View.html
- test2.css
- services
- someRandomSvc.js
- resourceSvc.js // this is where you consume your
// .NET back end API. E.G: test1Api & test2Api, etc..
- app.js
- app.routes.js
- etc...
RootView.cshtml
在服务器端构建,因此允许您使用 .NET bundling
、Asp.NET Auth
等。无论如何,整个页面将充当 shell对于 Angular
应用程序,整个 "front end app" 因此在该页面的上下文中运行。
RootView.cshtml
<head>
@Styles.Render("~/content/3rdPartyCSS")
@Styles.Render("~/content/appSpecificCSS")
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-collapse collapse glyphicons pull-right">
<ul class="nav navbar-nav">
<li><a ui-sref="home">Home</a></li>
<li><a ui-sref="test1">Test1</a></li>
<li><a ui-sref="test2">Test2</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
<div ng-view></div>
</div>
@Scripts.Render("~/bundles/3rdPartyJS")
@Scripts.Render("~/bundles/appSpecificJS")
</body>
你只需要一个 ASP.Net MVC Route
,正如我之前所说,你不会离开它(至少对于这个应用程序)
RootController.cs
namespace Tests.Controllers
{
public class RootController : Controller
{
public ActionResult RootView()
{
// as I've mentioned previously in another post,
// we're returning a partial to avoid the usage of _layout.cshtml
// as our RootView is acting as the layout in for the angular app.
// (it would introduce another level of not needed nesting)
return PartialView();
}
}
}
...但您将需要多条 Angular
路线。
app.routes.js
var app = angular.module('Tests');
app.config(['$stateprovider', function($stateprovider) {
$stateprovider
.state('home', { url: '', templateUrl: 'app/pages/home/homeView.html' }])
.state('test1', { url: '/test1', templateUrl: 'app/pages/test1/test1View.html'})
.state('test2', { url: '/test2', templateUrl: 'app/pages/test2/test2View.html'});
}]);
然后您将通过 WebAPI endpoints that you would need to consume via something like ngResource 公开其他服务器端逻辑或调用,然后您将在 Angular
控制器中使用它们。
testXView.html
<div ng-controller="testXCtrl as test">{{ test.something }}</div>
testXCtrl.js
var app = angular.module('Test');
app.controller('testXCtrl',['resourceSvc', function(resourceSvc) {
resourceSvc.getSomeData().then(function(data) {
this.something = data; //.. or whatever floats your boat :P
})
}]);
注.
- 将此约定与angular
.something(['service', function(service) { }]);
一起使用是使代码min safe。 (所以看到它的时候不要太害怕)
- 我在我的例子中使用了一个名为angular-ui-router的路由库,我建议你看看它,如果你在这个阶段可以自由选择......但是同样的原则也适用于
ngRoute
解决方案。
我对在 Asp.Net MVC 应用程序中使用 Angular 的路由有点困惑。
为了理解我的问题,我将显示我的应用程序的当前代码:
Index.cshtml:
<head>
...
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-collapse collapse glyphicons pull-right">
<ul class="nav navbar-nav">
<li ng-class="{active:isActive == '/test1'}">
<a href="#/test1">Test1</a>
</li>
<li ng-class="{active:isActive == '/test2'}">
<a href="#/test2">Test2</a>
</li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
<div ng-view></div>
</div>
@Scripts.Render("~/bundles/angular")
@Scripts.Render("~/bundles/app")
</body>
家庭控制器 (ASP.NET):
namespace Tests.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return PartialView();
}
public ActionResult Test1()
{
return PartialView();
}
public ActionResult Test2()
{
return PartialView();
}
}
}
我的Angular模块:
angular
.module('Tests', [
'ngRoute'
])
.config(config)
.run(['$rootScope', '$route', '$location', function($rootScope, $route, $location) {
$rootScope.$on('$routeChangeSuccess', function(event, currRoute, prevRoute) {
$rootScope.title = $route.current.title;
});
var path = function() {
return $location.path();
};
$rootScope.$watch(path, function(newPath, oldPath) {
$rootScope.isActive = newPath;
});
}]);
config.$inject = ['$routeProvider'];
function config($routeProvider) {
$routeProvider
.when('/test1', {
templateUrl: '/Home/Test1',
isActive: 'test1'
})
.when('/test2', {
templateUrl: '/Home/Test2',
isActive: 'test2'
})
.otherwise({
redirectTo: '/'
});
}
输出URL如下所示:localhost/Home/Index#/test1
问题:
我需要在 HomeController 中定义 Actions 吗?为什么?我以为我只需要 ActionResult 索引,因为我使用 PartialView()... 我怎样才能实现以下 URL: localhost/test1
当我点击 Menu Test1?
在我看来,您似乎在尝试让 MVC 将模板 URL 解析为部分网址。如果是这样,那么您不能对 MVC 路由和 Angular 路由使用相同的路由。
将其分解为步骤
1) 您是否需要 MVC 来解析模板路由(即动态生成的模板)如果需要,请制作一个模板控制器,并将每个模板构建为模板控制器上的部分操作。如果您不需要动态模板,只需将您的模板作为静态 HTML 存储在诸如 /Content/Templates 之类的文件夹中 - 这样可以避免 MVC 管道。
2) 如果 1) 正确,您应该有一个工作示例,但带有 # 路由。要使 HTML5 条路由正常工作,您需要从 MVC 管道中排除这些路由 - routes.IgnoreRoute("/Index/*"); in RouteConfig.cs 可能有效 - 我没试过。
除了@Andiih 在他的回答中所说的。 Angular
路由库旨在处理您的 Angular
路由 E.G.在 (找不到更好的术语) 前端 控制器之间。
您似乎以您期望 2 工作的方式混合了 Angular
和 ASP.NET MVC
路由。你的基本路线是 localhost/Home/Index#
从那一点开始 Angular
将它自己的(子)路线附加到基本 URL
,导致你看到的输出 URL
。
尽管根据需要在 MVC
和 Angular
路由和控制器之间跳转可能是可行的,但这将是一个比我假设您要实现的目标更复杂的场景。而且我过去从来不需要达到那种程度。
总结当前会发生什么:
如果您必须离开 Index.cshtml
"Root" 页面,您实际上会离开当前的 Angular
应用..或导航 到 不同的应用程序...根据解决方案结构,您甚至可以为每个单独的页面使用不同的 JavaScript MV* 框架...但这太疯狂了。
...但我怀疑这是你现阶段想要的,所以为了简单起见,我们坚持假设你只有一个 ASP.Net MVC Route
/ 页面,你只是想在 Angular
以某种方式从后端 .NET
服务向 Angular
路由或页面提供数据。
因此,您似乎可能会遗漏 link 每个框架在您当前拥有的堆栈中所扮演的角色。 (我会尽力澄清)
例如:
如果您查看(非常通用的)整体解决方案结构,可能如下所示。
- css
- bootstrap.css // all 3rd party css here
- libs
- angular.js // all 3rd party js libs here
- angular-ui-router.js
- controllers
- RootController.cs // This is your HomeController.
// It's effectively used to "deliver" the root view which is
// your core/base page for lack of a better term
- views
- RootView.cshtml // see code RootView.cshtml below,
// this defines your app "layout"
// as well as where you deliver your bundles,
// make use of server side auth, etc..
- webapi
- test1Api.cs // access to test1 data or serverside process
- test2Api.cs // etc..
- app
- pages
- home
- test1
- test1Ctrl.js
- test1View.html
- test1.css
- test2
- test2Ctrl.js
- test2View.html
- test2.css
- services
- someRandomSvc.js
- resourceSvc.js // this is where you consume your
// .NET back end API. E.G: test1Api & test2Api, etc..
- app.js
- app.routes.js
- etc...
RootView.cshtml
在服务器端构建,因此允许您使用 .NET bundling
、Asp.NET Auth
等。无论如何,整个页面将充当 shell对于 Angular
应用程序,整个 "front end app" 因此在该页面的上下文中运行。
RootView.cshtml
<head>
@Styles.Render("~/content/3rdPartyCSS")
@Styles.Render("~/content/appSpecificCSS")
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-collapse collapse glyphicons pull-right">
<ul class="nav navbar-nav">
<li><a ui-sref="home">Home</a></li>
<li><a ui-sref="test1">Test1</a></li>
<li><a ui-sref="test2">Test2</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
<div ng-view></div>
</div>
@Scripts.Render("~/bundles/3rdPartyJS")
@Scripts.Render("~/bundles/appSpecificJS")
</body>
你只需要一个 ASP.Net MVC Route
,正如我之前所说,你不会离开它(至少对于这个应用程序)
RootController.cs
namespace Tests.Controllers
{
public class RootController : Controller
{
public ActionResult RootView()
{
// as I've mentioned previously in another post,
// we're returning a partial to avoid the usage of _layout.cshtml
// as our RootView is acting as the layout in for the angular app.
// (it would introduce another level of not needed nesting)
return PartialView();
}
}
}
...但您将需要多条 Angular
路线。
app.routes.js
var app = angular.module('Tests');
app.config(['$stateprovider', function($stateprovider) {
$stateprovider
.state('home', { url: '', templateUrl: 'app/pages/home/homeView.html' }])
.state('test1', { url: '/test1', templateUrl: 'app/pages/test1/test1View.html'})
.state('test2', { url: '/test2', templateUrl: 'app/pages/test2/test2View.html'});
}]);
然后您将通过 WebAPI endpoints that you would need to consume via something like ngResource 公开其他服务器端逻辑或调用,然后您将在 Angular
控制器中使用它们。
testXView.html
<div ng-controller="testXCtrl as test">{{ test.something }}</div>
testXCtrl.js
var app = angular.module('Test');
app.controller('testXCtrl',['resourceSvc', function(resourceSvc) {
resourceSvc.getSomeData().then(function(data) {
this.something = data; //.. or whatever floats your boat :P
})
}]);
注.
- 将此约定与angular
.something(['service', function(service) { }]);
一起使用是使代码min safe。 (所以看到它的时候不要太害怕) - 我在我的例子中使用了一个名为angular-ui-router的路由库,我建议你看看它,如果你在这个阶段可以自由选择......但是同样的原则也适用于
ngRoute
解决方案。