Model Binding Issue with ASP.NET5 MVC6

北战南征 提交于 2019-12-10 12:46:57

问题


Im trying to post some JSON data on an angular form to my ASP.NET5 MVC6 Controller action. The model binder does not seem to be working. Not sure what I'm missing here.

My ASP Controller:

public class DefaultController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public IActionResult SubmitTest(QTestViewModel model)
    {
        return Json("true");
    }
}

My Angular Controller:

angular.module("testActiveMq", [])
.controller("MqTestController", ["$scope", "$http", function ($scope, $http) {
    // Submit Form
    $scope.submitForm = function () {
        debugger;
        var formData = (this.data) ? angular.toJson(this.data) : null;
        if (formData && this.qForm && this.qForm.$valid) {
            $http({
                url: "/Default/SubmitTest",
                data: formData,
                method: "POST",
                dataType: "json",
                contentType: "application/json; charset=utf-8"
            })
            .then(function successCallback(response) {
                debugger;
                // this callback will be called asynchronously
                // when the response is available
            }, function errorCallback(response) {
                debugger;
                // called asynchronously if an error occurs
                // or server returns response with an error status.
            });
        }
    };
}])

My View Model:

public class QTestViewModel
{
    public string MqBrokerUri { get; set; }

    public string ClientId { get; set; }

    public string UserName { get; set; }

    public string Password { get; set; }

    public int TotalRequests { get; set; }

    public int MaxConcurrentRequests { get; set; }

    public int DelayBetweenThreads { get; set; }
}

When I make a request, the HTTP Headers are ..

POST /Default/SubmitTest HTTP/1.1
Host: localhost:50877
Connection: keep-alive
Content-Length: 225
Accept: application/json, text/plain, */*
Origin: http://localhost:50877
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:50877/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

My form data looks like so ..

{"MqBrokerUri":"ssl://broker-uri:1616?transport.acceptInvalidBrokerCert=true","ClientId":"MqLoadTest","UserName":"myunm","Password":"mypwd","TotalRequests":100,"MaxConcurrentRequests":10,"DelayBetweenThreads":1}

I feel like I'm missing something super obvious. Why is my JSON data not binding to my model? Surely I dont need a custom model binder for something so simple?


回答1:


Your code was enough in MVC 5 and earlier versions to receive the model in your controller. However in MVC 6 you also need to set the [FromBody] parameter in your controller action:

[HttpPost]
public IActionResult SubmitTest([FromBody]QTestViewModel model)
{
    return Json("true");
}

Not sure why this is a requirement in MVC 6, but your model will keep its default values if you dont add the FromBody attribute.

  • Check for example the Web API tutorial in the official docs.

  • After some digging into the source, it seems the BodyModelBinder will only accept models that specifically enabled the body binding source, which is done adding the [FromBody] attribute.

    var allowedBindingSource = bindingContext.BindingSource;
    if (allowedBindingSource == null ||
        !allowedBindingSource.CanAcceptDataFrom(BindingSource.Body))
    {
        // Formatters are opt-in. This model either didn't specify [FromBody] or specified something
        // incompatible so let other binders run.
        return ModelBindingResult.NoResultAsync;
    }
    

PS. Angular is stringifying by default the json objects, but if in case you use something like jQuery you also need to manually call JSON.stringify.




回答2:


Sometime it's happened with json better to use it

var jsonResult=json("true");
jsonResult.maxJsonLength=int32.maxValue
return jsonresult;

Hope it will help for you.




回答3:


[edit] It appears this answer is incorrect. My issue was caused by the Action parameter being named the same as one of the properties of the object. This resulted in MVC using a prefix to prevent ambiguity. I don't agree that it is ambiguous and am discussing this on Github.


I've just logged an error on Github about this. It seems that if your parameter isn't named as the CamelCase of the Type of the parameter, then it expects that the fields in the payload to be prefixed with the parameter name.

You can fix this by adding [Bind(Prefix="")] before the Action's parameter. public IActionResult SubmitTest([Bind(Prefix="")]QTestViewModel model)




回答4:


Ok @Daniel J.G. answere did not work for me I had to use [FromForm] instead of [FromBody] To get the binging working

  [HttpPost]
public IActionResult SubmitTest([FromForm]QTestViewModel model)
{
    return Json("true");
}


来源:https://stackoverflow.com/questions/34080796/model-binding-issue-with-asp-net5-mvc6

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!