使用 AngularJS 1.4.7 服务调用 ASP.NET Web API 不起作用
Calling ASP.NET Web API using AngularJS 1.4.7 service doesn't work
我在这个项目中使用 Visual Studio 2015 社区版和 AngularJS 1.4.7。
ProductAPIController.cs
public class ProductAPIController : ApiController
{
[HttpGet]
public IQueryable<Product> MyProducts()
{
List<Product> p = new List<Product>() { new Product {ProductName ="abc", Id = 1, Description = "Desc 1" },
new Product {ProductName ="def", Id = 2, Description = "Desc 2" },
new Product {ProductName ="ghi", Id = 3, Description = "Desc 3" } };
return p.AsQueryable();
}
}
Product.cs
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
}
app.module.js
我按照最佳实践 here
的建议为应用程序模块使用了一个单独的文件
(function () {
'use strict';
angular.module('app', ['ngCookies', 'ngRoute'])
})();
homeCtrl.js
这里我在同一个文件中同时使用了服务和控制器。我什至尝试在单独的文件中使用它,但仍然没有用。
(function () {
'use strict';
angular.module('app')
.controller('homeCtrl', ['$scope', '$http', 'ProductService', '$location', function homeCtrl($scope, $http, ProductService, $location) {
$scope.products = [];
$scope.getProducts = function () {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
}])
.service('ProductService', ['$http', function ($http) {
this.getProducts = function () {
return $http.get('/api/ProductAPI');
};
}]);
})();
index.cshtml
这里我用的是data-ng-repeat="item in products"
<div class="row" ng-app="app">
<div class="col-md-12" ng-controller="homeCtrl">
<div class="row">
<div class="col-md-12">
<form id="test">
<div data-ng-repeat="item in products">
<div class="col-sm-4 column productbox">
<div class="producttitle">{{item.ProductName}}</div> <div class="action"></div>
<div class="productprice">
<div class="pull-right">
<div >{{item.Id}}</div>
<a href="" class="btn btn-danger btn-sm" role="button"><span class="glyphicon glyphicon-arrow-right"></span> Get Quote</a>
</div>
<div class="pricetext">{{item.Description}}</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@section scripts
{
@Scripts.Render("~/Scripts/angular.js")
@Scripts.Render("~/Scripts/angular-cookies.min.js")
@Scripts.Render("~/Scripts/angular-route.js")
@Scripts.Render("~/Ng/app.module.js")
@Scripts.Render("~/Ng/homeCtrl.js")
}
我尝试了几种不同的方法,但都失败了。我在这里做错了什么?
编辑
我已经将示例项目上传到 GitHub here 。下载后您可能需要重建项目来同步相关包。
编辑:回答
以备日后参考,万一像我这样的AngularJS初学者正在看这道题,答案如下。
基于@Miyuru Ratnayake 给出的,只是改变了
$scope.getProducts = function () {
......
}
至
function getProducts() {
...
}
并将其称为 before the function 声明。不需要单独的函数 activate()。
所以控制器是这样的:
.controller('homeCtrl', ['$scope', '$cookies', '$http', 'ProductService', '$location', function homeCtrl($scope, $cookies, $http, ProductService, $location) {
$scope.products = [];
getProducts();
function getProducts() {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
}])
您应该在控件中的某处调用 getProducts() 方法...我没有看到它被调用了。
通常我会创建一个激活方法,如下所示,并在控件中调用它:
(function () {
'use strict';
angular.module('app')
.controller('homeCtrl', ['$scope', '$cookies', '$http', 'ProductService', '$location', function homeCtrl($scope, $cookies, $http, ProductService, $location) {
$scope.products = [];
activate();
function activate() {
getProducts();
}
function getProducts () {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
}])
.service('ProductService', ['$http', function ($http) {
this.getProducts = function () {
return $http.get('/api/ProductAPI');
};
}]);
})();
您忘记在 API 调用中定义方法名称,试试这个:
.service('ProductService', ['$http', function ($http) {
this.getProducts = function () {
return $http.get('/api/ProductAPI/myProducts');
};
}]);
默认情况下 ASP.NET Web API 查找“api/{controller}/{id}”,这意味着 ProductAPIController 应该有 GET、POST、PUT、DELETE 等基于 REST 概念的方法来处理模型。
但是在您的 ProductAPIController 代码中,GetProducts() 是用 HTTPGET 装饰的自定义操作方法,但即使这样,Web API 路由也不会理解这一点,直到您定义路由应该是“api/{controller}/{action}/{id}".
打开WebApiConfig.cs,如下更改路由模板并进行测试。 我添加了 {action},以便 Web API 路由在 API 控制器中查找自定义操作。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
只是一个建议
如果您计划使用 'GetProducts'、'GetProductsByName' 等自定义操作方法;使用此路线模板。
在客户端代码中使用它们之前,始终使用 POSTMAN 或 Fiddler 测试 Web API。我附上了通过 PostMan 测试的 GetProducts 的屏幕截图。
如果您使用 github 中的当前代码版本实际查看浏览器控制台,您会立即发现问题在于函数在您的代码中声明的顺序controller 会导致您尝试执行尚未定义的函数。
我重新订购了您的控制器以执行以下操作:
$scope.products = [];
function activate() {
$scope.getProducts();
}
$scope.getProducts = function () {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
activate();
此外,在您的 index.cshtml
中,您引用的产品详细信息使用了错误的大小写。
例如,你有这个:
{{item.ProductName}}
什么时候应该是这样:
{{item.productName}}
我在这个项目中使用 Visual Studio 2015 社区版和 AngularJS 1.4.7。
ProductAPIController.cs
public class ProductAPIController : ApiController
{
[HttpGet]
public IQueryable<Product> MyProducts()
{
List<Product> p = new List<Product>() { new Product {ProductName ="abc", Id = 1, Description = "Desc 1" },
new Product {ProductName ="def", Id = 2, Description = "Desc 2" },
new Product {ProductName ="ghi", Id = 3, Description = "Desc 3" } };
return p.AsQueryable();
}
}
Product.cs
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public string Description { get; set; }
}
app.module.js 我按照最佳实践 here
的建议为应用程序模块使用了一个单独的文件(function () {
'use strict';
angular.module('app', ['ngCookies', 'ngRoute'])
})();
homeCtrl.js
这里我在同一个文件中同时使用了服务和控制器。我什至尝试在单独的文件中使用它,但仍然没有用。
(function () {
'use strict';
angular.module('app')
.controller('homeCtrl', ['$scope', '$http', 'ProductService', '$location', function homeCtrl($scope, $http, ProductService, $location) {
$scope.products = [];
$scope.getProducts = function () {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
}])
.service('ProductService', ['$http', function ($http) {
this.getProducts = function () {
return $http.get('/api/ProductAPI');
};
}]);
})();
index.cshtml
这里我用的是data-ng-repeat="item in products"
<div class="row" ng-app="app">
<div class="col-md-12" ng-controller="homeCtrl">
<div class="row">
<div class="col-md-12">
<form id="test">
<div data-ng-repeat="item in products">
<div class="col-sm-4 column productbox">
<div class="producttitle">{{item.ProductName}}</div> <div class="action"></div>
<div class="productprice">
<div class="pull-right">
<div >{{item.Id}}</div>
<a href="" class="btn btn-danger btn-sm" role="button"><span class="glyphicon glyphicon-arrow-right"></span> Get Quote</a>
</div>
<div class="pricetext">{{item.Description}}</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@section scripts
{
@Scripts.Render("~/Scripts/angular.js")
@Scripts.Render("~/Scripts/angular-cookies.min.js")
@Scripts.Render("~/Scripts/angular-route.js")
@Scripts.Render("~/Ng/app.module.js")
@Scripts.Render("~/Ng/homeCtrl.js")
}
我尝试了几种不同的方法,但都失败了。我在这里做错了什么?
编辑
我已经将示例项目上传到 GitHub here 。下载后您可能需要重建项目来同步相关包。
编辑:回答
以备日后参考,万一像我这样的AngularJS初学者正在看这道题,答案如下。
基于@Miyuru Ratnayake 给出的
$scope.getProducts = function () {
......
}
至
function getProducts() {
...
}
并将其称为 before the function 声明。不需要单独的函数 activate()。
所以控制器是这样的:
.controller('homeCtrl', ['$scope', '$cookies', '$http', 'ProductService', '$location', function homeCtrl($scope, $cookies, $http, ProductService, $location) {
$scope.products = [];
getProducts();
function getProducts() {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
}])
您应该在控件中的某处调用 getProducts() 方法...我没有看到它被调用了。
通常我会创建一个激活方法,如下所示,并在控件中调用它:
(function () {
'use strict';
angular.module('app')
.controller('homeCtrl', ['$scope', '$cookies', '$http', 'ProductService', '$location', function homeCtrl($scope, $cookies, $http, ProductService, $location) {
$scope.products = [];
activate();
function activate() {
getProducts();
}
function getProducts () {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
}])
.service('ProductService', ['$http', function ($http) {
this.getProducts = function () {
return $http.get('/api/ProductAPI');
};
}]);
})();
您忘记在 API 调用中定义方法名称,试试这个:
.service('ProductService', ['$http', function ($http) {
this.getProducts = function () {
return $http.get('/api/ProductAPI/myProducts');
};
}]);
默认情况下 ASP.NET Web API 查找“api/{controller}/{id}”,这意味着 ProductAPIController 应该有 GET、POST、PUT、DELETE 等基于 REST 概念的方法来处理模型。
但是在您的 ProductAPIController 代码中,GetProducts() 是用 HTTPGET 装饰的自定义操作方法,但即使这样,Web API 路由也不会理解这一点,直到您定义路由应该是“api/{controller}/{action}/{id}".
打开WebApiConfig.cs,如下更改路由模板并进行测试。 我添加了 {action},以便 Web API 路由在 API 控制器中查找自定义操作。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
只是一个建议 如果您计划使用 'GetProducts'、'GetProductsByName' 等自定义操作方法;使用此路线模板。
在客户端代码中使用它们之前,始终使用 POSTMAN 或 Fiddler 测试 Web API。我附上了通过 PostMan 测试的 GetProducts 的屏幕截图。
如果您使用 github 中的当前代码版本实际查看浏览器控制台,您会立即发现问题在于函数在您的代码中声明的顺序controller 会导致您尝试执行尚未定义的函数。
我重新订购了您的控制器以执行以下操作:
$scope.products = [];
function activate() {
$scope.getProducts();
}
$scope.getProducts = function () {
ProductService.getProducts().then(function (response) {
$scope.products = response.data;
}, function (err) {
alert(err);
});
};
activate();
此外,在您的 index.cshtml
中,您引用的产品详细信息使用了错误的大小写。
例如,你有这个:
{{item.ProductName}}
什么时候应该是这样:
{{item.productName}}