web-dev-qa-db-fra.com

Définition du sérialiseur JSON par défaut dans ASP.NET MVC

Je travaille sur une application existante qui a été partiellement convertie vers MVC. Chaque fois qu'un contrôleur répond avec un JSON ActionResult, les enums sont envoyés sous la forme de nombres opposés au nom de la chaîne. Il semble que le sérialiseur par défaut devrait être JSON.Net, ce qui devrait renvoyer les énumérations sous leur nom opposé à la représentation entière, mais ce n'est pas le cas ici.

Me manque-t-il un paramètre web.config qui le définit comme sérialiseur par défaut? Ou y a-t-il un autre paramètre qui doit être changé?

55
John

Dans ASP.Net MVC4, le sérialiseur JavaScript par défaut utilisé dans la classe JsonResult reste le JavaScriptSerializer (vous pouvez le vérifier dans le code ).

Je pense que vous l'avez confondu avec ASP.Net Web.API où JSON.Net est le sérialiseur JS par défaut mais MVC4 ne l'utilise pas.

Vous devez donc configurer JSON.Net pour qu’il fonctionne avec MVC4 (vous devez en principe créer votre propre variable JsonNetResult). Il existe de nombreux articles à ce sujet:

Si vous souhaitez également utiliser JSON.Net pour les paramètres d'action du contrôleur lors de la liaison de modèle, vous devez écrire votre propre implémentation ValueProviderFactory

Et vous devez enregistrer votre implémentation avec: 

ValueProviderFactories.Factories
    .Remove(ValueProviderFactories.Factories
                                  .OfType<JsonValueProviderFactory>().Single());
ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());

Vous pouvez utiliser la variable JsonValueProviderFactory intégrée à titre d'exemple ou cet article: ASP.NET MVC 3 - JsonValueProviderFactory amélioré utilisant Json.Net

71
nemesv

ASP.NET MVC 5 Correctif:

Je n'étais pas prêt à changer pour Json.NET pour l'instant et dans mon cas, l'erreur se produisait lors de la demande. La meilleure approche dans mon scénario consistait à modifier la variable JsonValueProviderFactory qui applique le correctif au projet global et peut être effectuée en modifiant le fichier global.cs en tant que tel.

JsonValueProviderConfig.Config(ValueProviderFactories.Factories);

ajoutez une entrée web.config:

<add key="aspnet:MaxJsonLength" value="20971520" />

puis créez les deux classes suivantes

public class JsonValueProviderConfig
{
    public static void Config(ValueProviderFactoryCollection factories)
    {
        var jsonProviderFactory = factories.OfType<JsonValueProviderFactory>().Single();
        factories.Remove(jsonProviderFactory);
        factories.Add(new CustomJsonValueProviderFactory());
    }
}

Il s’agit essentiellement d’une copie exacte de l’implémentation par défaut trouvée dans System.Web.Mvc, mais avec l’ajout d’une valeur configurable d’application web.config aspnet:MaxJsonLength.

public class CustomJsonValueProviderFactory : ValueProviderFactory
{

    /// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
    /// <returns>A JSON value-provider object for the specified controller context.</returns>
    /// <param name="controllerContext">The controller context.</param>
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");

        object deserializedObject = CustomJsonValueProviderFactory.GetDeserializedObject(controllerContext);
        if (deserializedObject == null)
            return null;

        Dictionary<string, object> strs = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        CustomJsonValueProviderFactory.AddToBackingStore(new CustomJsonValueProviderFactory.EntryLimitedDictionary(strs), string.Empty, deserializedObject);

        return new DictionaryValueProvider<object>(strs, CultureInfo.CurrentCulture);
    }

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

        string fullStreamString = (new StreamReader(controllerContext.HttpContext.Request.InputStream)).ReadToEnd();
        if (string.IsNullOrEmpty(fullStreamString))
            return null;

        var serializer = new JavaScriptSerializer()
        {
            MaxJsonLength = CustomJsonValueProviderFactory.GetMaxJsonLength()
        };
        return serializer.DeserializeObject(fullStreamString);
    }

    private static void AddToBackingStore(EntryLimitedDictionary backingStore, string prefix, object value)
    {
        IDictionary<string, object> strs = value as IDictionary<string, object>;
        if (strs != null)
        {
            foreach (KeyValuePair<string, object> keyValuePair in strs)
                CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);

            return;
        }

        IList lists = value as IList;
        if (lists == null)
        {
            backingStore.Add(prefix, value);
            return;
        }

        for (int i = 0; i < lists.Count; i++)
        {
            CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakeArrayKey(prefix, i), lists[i]);
        }
    }

    private class EntryLimitedDictionary
    {
        private static int _maximumDepth;

        private readonly IDictionary<string, object> _innerDictionary;

        private int _itemCount;

        static EntryLimitedDictionary()
        {
            _maximumDepth = CustomJsonValueProviderFactory.GetMaximumDepth();
        }

        public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
        {
            this._innerDictionary = innerDictionary;
        }

        public void Add(string key, object value)
        {
            int num = this._itemCount + 1;
            this._itemCount = num;
            if (num > _maximumDepth)
            {
                throw new InvalidOperationException("The length of the string exceeds the value set on the maxJsonLength property.");
            }
            this._innerDictionary.Add(key, value);
        }
    }

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

    private static string MakePropertyKey(string prefix, string propertyName)
    {
        if (string.IsNullOrEmpty(prefix))
        {
            return propertyName;
        }
        return string.Concat(prefix, ".", propertyName);
    }

    private static int GetMaximumDepth()
    {
        int num;
        NameValueCollection appSettings = ConfigurationManager.AppSettings;
        if (appSettings != null)
        {
            string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
            if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
            {
                return num;
            }
        }
        return 1000;
    }

    private static int GetMaxJsonLength()
    {
        int num;
        NameValueCollection appSettings = ConfigurationManager.AppSettings;
        if (appSettings != null)
        {
            string[] values = appSettings.GetValues("aspnet:MaxJsonLength");
            if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
            {
                return num;
            }
        }
        return 1000;
    }
}
0