简体   繁体   English

多态性WCF反序列化不起作用

[英]Polymorphism WCF deserialization doesn't work

I have created the following classes. 我创建了以下类。 one base class IObject and 2 derived classes A and B. 一个基类IObject和2个派生类A和B.

[KnownType(typeof(B))]
[KnownType(typeof(A))]
[DataContract(Name = "IObject")]
public class IObject
{
}

[DataContract(Name="A")]
public class A : IObject
{
    [DataMember]
    public string s1 { get; set; }     // Tag Name as it will be presented to the user

}

[DataContract(Name="B")]
public class B : IObject
{
    [DataMember]
    public string s2 { get; set; }         

}

I have also created the following Service: 我还创建了以下服务:

    [ServiceKnownType(typeof(B))]
    [ServiceKnownType(typeof(A))]
    public void GetR(IObject obj)
    {

        B other = (B)obj;
    }

What i want to do is get an instance of A or B but i don't know which one i will get so i expect to get an IObject and cast it later to either A or B as shown in the example i put. 我想要做的是得到一个A或B的实例,但我不知道我将得到哪一个,所以我希望得到一个IObject,然后将其转换为A或B,如我所放置的示例所示。

What happens when i send a json string containing s2 string is that i get IObject instance and not B instance. 当我发送包含s2字符串的json字符串时会发生什么,我得到IObject实例而不是B实例。 What is wrong with the code? 代码有什么问题?

Example of the client i'm using : 我正在使用的客户端示例:

    var url = serviceURL;
    var data = {s2: "Data"};
    var json = JSON.stringify(data);

    $.ajax({
      type: "POST",
      url: url,
      data: data,
      contentType: "application/json",
      dataType: 'json'
    });

Edited: I have uploaded an example code to gitHub at the following link: https://github.com/AlgoEitan/27588144 编辑:我已经通过以下链接将示例代码上传到gitHub: https//github.com/AlgoEitan/27588144

The client there is ac# client (I've tried it with both c# and javascript - web browser client) 客户端有ac#client(我用c#和javascript尝试过它 - web浏览器客户端)

DataContractJsonSerializer has a specific format in which it stores hints about known type information for polymorphic types, which one can discover with a bit of testing. DataContractJsonSerializer有一种特定的格式 ,它存储有关多态类型的已知类型信息的提示,可以通过一些测试发现。 I copied and pasted your classes as-is, and created the following test code: 我按原样复制并粘贴了您的类,并创建了以下测试代码:

public static class DataContractJsonSerializerPolymorphismTest
{
    public static void Test()
    {
        var a1 = new A() { s1 = "A" };
        var b1 = new B() { s2 = "B" };

        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(IObject));

        var jsona1 = DataContractJsonSerializerHelper.GetJson(a1, serializer);
        var jsonb1 = DataContractJsonSerializerHelper.GetJson(b1, serializer);

        Debug.WriteLine(jsona1);
        Debug.WriteLine(jsonb1);

        var newa1 = DataContractJsonSerializerHelper.GetObject<IObject>(jsona1, serializer);

        Debug.Assert(newa1.GetType() == a1.GetType()); // No assert
    }
}

With that, the following JSON was created: 有了它,创建了以下JSON:

{"__type":"A:#Tile.DataContractJsonSerializerPolymorphism","s1":"A"}
{"__type":"B:#Tile.DataContractJsonSerializerPolymorphism","s2":"B"}

Where Tile.DataContractJsonSerializerPolymorphism happens to be the name of the CLR namespace in my test application. 其中Tile.DataContractJsonSerializerPolymorphism恰好是我的测试应用程序中CLR命名空间的名称。 So, as you can see, the known type information got tucked away in this extra JSON property __type . 因此,正如您所看到的,已知的类型信息隐藏在这个额外的JSON属性__type Now, if you were using DataContractJsonSerializerHelper in your client also, you would never know this, because communication would just work. 现在,如果您在客户端也使用DataContractJsonSerializerHelper ,您将永远不会知道这一点,因为通信才会起作用。 But you are using JSON.stringify() which does not have this logic. 但是你使用的JSON.stringify()没有这个逻辑。 So, you may have to manually add the "__type":"DataContractName:DataContractNamespace" property on the client side. 因此,您可能必须在客户端手动添加"__type":"DataContractName:DataContractNamespace"属性。

More about the format for polymorphic types can be found here . 有关多态类型格式的更多信息,请参见此处 (I only tracked this documentation down after finding the hidden __type parameter, which gave me an extra Google search term.) (我在找到隐藏的__type参数后才跟踪此文档,这为我提供了额外的Google搜索字词。)

FYI, here is the helper class I used with the test code: 仅供参考,这是我与测试代码一起使用的助手类:

public static class DataContractJsonSerializerHelper
{
    private static MemoryStream GenerateStreamFromString(string value)
    {
        return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
    }

    public static string GetJson<T>(T obj, DataContractJsonSerializer serializer) where T : class
    {
        using (var memory = new MemoryStream())
        {
            serializer.WriteObject(memory, obj);
            memory.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(memory))
            {
                return reader.ReadToEnd();
            }
        }
    }

    public static string GetJson<T>(T obj) where T : class
    {
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
        return GetJson(obj, serializer);
    }

    public static T GetObject<T>(string json) where T : class
    {
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
        return GetObject<T>(json, serializer);
    }

    public static T GetObject<T>(string json, DataContractJsonSerializer serializer) where T : class
    {
        T obj = null;
        using (var stream = GenerateStreamFromString(json))
        {
            obj = (T)serializer.ReadObject(stream);
        }
        return obj;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM