Come posso restituire camelCase JSON serializzato da JSON.NET dai metodi del controller MVC ASP.NET?


247

Il mio problema è che desidero restituire i dati JSON camelCased (in contrapposizione allo standard PascalCase) tramite ActionResult s dai metodi del controller MVC ASP.NET, serializzati da JSON.NET .

Ad esempio, considera la seguente classe C #:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Per impostazione predefinita, quando si restituisce un'istanza di questa classe da un controller MVC come JSON, verrà serializzata nel modo seguente:

{
  "FirstName": "Joe",
  "LastName": "Public"
}

Vorrei che fosse serializzato (da JSON.NET) come:

{
  "firstName": "Joe",
  "lastName": "Public"
}

Come faccio a fare questo?

Risposte:


390

o, semplicemente, inserisci:

JsonConvert.SerializeObject(
    <YOUR OBJECT>, 
    new JsonSerializerSettings 
    { 
        ContractResolver = new CamelCasePropertyNamesContractResolver() 
    });

Per esempio:

return new ContentResult
{
    ContentType = "application/json",
    Content = JsonConvert.SerializeObject(new { content = result, rows = dto }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
    ContentEncoding = Encoding.UTF8
};

2
Questo è più complesso da usare, poiché è necessario configurare un ContentResult per ciascun metodo del controller.
Aknuds1

2
Sì, capisco che la tua risposta è stata una soluzione riutilizzabile, il mio punto è di chiarire che è solo un parametro sul metodo Serialize.
WebDever il

1
Se stai restituendo JSON da un Controllermetodo, probabilmente dovresti utilizzare un ApiController, nel qual caso questa risposta funziona alla grande.
Simon Hartcher,

1
@SimonHartcher Considera tuttavia l'ambito della domanda, non il caso generale.
aknuds1

1
Il tipo di contenuto valido per JSON è application/json, no text/plain.
Fred

94

Ho trovato un'ottima soluzione a questo problema sul blog di Mats Karlsson . La soluzione è scrivere una sottoclasse di ActionResult che serializzi i dati tramite JSON.NET, configurando quest'ultimo per seguire la convenzione camelCase:

public class JsonCamelCaseResult : ActionResult
{
    public JsonCamelCaseResult(object data, JsonRequestBehavior jsonRequestBehavior)
    {
        Data = data;
        JsonRequestBehavior = jsonRequestBehavior;
    }

    public Encoding ContentEncoding { get; set; }

    public string ContentType { get; set; }

    public object Data { get; set; }

    public JsonRequestBehavior JsonRequestBehavior { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
        }

        var response = context.HttpContext.Response;

        response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data == null)
            return;

        var jsonSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        response.Write(JsonConvert.SerializeObject(Data, jsonSerializerSettings));
    }
}

Quindi utilizzare questa classe come segue nel metodo del controller MVC:

public ActionResult GetPerson()
{
    return new JsonCamelCaseResult(new Person { FirstName = "Joe", LastName = "Public" }, JsonRequestBehavior.AllowGet)};
}

3
Risposta perfetta: pulita e riutilizzabile! Grazie.
levigatrice

1
Mentre questa soluzione funziona ancora. ma è stato suggerito 4 anni fa. Abbiamo una soluzione migliore?
SharpCoder

59

Per WebAPI , controlla questo link: http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx

Fondamentalmente, aggiungi questo codice al tuo Application_Start:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

4
API Web e MVC sono state unite in ASP.NET 6
AlexFoxGill il

1
Collegamento per comodità; questa configurazione funziona davvero bene con questa risposta: stackoverflow.com/a/26068063/398630 (domanda diversa, ma le utilizzo insieme e questo link potrebbe salvare me e altri in futuro in Google).
BrainSlugs83,

37

Penso che questa sia la risposta semplice che stai cercando. È dal blog di Shawn Wildermuth :

// Add MVC services to the services container.
services.AddMvc()
  .AddJsonOptions(opts =>
  {
    opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  });

2
Mi scuso ragazzi. Ho letto questo post troppo rapidamente. È per ASP.NET 5.
Quantium

8
Ironia della sorte, sono venuto qui in cerca di una risposta alla domanda a cui hai risposto qui, quindi sebbene non fosse la risposta alla domanda del PO, mi ha comunque aiutato. Grazie! :)
porco

1
Dico ciò che ha detto @porcus! Grazie @Quantium!
Gromer,

4
fyi Per ASP.NET Core 1.0 è il caso del cammello di default OOTB
Chris Marisic,

3
Si scopre che questo non è (esattamente) il valore predefinito per .NET Core 1.0 dopo tutto. Questa soluzione influenza le proprietà dinamiche e quelle non sono interessate per impostazione predefinita. stackoverflow.com/questions/41329279/…
Niels Brinch il

13

Un'alternativa al filtro personalizzato è quella di creare un metodo di estensione per serializzare qualsiasi oggetto su JSON.

public static class ObjectExtensions
{
    /// <summary>Serializes the object to a JSON string.</summary>
    /// <returns>A JSON string representation of the object.</returns>
    public static string ToJson(this object value)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new List<JsonConverter> { new StringEnumConverter() }
        };

        return JsonConvert.SerializeObject(value, settings);
    }
}

Quindi chiamalo al ritorno dall'azione del controller.

return Content(person.ToJson(), "application/json");

Elegante e semplice
markau,

1
È anche possibile trasferire le impostazioni in un campo di sola lettura statico e aggiungere un metodo di complemento FromJson.
Vapor in the Alley,

8

Semplice è meglio IMO!

Perché non lo fai?

public class CourseController : JsonController
{
    public ActionResult ManageCoursesModel()
    {
        return JsonContent(<somedata>);
    }
}

Il semplice controller della classe base

public class JsonController : BaseController
{
    protected ContentResult JsonContent(Object data)
    {
        return new ContentResult
        {
            ContentType = "application/json",
             Content = JsonConvert.SerializeObject(data, new JsonSerializerSettings { 
              ContractResolver = new CamelCasePropertyNamesContractResolver() }),
            ContentEncoding = Encoding.UTF8
        };
    }
}

7

In ASP.NET Core MVC.

    public IActionResult Foo()
    {
        var data = GetData();

        var settings = new JsonSerializerSettings 
        { 
            ContractResolver = new CamelCasePropertyNamesContractResolver() 
        });

        return Json(data, settings);
    }

E ancora meglio, inseriscilo nel file Startup.cs.
FatAlbert,

6

Di seguito è riportato un metodo di azione che restituisce una stringa json (cameCase) serializzando un array di oggetti.

public string GetSerializedCourseVms()
    {
        var courses = new[]
        {
            new CourseVm{Number = "CREA101", Name = "Care of Magical Creatures", Instructor ="Rubeus Hagrid"},
            new CourseVm{Number = "DARK502", Name = "Defence against dark arts", Instructor ="Severus Snape"},
            new CourseVm{Number = "TRAN201", Name = "Transfiguration", Instructor ="Minerva McGonal"}
        };
        var camelCaseFormatter = new JsonSerializerSettings();
        camelCaseFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
        return JsonConvert.SerializeObject(courses, camelCaseFormatter);
    }

Nota l'istanza JsonSerializerSettings passata come secondo parametro. Questo è ciò che rende possibile il camelCase.


4

Mi è piaciuto questo:

public static class JsonExtension
{
    public static string ToJson(this object value)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore,
            ReferenceLoopHandling = ReferenceLoopHandling.Serialize
        };
        return JsonConvert.SerializeObject(value, settings);
    }
}

questo è un semplice metodo di estensione nel core MVC, darà l'abilità ToJson () a ogni oggetto nel tuo progetto, secondo me in un progetto MVC la maggior parte degli oggetti dovrebbe avere la capacità di diventare json, ovviamente dipende :)


Prendi in considerazione l'estrazione della variabile "settings" al di fuori del metodo (come campo statico privato "camelCaseSettings") in modo da non inizializzare una nuova variabile ogni volta che viene chiamato il metodo ToJson.
Ekus

4

È necessario configurare le impostazioni nel file "Startup.cs"

Devi anche definirlo nei valori predefiniti di JsonConvert, questo se in seguito desideri utilizzare direttamente la libreria per serializzare un oggetto.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options => {
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
    }

Si noti che questa risposta è corretta per ASP.NET Core, ma non ASP.NET (che è il framework nella domanda).
Nate Barbettini,

0

Se stai restituendo ActionResult in api web core .net o risultato IHttpAction, puoi semplicemente avvolgere il tuo modello in un metodo Ok () che corrisponderà al caso sul tuo front-end e serializzalo per te. Non è necessario utilizzare JsonConvert. :)

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.