在我们的MVC 2应用程序中,我们有一个像这样实现的JSON模型绑定器:
public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
string input;
using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream))
{
input = reader.ReadToEnd();
}
return JsonConvert.DeserializeObject(
input,
bindingContext.ModelType);
}
更新到MVC 4后,我注意到我们收到了传入JSON帖子的空传入模型。当深入挖掘时,上游的某些东西正在推进。这很容易修复,就像这样
public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
string input;
//something upstream after MVC 4 upgrade is advancing the stream to end before we can read it
controllerContext.HttpContext.Request.InputStream.Position = 0;
using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream))
{
input = reader.ReadToEnd();
}
return JsonConvert.DeserializeObject(
input,
bindingContext.ModelType);
}
但我想知道发生了什么事情使得必要的改变?先前的实施只是巧合吗?
答案 0 :(得分:3)
不,先前的实施并非巧合。
ASP.NET MVC 3
引入了内置JSON绑定支持,使行为方法能够接收JSON编码数据并将其模型绑定到操作方法参数。
JsonValueProviderFactory
默认在ASP.NET MVC 3
及之后注册。 JSON
值提供程序在模型绑定之前运行,并将请求数据序列化为字典。然后将字典数据传递给model binder
。
让我们看看JsonValueProviderFactory
是如何工作的。这是ASP.NET MVC开源代码JsonValueProviderFactory.cs
JsonValueProviderFactory
源代码的链接
GetDeserializedObject
中定义的 JsonValueProviderFactory.cs
方法会在stream
设置为Content-Type
时读取application/json
,因此会离开Request.InputStream
在流的最后。所以首先调用GetDeserializedObject
,然后调用BindModel
。以来
GetDeserializedObject
已经读过一次流并将Request.InputStream
推进到流的末尾,我们需要在Request.InputStream
BindModel
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}