Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用DataContractJsonSerializer将类类型而不是命名空间序列化为Json字符串_C#_Wcf_Json_Serialization_Datacontractserializer - Fatal编程技术网

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

C# 如何使用DataContractJsonSerializer将类类型而不是命名空间序列化为Json字符串,c#,wcf,json,serialization,datacontractserializer,C#,Wcf,Json,Serialization,Datacontractserializer,我试图在WCF服务中使用DataContractJsonSerializer将类层次结构序列化为Json字符串。 序列化派生类的默认行为是向对象添加以下键值对: “uu类型”:“类名:#名称空间” 我的问题是名称空间很长,并且会使Json字符串膨胀。 我想以某种方式干预序列化并输出以下内容: “\uuu类型”:“ClassName” 在反序列化时,再次介入以指向正确的名称空间(我在运行时知道) 有什么方法可以做到这一点吗?描述了发出_类型属性的情况。简而言之,在WCF中,如果您使用派生类型和Kn

我试图在WCF服务中使用
DataContractJsonSerializer
将类层次结构序列化为Json字符串。 序列化派生类的默认行为是向对象添加以下键值对:

“uu类型”:“类名:#名称空间”

我的问题是名称空间很长,并且会使Json字符串膨胀。 我想以某种方式干预序列化并输出以下内容:

“\uuu类型”:“ClassName”

在反序列化时,再次介入以指向正确的名称空间(我在运行时知道)

有什么方法可以做到这一点吗?

描述了发出_类型属性的情况。简而言之,在WCF中,如果您使用派生类型和KnownTypeAttribute,那么您将获得一个_类型属性

例如:

假定

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

[DataContract]
public class Subscriber : Person { ... } 
此代码生成一个_类型属性:

    var o = new Subscriber("Fleming");
    var serializer = new DataContractJsonSerializer(typeof(Person));
    serializer.WriteObject(Console.OpenStandardOutput(), o);
但该代码不:

    var o = new Subscriber("Fleming");
    var serializer = new DataContractJsonSerializer(typeof(Subscriber));
    serializer.WriteObject(Console.OpenStandardOutput(), o);
请注意,第二个snip使用的DCJS与被序列化的对象具有相同的类型

要避免使用_类型,请不要使用派生类型,或者准确地说,请使用与实际序列化的类型对应的序列化程序。如果序列化是由WCF方法隐式执行的,则必须适当地键入该方法。在我的示例中,这意味着您必须使用返回类型“Subscriber”,而不是父类型“Person”

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

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


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

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

{
  "__type":"Subscriber:#My.Custom.Namespace",
  "Index":604455,
  "Name":"Fleming",
  "Id":580540
}
{
  "__type":"Subscriber:#",
  "Index":708759,
  "Name":"Fleming",
  "Id":675323
}
当数据类型驻留在全局名称空间中时,它如下所示:

{
  "__type":"Subscriber:#My.Custom.Namespace",
  "Index":604455,
  "Name":"Fleming",
  "Id":580540
}
{
  "__type":"Subscriber:#",
  "Index":708759,
  "Name":"Fleming",
  "Id":675323
}

注意:我在下面输入了这个答案,后来意识到DataContractJsonSerializer当前不支持DataContractResolver。不过,该框架的下一个版本可能很快就会发布。如果您关注的不仅仅是JSON,那么这也很有用

**

您可以使用DataContractResolver实现这一点,它允许您以自定义方式将类型映射到xsi:type(_-type)信息,反之亦然


为此,请查看,plus,plus将名称空间参数添加到数据协定中即可。
[DataContract(Namespace=”“)]

奇索的回答非常好。不过,我确实发现了清理_类型字段的改进:

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

[DataMember(Name = "__type")]
public string SubclassType
{
    get
    {
        return "Subscriber";
    }
    set { }
}
您仍然会被难看的名称“\uuuu type”所困扰,但我发现,因为我返回了一个子类型列表,所以我还是希望指定类型名称。您甚至可以返回值“”以进一步减小响应大小。您也可以将该属性声明为:

public string __type
但我发现,为了强调这一点,我坚持使用一个合适的属性名称,然后将其重命名

-乔伊

@Cheeso写道:

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

下面是我如何实现后处理的。我想我应该把它贴在这里,JIC,它可能会帮助其他人

首先是一些样板,展示如何生成JSON字符串:

// Instantiate & populate the object to be serialized to JSON
SomeClass xyz = new SomeClass();
... populate it ...

// Now serialize it
DataContractJsonSerializer ser = new DataContractJsonSerializer(xyz.GetType()); // Note xyz.GetType()
... serialize the object to json, many steps omitted here for brevity ...
string json = sr.ReadToEnd();
(序列化基于中的示例)

请注意,
SomeClass
上的
[DataContract]
不包含我在别处看到的
(name=”“)
语法。这只会从_类型中删除名称空间,代价是需要修饰DataContract属性,这会使代码变得混乱。相反,我的后处理器在_类型字段中处理程序集名称

现在字符串
json
包含了json文本,但不幸的是,它包含了所有您不想要但无法抑制的“_类型”垃圾

下面是我删除它的后处理代码:

// This strips out that unsuppressable __type clutter generated by the KnownType attributes
Attribute[] attrs = Attribute.GetCustomAttributes(xyz.GetType());
foreach (Attribute attr in attrs)
{
    if (attr is KnownTypeAttribute)
    {
        KnownTypeAttribute a = (KnownTypeAttribute)attr;
        string find = "\"__type\":\"" + a.Type.ReflectedType.Name + "." + a.Type.Name + ":#" + a.Type.Namespace + "\",";
        json = json.Replace(find, "");
    }
}
这做了一些假设,最明显的是_类型字段以逗号结尾,它假设后面有另一个字段,尽管(a)我的对象总是至少有一个字段,(b)我发现_类型字段在序列化对象的输出中总是第一个


和往常一样,你可能需要根据自己的情况调整一些东西,但我发现它对我的情况很有效。

前几次我决定解决这个问题。 我使用DataContractJsonSerializer 如果序列化方法具有基类参数,但您将其子类作为参数,那么json中将有_类型。 更多详情:

[DataContract]
[KnownType(typeof(B))]
public abstract class A
{
    [DataMember]
    public String S { get; set; }
}

[DataContract]
public class B : A
{
    [DataMember]
    public Int32 Age { get; set; }
}

public static String ToJson<T>(this T value)
{
    var serializer = new DataContractJsonSerializer(typeof(T));
    using (var stream = new MemoryStream())
    {
        serializer.WriteObject(stream, value);
        return Encoding.UTF8.GetString(stream.ToArray());
    }
}

publicstaticvoidreadtype(T类型)
{
WriteLine(ToJson(type));
}
在第一次测试中你会

{\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

第二:

{\'S\':\'Vv\',\'Age\':10}


这抑制了属性的名称空间部分,但不抑制跟踪类名的冒号。因此,+1可以节省一些成本,但仍然不是一个完整的解决方案。但是,如果问题是该对象中使用了子类型,该怎么办?请注意,如果完整文件中有多个级别的自定义对象,则需要递归调用它。最后,我用一个正则表达式将它剥离了:
“\”\uuu type\“\\s*:\\s*”[^\“]+\“\\s*,?\\s*”
在没有名称空间的情况下发送看起来非常不正常。不过,我要么干脆把它全部删除,要么就不发送