2010-12-21 14 views
11

ASP.NET MVC 3 RC2'de, varsayılan ModelBinder, Content-Typeapplication/json olarak ayarlanmışsa, istek gövdesini otomatik olarak ayrıştırır. Sorun şu ki, bu akımın sonunda Request.InputStream'u bırakır.ASP.NET MVC 3 RC2'de JSON ModelBinder'ı devre dışı bırakmanın bir yolu var mı?

// 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(); 

benim seri/deserialization yapmak Json.NET kullanıyorum, ben edilmesini istediğiniz: Bu, kendi kodunu kullanarak giriş akışı okumaya çalışırsanız, önce başlarına dayanan sıfırlamak var demektir varsayılan ModelBinder'ın bu ekstra ayrıştırmayı yapmasını engellemek için. Bunu yapmanın bir yolu var mı?

cevap

15

Sen Global.asax Application_Start aşağıdaki koyabilirsiniz: Bu yalnızca (varsayılan olarak vardır) bu tür bir tane varsayar

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

, ancak kolayca eğer çalışmak için değiştirilebilir Birden fazla var. Aradığın şey ise daha temiz bir yol olduğuna inanmıyorum.

+0

Teşekkürler, bu hile yaptı! Bu belgelenmemiş bir özellik mi yoksa sadece bir şey mi özledim? –

+0

MVC, varsayılan olarak bir dizi değer sağlayıcıları fabrika içerir. MVC3 ile JsonValueProviderFactory'yi varsayılanlardan biri olarak dahil ettiler. Yukarıdaki kodun tamamı onu bulur ve uygulama başladığında kaldırır. Çevresinde başka bir yol ajax istekleri içerik türü uygulama/json kullanmak zorunda olmayabilirdi, ama değer sağlayıcı fabrika çıkarılması muhtemelen daha doğru olduğunu hissediyorum. –

+0

Açıklama için teşekkürler. Hatta querystrings ve rotalar gibi şeyler için sağlayıcı fabrikalar olduğunu bile bilmiyordum. ModelBinder'ın hepsini ele aldığını varsaymıştım. –

0

Açıkçası bu yanıtı vermekte geciktim ama MVC5'te belirli bir eylem için IValueProvider'u değiştirmenin bir yolunu geliştirdim. Bu sorunun yaşlandığından MVC3'te bunun mümkün olup olmadığına bakma çabasından hiç geçmedim, ama sanırım bir şekilde benzer.

Yasal Uyarı: Hoş değil.

Birincisi, biz eyleme özgü yapılandırmaları yapmak için, bir ayrıntıda uygulayabileceği yeni bir arayüz oluşturmak: kanca (eğer async kullanıyorsanız veya AsyncControllerActionInvoker) Sonra

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

, biz özel bir ControllerActionInvoker oluşturmak bizim yeni arayüz:

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

Şimdi, ayarlamak için özel bir DefaultControllerFactory uygulamak zorunda Controller.ActionInvoker:

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

ve özel ayrıntı bizim IActionConfigurator arabirimini uygulamak: Yeni Denetleyici örneği yana

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

Son olarak, başlatma kodu varsayılan olarak bizim özel kontrolörü fabrika set Her istek üzerine oluşturulur, MVC'nin eylemi nasıl işlediğini değiştirmek için denetleyiciye eyleme özel değerler atayabiliriz.

[AcceptVerbs(HttpVerbs.Post)] 
[IgnoreJsonActionConfigurator] 
public async Task<ActionResult> Foo() { ... }