Angular JS MVC Web API模型/参数不绑定.NET Core

Daw*_*wan 6 angularjs asp.net-core-mvc asp.net-core asp.net-core-webapi

我正在使用带有TypeScript和ASP.NET Core MVC/API的Angular JS.

我有一个apiService处理服务器的所有POSTGET请求,如下所示:

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, success, failure) {

            return this.$http.post(url,data)
                .then(result => { this.handleResponse(result, success); }, result => { this.handleError(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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我发送此请求时:

    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);
        });
    }
Run Code Online (Sandbox Code Playgroud)

它没有绑定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, xPTStatusCodesEnum.Success, "Loaded assets successfully");

            });
        }

}
Run Code Online (Sandbox Code Playgroud)

即使我在浏览器中检查了请求,也表明companyId在Payload中.

在此输入图像描述

注意:当我发布ViewModel时,相同的功能

编辑

在上面的场景中,我只将一个参数传递给控制器​​,但在某些情况下,我希望能够在不使用ViewModel的情况下传递2或3个参数.

例如

public IActionResult GetAssetListByCompany([FromBody]int companyId, [FromBody]int assetId)
{....
Run Code Online (Sandbox Code Playgroud)

要么

public IActionResult GetAssetListByCompany([FromBody]int companyId, [FromBody]int assetId, [FromBody]bool canEdit = false)
    {.....
Run Code Online (Sandbox Code Playgroud)

然后在客户端我可以这样做:

this.apiService.post('/api/Dashboard/GetAssetListByCompany', { companyId: selectedCompany.id, assetId: 123 }.....
Run Code Online (Sandbox Code Playgroud)

要么

this.apiService.post('/api/Dashboard/GetAssetListByCompany', { companyId: selectedCompany.id, canEdit: true, assetId: 22 }....
Run Code Online (Sandbox Code Playgroud)

Igo*_*gor 4

此处最好的方法是遵循 HTTP 准则,并将操作从 POST 更改为 GET,因为您不修改任何数据。这做起来相当简单,并且仍然能够使用 URI 发送带有请求的数据。

MVC 变化

有关各种选项,请参阅模型绑定,此处最好的方法是基于查询字符串进行绑定,因为您只需要单个基元类型。如果您有一个原始类型数组,您仍然可以绑定到查询字符串,则查询字符串变量名称将为每个值重复一次。

因此,我们所做的唯一更改是指定参数来自查询字符串,并且它与 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, xPTStatusCodesEnum.Success, "Company Id is 0"); }

           //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId, userModel);

            return new xPTJsonResult(null, xPTStatusCodesEnum.Success, "Loaded assets successfully");

        });
    }
}
Run Code Online (Sandbox Code Playgroud)

AngularJS 的变化

我们扩展了 apiService 以允许使用 HttpGet 传递调用数据。这可以使用$http 调用上的参数来完成,它将根据传入的数据动态创建 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, config, data, success, failure) {
        return this.$http({
            url: url,
            config: config,
            params: data,
            method: "GET"
            })
            .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) });
    }
}
Run Code Online (Sandbox Code Playgroud)

在通话中,我们只需将其从 更改为post即可get,它应该可以工作。

// only change from post to get
onCompanyChanged(selectedCompany, model, companyName) {
    this.apiService.get('/api/Dashboard/GetAssetListByCompany', { companyId: selectedCompany.id },
        response => {
            this.assetListViewModel = response.data.data;
        }, response => {
        this.notificationService.displayError(response.data.message);
    });
}
Run Code Online (Sandbox Code Playgroud)

编辑 - 这很灵活

更重要的一点是,这种设计在有角度的一侧是灵活的。如果您扩展 MVC 操作或具有采用其他参数的各种操作,则无需实现任何其他更改即可工作。例子:

[HttpGet]
[Route("GetSomethingElseFromServer")]
public IActionResult GetSomethingElseFromServer([FromQuery]int companyId, [FromQuery]string assetName, [FromQuery]string companyModelNumber) // use FromQuery
Run Code Online (Sandbox Code Playgroud)

对你的 Angular api 的调用是

this.apiService.get('/api/Dashboard/GetSomethingElseFromServer', { companyId: companyId, assetName: somePassedInAssetNameVar, companyModelNumber: somePassedInModelNumber }
Run Code Online (Sandbox Code Playgroud)

编辑 - 您还可以发送数组

要回答如何将多个基元类型作为数组发送的问题,您可以这样做。同样,这假设您发送的不是复杂类型,而是公司 ID 列表等。

时间:2019-03-17 标签:c#code

[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
Run Code Online (Sandbox Code Playgroud)

Angular调用,注意不需要更改服务

onCompanyChanged(selectedCompany, model, companyName) {
    this.apiService.get('/api/Dashboard/GetAssetListByCompany', { "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);
    });
}
Run Code Online (Sandbox Code Playgroud)

编辑 - 如果你还是想发布

您当前仅发送单个原始字段,因此 MVC 框架不会在 POST 中正确反序列化该字段。您需要将参数包装在视图模型中,将其作为查询字符串部分发送,或将其作为表单字段值发送。这是带有查询字符串部分的 POST,效果很好。

选项1

将其附加到 URL

[HttpPost] // change to HttpGet
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromQuery] int companyId) // use FromQuery
Run Code Online (Sandbox Code Playgroud)

角度调用

this.apiService.post('/api/Dashboard/GetAssetListByCompany/?companyId=' + selectedCompany.id + , null, // the rest of the code remains unchanged so I did not include it
Run Code Online (Sandbox Code Playgroud)

选项2

扩展 apiService 以获取 params 对象,以便它可以构建您的查询。无论哪种方式,调用者都必须了解一些有关正在进行的 http 调用的信息。

this.apiService.post('/api/Dashboard/GetAssetListByCompany', null, {companyId: selectedCompany.id}, null, // the rest of the code remains unchanged so I did not include it

post(url, config, data, params, success, failure) {
    return this.$http({
        url: url,
        config: config,
        data: data,
        params: params,
        method: "POST"
        })
        .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) });
}
Run Code Online (Sandbox Code Playgroud)

选项3

更新您的视图模型以采用复杂类型,这不需要更改您的角度代码。

public class ListByCompanyModel {
    public int CompanyId {get;set;}
}

[HttpPost] // change to HttpGet
[Route("GetAssetListByCompany")]
public IActionResult GetAssetListByCompany([FromBody] ListByCompanyModel model) // use FromQuery
Run Code Online (Sandbox Code Playgroud)