2010-12-21 35 views
11

在ASP.NET MVC 3 RC2中,如果Content-Type設置爲application/json,默認的ModelBinder將自動分析請求主體。問題是,這將Request.InputStream留在流的末尾。這意味着,如果你試圖使用自己的代碼讀取輸入流,你首先必須重置回開頭:有什麼辦法可以禁用ASP.NET MVC 3 RC2中的JSON ModelBinder?

// 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做我的序列化/反序列化,我想禁用默認的ModelBinder進行額外的解析。有沒有辦法做到這一點?

回答

15

你可以把在的Application_Start以下在Global.asax中:

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

這是假設僅存在類型(默認情況下存在)中的一個,但它可以很容易地改變,如果工作有不止一個。我不相信如果那是你正在尋找的東西,有一種更清潔的方式。

+0

謝謝,這個伎倆!這是一個無證的功能,還是我錯過了什麼? – 2010-12-21 19:11:15

+0

默認情況下,MVC包含一組價值提供者工廠。使用MVC3,他們將JsonValueProviderFactory作爲默認值之一。以上所有代碼都是在應用程序啓動時找到它並將其刪除。解決這個問題的另一個方法可能不是讓你的ajax請求使用內容類型application/json,但我覺得刪除價值提供者工廠可能更正確。 – 2010-12-21 19:21:18

+0

感謝您的解釋。我甚至不知道有提供工廠的東西,如querystrings和路線。我假設ModelBinder處理了所有這些。 – 2010-12-21 19:25:39

0

我在回答這個問題時顯然很晚,但我開發了一種方法來更改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() { ... } 
相關問題