2012-07-15 34 views
2

以下是設置:具有特定JsonConverter的MVC3控制器

我有一些MVC控制器,旨在被jQuery ajax請求使用。一個正常的要求會有些看起來是這樣的:

$.ajax("/Solicitor/AddSolicitorToApplication", { 
    data: putData, 
    type: "POST", contentType: "application/json", 
    success: function (result) { 
     //My success callback 
     } 
    } 
}); 

我的控制器看起來是這樣的:

[HttpPost] 
public ActionResult InsertLoanApplication(MortgageLoanApplicationViewModel vm) 
{ 
    var mortgageLoanDTO = vm.MapToDTO(); 
    return Json(_mortgageLoanService.UpdateMortgageLoanApplication(mortgageLoanDTO), JsonRequestBehavior.DenyGet); 
} 

這適用於傳遞給控制器​​的大多數對象完全正常的,但在這種特殊情況下的一個被傳遞的對象的屬性需要以特定的方式進行反序列化。

我已經添加了一個以前用MVC4 Web API的JsonConverter,但在這種情況下,我需要將它應用於常規的mvc控制器。

我試着註冊JsonConverter在我的Global.asax是這樣的:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new GrizlyStringConverter()); 

但到目前爲止,還沒有能夠反序列化對象。

回答

4

如果您想在綁定JSON請求以查看模型時使用Json.NET,則應該使用自定義的類替換內置的JsonValueProviderFactory類。

如圖this gist你可以寫一個:

public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory 
{ 
    public override IValueProvider GetValueProvider(ControllerContext controllerContext) 
    { 
     if (controllerContext == null) 
     { 
      throw new ArgumentNullException("controllerContext"); 
     } 

     if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) 
     { 
      return null; 
     } 

     using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream)) 
     { 
      var bodyText = reader.ReadToEnd(); 

      return String.IsNullOrEmpty(bodyText) 
       ? null : 
       new DictionaryValueProvider<object>(
        JsonConvert.DeserializeObject<ExpandoObject>(
         bodyText, 
         new ExpandoObjectConverter() 
        ), 
        CultureInfo.CurrentCulture 
       ); 
     } 
    } 
} 

,然後更換內置的與您的自定義一個在Application_Start

ValueProviderFactories.Factories.Remove(
    ValueProviderFactories 
     .Factories 
     .OfType<JsonValueProviderFactory>() 
     .FirstOrDefault() 
); 
ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory()); 

就是這樣。現在,您正在使用Json.Net而不是JavaScriptSerializer來處理傳入的JSON請求。

+0

是的,謝謝達林。我已經這樣做了,對於大多數物體來說它工作正常。除了具有「GrizlyString」屬性的對象外。 我需要找到一種方法來指定使用自定義的JsonConverter。 – amhed 2012-07-15 15:05:33

+0

您可以將您的自定義轉換器作爲構造函數參數傳遞給我已顯示的JsonDotNetValueProviderFactory。 – 2012-07-15 16:19:30

+0

我嘗試了這樣的反序列化: var deserializeObject = JsonConvert.DeserializeObject (bodyText,new ExpandoObjectConverter(),new GrizlyStringConverter()); – amhed 2012-07-15 19:43:05

0

修改後的版本:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Dynamic; 
using System.Globalization; 
using System.IO; 
using System.Web.Mvc; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Converters; 

namespace MvcJsonNetTests.Utils 
{ 
    public class JsonNetValueProviderFactory : ValueProviderFactory 
    { 
     public JsonNetValueProviderFactory() 
     { 
      Settings = new JsonSerializerSettings 
      { 
       ReferenceLoopHandling = ReferenceLoopHandling.Error, 
       Converters = { new ExpandoObjectConverter() } 
      }; 
     } 

     public JsonSerializerSettings Settings { get; set; } 

     public override IValueProvider GetValueProvider(ControllerContext controllerContext) 
     { 
      if (controllerContext == null) 
       throw new ArgumentNullException("controllerContext"); 

      if (controllerContext.HttpContext == null || 
       controllerContext.HttpContext.Request == null || 
       controllerContext.HttpContext.Request.ContentType == null) 
      { 
       return null; 
      } 

      if (!controllerContext.HttpContext.Request.ContentType.StartsWith(
        "application/json", StringComparison.OrdinalIgnoreCase)) 
      { 
       return null; 
      } 

      if (!controllerContext.HttpContext.Request.IsAjaxRequest()) 
      { 
       return null; 
      } 

      using (var streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream)) 
      { 
       using (var jsonReader = new JsonTextReader(streamReader)) 
       { 
        if (!jsonReader.Read()) 
         return null; 

        var jsonSerializer = JsonSerializer.Create(this.Settings); 

        Object jsonObject; 
        switch (jsonReader.TokenType) 
        { 
         case JsonToken.StartArray: 
          jsonObject = jsonSerializer.Deserialize<List<ExpandoObject>>(jsonReader); 
          break; 
         default: 
          jsonObject = jsonSerializer.Deserialize<ExpandoObject>(jsonReader); 
          break; 
        } 

        var backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); 
        addToBackingStore(backingStore, String.Empty, jsonObject); 
        return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture); 
       } 
      } 
     } 

     private static void addToBackingStore(IDictionary<string, object> backingStore, string prefix, object value) 
     { 
      var dictionary = value as IDictionary<string, object>; 
      if (dictionary != null) 
      { 
       foreach (var entry in dictionary) 
       { 
        addToBackingStore(backingStore, makePropertyKey(prefix, entry.Key), entry.Value); 
       } 
       return; 
      } 

      var list = value as IList; 
      if (list != null) 
      { 
       for (var index = 0; index < list.Count; index++) 
       { 
        addToBackingStore(backingStore, makeArrayKey(prefix, index), list[index]); 
       } 
       return; 
      } 

      backingStore[prefix] = value; 
     } 

     private static string makeArrayKey(string prefix, int index) 
     { 
      return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]"; 
     } 

     private static string makePropertyKey(string prefix, string propertyName) 
     { 
      return (string.IsNullOrWhiteSpace(prefix)) ? propertyName : prefix + "." + propertyName; 
     } 
    } 
} 

還以右手食指在其註冊:

public static void RegisterFactory() 
{ 
    var defaultJsonFactory = ValueProviderFactories.Factories 
     .OfType<JsonValueProviderFactory>().FirstOrDefault(); 
    var index = ValueProviderFactories.Factories.IndexOf(defaultJsonFactory); 
    ValueProviderFactories.Factories.Remove(defaultJsonFactory); 
    ValueProviderFactories.Factories.Insert(index, new JsonNetValueProviderFactory()); 
}