web-dev-qa-db-fra.com

Forcer les noms de propriété en minuscule à partir de Json () dans ASP.NET MVC

Compte tenu de la classe suivante,

public class Result
{      
    public bool Success { get; set; }

    public string Message { get; set; }
}

Je retourne un de ceux-ci dans une action de contrôleur comme telle,

return Json(new Result() { Success = true, Message = "test"})

Cependant, ma structure côté client s'attend à ce que ces propriétés soient un succès et un message en minuscule. Sans avoir à avoir des noms de propriété en minuscules, est-ce une façon d’obtenir cette pensée l’appel de fonction Json normal?

79
James Hughes

Pour ce faire, vous devez implémenter une JsonResult personnalisée, comme ici: Création d'un ValueType personnalisé et sérialisation avec un JsonResult personnalisé(lien d'origine mort)}.

Et utilisez un autre sérialiseur tel que JSON.NET , qui prend en charge ce type de comportement, e.g .:

Product product = new Product
{
  ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
  Name = "Widget",
  Price = 9.99m,
  Sizes = new[] {"Small", "Medium", "Large"}
};

string json = 
  JsonConvert.SerializeObject(
    product,
    Formatting.Indented,
    new JsonSerializerSettings 
    { 
      ContractResolver = new CamelCasePropertyNamesContractResolver() 
    }
);

Résulte en

{
  "name": "Widget",
  "expiryDate": "\/Date(1292868060000)\/",
  "price": 9.99,
  "sizes": [
    "Small",
    "Medium",
    "Large"
  ]
}
126
James Hughes

Le changement de sérialiseur est simple si vous utilisez l'API Web, mais malheureusement, MVC lui-même utilise JavaScriptSerializer sans possibilité de le modifier pour utiliser JSON.Net.

La réponse de James et La réponse de Daniel vous donne la flexibilité de JSON.Net mais signifie que partout où vous feriez normalement return Json(obj) vous devez changer en return new JsonNetResult(obj) ou similaire, ce qui pourrait s'avérer être un et n’est pas très flexible si vous changez d’avis sur le sérialiseur que vous souhaitez utiliser.


J'ai décidé de suivre la route ActionFilter. Le code ci-dessous vous permet d'effectuer toute action à l'aide de JsonResult et de lui appliquer simplement un attribut lui permettant d'utiliser JSON.Net (avec des propriétés en minuscule):

[JsonNetFilter]
[HttpPost]
public ActionResult SomeJson()
{
    return Json(new { Hello = "world" });
}

// outputs: { "hello": "world" }

Vous pouvez même configurer cela pour s’appliquer automatiquement à toutes les actions (avec seulement le coup de performance mineur d’une vérification is):

FilterConfig.cs

// ...
filters.Add(new JsonNetFilterAttribute());

Le code

public class JsonNetFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is JsonResult == false)
            return;

        filterContext.Result = new CustomJsonResult((JsonResult)filterContext.Result);
    }

    private class CustomJsonResult : JsonResult
    {
        public CustomJsonResult(JsonResult jsonResult)
        {
            this.ContentEncoding = jsonResult.ContentEncoding;
            this.ContentType = jsonResult.ContentType;
            this.Data = jsonResult.Data;
            this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
            this.MaxJsonLength = jsonResult.MaxJsonLength;
            this.RecursionLimit = jsonResult.RecursionLimit;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
                && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
                throw new InvalidOperationException("GET not allowed! Change JsonRequestBehavior to AllowGet.");

            var response = context.HttpContext.Response;

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

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

            if (this.Data != null)
            {
                var json = JsonConvert.SerializeObject(
                    this.Data,
                    new JsonSerializerSettings
                        {
                            ContractResolver = new CamelCasePropertyNamesContractResolver()
                        });

                response.Write(json);
            }
        }
    }
}
11
dav_i

Avec ma solution, vous pouvez renommer chaque propriété que vous voulez.

J'ai trouvé une partie de la solution ici et sur SO

public class JsonNetResult : ActionResult
    {
        public Encoding ContentEncoding { get; set; }
        public string ContentType { get; set; }
        public object Data { get; set; }

        public JsonSerializerSettings SerializerSettings { get; set; }
        public Formatting Formatting { get; set; }

        public JsonNetResult(object data, Formatting formatting)
            : this(data)
        {
            Formatting = formatting;
        }

        public JsonNetResult(object data):this()
        {
            Data = data;
        }

        public JsonNetResult()
        {
            Formatting = Formatting.None;
            SerializerSettings = new JsonSerializerSettings();
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            var response = context.HttpContext.Response;
            response.ContentType = !string.IsNullOrEmpty(ContentType)
              ? ContentType
              : "application/json";
            if (ContentEncoding != null)
                response.ContentEncoding = ContentEncoding;

            if (Data == null) return;

            var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
            var serializer = JsonSerializer.Create(SerializerSettings);
            serializer.Serialize(writer, Data);
            writer.Flush();
        }
    }

Alors que dans mon contrôleur, je peux le faire

        return new JsonNetResult(result);

Dans mon modèle, je peux maintenant avoir:

    [JsonProperty(PropertyName = "n")]
    public string Name { get; set; }

Notez que vous devez maintenant définir la variable JsonPropertyAttribute pour chaque propriété que vous souhaitez sérialiser.

9
Daniel

Bien que ce soit une vieille question, l’espoir ci-dessous sera utile aux autres 

Je l'ai fait ci-dessous avec l'API Web MVC5.

public JsonResult<Response> Post(Request request)
    {
        var response = new Response();

        //YOUR LOGIC IN THE METHOD
        //.......
        //.......

        return Json<Response>(response, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
    }
1
Prasoon

Vous pouvez ajouter ce paramètre à Global.asax et il fonctionnera partout. 

public class Global : HttpApplication
{   
    void Application_Start(object sender, EventArgs e)
    {
        //....
         JsonConvert.DefaultSettings = () =>
         {
             var settings = new JsonSerializerSettings
             {
                 ContractResolver = new CamelCasePropertyNamesContractResolver(),
                 PreserveReferencesHandling = PreserveReferencesHandling.None,
                 Formatting = Formatting.None
             };

             return settings;
         }; 
         //....
     }
}
0
Maksym Labutin