This question is similar to other questions asked before, but my usage (and MVC knowledge) is different enough so I can't figure out how to adapt the other answers to fit my needs.
I have a form where a user requests a price for a product. That product has a number of optional modules, which affect the overall price. The controller should then send me an email with the chosen module(s)' DisplayName
included.
I can render out these module titles okay in the request form, but cannot read them back when the form is submitted. Debugging shows !ModelState.IsValid
, and within the model state there is a conversion exception:
The parameter conversion from type 'System.String' to type 'MyNamspace.Models.MyProductModule' failed because no type converter can convert between these types.
My entire approach may be wrong, but I've defined the modules in the product model (simplified example for SO), working from this tutorial:
public class MyProductModule
{
public string ModuleName { get; set; }
public bool Checked { get; set; }
}
public class ProductRequest
{
public ProductRequest()
{
Modules = LoadModules();
}
private List<MyProductModule> LoadModules()
{
return new List<MyProductModule>()
{
new MyProductModule() { ModuleName = "Module One", Checked = false },
new MyProductModule() { ModuleName = "Module Two", Checked = false },
new MyProductModule() { ModuleName = "Module Three", Checked = false }
};
}
[DisplayName("MyProduct Modules")]
public List<MyProductModule> Modules { get; set; }
}
Here's the code I use to render the check box list:
@model MyNamespace.Models.ProductRequest
@foreach (var item in Model.Modules)
{
<label>
<input type="checkbox" name="Modules" value="@item.ModuleName" checked="@item.Checked" />
@item.ModuleName
</label>
}
Here's how I am trying to collect the posted form data:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ProcessRequest(ProductRequest qd)
{
if (!ModelState.IsValid)
{
return View("Index", qd); // Code exits here with ModelState error
}
else
{
StringBuilder sb = new StringBuilder();
// null checks removed for brevity...
sb.Append("<ol>");
var selectedModules = qd.Modules.Where(x => x.Checked).Select(x => x).ToList();
foreach (MyProductModule sm in selectedModules)
{
sb.AppendFormat("<li>{0}</li>", sm.ModuleName);
}
sb.Append("</ol>");
}
// ....
}
Any help or advice would be much appreciated. As a long-term webforms developer, I am finding the MVC learning curve relentless!
Solution
See posted answer.