2

这是设置:

我有一些旨在供 jQuery ajax 请求使用的 MVC 控制器。一个正常的请求看起来有点像这样:

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

这对于传递给控制器​​的大多数对象都非常有效,除了在这种特定情况下,传递的对象的属性之一需要以特定方式反序列化。

我添加了一个 JsonConverter,我之前在 MVC4 Web API 中使用过它,但在这种情况下,我需要将它应用到常规的 mvc 控制器上。

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

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

但到目前为止还无法反序列化该对象。

4

2 回答 2

4

JsonValueProviderFactory如果您想Json.NET在将 JSON 请求绑定到视图模型时使用,您应该将内置类替换为自定义类。

您可以编写一个,如本要点所示:

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 请求。

于 2012-07-15T08:31:31.067 回答
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());
}
于 2014-09-07T10:53:08.873 回答