Sözlükleri serileştirirken büyük / küçük harf kullanımına devam et


92

Şu şekilde yapılandırılan bir Web Api projem var:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

Ancak, sözlük anahtarlarının kasasının değişmeden kalmasını istiyorum. Newtonsoft.Jsonserileştirme sırasında büyük / küçük harflerin değişmeden kalmasını istediğimi belirtmek için bir sınıfa kullanabileceğim herhangi bir özellik var mı?

public class SomeViewModel
{
    public Dictionary<string, string> Data { get; set; }    
}

1
Varsayılan çözümleyiciyi denediniz mi?
Matthew

1
@Matthew Hayır, yapmadım; kodun nasıl görüneceğini bir örnekle açıklayabilir misiniz? Not, hala tüm web api isteklerim için Camel vaka serileştirmesini istiyorum, sadece bir sınıf için (veya belki herhangi bir sözlük anahtarı için) özel serileştirme istiyorum.
zafeiris. M

Yanıtlar:


133

Bunu yapacak bir öznitelik yoktur, ancak bunu çözümleyiciyi özelleştirerek yapabilirsiniz.

Görüyorum ki zaten bir CamelCasePropertyNamesContractResolver. Bundan yeni bir çözümleyici sınıfı türetir ve CreateDictionaryContract()yöntemi geçersiz kılarsanız DictionaryKeyResolver, anahtar adlarını değiştirmeyen bir yedek işlev sağlayabilirsiniz .

İşte ihtiyacınız olan kod:

class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
    protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
    {
        JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);

        contract.DictionaryKeyResolver = propertyName => propertyName;

        return contract;
    }
}

Demo:

class Program
{
    static void Main(string[] args)
    {
        Foo foo = new Foo
        {
            AnIntegerProperty = 42,
            HTMLString = "<html></html>",
            Dictionary = new Dictionary<string, string>
            {
                { "WHIZbang", "1" },
                { "FOO", "2" },
                { "Bar", "3" },
            }
        };

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
            Formatting = Formatting.Indented
        };

        string json = JsonConvert.SerializeObject(foo, settings);
        Console.WriteLine(json);
    }
}

class Foo
{
    public int AnIntegerProperty { get; set; }
    public string HTMLString { get; set; }
    public Dictionary<string, string> Dictionary { get; set; }
}

İşte yukarıdan çıktı. Tüm sınıf özellik adlarının deve harfli olduğuna, ancak sözlük anahtarlarının orijinal büyük / küçük harflerini koruduğuna dikkat edin.

{
  "anIntegerProperty": 42,
  "htmlString": "<html></html>",
  "dictionary": {
    "WHIZbang": "1",
    "FOO": "2",
    "Bar": "3"
  }
}

2
Bilginize, PropertyNameResolver artık kullanılmıyor. Görünüşe göre contract.DictionaryKeyResolver = key => key;gayet iyi çalışıyor.
John Gietzen

1
Bu, özellikle yapının çoğu için deve kasası istediğimizde, ancak sözlüklerdeki anahtarların deveye dönüştürülmesini istemediğimizde, anonim tiplerle hala ÇOK ilgilidir.
Chris Schaller

Chris'e kesinlikle katılıyorum. Sözlüklerin camelCased olmasını engelleyemediğim için JavaScript'imde çemberlerden geçmek zorunda kaldım. Bir satır kodun bu sorunu çözeceği (ve JavaScript'imi çok daha basit hale getireceği) ortaya çıktı!
Stephen Chung

@BrianRogers harika çalışıyor! Ancak, DictionaryKeyResolveryalnızca Sözlük özelliğimde bazı özel Nitelikler varsa, kendi koşulumu kullanabilir miyim?
Mugen

@Mugen Kafamın üstünden değil. Bunu yeni bir Soru olarak sormanızı tavsiye ederim. Bağlam sağlamanız gerekiyorsa bu soruya tekrar bağlantı verebilirsiniz.
Brian Rogers

67

Json.NET 9.0.1 , NamingStrategybu tür sorunları ele almak için sınıf hiyerarşisini tanıttı . Sözleşme çözümleyiciden özellik adlarının algoritmik olarak yeniden eşleştirilmesi mantığını, sözlük anahtarlarının , açıkça belirtilen özellik adlarının ve uzantı veri adlarının ( 10.0.1'de ) yeniden eşlenip eşlenmeyeceğinin kontrolüne izin veren ayrı, hafif bir sınıfa çıkarır .

Bir örneğinizi kullanarak DefaultContractResolverve ayarlayarak , deve harfli özellik adları ve değiştirilmemiş sözlük anahtarları ile JSON'u şurada ayarlayarak oluşturabilirsiniz :NamingStrategyCamelCaseNamingStrategyJsonSerializerSettings.ContractResolver

var resolver = new DefaultContractResolver
{
    NamingStrategy = new CamelCaseNamingStrategy
    {
        ProcessDictionaryKeys = false,
        OverrideSpecifiedNames = true
    }
};
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = resolver;

Notlar:

  • Şu anki uygulaması CamelCasePropertyNamesContractResolverayrıca, açıkça belirtilmiş özellik adlarına sahip .Net üyelerinin JsonPropertyAttribute.PropertyNameadlarının yeniden eşleştirilmesi gerektiğini belirtir :

    public CamelCasePropertyNamesContractResolver()
    {
        NamingStrategy = new CamelCaseNamingStrategy
        {
            ProcessDictionaryKeys = true,
            OverrideSpecifiedNames = true
        };
    }
    

    Yukarıdakiler resolverbu davranışı korur. Bunu istemiyorsan ayarla OverrideSpecifiedNames = false.

  • Json.NET, aşağıdakileri içeren birkaç yerleşik adlandırma stratejisine sahiptir:

    1. CamelCaseNamingStrategy. Önceden gömülü olan ad yeniden eşleme mantığını içeren bir deve durumu adlandırma stratejisi CamelCasePropertyNamesContractResolver.
    2. SnakeCaseNamingStrategy. Bir yılan vakası adlandırma stratejisi.
    3. DefaultNamingStrategy. Varsayılan adlandırma stratejisi. Özellik adları ve sözlük anahtarları değişmez.

    Veya soyut temel sınıftan miras alarak kendi sınıfınızı oluşturabilirsiniz NamingStrategy.

  • NamingStrategyBir örneğini değiştirmek de mümkün olsa da CamelCasePropertyNamesContractResolver, ikincisi sözleşme bilgilerini her bir türün tüm örneklerinde küresel olarak paylaştığından , uygulamanız birden çok örneğini kullanmaya çalışırsa bu beklenmedik yan etkilere yol açabilir CamelCasePropertyNamesContractResolver. Böyle bir sorun yoktur DefaultContractResolver, bu nedenle büyük / küçük harf mantığının özelleştirilmesi gerektiğinde kullanmak daha güvenlidir.


Bu çözüm gibi bir mülk için çalışmıyor public Dictionary<string, Dictionary<string, string>> Values { get; set; }. İç sözlük anahtarları için hala camelCase yapar.
hikalkan

@hikalkan - sorununuzu tam olarak yeniden oluşturamazken, birden çok örneğini kullanırken bir sorun bulabildim CamelCasePropertyNamesContractResolver. Temelde NamingStrategybirincisi, ikincisi tarafından üretilen sözleşmeleri etkileyecektir. Gördüğünüz bu olabilir . Bunun yerine yeni öneriyi deneyin ve sorununuzu çözüp çözmediğini bana bildirin.
dbc

1
NamingStrategyHem deve durumunu hem de Pascal durumunu çözümleyebilecek esnek bir var mı ?
Shimmy Weitzhandler

@dbc İlk kod örneğinde ne olması configgerekiyor?
Ryan Lundy

@RyanLundy - kod aşağıdaki satırı göstermektedir, ilk soru kopyalandığına: config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();. MVC 4 Web API'si gibi görünüyor HttpConfiguration, bkz . MVC 4 Web API'sinde Json.NET için özel JsonSerializerSettings nasıl ayarlanır? .
dbc

12

Bu çok güzel bir cevap. Ama neden sadece geçersiz kılmıyorsunuz ResolveDictionaryKey?

class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver
    {
        #region Overrides of DefaultContractResolver

        protected override string ResolveDictionaryKey(string dictionaryKey)
        {
            return dictionaryKey;
        }

        #endregion
    }

Çok kısa. Paylaşım için teşekkürler.
Ebu Abdullah

1

Seçilen cevap mükemmel ama sanırım bunu yazdığım zaman, sözleşme çözümleyicinin böyle bir şeye dönüşmesi gerekiyor çünkü DictionaryKeyResolver artık mevcut değil :)

public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
    {
        protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
        {
            JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);
            contract.PropertyNameResolver = propertyName => propertyName;
            return contract;
        }
    }

5
Aslında tersi doğrudur. Json.Net'in eski bir sürümünü kullanıyor olmalısınız. 7.0.1 sürümündeDictionaryKeyResolver eklendi ve artık kullanılmıyor olarak işaretlendi. PropertyNameResolver
Brian Rogers
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.