[c#] 사전을 직렬화 할 때 대 / 소문자 유지

다음과 같이 구성된 Web Api 프로젝트가 있습니다.

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

그러나 사전 키 대소 문자를 변경하지 않고 유지하고 싶습니다. Newtonsoft.Json직렬화 중에 대 / 소문자를 변경하지 않고 유지하기를 원한다는 것을 나타 내기 위해 클래스에 사용할 수 있는 속성이 있습니까?

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



답변

이를 수행하는 속성은 없지만 리졸버를 사용자 정의하여 수행 할 수 있습니다.

이미 CamelCasePropertyNamesContractResolver. 여기에서 새 리졸버 클래스를 파생하고 CreateDictionaryContract()메서드를 재정의 DictionaryKeyResolver하면 키 이름을 변경하지 않는 대체 함수를 제공 할 수 있습니다 .

다음은 필요한 코드입니다.

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

        contract.DictionaryKeyResolver = propertyName => propertyName;

        return contract;
    }
}

데모:

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

다음은 위의 출력입니다. 모든 클래스 속성 이름은 카멜 케이스이지만 사전 키는 원래 케이스를 유지합니다.

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


답변

Json.NET 9.0.1NamingStrategy이러한 종류의 문제를 처리하기 위해 클래스 계층 구조를 도입했습니다 . 계약 확인자에서 사전 키 , 명시 적으로 지정된 속성 이름확장 데이터 이름 ( 10.0.1 )이 다시 매핑 되는지 여부를 제어 할 수있는 별도의 경량 클래스로 속성 이름을 알고리즘 방식으로 다시 매핑하는 논리를 추출합니다 .

의 인스턴스 를 사용 DefaultContractResolver하고 설정 NamingStrategy하면 다음에서 설정 하여 CamelCaseNamingStrategy낙타 케이스 속성 이름과 수정되지 않은 사전 키로 JSON을 생성 할 수 있습니다 JsonSerializerSettings.ContractResolver.

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

메모:

  • 의 현재 구현은 CamelCasePropertyNamesContractResolver또한 명시 적으로 지정된 속성 이름 (예 : 설정된 속성 이름)을 가진 .Net 구성원 JsonPropertyAttribute.PropertyName의 이름을 다시 매핑해야한다고 지정합니다.

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

    위의 내용 resolver은이 동작을 유지합니다. 원하지 않는 경우을 설정하십시오 OverrideSpecifiedNames = false.

  • Json.NET에는 다음과 같은 몇 가지 기본 제공 이름 지정 전략이 있습니다.

    1. CamelCaseNamingStrategy. 이전에 .NET에 포함 된 이름 다시 매핑 논리를 포함하는 낙타 케이스 명명 전략입니다 CamelCasePropertyNamesContractResolver.
    2. SnakeCaseNamingStrategy. 뱀 케이스 명명 전략.
    3. DefaultNamingStrategy. 기본 명명 전략입니다. 속성 이름과 사전 키는 변경되지 않습니다.

    또는 추상 기본 클래스에서 상속하여 직접 만들 수 있습니다 NamingStrategy.

  • 그것은 수정하는 것도 가능하지만 NamingStrategy의 인스턴스를 CamelCasePropertyNamesContractResolver, 후자 이후, 전 세계적으로 각 유형의 모든 인스턴스에서 공유 계약 정보 응용 프로그램의 여러 인스턴스를 사용하려고하면,이 예기치 않은 부작용을 초래할 수 있습니다 CamelCasePropertyNamesContractResolver. 에는 이러한 문제가 DefaultContractResolver없으므로 케이싱 논리의 사용자 정의가 필요할 때 사용하는 것이 더 안전합니다.


답변

아주 좋은 대답입니다. 그러나 왜 그냥 무시하지 ResolveDictionaryKey않습니까?

class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver
    {
        #region Overrides of DefaultContractResolver

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

        #endregion
    }


답변

선택한 대답은 완벽하지만 이것을 입력 할 때까지 DictionaryKeyResolver가 더 이상 존재하지 않기 때문에 계약 해결 프로그램이 이와 같이 변경되어야한다고 생각합니다. 🙂

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


답변