2010-12-21 5 views
11

ASP.NET MVC 3 RC2では、Content-Typeapplication/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

あなたのGlobal.asaxの中のApplication_Startに次のように置くことができます:これは(デフォルトであり)そのタイプのものがあると仮定し

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

、簡単ならば動作するように変更することができます複数ある。それがあなたが探しているものなら、よりクリーンな方法があるとは思わない。

+0

トリックをしたおかげで、!これは文書化されていない機能ですか、それとも私は何かを見逃しましたか? –

+0

MVCには、デフォルトで値プロバイダファクトリのセットが含まれています。 MVC3では、デフォルトの1つとしてJsonValueProviderFactoryが含まれていました。上記のすべてのコードは、アプリケーションを見つけてアプリケーションの起動時に削除します。それを回避するもう1つの方法は、あなたのAjaxリクエストは、コンテンツタイプapplication/jsonのを使用していないことだったかもしれないが、私は値プロバイダーファクトリを削除すると、おそらくより正確であると感じています。 –

+0

説明をありがとう。私はクエリーストリングやルートのようなもののプロバイダ工場があることに気づいていませんでした。私はModelBinderがそのすべてを処理していると仮定しました。 –

0

私はかなり遅く、これを答える明らかだけど、私はMVC5で特定のアクションのためにIValueProviderを変更する方法を開発しました。私はMVC3でこれが可能かどうか見ていく努力を怠っていません。なぜならこの質問は古かったからですが、やや似ていると思います。

免責事項:それはかなりではありません。

まず、我々は、アクション固有の設定を行うために属性に実装できる新しいインターフェースを作成:(あなたがasyncを使用している場合やAsyncControllerActionInvoker)次に

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

を、私たちは私たちをフックするカスタムControllerActionInvokerを作成します新しいインターフェイス:

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

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); 
    } 
} 
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; 
    } 
} 

最後に、我々は、スタートアップコードのデフォルトとして、当社のカスタムコントローラファクトリを設定します各リクエストで作成されるため、MVCがアクションをどのように処理するかを変更するために、コントローラにアクション固有の値を設定することができます。

[AcceptVerbs(HttpVerbs.Post)] 
[IgnoreJsonActionConfigurator] 
public async Task<ActionResult> Foo() { ... } 
関連する問題