【问题标题】:Calling ASP.NET Web API using AngularJS 1.4.7 service doesn't work使用 AngularJS 1.4.7 服务调用 ASP.NET Web API 不起作用
【发布时间】:2016-01-09 09:55:32
【问题描述】:

我在这个项目中使用 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 给出的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);
        });
    };
}])

【问题讨论】:

  • 您看到任何错误吗?当你从浏览器访问 yoursite/api/productapi 时会发生什么,你得到数据了吗?
  • 为什么返回 IQueryable?只需返回列表即可。
  • 查看浏览器网络控制台是否有错误。很可能被命中的端点不正确。
  • @Crowcoder,仍然更改为 List 并不能解决问题。它不返回数据。它是 IQuueryable,因为我刚刚从另一个项目中复制。我的问题在于角度服务调用。
  • @user1068538 将其更改为 list 在这里不会有什么不同,因为序列化程序将解析您的 IQueryable。然而,其他的问题是正确的。您实际收到了哪些错误消息?

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


【解决方案1】:

如果您实际上使用 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}}

【讨论】:

  • 不需要在github.com/johnpapa/angular-styleguide#bindable-members-up-top之后调用该函数。是的,关于变量 productName 的情况是一个很好的观点。这是由于行 config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();在 WebApiConfig.cs 中。这是我从另一个项目中剪切和粘贴以匆忙上传到 GitHub 的问题。我忘了删除那行。
  • 该链接描述的内容与您所拥有的代码不匹配(请注意代码示例调用在控制器中声明的函数,而您正在针对 $scope 调用函数)。我从 github 下载了你的代码并运行它。在浏览器控制台中,由于 $scope.getProducts() 尚未定义,对 activate() 的调用失败。
【解决方案2】:

默认情况下,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 Controller 中查找自定义操作。

config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

只是一个建议 如果您计划使用“GetProducts”、“GetProductsByName”等自定义操作方法;使用这个路由模板。

始终使用 POSTMAN 或 Fiddler 测试 Web API,然后在客户端代码中使用它们。我附上了通过 PostMan 测试的 GetProducts 的屏幕截图。

【讨论】:

  • 我认为您错过了 OP 声明他可以从浏览器成功命中端点的部分 - 这只是他的角度代码的一个问题。
  • 好建议,但是对于这个控制器,方法名称是可选的,因为它具有 [HttpGet] 属性,并且它只有一个 GET 方法。此外,我总是使用 Fiddler 测试 Web 服务,我在问题下的评论中提到了它。
【解决方案3】:

您忘记在 API 调用中定义方法名称,试试这个:

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

【讨论】:

  • 方法名称对于给定的控制器来说不是必需的,因为它只有一个 GET 方法并且使用 [HttpGet] 属性进行标记。
【解决方案4】:

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

【讨论】:

  • 我试过你的代码,还是没有结果。我会将我的完整项目上传到 GitHub。
  • 您编辑的代码确实有效。谢谢。需要注意的一件事 Activate() 函数不是必需的,您可以直接调用 getProducts() 函数。我已在问题底部注明。
猜你喜欢
  • 2023-03-04
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 2013-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多