【问题标题】:How do I sub in JSON.NET as model binder for ASP.NET MVC controllers?如何在 JSON.NET 中子作为 ASP.NET MVC 控制器的模型绑定器?
【发布时间】:2014-01-25 15:27:17
【问题描述】:

ASP.NET Web API 团队决定使用 JSON.NET 库来绑定 JSON 数据。然而,“普通”的 MVC 控制器仍然使用劣质的 JsonDataContractSerializer。这会导致解析日期出现问题,让我很头疼。

请参阅此内容:
http://www.devcurry.com/2013/04/json-dates-are-different-in-aspnet-mvc.html

作者选择在客户端的Knockout层解决问题。但我更愿意通过在 MVC 控制器中使用与在 Web API 控制器中相同的 JSON.NET 模型绑定器来解决这个问题。

如何将不同的 JSON 模型绑定器替换为 ASP.NET MVC?具体来说,JSON.NET 库。如果可能,使用来自 Web API 的相同模型绑定器将是理想的。

【问题讨论】:

标签: asp.net-mvc json model-binding


【解决方案1】:

我已经这样做了,并且还大量定制了 Json.NET 正在做的序列化,通过:

替换 global.asax.cs 中的默认格式化程序,Application_Start:

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.Add(new CustomJsonMediaTypeFormatter());

而我的 CustomJsonMediaTypeFormatter 是:

public static class CustomJsonSettings
{
    private static JsonSerializerSettings _settings;

    public static JsonSerializerSettings Instance
    {
        get
        {
            if (_settings == null)
            {
                var settings = new JsonSerializerSettings();

                // Must convert times coming from the client (always in UTC) to local - need both these parts:
                settings.Converters.Add(new IsoDateTimeConverter { DateTimeStyles = System.Globalization.DateTimeStyles.AssumeUniversal }); // Critical part 1
                settings.DateTimeZoneHandling = DateTimeZoneHandling.Local;   // Critical part 2

                // Skip circular references
                settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

                // Handle special cases in json (self-referencing loops, etc)
                settings.ContractResolver = new CustomJsonResolver();

                _settings = settings;
            }

            return _settings;
        }
    }
}

public class CustomJsonMediaTypeFormatter : MediaTypeFormatter
{
    public JsonSerializerSettings _jsonSerializerSettings;

    public CustomJsonMediaTypeFormatter()
    {
        _jsonSerializerSettings = CustomJsonSettings.Instance;

        // Fill out the mediatype and encoding we support
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
        SupportedEncodings.Add(new UTF8Encoding(false, true));
    }

    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override bool CanWriteType(Type type)
    {
        return true;
    }

    public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger)
    {
        // Create a serializer
        JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);

        // Create task reading the content
        return Task.Factory.StartNew(() =>
        {
            using (StreamReader streamReader = new StreamReader(stream, SupportedEncodings.First()))
            {
                using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
                {
                    return serializer.Deserialize(jsonTextReader, type);
                }
            }
        });
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
    {
        // Create a serializer
        JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings);

        // Create task writing the serialized content
        return Task.Factory.StartNew(() =>
        {
            using (StreamWriter streamWriter = new StreamWriter(stream, SupportedEncodings.First()))
            {
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter))
                {
                    serializer.Serialize(jsonTextWriter, value);
                }
            }
        });
    }
}

最后是 CustomJsonResolver:

public class CustomJsonResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
    {
        var list = base.CreateProperties(type, memberSerialization);

        // Custom stuff for my app
        if (type == typeof(Foo))
        {
            RemoveProperty(list, "Bar");
            RemoveProperty(list, "Bar2");
        }

        return list;
    }

    private void RemoveProperty(IList<JsonProperty> list, string propertyName)
    {
        var rmc = list.FirstOrDefault(x => x.PropertyName == propertyName);

        if (rmc != null)
        {
            list.Remove(rmc);
        }
    }
}

【讨论】:

  • 它是,但你可能并不需要它,例如自定义解析器是特定于我的应用程序的
  • 这似乎适用于 WebApi,而不是 MVC5。
  • 如果那是一个纯 MVC5 项目,那么没有可用的 GlobalConfiguration。这个问题显然是针对 MVC 的
【解决方案2】:

JsonNetValueProviderFactory proposed here 比我尝试过的其他方法更好(例如,我在使用 Greg Ennis 的数组时遇到了问题)。此链接还提出了一种从操作中返回 Json 的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多