如何使用DataContractJsonSerializer将类类型而不是命名空间序列化为Json字符串

ron*_*y l 11 c# wcf serialization json datacontractserializer

我正在尝试使用DataContractJsonSerializerWCF服务中的类层次结构序列化为Json字符串.序列化派生类的默认行为是将以下键值对添加到对象:

"__type":"ClassName:#Namespace"

我的问题是命名空间很长并且它们使Json字符串膨胀.我想以某种方式干预序列化并输出它:

"__type":"ClassName"

并且在反序列化时再次介入指向正确的命名空间(我在运行时知道).

有没有办法做这样的事情?

Che*_*eso 13

此页面描述了发出__type属性的环境.简而言之,在WCF中,如果使用派生类型和KnownTypeAttribute,那么您将获得__type属性.

例:

假设

[DataContract]
[KnownType(typeof(Subscriber))]
public class Person { ... }

[DataContract]
public class Subscriber : Person { ... } 
Run Code Online (Sandbox Code Playgroud)

此代码生成__type属性:

    var o = new Subscriber("Fleming");
    var serializer = new DataContractJsonSerializer(typeof(Person));
    serializer.WriteObject(Console.OpenStandardOutput(), o);
Run Code Online (Sandbox Code Playgroud)

但是这段代码没有:

    var o = new Subscriber("Fleming");
    var serializer = new DataContractJsonSerializer(typeof(Subscriber));
    serializer.WriteObject(Console.OpenStandardOutput(), o);
Run Code Online (Sandbox Code Playgroud)

请注意,第二个剪辑使用的DCJS与要序列化的对象的类型相同.

要避免__type,请不要使用派生类型,或者确切地说,使用类型化的序列化程序来实际序列化.如果通过WCF方法隐式执行序列化,则必须适当地键入该方法.在我的示例中,这意味着您必须使用返回类型"订阅者",而不是父类型"人".

__type由(内部)System.Runtime.Serialization.Json.XmlJsonWriter类上的(私有)WriteServerTypeAttribute方法发送到JSON流中.据我所知,没有公开的,有文档记录的,支持的方式来修改它.

为避免这种情况,您可能需要从WCF方法返回一个字符串,自己执行序列化,并对发出的JSON进行后处理.


如果您不介意__type事物,但只想从值中删除限定命名空间,那么将您的类型放在全局命名空间中.换句话说,将它们namespace放在代码中的任何声明之外.

示例:当数据类型驻留在命名空间中时,当我使用派生类型时,序列化的JSON如下所示:

{
  "__type":"Subscriber:#My.Custom.Namespace",
  "Index":604455,
  "Name":"Fleming",
  "Id":580540
}
Run Code Online (Sandbox Code Playgroud)

当数据类型驻留在全局命名空间中时,它看起来像这样:

{
  "__type":"Subscriber:#",
  "Index":708759,
  "Name":"Fleming",
  "Id":675323
}
Run Code Online (Sandbox Code Playgroud)


ron*_*y l 8

将namespace参数添加到数据协定就可以了. [DataContract(Namespace = "")]


小智 6

Cheeso的答案很棒.我确实发现了清理__type字段的一个改进:

您可以添加如下属性,而不是从其命名空间中删除子类:

[DataMember(Name = "__type")]
public string SubclassType
{
    get
    {
        return "Subscriber";
    }
    set { }
}
Run Code Online (Sandbox Code Playgroud)

你仍然坚持使用丑陋的名字"__type",但我发现因为我正在返回一个子类型列表,所以我想指定类型名称.您甚至可以返回值""以进一步减小响应大小.您也可以将该属性声明为:

public string __type
Run Code Online (Sandbox Code Playgroud)

但我发现要强调黑客攻击,所以我坚持使用适当的属性名称,然后将其重命名.

-Joey