I have a model like this:
public PurchaseOrder
{
[Required] [StringLength(15)]
public virtual string OrderNumber {get;set;}
// etc.
}
When I submit an order from the view (using $.post, not input type=submit) it goes to my controller class:
public class PurchaseOrderController
{
public JsonResult Save(PurchaseOrder order)
{
// TryUpdateModel(order); // commented out since modelstate.isvalid remains false anyway
if (ModelState.IsValid)
{
// its never valid
}
}
}
ModelState.IsValid always returns false, with the error: "The Order Number field is required." But there is a value in this field (?? why)
Why would it say "value is required" when it does have a value? Have I missed something? Is it because of the $.post instead of the submit? What can I do?
This is what the debugger looks like:
alt text http://www.freeimagehosting.net/uploads/f734f3d95d.png
EDIT: Extra info....
I really think that for some reason the model binding is not happening. When I try this code found here: )
if (!ModelState.IsValid)
{
ModelState.Clear();
ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => order, order.GetType());
ModelValidator compositeValidator = ModelValidator.GetModelValidator(modelMetadata, base.ControllerContext);
foreach (ModelValidationResult result in compositeValidator.Validate(null))
{
this.ModelState.AddModelError(result.MemberName, result.Message);
}
}
Then ModelState.IsValid = true. compositeValidator.Validate() returns 0 errors. I think this indicates the model was not bound, but I still don't know why.
The controller method actually looks like this (I missed out the filter when originally writing this question)
[JsonFilter(Param = "order", JsonDataType = typeof(PurchaseOrder))]
public JsonResult Save(PurchaseOrder order) { // etc ... }
And the JsonFilter does this to extract the POCO from the json submitted data:
filterContext.ActionParameters[Param]
= jsSerializer.Deserialize(inputContent, JsonDataType);
I put a breakpoint on this line, and order is valid, plus order.OrderNumber has the correct value.
So still unresolved, but hopefully this extra info will help with finding a solution
Well I have "solved" it, but I do not really understand why the changes I made have helped.
I had to do three things:
Remove the json filter (filters don't bind)
Change the contentType to application/json
$.ajaxSetup({ contentType: "application/json; charset=utf-8" });
Use the MVC futures download Microsoft.Mvc.dll as described here: http://haacked.com/archive/2010/04/15/sending-json-to-an-asp-net-mvc-action-method-argument.aspx. Where is says to add this to Application_Start() in Global.asax.cs:
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
Now I dont know exactly why that has worked, but it has.
Unfortunately it has had a negative side effect: the contenttype is applied to all $.get() and $.post() methods, and broken all my jqgrids - they only seem to work if the content type is the default of application/x-www-form-urlencoded
So I've asked 2 follow on questions:
Is it possible to set the content type in a $.post() call? Then I wouldn't need to set it globally Jquery - How to make $.post() use contentType=application/json?
Is it possible to make jqrid work if the contenttype is application/json? Jquery - How to make $.post() use contentType=application/json?