ASPNET Core HttpPost [FromBody] parameter is always null

I'm learning MVC and trying to follow the tutorial on PluralSight. I try to follow exactly what the author has, but in the video he is able to add new stop while I cannot because the binding parameter in HttpPost method is always null. I try to switch [FromBody] to string type, but still does not work.

public class StopViewModel
{
    [Required()]
    [StringLength(100, MinimumLength = 5)]
    public string Name { get; set; }

    public double Latitude { get; set; }
    public double Longitude { get; set; }

    [Required()]
    public int Order { get; set; }

    [Required()]
    public DateTime Arrival { get; set; }
}

Client view layout:

 <form novalidate name="newStopForm" ng-submit="vm.addStop()">
    <div class="form-group">
        <label>Date</label>
        <input class="form-control" id="arrival" name="arrival"
               ng-model="vm.newStop.arrival"
               required
               ng-pattern="/^(\d{2})\/(\d{2})\/(\d{4})$/" />
        <span class="text-danger" ng-show="newStopForm.arrival.$error.required">Required</span>
        <span class="text-danger" ng-show="newStopForm.arrival.$error.pattern">Must be in format of MM/DD/YYYY.</span>
    </div>
    <div class="form-group">
        <label>Location</label>
        <input class="form-control" id="loc" name="loc" ng-model="vm.newStop.loc" required ng-minlength="5" />
        <span class="text-danger" ng-show="newStopForm.loc.$error.required">Required</span>
        <span class="text-danger" ng-show="newStopForm.loc.$error.minlength">Must be 5 characters or more</span>
    </div>
    <div>
        <input type="submit" value="Add" class="btn btn-success" ng-disabled="newStopForm.$invalid" />
    </div>
</form>

Controller:

This is where the null occurs. "[FromBoyd]StopViewModel vm" and vm is always null.

[HttpPost("Api/Trips/{vacation}/stops")]
public async Task<IActionResult> AddNewStop(string vacation, [FromBody]StopViewModel vm)
{
    try
    {
        if (ModelState.IsValid)
        {
            var newStop = Mapper.Map<Stop>(vm);

            _vacationRepo.AddStop(vacation, User.Identity.Name, newStop);

            //now we add new stop to the database
            if (await _vacationRepo.AddToDbAsync())
            {
                return Created($"api/trips/{vacation}/stops/{newStop.Name}",
                    Mapper.Map<StopViewModel>(newStop));
            }
        }
        else
        {
            foreach (var modelStateKey in ViewData.ModelState.Keys)
            {
                var modelStateVal = ViewData.ModelState[modelStateKey];
                foreach (var error in modelStateVal.Errors)
                {
                    var key = modelStateKey;
                    var errorMessage = error.ErrorMessage;
                    var exception = error.Exception;
                }
            }
        }
    }
    catch(Exception err)
    {
        string info = err.Message;
    }

    return BadRequest("Post- Bad things happened");
}

1 answer

  • answered 2018-07-21 15:41 Nkosi

    You are submitting a form. Try using the [FromForm] attribute to bind your model.

    [FromForm]: Use this to specify the exact binding source you want to apply.

    [HttpPost("Api/Trips/{vacation}/stops")]
    public async Task<IActionResult> AddNewStop(string vacation, [FromForm]StopViewModel vm) {
        //...code omitted for brevity
    }
    

    Reference Model Binding in ASP.NET Core