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:

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