Wie kann ich von JSON.NET serialisiertes camelCase JSON von ASP.NET MVC-Controller-Methoden zurückgeben?

246

Mein Problem ist, dass ich camelCased (im Gegensatz zu den Standard-PascalCase) JSON-Daten über ActionResult s von ASP.NET MVC-Controller-Methoden zurückgeben möchte , die von JSON.NET serialisiert wurden .

Betrachten Sie als Beispiel die folgende C # -Klasse:

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

Wenn eine Instanz dieser Klasse von einem MVC-Controller als JSON zurückgegeben wird, wird sie standardmäßig wie folgt serialisiert:

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

Ich möchte, dass es (von JSON.NET) wie folgt serialisiert wird:

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

Wie mache ich das?

aknuds1
quelle

Antworten:

389

oder einfach ausgedrückt:

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

Zum Beispiel:

return new ContentResult
{
    ContentType = "application/json",
    Content = JsonConvert.SerializeObject(new { content = result, rows = dto }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
    ContentEncoding = Encoding.UTF8
};
WebDever
quelle
2
Dies ist jedoch komplexer zu verwenden, da Sie für jede Controller-Methode ein ContentResult konfigurieren müssen.
Aknuds1
2
Ja, ich verstehe, dass Ihre Antwort eine wiederverwendbare Lösung war. Ich möchte klarer machen, dass es sich nur um einen Parameter der Serialize-Methode handelt.
WebDever
1
Wenn Sie JSON von einer ControllerMethode zurückgeben, sollten Sie wahrscheinlich eine verwenden ApiController. In diesem Fall funktioniert diese Antwort hervorragend.
Simon Hartcher
1
@ SimonHartcher Betrachten Sie jedoch den Umfang der Frage, nicht den allgemeinen Fall.
aknuds1
1
Der gültige Inhaltstyp für JSON ist application/jsonnicht text/plain.
Fred
94

Ich habe auf Mats Karlssons Blog eine hervorragende Lösung für dieses Problem gefunden . Die Lösung besteht darin, eine Unterklasse von ActionResult zu schreiben, die Daten über JSON.NET serialisiert und letztere so konfiguriert, dass sie der camelCase-Konvention folgen:

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

Verwenden Sie diese Klasse dann wie folgt in Ihrer MVC-Controller-Methode:

public ActionResult GetPerson()
{
    return new JsonCamelCaseResult(new Person { FirstName = "Joe", LastName = "Public" }, JsonRequestBehavior.AllowGet)};
}
aknuds1
quelle
3
Perfekte Antwort: sauber und wiederverwendbar! Danke dir.
Schleifer
1
Während diese Lösung noch funktioniert. aber es wurde vor 4 Jahren vorgeschlagen. Haben wir eine bessere Lösung?
SharpCoder
59

Für WebAPI , überprüfen Sie diesen Link aus: http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx

Fügen Sie diesen Code grundsätzlich zu Ihrem Application_Start:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Assaf S.
quelle
4
Web API und MVC wurden in ASP.NET 6
AlexFoxGill
1
Verknüpfung zur Vereinfachung; Dieses Setup spielt sehr gut mit dieser Antwort: stackoverflow.com/a/26068063/398630 (andere Frage, aber ich verwende sie zusammen, und dieser Link könnte mir und anderen in Zukunft das Googeln ersparen).
BrainSlugs83
37

Ich denke, das ist die einfache Antwort, die Sie suchen. Es ist aus Shawn Wildermuths Blog:

// Add MVC services to the services container.
services.AddMvc()
  .AddJsonOptions(opts =>
  {
    opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  });
Quantium
quelle
2
Ich entschuldige mich, Leute. Ich habe diesen Beitrag zu schnell durchgelesen. Es ist für ASP.NET 5.
Quantium
8
Ironischerweise bin ich hierher gekommen, um eine Antwort auf die Frage zu suchen, die Sie hier beantwortet haben. Obwohl dies nicht die Antwort auf die Frage des OP war, hat es mir trotzdem geholfen. Vielen Dank! :)
Porcus
1
Ich stimme dem zu, was @porcus gesagt hat! Danke @Quantium!
Gromer
4
fyi Für ASP.NET Core 1.0 ist es standardmäßig Kamelfall OOTB
Chris Marisic
3
Es stellt sich heraus, dass dies nicht (genau) die Standardeinstellung für .NET Core 1.0 ist. Diese Lösung wirkt sich auf dynamische Eigenschaften aus und diese sind standardmäßig nicht betroffen. stackoverflow.com/questions/41329279/…
Niels Brinch
13

Eine Alternative zum benutzerdefinierten Filter besteht darin, eine Erweiterungsmethode zum Serialisieren eines beliebigen Objekts in JSON zu erstellen.

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

Rufen Sie es dann auf, wenn Sie von der Controller-Aktion zurückkehren.

return Content(person.ToJson(), "application/json");
Stuart Hallows
quelle
Elegant und einfach.
Markau
1
Sie können die Einstellungen sogar in ein statisches schreibgeschütztes Feld übertragen und eine FromJson-Komplementmethode hinzufügen.
Dampf in der Gasse
8

Einfacher ist besser IMO!

Warum machst du das nicht?

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

Der einfache Basisklassen-Controller

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
        };
    }
}
jwize
quelle
7

In ASP.NET Core MVC.

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

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

        return Json(data, settings);
    }
Fred
quelle
Und noch besser, legen Sie es in der Datei Startup.cs ab.
FatAlbert
6

Im Folgenden finden Sie eine Aktionsmethode, die einen JSON-String (CameCase) zurückgibt, indem ein Array von Objekten serialisiert wird.

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

Beachten Sie die als zweiten Parameter übergebene JsonSerializerSettings-Instanz. Das macht den camelCase möglich.

DanKodi
quelle
4

Mir hat das gefallen:

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

Dies ist eine einfache Erweiterungsmethode im MVC-Kern. Sie gibt jedem Objekt in Ihrem Projekt die ToJson () -Fähigkeit. Meiner Meinung nach sollte in einem MVC-Projekt der größte Teil des Objekts die Fähigkeit haben, json zu werden, natürlich hängt es davon ab :)

Ali Alp
quelle
Ziehen Sie in Betracht, die Variable "settings" außerhalb der Methode zu extrahieren (als privates statisches Feld "camelCaseSettings"), damit Sie nicht bei jedem Aufruf der ToJson-Methode eine neue Variable initialisieren.
Ekus
4

Sie müssen die Einstellungen in der Datei 'Startup.cs' vornehmen.

Sie müssen es auch in den Standardwerten von JsonConvert definieren. Dies ist der Fall, wenn Sie später die Bibliothek direkt zum Serialisieren eines Objekts verwenden möchten.

    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()
        };
    }
Daniel Sánchez
quelle
Beachten Sie, dass diese Antwort für ASP.NET Core korrekt ist, nicht jedoch für ASP.NET (das Framework in der Frage).
Nate Barbettini
0

Wenn Sie ActionResult in der .net Core-Web-API oder im IHttpAction-Ergebnis zurückgeben, können Sie Ihr Modell einfach in eine Ok () -Methode einbinden, die dem Fall auf Ihrem Front-End entspricht, und es für Sie serialisieren. JsonConvert muss nicht verwendet werden. :) :)

LukePerrin
quelle