我正在使用带有TypeScript和ASP.NET Core MVC / API的Angular JS.
我有一个apiService来处理对服务器的所有POST和GET请求,如下所示:
module TBApp {
export class apiService {
static $inject = ['$http','notificationService'];
constructor(private $http,private notificationService: notificationService) {
}
get(url,config,success,failure) {
return this.$http.get(url,config)
.then(result => { this.handleResponse(result,success); },result => { this.handleError(result,failure) });
}
post(url,data,failure) {
return this.$http.post(url,data)
.then(result => { this.handleResponse(result,failure) });
}
handleResponse(result,success) {
alert('success');
success(result);
}
handleError(result,failure) {
if (result.status === '401') {
this.notificationService.displayError('Authentication required.');
//this.$rootScope.prevIoUsstate = this.$location.path();
//this.$location.path('/login');
}
else if (failure !== null) {
failure(result);
}
}
}
}
现在,当我发送此请求时:
onCompanyChanged(selectedCompany,model,companyName) {
this.apiService.post('/api/Dashboard/GetAssetListByCompany',{ companyId: selectedCompany.id },response => {
this.assetListviewmodel = response.data.data;
},response => {
this.notificationService.displayError(response.data.message);
});
}
它没有绑定控制器中的companyId
这是控制器:
[Route("api/[controller]")]
public class DashboardController : BaseController
{
[HttpPost]
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromBody]int companyId)
{
return CreateJsonResult(() =>
{
if (companyId == 0) { return new xPTJsonResult(null,xPTStatusCodesEnum.Success,"Company Id is 0"); }
//var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId,usermodel);
return new xPTJsonResult(null,"Loaded assets successfully");
});
}
}
即使我在浏览器中检查了请求,也表明companyId在Payload中.

NOTE: The same function works when I post a viewmodel
编辑
在上面的场景中,我只将一个参数传递给控制器,但在某些情况下,我希望能够在不使用viewmodel的情况下传递2或3个参数.
例如
public IActionResult GetAssetListByCompany([FromBody]int companyId,[FromBody]int assetId)
{....
要么
public IActionResult GetAssetListByCompany([FromBody]int companyId,[FromBody]int assetId,[FromBody]bool canEdit = false)
{.....
然后在客户端我可以这样做:
this.apiService.post('/api/Dashboard/GetAssetListByCompany',{ companyId: selectedCompany.id,assetId: 123 }.....
要么
this.apiService.post('/api/Dashboard/GetAssetListByCompany',canEdit: true,assetId: 22 }....
这里最好的方法是遵循HTTP准则并将操作从POST更改为GET,因为您不修改任何数据.这很简单,仍然可以使用URI通过您的请求发送数据.
MVC改变了
有关各种选项,请参阅Model Binding,此处的最佳方法是基于查询字符串进行绑定,因为您只需要一个基本类型.如果您有一个基本类型数组仍然可以绑定到查询字符串,则查询字符串变量名称将为每个值重复一次.
因此,我们所做的唯一更改是指定参数来自查询字符串,并且它与Http Get请求而不是Post相关联.
[Route("api/[controller]")]
public class DashboardController : BaseController
{
[HttpGet] // change to HttpGet
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromQuery]int companyId) // use FromQuery
{
return CreateJsonResult(() =>
{
if (companyId == 0) { return new xPTJsonResult(null,"Company Id is 0"); }
//var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId,usermodel);
return new xPTJsonResult(null,"Loaded assets successfully");
});
}
}
AngularJS发生了变化
我们扩展apiService以允许使用HttpGet传递调用数据.这可以使用params on the $http call完成,它将使用名称作为查询字符串值名称和值作为值部分,根据传入的数据动态创建URL.
export class apiService {
/* all other code is left as is,just change the get method to also accept data via the params. If null is passed in then it is ignored. */
get(url,failure) {
return this.$http({
url: url,config: config,params: data,method: "GET"
})
.then(result => { this.handleResponse(result,failure) });
}
}
在通话中我们只需要从post更改为get,它应该可以工作.
// only change from post to get
onCompanyChanged(selectedCompany,companyName) {
this.apiService.get('/api/Dashboard/GetAssetListByCompany',response => {
this.assetListviewmodel = response.data.data;
},response => {
this.notificationService.displayError(response.data.message);
});
}
编辑 – 这很灵活
更重要的是,这种设计在角度方面是灵活的.如果您扩展MVC操作或具有采取其他参数的各种操作,则无需执行任何其他更改即可运行.例:
[HttpGet]
[Route("GetSomethingElseFromServer")]
public IActionResult GetSomethingElseFromServer([FromQuery]int companyId,[FromQuery]string assetName,[FromQuery]string companyModelNumber) // use FromQuery
对你的角度api的调用将是
this.apiService.get('/api/Dashboard/GetSomethingElseFromServer',{ companyId: companyId,assetName: somePassedInAssetNameVar,companyModelNumber: somePassedInModelNumber }
编辑 – 您也可以发送数组
要回答关于如何将多个基元类型作为数组发送的问题,您可以这样做.同样,这假设它不是您要发送的复杂类型,但是,例如,公司ID列表.
c#代码
[HttpGet]
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromQuery]int[] companyIds) // use an array of int ie. int[]. i changed the variable name to make it clear there can be more than 1
Angular调用,注意没有必要更改服务
onCompanyChanged(selectedCompany,{ "companyIds[]": [id1,id2,id3] },// note the name is Now enclosed in quotes,made plural,and includes []. The value is an array
response => {
this.assetListviewmodel = response.data.data;
},response => {
this.notificationService.displayError(response.data.message);
});
}
编辑 – 如果你想要POST
您目前只发送一个原始字段,因此POST中的MVC框架无法正确反序列化.您需要将参数包装在视图模型中,将其作为查询字符串部分发送,或将其作为表单字段值发送.这是带有查询字符串部分的POST,它可以正常工作.
选项1
将其附加到URL
[HttpPost] // change to HttpGet
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromQuery] int companyId) // use FromQuery
角度呼叫
this.apiService.post('/api/Dashboard/GetAssetListByCompany/?companyId=' + selectedCompany.id +,null,// the rest of the code remains unchanged so I did not include it
选项2
扩展apiService以获取params对象,以便它可以构建您的查询.无论哪种方式,你都会遇到调用者不得不对http调用有所了解.
this.apiService.post('/api/Dashboard/GetAssetListByCompany',{companyId: selectedCompany.id},// the rest of the code remains unchanged so I did not include it
post(url,params,failure) {
return this.$http({
url: url,data: data,params: params,method: "POST"
})
.then(result => { this.handleResponse(result,failure) });
}
选项3
更新视图模型以采用复杂类型,这不需要更改角度代码.
public class ListByCompanyModel {
public int CompanyId {get;set;}
}
[HttpPost] // change to HttpGet
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromBody] ListByCompanyModel model) // use FromQuery