使用Json.NET进行Json模型绑定

使用Json.NET进行Json模型绑定,json,asp.net-mvc,json.net,model-binding,Json,Asp.net Mvc,Json.net,Model Binding,我有一个通过AJAX发布到的方法,其标题如下: public JsonResult GetDocuments(string searchTerm, SortRequest sort) SortRequest对象定义如下: [DataContract] public class SortRequest { [DataMember(Name = "field")] public string Field { get; set; } [DataMember(Name = "

我有一个通过AJAX发布到的方法,其标题如下:

public JsonResult GetDocuments(string searchTerm, SortRequest sort)
SortRequest对象定义如下:

[DataContract]
public class SortRequest
{
    [DataMember(Name = "field")]
    public string Field { get; set; }

    [DataMember(Name = "dir")]
    public string Direction { get; set; }
}
[DataContract]
public class SortRequest
{
    [DataMember(Name = "field")]
    [JsonProperty("field")]
    public string Field { get; set; }

    [DataMember(Name = "dir")]
    [JsonProperty("dir")]
    public string Direction { get; set; }
}
由于遗留代码,JSON对象的属性名“dir”与C#属性名不直接匹配。我们希望使用Json.NET作为Json请求的模型绑定器,因为它能够处理这个问题,但问题是进入模型绑定器的Json看起来像一个具有两个顶级属性“searchTerm”和“sort”的单个对象。然后,反序列化过程尝试将整个JSON字符串映射到每个方法参数中,但显然失败了

我已经尝试查看了现在开源的.NETMVC代码,但还不能确定DefaultModelBinder类如何优雅地处理这个问题。到目前为止,我看到的唯一选择是将每个JSON操作转换为一个请求参数,但这似乎不是一个好的解决方案,因为DefaultModelBinder不需要这样做

编辑以澄清:

JSON请求字符串如下所示:

{
    "searchTerm": "test",
    "sort": {
        "field": "name",
        "dir": "asc"
    }
}
我们正在重写DefaultModelBinder,并且仅在请求类型为application/Json时使用Json.NET。以下是相关代码:

var request = controllerContext.HttpContext.Request;

request.InputStream.Seek(0, SeekOrigin.Begin);

using (var reader = new StreamReader(request.InputStream))
{
    var jsonString = reader.ReadToEnd();

    result = JsonConvert.DeserializeObject(jsonString, bindingContext.ModelType);
}

bindingContext.ModelType将被设置为方法中每个参数的String和SortRequest,但由于上面是一个单独的JSON对象,它不会映射到这两种类型中的任何一种,因此在方法本身内部,所有内容都设置为默认值。

我认为
JsonProperty
属性可用于此操作,如下所示:

[DataContract]
public class SortRequest
{
    [DataMember(Name = "field")]
    public string Field { get; set; }

    [DataMember(Name = "dir")]
    public string Direction { get; set; }
}
[DataContract]
public class SortRequest
{
    [DataMember(Name = "field")]
    [JsonProperty("field")]
    public string Field { get; set; }

    [DataMember(Name = "dir")]
    [JsonProperty("dir")]
    public string Direction { get; set; }
}
更新

根据json添加绑定前缀:

public JsonResult GetDocuments(string searchTerm, [Bind(Prefix="sort"] SortRequest sort)

我最终使用Json.NET库中的方法实现了一个解决方案。实际上,我们检查JSON对象的顶级属性,看看是否存在我们试图绑定到的当前操作参数。如果操作的参数名和传入的单个请求的属性名之间存在重叠,则会出现这种情况。我认为这是一个足够的边缘情况,让幻灯片,因为它将只需要一个单一的对象被传递到一个行动,是期待多个

以下是修改后的BindModel方法:

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    object result;

    if (IsJSONRequest(controllerContext))
    {
        var request = controllerContext.HttpContext.Request;

        request.InputStream.Seek(0, SeekOrigin.Begin);

        using (var reader = new StreamReader(request.InputStream))
        {
            var jsonString = reader.ReadToEnd();

            // Only parse non-empty requests.
            if (!String.IsNullOrWhiteSpace(jsonString))
            {
                // Parse the JSON into a generic key/value pair object.
                var obj = JToken.Parse(jsonString);

                // If the string parsed and there is a top level property of the same
                // name as the parameter name we are looking for, use that property
                // as the JSON object to de-serialize.
                if (obj != null && obj.HasValues && obj[bindingContext.ModelName] != null)
                {
                    jsonString = obj[bindingContext.ModelName].ToString();
                }
            }

            result = JsonConvert.DeserializeObject(jsonString, bindingContext.ModelType);
        }
    }
    else
    {
        result = base.BindModel(controllerContext, bindingContext);
    }

    return result;
}

查找
[JsonProperty()]
,并在您的
模型中使用它,用于每个
属性。当DataMember属性是唯一的方法参数时,它似乎受到Json.NET的尊重。问题是,当有多个参数试图通过一个JSON对象映射到时,没有骰子,整个请求字符串仍在尝试反序列化。你的建议确实让我想到,也许我们的模型绑定器代码本身就是问题所在。我已经用BindModel方法的相关部分更新了上面的内容。我在想,也许我们获取参数本身的方式不对。@rpf3对不起,我不确定我认为这通常对我有效。我会删除,希望其他人能回答。不用担心,也不要删除。我认为在这里有所有的选择是有用的,这样人们就知道已经尝试了什么。Thanks@rpf3好的,没问题。我现在就不谈了。祝你好运