在ASP.NET MVC 3 RC2中,默认modelbinder将自动解析请求主体 Content-Type 被设定为 application/json. 。问题是,这留下了 Request.InputStream 在流的尽头。这意味着,如果您尝试使用自己的代码读取输入流,则首先将其重置回开始:

// client sends HTTP request with Content-Type: application/json and a JSON
// string in the body

// requestBody is null because the stream is already at the end
var requestBody = new StreamReader(Request.InputStream).ReadToEnd();

// resets the position back to the beginning of the input stream
var reader = new StreamReader(Request.InputStream);
reader.BaseStream.Position = 0;
var requestBody = reader.ReadToEnd();

因为我正在使用 Json.NET 为了进行我的序列化/避难所化,我想禁用默认的模型邀请机,以免进行此额外的解析。有什么方法可以做到吗?

有帮助吗?

解决方案

您可以在global.asax中将以下内容列入application_start:

ValueProviderFactories.Factories.Remove(
            ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().First());

假设只有一种类型(默认情况下),但是如果有多个,则可以轻松地更改为工作。我不相信您要寻找的是一种更干净的方式。

其他提示

我显然在回答这个问题时很晚,但是我已经开发了一种方法来改变 IValueProvider 对于MVC5中的特定动作。我还没有努力查看MVC3是否可能发生这种情况,因为这个问题是旧的,但我认为这有些相似。

免责声明:不漂亮。

首先,我们创建一个可以在属性中实现的新界面,以制作特定于动作的配置:

internal interface IActionConfigurator
{
    void Configure(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}

然后,我们创建一个自定义 ControllerActionInvoker (或者 AsyncControllerActionInvoker 如果您使用 async)连接我们的新界面:

internal sealed class CustomControllerActionInvoker : AsyncControllerActionInvoker
{
    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
    {
        var actionDescriptor = base.FindAction(controllerContext, controllerDescriptor, actionName);
        var configurators = actionDescriptor.GetCustomAttributes(typeof(IActionConfigurator), true).Cast<IActionConfigurator>();
        foreach (var configurator in configurators)
            configurator.Configure(controllerContext, actionDescriptor);
        return actionDescriptor;
    }
}

现在,我们必须实施一个自定义 DefaultControllerFactory 设置 Controller.ActionInvoker:

internal sealed class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        var instance = base.GetControllerInstance(requestContext, controllerType);
        var controller = instance as Controller;
        if (controller != null)
            controller.ActionInvoker = new CustomControllerActionInvoker();
        return instance;
    }
}

最后,我们将自定义控制器工厂设置为启动代码中的默认值:

ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));

并实施我们的 IActionConfigurator 自定义属性中的接口:

internal sealed class IgnoreJsonActionConfiguratorAttribute : Attribute, IActionConfigurator
{
    public void Configure(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        // Here we can configure action-specific stuff on the controller
        var factories = ValueProviderFactories.Factories.Where(f => !(f is JsonValueProviderFactory)).ToList();
        controllerContext.Controller.ValueProvider = new ValueProviderFactoryCollection(factories).GetValueProvider(controllerContext);
    }
}

由于在每个请求上创建了一个新的控制器实例,因此我们能够在控制器上设置特定于操作的值,以修改MVC如何处理操作。

[AcceptVerbs(HttpVerbs.Post)]
[IgnoreJsonActionConfigurator]
public async Task<ActionResult> Foo() { ... }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top