使用Json.NET进行Json模型绑定
我有一个通过AJAX发布到的方法,其标题如下:使用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 = "
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好的,没问题。我现在就不谈了。祝你好运