Wymuś nazwy właściwości małymi literami z Json () w ASP.NET MVC


89

Biorąc pod uwagę następującą klasę,

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

    public string Message { get; set; }
}

Zwracam jeden z nich w takiej akcji kontrolera,

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

Jednak moja struktura po stronie klienta oczekuje, że te właściwości będą sukcesem i komunikatem małymi literami. Bez faktycznej konieczności posiadania nazw właściwości pisanych małymi literami, czy jest to sposób na osiągnięcie tej myśli w normalnym wywołaniu funkcji Json?

Odpowiedzi:


130

Sposobem na osiągnięcie tego jest zaimplementowanie niestandardowego, JsonResulttakiego jak tutaj: utworzenie niestandardowego ValueType i serializacja z niestandardowym JsonResult (oryginalny link nie działa ) .

I użyj alternatywnego serializatora, takiego jak JSON.NET , który obsługuje tego typu zachowanie, np .:

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

Prowadzi do

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


Jeśli używasz JSON.NET i nie chcesz camelCase, ale snake_case, zapoznaj się z tym sednem, naprawdę mi pomogło! gist.github.com/crallen/9238178
Niclas Lindqvist

Jak przeprowadzić deserializację? Dawny. od „małego” do „małego”
wieża

1
@NiclasLindqvist W przypadku nowoczesnych wersji JSON.NET istnieje znacznie prostszy sposób na uzyskanie snake_case: newtonsoft.com/json/help/html/NamingStrategySnakeCase.htm
Søren Boisen

17

Zmiana serializatora jest prosta, jeśli używasz interfejsu API sieci Web, ale niestety samo MVC używa JavaScriptSerializerbez opcji zmiany tego, aby używać JSON.Net.

Odpowiedź Jamesa i odpowiedź Daniela zapewniają elastyczność JSON.Net, ale oznaczają, że wszędzie tam, gdzie normalnie byś to zrobił return Json(obj), musisz zmienić na return new JsonNetResult(obj)lub coś podobnego, co w przypadku dużego projektu może okazać się problemem, a także nie jest zbyt elastyczne, jeśli zmienisz zdanie na temat serializatora, którego chcesz użyć.


Postanowiłem pójść tą ActionFiltertrasą. Poniższy kod umożliwia wykonanie dowolnej akcji przy użyciu JsonResulti po prostu zastosowanie do niego atrybutu, aby użyć JSON.Net (z właściwościami małych liter):

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

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

Możesz nawet ustawić to tak, aby automagicznie stosowało się do wszystkich akcji (z tylko niewielkim uderzeniem wydajnościowym podczas isczeku):

FilterConfig.cs

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

Kod

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

Dzięki mojemu rozwiązaniu możesz zmienić nazwę każdej nieruchomości, którą chcesz.

Znalazłem część rozwiązania tutaj i na 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();
        }
    }

Więc w moim kontrolerze mogę to zrobić

        return new JsonNetResult(result);

W moim modelu mogę teraz mieć:

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

Zauważ, że teraz musisz ustawić na JsonPropertyAttributekażdą właściwość, którą chcesz serializować.


1

Chociaż to stare pytanie, mam nadzieję, że poniższy fragment kodu będzie pomocny dla innych,

Zrobiłem poniżej z 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

Możesz dodać to ustawienie do Global.asaxi będzie działać wszędzie.

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;
         }; 
         //....
     }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.