2014-11-22 1 views
1

ID를 나타 내기 위해 사용되는 클래스가 있습니다.이 클래스에는 string 값이 들어 있습니다.Newtonsoft.Json DeserializeObject가 guid에 null을 전달합니다 00000000-0000-0000-0000-000000000000

그런 다음 이벤트를 나타내는 데 사용되는 다른 클래스가 있습니다. 여기에는 ID 개체와 문자열 이름이 포함됩니다. 내가 이의를 JSON 위의에서 갈 때 문자열 identityValue이로 전달 된 MyIdentity 생성자에서, 그러나

{"Id":{"Value":"2e4146c2-66c9-4637-8936-29ccfc5df638"},"Name":"Jon Doe"}

:

내가 JSON 문자열 벌금 객체에서 직렬화 할 수

, 나는 문자열을 얻을 "00000000-0000-0000-0000-000000000000".

또한 MyIdentity, 문자열 및 Guid에 대해 두 개의 생성자를 제공했지만 동일한 결과를 제공하려고 시도했습니다. 이 아이디어는 데이터를 문자열로 저장하는 것이지만 필요하다면 ID를 문자열로 또는 GUID로 구성하므로 Guid로 변환 할 수 있다는 것을 기억하십시오. @hvd이 친절하게 주석함에 따라

public class MyEntityId : MyIdentity 
{ 
    public MyEntityId(Guid identityValue) 
     : base(identityValue) 
    { 
    } 
} 

public abstract class MyIdentity 
{ 
    protected readonly bool convertableAsGuid; 
    protected readonly string value; 

    public string Value { get { return this.value; } } 

    public MyIdentity(string identityValue) 
    { 
     this.value = identityValue; 

     Guid guid; 
     if(Guid.TryParse(identityValue, out guid)==false) 
      this.convertableAsGuid = false; 
    } 

    public MyIdentity(Guid identityValue) 
    { 
     this.value = identityValue.ToString(); 
     this.convertableAsGuid = true; 
    } 
} 

static void Main(string[] args) 
{ 
    var evnt = new MyEvent(new MyEntityId(Guid.NewGuid()), "Jon Doe"); 

    var eventHeaders = new Dictionary<string, object> 
    { 
     {"EventClrTypeName", evnt.GetType().AssemblyQualifiedName} 
    }; 
    var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None }; 
    var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings)); 
    var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings)); 
    string dataAsString = Encoding.UTF8.GetString(data); 

    var eventClrTypeName = JObject.Parse(Encoding.UTF8.GetString(metadata)).Property("EventClrTypeName").Value; 
    var obj = JsonConvert.DeserializeObject(dataAsString, Type.GetType((string)eventClrTypeName)); 
    // stepping through the above, a zero initialised GUID string is passed in to MyIdentity constructor 
} 

, 내가 또한 다음 세트 속성을 추가하면 값 만 얻을 속성, 그것은 (그래서 생성자 문자열 값이 실제로 사용하지 않을 생각) 작동 한 것 같다 . 나는 정체성에 대한 세터를두고 싶지 않은 이유는 프로그래밍 디자인을위한 것입니다. 그것은 정체성이며 한번 생성 된 후에는 변경되어서는 안됩니다.

공용 속성으로 get 및 protected 집합과 함께 살 수 있습니다. 키워드 [JsonProperty]을 시도했지만 작동합니다 ... 그러나 이러한 특성을 가진 내 도메인 개체를 장식하고 싶지 않습니다. 다른 방법이 있습니까?

+2

문제는 '값'속성이 더 세터가 없으며이 될 수 없다는 아마 생성자 인수에 매핑되지만 실제로 수정하는 데 도움이되지는 않습니다. – hvd

답변

1

제대로 이해했다면 비 직렬화에 Guid을 초기화하는 데 문제가 있으며 성공적인 직렬화를 위해 설정자를 만들거나 특성을 사용하지 않으려합니다. Guid 매개 변수를 허용하는 생성자를 제거하여 MyIdentity 클래스를 변경 했으므로 Guid 논리를 구문 분석하도록 변경 했으므로 convertableAsGuid 속성을 올바르게 초기화하지 않았고 MyEvent 클래스를 만들지 않았으므로 클래스에 게시하지 않았으므로 문제. 또한 deserialization 동안 사용되는 MyCustomConverter 클래스를 만들었습니다. 여기

public class MyCustomConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof (MyEvent); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var jObject = JObject.Load(reader); 
     existingValue = new MyEvent(new MyEntityId(jObject["Id"]["Value"].ToString()), jObject["Name"].ToString()); 

     return existingValue; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class MyEvent 
{ 
    public MyEntityId Id { get; set; } 

    public string Name { get; set; } 

    public MyEvent(MyEntityId id, string name) 
    { 
     Id = id; 
     Name = name; 
    } 
} 

public class MyEntityId : MyIdentity 
{ 
    public MyEntityId(string identityValue) 
     : base(identityValue) 
    { 
    } 
} 

public abstract class MyIdentity 
{ 
    protected readonly bool convertableAsGuid; 
    protected readonly string value; 

    public string Value { get { return this.value; } } 

    public MyIdentity(string identityValue) 
    { 
     this.value = identityValue; 

     Guid guid; 
     if (Guid.TryParse(identityValue, out guid)) 
      this.convertableAsGuid = true; 
    } 
} 

그리고 직렬화 및 역 직렬화 논리입니다 : 다음은 클래스는

static void Main(string[] args) 
{ 
    var evnt = new MyEvent(new MyEntityId(Guid.NewGuid().ToString()), "Jon Doe"); 

    var eventHeaders = new Dictionary<string, object> 
     { 
      {"EventClrTypeName", evnt.GetType().AssemblyQualifiedName} 
     }; 
    var serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.None }; 
    var metadata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventHeaders, serializerSettings)); 
    var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(evnt, serializerSettings)); 
    string dataAsString = Encoding.UTF8.GetString(data); 

    var eventClrTypeName = JObject.Parse(Encoding.UTF8.GetString(metadata)).Property("EventClrTypeName").Value; 
    var obj = JsonConvert.DeserializeObject<MyEvent>(dataAsString, new JsonConverter[] {new MyCustomConverter()}); 
} 

데모 : https://dotnetfiddle.net/asRtEI

관련 문제