使用AngularJS 1.4.7服务调用ASP.NET Web API不起作用

时间:2015-10-12 02:23:06

标签: c# asp.net angularjs asp.net-mvc-4 asp.net-web-api2

我在这个项目中使用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

中的建议,为app模块使用了单独的文件
(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给出的accepted answer,改变了

$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);
        });
    };
}])

4 个答案:

答案 0 :(得分:2)

你应该在某个控件中调用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');
        };
    }]);
})();

答案 1 :(得分:0)

您忘记在API调用中定义方法名称,请尝试以下操作:

.service('ProductService', ['$http', function ($http) {
   this.getProducts = function () {
      return $http.get('/api/ProductAPI/myProducts');
   };
}]);

答案 2 :(得分:0)

默认情况下,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屏幕截图。

GetProducts response in PostMan

答案 3 :(得分:0)

如果您实际使用github中的当前版本代码查看浏览器控制台,您会立即看到问题是控制器中声明函数的顺序会导致您出现这种情况你试图执行尚未定义的函数。

我重新安排你的控制器执行以下操作:

$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}}