Intro:

Web application, ASP.NET MVC 3, a controller action that accepts an instance of POCO model class with (potentially) large field.

模型类:

public class View
{
    [Required]
    [RegularExpression(...)]
    public object name { get; set; }
    public object details { get; set; }
    public object content { get; set; } // the problem field
}

Controller action:

[ActionName(...)]
[Authorize(...)]
[HttpPost]
public ActionResult CreateView(View view)
{
    if (!ModelState.IsValid) { return /*some ActionResult here*/;}
    ... //do other stuff, create object in db etc. return valid result
}

Problem:

一个操作应该能够接受大型JSON对象(在一个请求中至少达到httpRuntime maxRequestLength兆字节,这不是Jest 的).默认情况下,我遇到了一些限制,比如httpRuntime maxRequestLength等——除了MaxJsonLengh之外,所有限制都已解决——这意味着用于JSON的默认值ProviderFactory无法处理此类对象.

Tried:

背景

  <system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization maxJsonLength="2147483647"/>
      </webServices>
    </scripting>
  </system.web.extensions>
  • 没有帮助.

按照@Darin的回答创建我自己的自定义ValueProviderFactory:

JsonValueProviderFactory throws "request too large"

  • 也失败了,因为我不可能使用JSON.净(由于非技术原因).我试图在这里实现正确的反序列化,但显然这有点超出了我的知识范围.我可以在这里将JSON字符串反序列化为Dictionary<String,Object>,但这不是我想要的——我想将其反序列化为可爱的POCO对象,并将其用作操作的输入参数.

So, the questions:

  1. 有谁知道在不实施通用定制值ProviderFactory的情况下解决这个问题的更好方法吗?
  2. Is there a possibility to specify for what specific controller and action I want to use my custom ValueProviderFactory? If I know the action beforehand than I will be able to deserialize JSON to POCO without much coding in ValueProviderFactory...
  3. I'm also thinking about implementing a custom ActionFilter for that specific problem, but I think it's a bit ugly.

谁能提出一个好的解决方案?

推荐答案

The built-in JsonValueProviderFactory ignores the <jsonSerialization maxJsonLength="50000000"/> setting. So you could write a custom factory by using the built-in implementation:

public sealed class MyJsonValueProviderFactory : ValueProviderFactory
{
    private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
    {
        IDictionary<string, object> d = value as IDictionary<string, object>;
        if (d != null)
        {
            foreach (KeyValuePair<string, object> entry in d)
            {
                AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
            }
            return;
        }

        IList l = value as IList;
        if (l != null)
        {
            for (int i = 0; i < l.Count; i++)
            {
                AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
            }
            return;
        }

        // primitive
        backingStore[prefix] = value;
    }

    private static object GetDeserializedObject(ControllerContext controllerContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
        {
            // not JSON request
            return null;
        }

        StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
        string bodyText = reader.ReadToEnd();
        if (String.IsNullOrEmpty(bodyText))
        {
            // no JSON data
            return null;
        }

        JavaScriptSerializer serializer = new JavaScriptSerializer();
        serializer.MaxJsonLength = 2147483647;
        object jsonData = serializer.DeserializeObject(bodyText);
        return jsonData;
    }

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

        object jsonData = GetDeserializedObject(controllerContext);
        if (jsonData == null)
        {
            return null;
        }

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

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

    private static string MakePropertyKey(string prefix, string propertyName)
    {
        return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
    }
}

The only modification I did compared to the default factory is adding the following line:

serializer.MaxJsonLength = 2147483647;

不幸的是,这个工厂根本无法扩展,所以我不得不重新创建它.

and in your Application_Start:

ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<System.Web.Mvc.JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());

Json相关问答推荐

震击:三针并用震击

Python将Pandas转换为嵌套的JSON

Jolt变换将字段移动到数组的每个元素中

在Reaction中从JSON文件中筛选数组

Azure数据工厂-WEB活动输出赢得';t返回JSON

(Kotlin)com.google.gson.internal.LinkedTreeMap无法转换为com.example.phonetest2.model.HallData

jq:将一个数组与多个数组连接起来

Jolt Spec 跳过数组中的第一个元素

打印与 JSON 和 PowerShell 中的模式匹配的子项的父项名称

将请求中的数据推送到数组中

Powershell - 如何从 JSON 中删除/过滤元素但保留其余部分?

使用 Javascript 判断 JSON 对象是否包含值

如何为所有 API 端点全局设置 http.ResponseWriter Content-Type 标头?

解析包含换行符的 JSON

Android 上的 JSON - 序列化

如何使用 Newtonsoft.Json 包在 C#(4.0) 中解析我的 json 字符串?

如何在 Rails 模型中验证字符串是否为 json

在 HTML 数据属性上添加 JSON 是不是很糟糕?

PHP json_encode json_decode UTF-8

类型是接口或抽象类,不能实例化