C# 在到达ModelBinder之前推进Request.InputStream

C# 在到达ModelBinder之前推进Request.InputStream,c#,asp.net-mvc,asp.net-mvc-4,C#,Asp.net Mvc,Asp.net Mvc 4,在我们的MVC 2应用程序中,我们实现了一个JSON模型绑定器,如下所示: public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { string input; using (var reader = new StreamReader(controllerContext.HttpContext

在我们的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);
    }
在更新到MVC4之后,我注意到我们得到了传入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);
    }

但我想知道发生了什么使得改变成为必要?先前的实现是否只是巧合?

否,先前的实现不是巧合

ASP.NET MVC 3
引入了内置的JSON绑定支持,使操作方法能够接收JSON编码的数据并将其模型绑定到操作方法参数

JsonValueProviderFactory
默认情况下在ASP.NET MVC 3及以后版本中注册。
JSON
值提供程序在模型绑定之前运行,并将请求数据序列化到字典中。然后将字典数据传递到
模型活页夹

让我们看看
JsonValueProviderFactory
是如何工作的。下面是ASP.NET MVC开放源代码中提供的
JsonValueProviderFactory
源代码的链接

JsonValueProviderFactory.cs
中定义的
GetDeserializedObject
方法,如果
内容类型设置为
application/json
,则读取
,从而将
请求.InputStream
保留在流的末尾。因此这里首先调用
GetDeserializedObject
,然后调用
BindModel
。自从
GetDeserializedObject
已经读取了一次流,并提升了
请求。InputStream
到流的末尾,我们需要重置
请求。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;
}

请求内容的价值是什么?已经有人住了吗?如果是这样,这可能解释了为什么需要重新定位InputStream。MVC4还添加了RESTfulWebAPI,它直接支持将请求主体解析为模型参数。您引用的词典是否与@B2K注释中引用的请求内容相同?我是否应该更改模型绑定器实现以使用此词典?