nullnvoid
nullnvoid

Reputation: 562

When I post back to my controller all values for my model are null

I have cut the model back to one field:

//Model

public class LetterViewModel
{
    public string LetterText;
}

//Controller

public ActionResult Index()
{
    var model = new LetterViewModel();
    model.LetterText = "Anything";

    return View(model);
}

[HttpPost]
public ActionResult Index(LetterViewModel model)
{ 
    //model.LetterText == null
    return View(model);
}

//view

@model Test.Models.LetterViewModel
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
    ViewBag.Title = "Create a Letter";
}
@using (Html.BeginForm())
{
    <div id="Bottom">
        @Html.TextAreaFor(m => m.LetterText)
        <input type="submit" value="Ok" class="btn btn-default" />
    </div>
}

When I check the Network tab in dev tools it is showing the value entered is being included in the request. However, when the HttpPost controller is fired the field is empty.

Upvotes: 1

Views: 2068

Answers (3)

Sanket Parchande
Sanket Parchande

Reputation: 984

You need to add [FromBody] before parameter to Action

[HttpPost]
public ActionResult Index([FromBody]LetterViewModel model)
{ 
    //model.LetterText == null
    return View(model);
}

Upvotes: 0

toddmo
toddmo

Reputation: 22416

You can also use a custom binder instead of the default binder in cases where you don't have the option to convert fields to properties.

Loop through the form inputs and set them using reflection. MemberInformation is my class but you can just use FieldInfo.

This doesn't do an object graph but if I need that ability I'll enhance my answer. The tuple in the foreach uses c# 7.0. It also assumes that you saved your object from the previous GET before this POST.

using CommonBusinessModel.Metadata;
using GHCOMvc.Controllers;
using System;
using System.Linq;
using System.Web.Mvc;

namespace AtlasMvcWebsite.Binders
{
  public class FieldModelBinder : DefaultModelBinder
  {
    // this runs before any filters (except auth filters)
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
      var form = controllerContext.HttpContext.Request.Form;
      Type type = typeof(GHCOBusinessModel.GHCOPPAType);
      AtlasKernelBusinessModel.VersionedObject instance = PolicyController.Policy;

      foreach ((var value, var member) in (from string input in form
                                           let fi = type.GetField(input)
                                           where fi != null
                                           let mi = new MemberInformation(fi, instance)
                                           where !mi.ReadOnly
                                           select (form[input], mi)))
        member.SetValue(value);

      return instance;
    }

  }
}

Upvotes: 0

user3559349
user3559349

Reputation:

The DefaultModelBinder does not set the value of fields, only properties. You need to change you model to include properties

public class LetterViewModel
{
    public string LetterText { get; set; } // add getter/setter
}

Upvotes: 10

Related Questions