具有特定JsonConverter的MVC3控制器

时间:2012-07-15 08:24:42

标签: asp.net-mvc json serialization

以下是设置:

我有一些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控制器。

我尝试在我的global.asax中注册JsonConverter,如下所示:

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

但到目前为止还没有能够反序列化该对象。

2 个答案:

答案 0 :(得分: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请求。

答案 1 :(得分: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());
}