2011-12-28 95 views
2

我有一個WCF REST服務接受一個自定義的DataContract參數作爲JSON,可以是超類型或子類型。當我傳遞包含額外空白的JSON時,對象總是反序列化爲超類型。當我從JSON中刪除所有空白時,對象將作爲子類型進行反序列化。WCF JSON反序列化問題與空白

下面是一個例子:

[DataContract] 
[KnownType(typeof(SubClass))] 
public class SuperClass 
{ 
    [DataMember] 
    public string Message { get; set; } 
} 

[DataContract] 
public class SubClass : SuperClass 
{ 
    [DataMember] 
    public string Extra { get; set; } 
} 

[ServiceContract] 
public interface IService1 
{ 
    [OperationContract] 
    [WebInvoke] 
    void LogMessage(SuperClass arg); 
} 

public class Service1 : IService1 
{ 
    public void LogMessage(SuperClass arg) 
    { 
     if (arg is SubClass) 
     { 
      Debug.WriteLine("SubClass"); 
     } 
     else if (arg is SuperClass) 
     { 
      Debug.WriteLine("SuperClass"); 
     } 
    } 
} 

如果我發送如下信息,該服務將打印SuperClass

POST http://localhost:5763/Service1.svc/LogMessage HTTP/1.1 
User-Agent: Fiddler 
Content-Type: text/json 
Host: localhost:5763 
Content-Length: 86 

{ "__type":"SubClass:#WhitespaceTest", "Message":"Message", "Extra":"Extra" } 

我得到同樣的結果,如果我「漂亮打印」的數據包作爲以便JSOn分成多行。然而,服務將打印​​如果我剝離空格如下:

POST http://localhost:5763/Service1.svc/LogMessage HTTP/1.1 
User-Agent: Fiddler 
Content-Type: text/json 
Host: localhost:5763 
Content-Length: 73 

{"__type":"SubClass:#WhitespaceTest","Message":"Message","Extra":"Extra"} 

我已經調試的System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage.ToString()輸出,並注意到從JSON生成的XML是2個分組之間不同:

<!-- First packet, deserializes to SuperClass --> 
<root type="object"> 
    <__type type="string">SubClass:#WhitespaceTest</__type> 
    <Message type="string">Message</Message> 
    <Extra type="string">Extra</Extra> 
</root> 

<!-- Second packet, deserializes to SubClass --> 
<root type="object" __type="SubClass:#WhitespaceTest"> 
    <Message type="string">Message</Message> 
    <Extra type="string">Extra</Extra> 
</root> 

所以,似乎空白混淆了JSON解串器。有誰知道爲什麼會發生這種情況,我能做些什麼呢?

回答

3

這是一個已知問題,在4.5框架中已經修復。不幸的是,如果你想在當前框架版本中使用多態性,你基本上需要去掉對象前面的空白。一種方法是使用由JsonReaderWriterFactory創建的讀寫器來讀/寫JSON,因爲它會去除元素周圍的空白(或任何漂亮的打印)。

public class StackOverflow_8661714 
{ 
    [DataContract(Name = "SuperClass", Namespace = "WhitespaceTest")] 
    [KnownType(typeof(SubClass))] 
    public class SuperClass 
    { 
     [DataMember] 
     public string Message { get; set; } 
    } 

    [DataContract(Name = "SubClass", Namespace = "WhitespaceTest")] 
    public class SubClass : SuperClass 
    { 
     [DataMember] 
     public string Extra { get; set; } 
    } 
    public static void Test() 
    { 
     string originalJson = "{ \"__type\":\"SubClass:WhitespaceTest\", \"Message\":\"Message\", \"Extra\":\"Extra\" }"; 
     byte[] originalJsonBytes = Encoding.UTF8.GetBytes(originalJson); 
     MemoryStream writeStream = new MemoryStream(); 
     XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(writeStream, Encoding.UTF8, false); 
     XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(originalJsonBytes, 0, originalJsonBytes.Length, XmlDictionaryReaderQuotas.Max); 
     jsonWriter.WriteNode(jsonReader, true); 
     jsonWriter.Flush(); 
     Console.WriteLine(Encoding.UTF8.GetString(writeStream.ToArray())); 
     writeStream.Position = 0; 

     DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(SuperClass), new Type[] { typeof(SubClass) }); 
     object o = dcjs.ReadObject(writeStream); 
     Console.WriteLine(o); 
    } 
} 
+0

謝謝。有沒有來自Microsoft的知識庫文章,這是一個錯誤? – Imran 2016-03-24 20:07:31

3

不幸的是,我對此沒有很好的答案。我們遇到了同樣的問題,並與Microsoft聯繫。他們堅持認爲,由於考慮到性能問題,他們所做的事情是可以的,考慮到整個管道的工作原理,這是可笑的。

所以我們的經驗是,許多地方的空白造成了問題。此外,如果您將__type字段放在第一個字段的任何位置,您將獲得超類型。

我的建議是看看JSON的其他解決方案。不幸的是,我沒有選擇或者我會提出一些建議。

編輯:正如carlosfigueira指出的,這顯然已被固定在4.5。我還沒有嘗試過。

+1

作爲一種替代方案,我認爲唯一明智的做法是直接將JSON傳遞給您的服務,然後使用類似[Json.Net](http://james.newtonking.com/pages /json-net.aspx)手動解串對象。無論是或者試圖找出一個預處理器,攔截所有JSON並在消息到達解串器之前去除任何空白/換行符,這可能會導致錯誤進一步下降。 – 2011-12-29 00:26:18