I had such a problem with this as well. I was posting JSON to an action, yet my JsonProperty names were ignored. Thus, my model properties were always empty.
public class MyModel
{
    [JsonProperty(PropertyName = "prop1")]
    public int Property1 { get; set; }
    [JsonProperty(PropertyName = "prop2")]
    public int Property2 { get; set; }
    [JsonProperty(PropertyName = "prop3")]
    public int Property3 { get; set; }
    public int Foo { get; set; }
}
I am posting to an action using this custom jquery function:
(function ($) {
    $.postJSON = function (url, data, dataType) {
        var o = {
            url: url,
            type: 'POST',
            contentType: 'application/json; charset=utf-8'
        };
        if (data !== undefined)
            o.data = JSON.stringify(data);
        if (dataType !== undefined)
            o.dataType = dataType;
        return $.ajax(o);
    };
}(jQuery));
And I call it like this:
data = {
    prop1: 1,
    prop2: 2,
    prop3: 3,
    foo: 3,
};
$.postJSON('/Controller/MyAction', data, 'json')
            .success(function (response) {
                ...do whatever with the JSON I got back
            });
Unfortunately, only foo was ever getting bound (odd, since the case is not the same, but I guess the default modelbinder isn't case-sensitive)
[HttpPost]
public JsonNetResult MyAction(MyModel model)
{
    ...
}
The solution ended up being rather simple
I just implemented a generic version of Dejan's model binder which works very nicely for me. It could probably use some dummy checks (like making sure the request is actually application/json), but it's doing the trick right now.
internal class JsonNetModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        controllerContext.HttpContext.Request.InputStream.Position = 0;
        var stream = controllerContext.RequestContext.HttpContext.Request.InputStream;
        var readStream = new StreamReader(stream, Encoding.UTF8);
        var json = readStream.ReadToEnd();
        return JsonConvert.DeserializeObject(json, bindingContext.ModelType);
    }
}
When I want to use it on a specific action, I simply tell it that I want to use my custom Json.Net model binder instead:
[HttpPost]
public JsonNetResult MyAction([ModelBinder(typeof(JsonNetModelBinder))] MyModel model)
{
    ...
}
Now my [JsonProperty(PropertyName = "")] attributes are no longer ignored on MyModel and everything is bound correctly!