Forza i nomi delle proprietà in minuscolo da Json () in ASP.NET MVC


89

Data la seguente classe,

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

    public string Message { get; set; }
}

Sto restituendo uno di questi in un'azione Controller in questo modo,

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

Tuttavia, il mio framework lato client si aspetta che queste proprietà siano il successo e il messaggio in minuscolo. Senza dover effettivamente avere nomi di proprietà in minuscolo, è un modo per ottenere questo pensiero la normale chiamata di funzione Json?

Risposte:


130

Il modo per ottenere questo risultato è implementare un custom JsonResultcome qui: creazione di un ValueType personalizzato e serializzazione con un JsonResult personalizzato (link originale morto) .

E usa un serializzatore alternativo come JSON.NET , che supporta questo tipo di comportamento, ad esempio:

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() 
    }
);

Risultati in

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


Se stai usando JSON.NET e non vuoi camelCase ma snake_case, dai un'occhiata a questa sintesi, mi ha davvero aiutato! gist.github.com/crallen/9238178
Niclas Lindqvist

Come deserializzare? Ex. da "piccola" a "piccola"
torre

1
@NiclasLindqvist Per le moderne versioni di JSON.NET, c'è un modo molto più semplice per ottenere snake_case: newtonsoft.com/json/help/html/NamingStrategySnakeCase.htm
Søren Boisen

17

La modifica del serializzatore è semplice se si utilizza l'API Web, ma sfortunatamente lo stesso MVC non utilizza JavaScriptSerializeralcuna opzione per modificarlo per utilizzare JSON.Net.

La risposta di James e la risposta di Daniel ti danno la flessibilità di JSON.Net ma significa che ovunque tu faresti normalmente return Json(obj)devi cambiare return new JsonNetResult(obj)o qualcosa di simile che se hai un grande progetto potrebbe rivelarsi un problema, e inoltre non è molto flessibile se cambi idea sul serializzatore che desideri utilizzare.


Ho deciso di seguire la ActionFilterstrada. Il codice seguente ti consente di eseguire qualsiasi azione utilizzando JsonResulte semplicemente applicare un attributo ad esso per utilizzare JSON.Net (con proprietà minuscole):

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

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

Puoi anche impostarlo in modo che si applichi automaticamente a tutte le azioni (con solo la minima prestazione di un isassegno):

FilterConfig.cs

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

Il codice

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);
            }
        }
    }
}

10

Con la mia soluzione, puoi rinominare ogni proprietà che desideri.

Ho trovato parte della soluzione qui e su 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();
        }
    }

In modo che nel mio controller, posso farlo

        return new JsonNetResult(result);

Nel mio modello, ora posso avere:

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

Tieni presente che ora devi impostare JsonPropertyAttributesu ogni proprietà che desideri serializzare.


1

Sebbene sia una vecchia domanda, spero che lo snippet di codice riportato di seguito possa essere utile ad altri,

Ho fatto di seguito con MVC5 Web API.

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

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

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

0

Puoi aggiungere questa impostazione a Global.asaxe funzionerà ovunque.

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;
         }; 
         //....
     }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.