2017-04-14 3 views
0

Json.Net은 이 아니며 내 Control 클래스의 적절한 파생물로받는 객체를 비 직렬화합니다. (문제의 다음 설명을 참조하십시오. 또한이 문제를 설명하는 데 필요한 코드의 최소 금액을 느낍니다.이 문제를 검토해 주셔서 미리 감사드립니다.)Json.Net은 C# 파생 클래스로 deserialize합니다.

serialize/deserialize 다음 클래스는 JSON에/JSON에서 가져옵니다. 여기

public class Page { 
    public Guid Id { get; set; } 
    public Guid CustomerId { get; set; } 
    public IList<Control> Controls { get; set; } 
} 

그리고

은 컨트롤 클래스입니다 :

public class Control : ControlBase 
{ 
    public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.Base; } } 
} 

그리고 여기 ControlBase 추상 클래스입니다 :

public abstract class ControlBase 
{ 
    public Guid Id { get; set; } 

    public virtual Enums.CsControlType CsControlType { get; } 

    public Enums.ControlType Type { get; set; } 

    public string PropertyName { get; set; } 

    public IList<int> Width { get; set; } 

    public string FriendlyName { get; set; } 

    public string Description { get; set; } 
} 

그리고 여기 Control에서 파생 된 OptionsControl입니다 :

public class OptionsControl : Control 
{ 
    public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.OptionsControl; } } 

    public IDictionary<string, string> Options; 
} 

OptionsControl이 직렬화되면 JSON은 다음과 같이 보입니다. Json.Net은 $type 속성을 추가합니다. 따라서 (아마도) 컨트롤을 다시 deserialize하여 OptionsControl으로 다시 설정할 수 있습니다. 내가 (기본 컨트롤 및 OptionsControls를 포함) 페이지를 역 직렬화 할 때, 모든 컨트롤 (위, 국가의 목록을 포함) 기본 제어 및 options 재산으로 직렬화된다 그러나

   { 
       "options":{ 
        "TN":"TN" 
       }, 
       "csControlType":4, 
       "id":"00000000-0000-0000-0000-000000000000", 
       "type":4, 
       "propertyName":"addresses[0].state", 
       "width":[ 
        2, 
        2, 
        6 
       ], 
       "friendlyName":"State", 
       "description":null, 
       "$type":"MyApp.Infrastructure.Core.Models.UI.Controls.OptionsControl, MyApp.Infrastructure.Core" 
       } 

는 무시됩니다 .

내가 내가 WebAPI 서비스를 통해받는 페이지 객체 직렬화 (업데이트)을 시도하는 방법입니다

[HttpPut] 
    [ActionName("UpdatePage")] 
    public async Task<CommandResult> UpdatePageAsync([FromBody]Object page) 
    { 
     try 
     { 
      // Deserialize the page into the correct object 
      // When I Debug.WriteLine the page.ToString(), the page still has the $type property at this point (before it is deserialized). 
      var dsPage = return JsonConvert.DeserializeObject<Page>(page.ToString(), new JsonSerializerSettings 
      { 
       TypeNameHandling = TypeNameHandling.All 
      }); 

      // The dsPage passed in here does not have any OptionsControls. 
      // At this point, they have all been deserialized into the base Control, unfortunately. 
      return await _uiCommandFacade.UpdatePageAsync(dsPage, msg); 
     } 
     catch (Exception ex) 
     { 
      return new CommandResult() 
      { 
       ErrorType = ErrorType.ControllerError, 
       DeveloperMessage = $"Unable to update page", 
       Exception = ex 
      }; 
     } 
    } 

당신이, 내가 (TypeNameHandling.All를 사용하고 볼 수 있듯이을 문서에 설명 된대로 및 SO에서 여러 번 언급했다.) (직렬화 중에 JSON의 $type 속성을 생성하는 것과 마찬가지로) 직렬화를 위해. 그러나 Page 객체를 deserialize 할 때 Page 객체의 OptionsControl은 일반 밑수 Control으로 역 직렬화되므로 Options 속성은 무시됩니다 (따라서 내 상태 목록은 업데이트/삭제되지 않습니다).

내 컨트롤과 그 파생물을 제대로 deserialize하기 위해 Json.Net을 얻으려면 어떻게해야합니까?

답변

2

$type 메타 데이터 속성이 JSON의 제어를위한 첫 번째 속성이 아니기 때문에 문제가 발생한 것 같습니다. 일반적으로 Json.Net은이 속성을 인식하기 위해이 속성이 가장 먼저 필요합니다. 비 직렬화 할 때

MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead 

을 설정에 추가하십시오. 그것은 Json을 허용해야합니다.Net을 사용하여 JSON에서 나중에 $type 속성을 찾습니다.

+0

귀하는 신사이며 학자입니다. – Targaryen

+0

기꺼이 도와 드리겠습니다. –

0

Web-API 시작 클래스에서 구성을 설정해야한다고 생각합니다. startup.cs에서

봅니다 페이지를 호출하여

 GlobalConfiguration.Configuration.Formatters.Clear(); // or remove just the json one 

     var jsonformatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter() 
     { 
      SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings() 
      { 
       // all your configurations 
       TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All 
      } 
     }; 

     GlobalConfiguration.Configuration.Formatters.Add(jsonformatter); 

같은 난 당신이 방법에 직렬화 된 객체 항목 (페이지)를 얻을 수 있기 때문에, 당신은 다시 직렬화 당신이 정보를 잃어 가고있다 생각 파일 .tostring() 메서드를 호출 한 다음 serializer 속성을 사용하여 다시 deserialize합니다.