Reputation: 562
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
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
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
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