web-dev-qa-db-fra.com

Sérialisation JSON appropriée dans MVC 4

J'aimerais que JSON soit sérialisé correctement (camelCase) et la possibilité de changer les formats de date si nécessaire.

Pour l'API Web, c'est très simple - dans Global.asax j'exécute le code suivant

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

Ce code, au niveau du pipeline, gère la sérialisation comme je le voudrais.

Je voudrais accomplir la même chose dans MVC 4 - que tout JSON retourné par les méthodes d'action du contrôleur soit sérialisé correctement. Avec un peu de recherche, j'ai trouvé le code suivant à lancer dans le démarrage de l'application Global.asax:

HttpConfiguration config = GlobalConfiguration.Configuration;
Int32 index = config.Formatters.IndexOf(config.Formatters.JsonFormatter);
config.Formatters[index] = new JsonMediaTypeFormatter
{
     SerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }
};

Il semble fonctionner correctement mais quand je renvoie JSON à partir d'un contrôleur, tout est PascalCased. Un exemple simple de ma méthode d'action:

private JsonResult GetJsonTest()
{
    var returnData = dataLayer.GetSomeObject();
    return Json(returnData, JsonRequestBehavior.AllowGet);
}

Suis-je en train de me tromper? Avez-vous une idée de comment accomplir cela au niveau du pipeline?

43
Mario

Je recommanderais d'utiliser quelque chose comme ServiceStack ou Json.NET pour gérer la sortie Json dans votre application MVC. Cependant, vous pouvez facilement écrire une classe et remplacer la méthode Json à l'aide d'une classe de base. Voir mon exemple ci-dessous.

REMARQUE: avec cela, vous n'avez besoin de rien dans votre fichier Global.ascx.cs.

classe JsonDotNetResult personnalisée:

public class JsonDotNetResult : JsonResult
{
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Converters = new List<JsonConverter> { new StringEnumConverter() }
    };

    public override void ExecuteResult(ControllerContext context)
    {
        if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
            string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("GET request not allowed");
        }

        var response = context.HttpContext.Response;

        response.ContentType = !string.IsNullOrEmpty(this.ContentType) ? this.ContentType : "application/json";

        if (this.ContentEncoding != null)
        {
            response.ContentEncoding = this.ContentEncoding;
        }

        if (this.Data == null)
        {
            return;
        }

        response.Write(JsonConvert.SerializeObject(this.Data, Settings));
    }
}

Classe du contrôleur de base:

public abstract class Controller : System.Web.Mvc.Controller
{
    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonDotNetResult
            {
                Data = data,
                ContentType = contentType,
                ContentEncoding = contentEncoding,
                JsonRequestBehavior = behavior
            };
    }
}

Maintenant, sur l'action de votre contrôleur, vous pouvez simplement retourner quelque chose comme ça.

return Json(myObject, JsonRequestBehavior.AllowGet);

BAM. Vous avez maintenant des objets camelcase retournés avec Json :)

REMARQUE: il existe des moyens de le faire avec les paramètres du sérialiseur sur chaque objet que vous créez avec Json. Mais qui voudrait taper ça à chaque fois que tu veux rendre Json?

88
technicallyjosh

Alors que l'API Web utilise JSON.NET, MVC4 utilise par défaut JavaScriptSerializer, et je ne pense pas qu'il supporte le passage à la sérialisation Camel Case. Vérifiez ceci: Définition du sérialiseur JSON par défaut dans ASP.NET MVC

Ma suggestion est que vous créez un JsonNetResult personnalisé comme décrit ici L'utilisation de JSON.NET comme sérialiseur JSON par défaut dans ASP.NET MVC 3 - est-il possible? et changez la dernière ligne en:

var serializedObject = JsonConvert.SerializeObject(
      Data,
      Formatting.Indented, ,
      new JsonSerializerSettings { MappingResolver = new CamelCaseMappingResolver() });
6
fcuesta
Note that below information is for Asp .Net core

L'équipe .Net a récemment annoncé que MVC sérialise désormais JSON avec des noms de cas de chameau par défaut.

Avec quelques lignes ci-dessous, vous pourrez activer cette fonctionnalité:

services
.AddMvc()
.AddJsonOptions(options =>
options.SerializerSettings.ContractResolver = new DefaultContractResolver());

J'ai écrit un petit blog sur le même qui est ici .

5
Neel