2014-04-14 54 views
5

我在學習如何使用AngularJS的$資源來調用Web Api後端。我想傳遞一個對象層次結構作爲條件並獲取IEnumerable<Program>。這裏是一個標準的例子:

$scope.criteria = { 
    Categories:[ 
     { 
      Name: "Cat1", 
      Options: [ 
       {Text: "Opt1", Value: true}, 
       {Text: "Opt2", Value: false} 
      ] 
     }, 
     { 
      Name: "Cat2", 
      Options: [ 
       {Text: "Opt3", Value: true}, 
       {Text: "Opt4", Value: false} 
      ] 
     } 
    ] 
} 

我在C#中的服務器上定義了相同的對象。

public class CriteriaModel 
{ 
    public IEnumerable<CriteriaCategory> Categories { get; set; } 
} 

public class CriteriaCategory 
{ 
    public string Name { get; set; } 
    public IEnumerable<CriteriaOption> Options { get; set; } 
} 

public class CriteriaOption 
{ 
    public string Text { get; set; } 
    public bool Value { get; set; } 
} 

以下是我正在配置$資源:

angular.module('my.services') 
    .factory('api', [ 
     '$resource', 
     function ($resource) { 
      return { 
       Profile: $resource('/api/profile/:id', { id: '@id' }), 
       Settings: $resource('/api/settings/:id', { id: '@id' }), 
       Program: $resource('/api/program/:id', { id: '@id' }) 
      }; 
     } 
    ]); 

我這樣稱呼它:

api.Program.query({ criteria: $scope.criteria }, function (response) { 
    $scope.programs = response; 
}); 

不管我怎麼努力我要麼得到null作爲標準參數或該行爲根本不執行。我不知道問題是在角度,網頁API還是兩者兼而有之。這裏是動作:

public class ProgramController : ApiController 
{ 
    public IEnumerable<Program> GetByCriteria([FromUri]CriteriaModel criteria) 
    { 
     // Either criteria is null or this action doesn't even get 
     // executed depending on what I try. 
    } 
} 

有人可以幫助我得到一個工作示例去搜索和返回使用AngularJS $資源和網絡API項目?

回答

9

您將需要一個自定義模型綁定器。從what I understandFromUri將不會處理複雜的嵌套類型或$resource將放入查詢字符串中的json。

Github Sample

型號粘合劑:

public class CriteriaModelBinder : IModelBinder 
{ 
    public bool BindModel(
     HttpActionContext actionContext, 
     ModelBindingContext bindingContext 
    ) 
    { 
     if (bindingContext.ModelType != typeof (CriteriaModel)) 
     { 
      return false; 
     } 

     var value = bindingContext.ValueProvider.GetValue("Categories"); 

     if (value == null) 
     { 
      return false; 
     } 

     var categoryJson = value.RawValue as IEnumerable<string>; 

     if (categoryJson == null) 
     { 
      bindingContext.ModelState.AddModelError(
       bindingContext.ModelName, "Categories cannot be null."); 
      return false; 
     } 

     var categories = categoryJson 
      .Select(JsonConvert.DeserializeObject<CriteriaCategory>) 
      .ToList(); 

     bindingContext.Model = new CriteriaModel {Categories = categories}; 
     return true; 
    } 
} 

控制器:

[RoutePrefix("api/program")] 
public class ProgramController : ApiController 
{ 
    [Route("getbycriteria")] 
    [HttpGet] 
    public HttpResponseMessage GetByCriteria(
     [ModelBinder(typeof(CriteriaModelBinder))]CriteriaModel criteria 
    ) 
    { 
     return new HttpResponseMessage(HttpStatusCode.OK); 
    } 
} 

角控制器:

angular.module('myApp'). 
    controller('HomeController', function($scope, $resource) { 
     var Program = $resource('/api/program/:id', {}, { 
      getByCriteria: { 
       url: '/api/program/getbycriteria', 
       method: 'GET', 
       isArray: true 
      } 
     }); 

     var program = new Program(); 
     var criteria = { 
      Categories: [ 
       { 
        Name: "Cat1", 
        Options: [ 
         { Text: "Opt1", Value: true }, 
         { Text: "Opt2", Value: false } 
        ] 
       }, 
       { 
        Name: "Cat2", 
        Options: [ 
         { Text: "Opt3", Value: true }, 
         { Text: "Opt4", Value: false } 
        ] 
       } 
      ] 
     }; 

     $scope.submit = function() { 
      console.log(program); 
      program.$getByCriteria(criteria); 
     }; 
    }); 

編輯:

這裏是POST

控制器:

[RoutePrefix("api/program")] 
public class ProgramController : ApiController 
{ 
    [Route("getbycriteria")] 
    [HttpPost] 
    public HttpResponseMessage GetByCriteria(CriteriaModel criteria) 
    { 
     return new HttpResponseMessage(HttpStatusCode.OK); 
    } 
} 

角:

angular.module('myApp'). 
    controller('HomeController', function($scope, $resource) { 
     var Program = $resource('/api/program/:id', {}, { 
      getByCriteria: { 
       url: '/api/program/getbycriteria', 
       method: 'POST', 
       isArray: true 
      } 
     }); 

     var program = new Program(); 
     program.Categories = [ 
       { 
        Name: "Cat1", 
        Options: [ 
         { Text: "Opt1", Value: true }, 
         { Text: "Opt2", Value: false } 
        ] 
       }, 
       { 
        Name: "Cat2", 
        Options: [ 
         { Text: "Opt3", Value: true }, 
         { Text: "Opt4", Value: false } 
        ] 
       } 
      ]; 

     $scope.submit = function() { 
      console.log(program); 
      program.$getByCriteria(); 
     }; 
    }); 
+0

所以,如果我創建了$資源的新作用,這確實一個POST,把[FromUri]關該參數,將照顧它,而無需我創建一個自定義模型聯編程序? – adam0101

+0

默認的模型聯編程序在請求的主體中查找JSON。 '$ resource'是RESTful,並在查詢字符串中發送JSON。不匹配的原因是您需要使用模型綁定器或使用'$ http'。 – Romoku

+0

等一下,我很困惑。根據文檔,您可以使用'POST'方法在$ resource上指定新操作。你是說它忽略了它,並把它放在查詢字符串呢? – adam0101