简体   繁体   中英

Model Binding Issue with ASP.NET5 MVC6

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?

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 .

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.

[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)

Ok @Daniel JG 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");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM