【问题标题】:Custom (OData) routes in RestangularRestangular中的自定义(OData)路由
【发布时间】:2018-02-13 21:50:15
【问题描述】:

在服务器端,我将 Web API 与 OData 路由约定一起使用,这意味着我获取单个实体的路由如下所示:

/api/v1/Products(1)

而不是:

/api/v1/Products/1

通常,在 Restangular 中,我可以通过以下方式获得单个实体:

Restangular.one('Product', 1);

但这不适用于我的 OData 端点。我查看了customGETsetRequestInterceptor,但我似乎无法找到示例或弄清楚如何更改路由以匹配我的端点。最好在全球范围内,因为我所有的实体都将具有相同的格式。

非常感谢任何帮助。

【问题讨论】:

    标签: angularjs asp.net-web-api restangular


    【解决方案1】:

    Restangular 文档详细说明了如何创建自定义配置,您可以通过编辑源代码 restangular.js 来做同样的事情,但是这个可扩展点允许我们保持一个干净的实现,它应该与大多数自定义或未来版本的 RestAngular 兼容允许并行标准 REST API 和 OData v4 API。

    How to create a Restangular service with a different configuration from the global one

    // Global configuration
    app.config(function(RestangularProvider) {
      RestangularProvider.setBaseUrl('http://localhost:16486');
      RestangularProvider.setRestangularFields({ id: 'Id' });
    });
    
    // Restangular service targeting OData v4 on a the specified route
    app.factory('ODataRestangular', function(Restangular) {
      return Restangular.withConfig(function(RestangularConfigurer) {
        RestangularConfigurer.setBaseUrl(RestangularConfigurer.baseUrl + '/odata');
    
        // OData v4 controller(key) Item Route convention
        RestangularConfigurer.urlCreatorFactory.path.prototype.base = function(current) {
          var __this = this;
          return _.reduce(this.parentsArray(current), function(acum, elem) {
            var elemUrl;
            var elemSelfLink = RestangularConfigurer.getUrlFromElem(elem);
            if (elemSelfLink) {
              if (RestangularConfigurer.isAbsoluteUrl(elemSelfLink)) {
                return elemSelfLink;
              } else {
                elemUrl = elemSelfLink;
              }
            } else {
              elemUrl = elem[RestangularConfigurer.restangularFields.route];
    
              if (elem[RestangularConfigurer.restangularFields.restangularCollection]) {
                var ids = elem[RestangularConfigurer.restangularFields.ids];
                if (ids) {
                  // Crude Implementation of 'several', don't try this with more than
                  // 60 Ids, performance degrades exponentially for large lists of ids.
                  elemUrl += '?$filter=((Id eq ' + ids.join(')or(Id eq ') + '))';
                }
              } else {
                var elemId;
                if (RestangularConfigurer.useCannonicalId) {
                  elemId = RestangularConfigurer.getCannonicalIdFromElem(elem);
                } else {
                  elemId = RestangularConfigurer.getIdFromElem(elem);
                }
    
                if (RestangularConfigurer.isValidId(elemId) && !elem.singleOne) {
                  elemUrl += '(' + (RestangularConfigurer.encodeIds ? encodeURIComponent(elemId) : elemId) + ')';
                }
              }
            }
            acum = acum.replace(/\/$/, '') + '/' + elemUrl;
            return __this.normalizeUrl(acum);
    
          }, RestangularConfigurer.baseUrl);
        };
    
        // add a response interceptor for OData v4:
        RestangularConfigurer.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
          var extractedData;
          // Collection requests are 'getList' operations
          if (operation === "getList") {
            // return the value array
            extractedData = data.value;
          } else {
            // return the first item in the array
            if(data.value.length > 0)
              extractedData = data.value[0];
          }
          // pass the metadata back
          if(extractedData) {
            extractedData.meta = { context: data['@odata.context'] };
            if(data['@odata.count'])
              extractedData.meta.count = data['@odata.count'];
          }
          return extractedData;
        });
      });
    });
    

    实现示例:

    // Controller for list route
    function ListCtrl($scope, ODataRestangular) {
      $scope.providers = ODataRestangular.all("providers").getList({ $count:true }).$object;
      $scope.some = ODataRestangular.several("providers", 15,16,17,18).getList();
      $scope.single = ODataRestangular.one("providers", 15).get();
    }
    

    从网络流量中捕获的 URL:

    http://localhost:16486/odata/providers?$count=true

    http://localhost:16486/odata/providers?$filter=((Id eq 15)or(Id eq 16)or(Id eq 17)or(Id eq 18))

    http://localhost:16486/odata/providers(15)

    我努力尝试编写自定义服务工厂并修改 BreezeJS 以与 OData v4 一起使用,直到最近才偶然发现 Restangular,我现在可以真正体会到 restangular 的可扩展设计,通常缺乏文档化的客户端框架支持一直是阻止 OData v4 更广泛采用的致命弱点。我希望这个答案有助于让更多开发人员加入第 4 版。

    【讨论】:

      【解决方案2】:

      Restangular 不明确支持 OData API。您可以使基础工作,但您可能最好使用支持查询 OData API 的库,例如 breeze.js

      【讨论】:

      • 谢谢,我会研究一下breeze.js
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-20
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 2015-06-08
      • 2019-08-07
      相关资源
      最近更新 更多