“类型不是预期的”,使用 DataContractSerializer - 但它只是一个简单的类,没有有趣的东西?

Posted

技术标签:

【中文标题】“类型不是预期的”,使用 DataContractSerializer - 但它只是一个简单的类,没有有趣的东西?【英文标题】:"Type not expected", using DataContractSerializer - but it's just a simple class, no funny stuff? 【发布时间】:2012-02-06 08:27:17 【问题描述】:

我正在重构我的 XML 序列化,并想试试 DataContractSerializer。 一切运行顺利,直到需要序列化这个类:

using System;
using System.Runtime.Serialization;

namespace VDB_Sync.Model

[DataContract(Name="Konstant")]
public class Konstant : DataFelt

    [DataMember]
    private mysqlDbType mydataType;
    [DataMember]
    private object value;

    public Konstant(string navn, MySqlDbType dataType, object value)
        : base(navn, dataType, "*Konstant", false, false)
    
        //this.navn = navn;
        this.mydataType = dataType;
        this.value = value;

        if (navn.Contains("*Løbenummer"))
        
            navn = "*Konstant: " + Convert.ToString(value);
        
    

    public object Value
    
        get
        
            return value;
        
    



它给了我这个:

不应使用数据合同名称“Konstant:http://schemas.datacontract.org/2004/07/VDB_Sync.Model”键入“VDB_Sync.Model.Konstant”。考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。

*到目前为止我找到的帮助指向集合和类型。我的班级确实有一个枚举(MySqlDbType) - 但得到这个:当我根本没有声明 DataMembers 时,我什至得到同样的错误:-x 那么 - 这里发生了什么?我错过了什么?

作为参考,我是这样序列化它的,VDB_SessionController 是根:*

    public void GemKonfig(VDB_SessionController session)
    
        var settings = new XmlWriterSettings()
        
            Indent = true,
            IndentChars = "\t"
        ;

        var writer = XmlWriter.Create(defaultFile, settings);
        DataContractSerializer ser =
            new DataContractSerializer(typeof(VDB_SessionController));

        ser.WriteObject(writer, session);
        writer.Close();
    

【问题讨论】:

【参考方案1】:

报告的异常是针对 VDB_Sync.Model.Konstant。这意味着在链的更上游的某个地方,这个类被拉到另一个类中,而那个类就是被序列化的类。

问题在于,根据 Konstant 在此类中的嵌入方式(例如,如果它在集合或通用列表中),DataContractSerializer 可能没有准备好在反序列化期间出现。

要解决此问题,您需要将 known-type 属性应用于包含 Konstant 的类。根据您的序列化代码,我怀疑这是VDB_SessionController

所以,尝试用 KnownType 属性装饰这个类:

[KnownType(typeof(VDB_Sync.Model.Konstant)]
public class VDB_SessionController

【讨论】:

太棒了——它有效!看来我需要通过很多课程来做到这一点,谢谢! 如果类是由实体框架生成的,我该如何添加这个装饰? 太棒了!现在我也明白了“KnownType”修饰的目的了!谢谢! 你给我省了很多麻烦。我希望我能投票两次。 谢谢!。我的问题与 IReadOnlyCollection 不可序列化有关。改用 IList 让它工作。【参考方案2】:

将此添加到 WebApiConfig.cs

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

var json = config.Formatters.JsonFormatter;

json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

参考:http://www.datazx.cn/Forums/en-US/a5adf07b-e622-4a12-872d-40c753417645/action?threadDisplayName=web-api-error-the-objectcontent1-type-failed-to-serialize-the-response-body-for-content&forum=wcf

【讨论】:

所有这些都是禁用 XML 序列化,这就是异常消失的原因。但是,如果您需要 XML 序列化,此答案将无济于事。此外,您只需要最后一行:config.Formatters.Remove(config.Formatters.XmlFormatter); 该行以上的所有内容都无关紧要。【参考方案3】:

您还可以将[KnownType] 和反射结合起来,使您的代码更能抵抗未来的变化。

[DataContract]
[KnownType("GetKnownPersonTypes")]
internal class Person

    private static IEnumerable<Type> _personTypes;

    private static IEnumerable<Type> GetKnownTypes()
    
        if (_personTypes == null)
            _personTypes = Assembly.GetExecutingAssembly()
                                    .GetTypes()
                                    .Where(t => typeof (Person).IsAssignableFrom(t))
                                    .ToList();
        return _personTypes;
    

现在 DataContractSerializer / DataContractJsonSerializer / XmlSerializer 配置为与 Person 一起使用,也将与派生自 Personany 类型一起使用(只要它在相同的程序集)。

【讨论】:

【参考方案4】:

使用 KnownTypeAttribute 来解析 DataFelt 类。 见:http://msdn.microsoft.com/en-us/library/system.runtime.serialization.knowntypeattribute.aspx

【讨论】:

【参考方案5】:

我的问题是我从我的 WebAPI 控制器返回接口 (IIndividual)。当我将该返回类型更改为 Class (Individual) 类型时,此错误就消失了。

不工作:

    [HttpGet]
    [Route("api/v1/Individual/Get/id")]
    public IIndividual Get([FromUri]int id)
    
        return _individualService.Get(id);
    

工作:

    [HttpGet]
    [Route("api/v1/Individual/Get/id")]
    public Individual Get([FromUri]int id)
    
        IIndividual individual = _individualService.Get(id);
        return individual as Individual;
    

【讨论】:

【参考方案6】:

就像@Leon 建议的那样,但是通过@Bryan 的修复,“KnownTypeAttribute”应该在基类上,所以应该是这样的:

[DataContract(Name="DataFelt")]
[KnownType(typeof(somenamespace.Konstant))]
public class DataFelt

在子类中:

[DataContract(Name="Konstant")]
public class Konstant : DataFelt

【讨论】:

【参考方案7】:

改变这个:

[DataContract(Name="Konstant")]
public class Konstant : DataFelt

到这里:

[DataContract(Name="Konstant")]
[KnownTypes(typeof(somenamespace.DataFelt))]
public class Konstant : DataFelt

【讨论】:

KnownTypeAttribute 需要放在基类上。 如果您无权访问基本类型怎么办?

以上是关于“类型不是预期的”,使用 DataContractSerializer - 但它只是一个简单的类,没有有趣的东西?的主要内容,如果未能解决你的问题,请参考以下文章

使用 DataContract 属性时 ProtoBuf.NET 未序列化

如何找出类是不是具有 DataContract 属性?

我可以同时使用 DataContract 和 Serializable 吗?

DataContract with Json.Net

DataContract,默认 DataMember 值

从 XSD 生成 DataContract