Как я могу вернуть camelCase JSON, сериализованный JSON.NET, из методов контроллера ASP.NET MVC?

247

Моя проблема в том, что я хочу вернуть данные JSON camelCased (в отличие от стандартного PascalCase) через ActionResult из методов контроллера ASP.NET MVC, сериализованных JSON.NET .

В качестве примера рассмотрим следующий класс C #:

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

По умолчанию при возврате экземпляра этого класса из контроллера MVC в виде JSON он будет сериализован следующим образом:

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

Я хотел бы, чтобы он был сериализован (JSON.NET) как:

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

Как мне это сделать?

aknuds1
источник

Ответы:

390

или, проще говоря:

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

Например:

return new ContentResult
{
    ContentType = "application/json",
    Content = JsonConvert.SerializeObject(new { content = result, rows = dto }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
    ContentEncoding = Encoding.UTF8
};
WebDever
источник
2
Это сложнее в использовании, поскольку вы должны настроить ContentResult для каждого метода контроллера.
aknuds1
2
Да, я понимаю, что ваш ответ был решением, которое можно использовать многократно, и я хочу пояснить, что это только параметр метода Serialize.
WebDever
1
Если вы возвращаете JSON из Controllerметода, вам, вероятно, следует использовать ApiController, и в этом случае этот ответ прекрасно работает.
Саймон Хартчер
1
@SimonHartcher Рассмотрим суть вопроса, а не общий случай.
aknuds1
1
Допустимый тип содержимого для JSON - application/jsonнет text/plain.
Фред
94

Я нашел отличное решение этой проблемы в блоге Матса Карлссона . Решением является написание подкласса ActionResult, который сериализует данные через JSON.NET, настраивая последний в соответствии с соглашением 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));
    }
}

Затем используйте этот класс следующим образом в вашем методе контроллера MVC:

public ActionResult GetPerson()
{
    return new JsonCamelCaseResult(new Person { FirstName = "Joe", LastName = "Public" }, JsonRequestBehavior.AllowGet)};
}
aknuds1
источник
3
Идеальный ответ: чистый и многоразовый! Спасибо.
Sander
1
Пока это решение все еще работает. но это было предложено 4 года назад. У нас есть лучшее решение?
SharpCoder
59

Для WebAPI , проверьте эту ссылку: http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx

В основном, добавьте этот код в ваш Application_Start:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Ассаф С.
источник
4
Веб-API и MVC были объединены в ASP.NET 6
AlexFoxGill
1
Ссылки для удобства; эта настройка очень хорошо работает с этим ответом: stackoverflow.com/a/26068063/398630 (другой вопрос, но я использую их вместе, и эта ссылка может спасти меня и других от поиска в будущем).
BrainSlugs83
37

Я думаю, что это простой ответ, который вы ищете. Это из блога Шона Вильдермута :

// Add MVC services to the services container.
services.AddMvc()
  .AddJsonOptions(opts =>
  {
    opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  });
Quantium
источник
2
Мои извинения, ребята. Я прочитал это сообщение слишком быстро. Это для ASP.NET 5.
Quantium
8
По иронии судьбы, я пришел сюда в поисках ответа на вопрос, на который вы здесь ответили, поэтому, хотя это был не ответ на вопрос ОП, он все равно помог мне. Спасибо! :)
porcus
1
Я второй, что сказал @porcus! Спасибо @Quantium!
Громер
4
fyi Для ASP.NET Core 1.0 это верблюжий случай по умолчанию OOTB
Крис Марисик
3
Оказывается, это не (точно) по умолчанию для .NET Core 1.0 в конце концов. Это решение влияет на динамические свойства и на них не влияют по умолчанию. stackoverflow.com/questions/41329279/…
Нильс Бринч
13

Альтернативой пользовательскому фильтру является создание метода расширения для сериализации любого объекта в 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);
    }
}

Затем вызовите его при возврате из действия контроллера.

return Content(person.ToJson(), "application/json");
Стюарт Хэллоуз
источник
Элегантно и просто.
марта
1
Вы даже можете перенести настройки в статическое поле только для чтения и добавить метод дополнения FromJson.
Пар в переулке
8

Проще лучше ИМО!

Почему бы тебе не сделать это?

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

Простой контроллер базового класса

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
источник
7

В ASP.NET Core MVC.

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

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

        return Json(data, settings);
    }
Фред
источник
А еще лучше, поместите его в файл Startup.cs.
FatAlbert
6

Ниже приведен метод действия, который возвращает строку json (cameCase) путем сериализации массива объектов.

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

Обратите внимание, что экземпляр JsonSerializerSettings передается как второй параметр. Вот что делает CamelCase случиться.

DanKodi
источник
4

Я сделал это так:

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

это простой метод расширения в ядре MVC, он даст возможность ToJson () каждому объекту в вашем проекте. По моему мнению, в проекте MVC большинство объектов должны иметь возможность стать json, конечно, это зависит от :)

Али Алп
источник
Подумайте об извлечении переменной «settings» вне метода (в виде частного статического поля «camelCaseSettings»), чтобы не инициализировать новую переменную каждый раз, когда вызывается метод ToJson.
Ekus
4

Вы должны установить настройки в файле «Startup.cs»

Вы также должны определить его в значениях по умолчанию JsonConvert, это если вы позже захотите напрямую использовать библиотеку для сериализации объекта.

    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()
        };
    }
Даниэль Санчес
источник
Обратите внимание, что этот ответ является правильным для ASP.NET Core, но не для ASP.NET (который является основой в вопросе).
Нейт Барбеттини,
0

Если вы возвращаете ActionResult в .net core web api или в результате IHttpAction, то вы можете просто обернуть вашу модель в метод Ok (), который будет соответствовать регистру на вашем внешнем интерфейсе, и сериализовать его для вас. Нет необходимости использовать JsonConvert. :)

LukePerrin
источник