【问题标题】:Serializing a List of Interfaces using the DataContractSerializer使用 DataContractSerializer 序列化接口列表
【发布时间】:2013-02-18 13:07:15
【问题描述】:

我有一个类,其中有一些嵌套类。我将其序列化并使用没有问题的方法将其发送到 wcf 服务。这是课程;

public class ComputerDTO
{
    [DataMember]
    public ComputerTypeDTO Type { get; set; }

    [DataMember]
    public string ComputerName { get; set; }

    [DataMember]
    public MonitorDTO Monitor { get; set; }
}

方法如下;

public void Check()
{
    Computer c = new Computer();

    ISystemInfoOperations cli = GetServiceClient();

    Mapper.CreateMap<Monitor, MonitorDTO>();
    Mapper.CreateMap<IHardwarePart, IHardwarePartDTO>();

    Mapper.CreateMap<Computer, ComputerDTO>()
            .ForMember(s => s.Hardware, m => m.MapFrom(q => Mapper.Map<List<IHardwarePart>, List<IHardwarePartDTO>>(q.Hardware)));


    Mapper.AssertConfigurationIsValid();

    ComputerDTO dto = Mapper.Map<Computer, ComputerDTO>(c);

    string sendComputerInfo = cli.SendComputerInfo(dto);
}

但我还有一个要发送的接口列表。所以我像下面这样更改代码并得到一个错误。

public class ComputerDTO
{
    [DataMember]
    public ComputerTypeDTO Type { get; set; }

    [DataMember]
    public string ComputerName { get; set; }

    [DataMember]
    public MonitorDTO Monitor { get; set; }

    [DataMember]
    public List<IHardwarePartDTO> Hardware { get; set; }
}

public interface IHardwarePartDTO
{
    [DataMember]
    string Name { get; set; }

    [DataMember]
    HardwarePartTypeDTO PartType { get; set;  }
}

硬件内部正在填充项目。但是如果我尝试发送它,我会收到这个著名的错误:

类型 '代理' 带有数据合同名称 '_x0030__Culture_x003D_neutral_PublicKeyToken_x003D_null_x003E_:http://schemas.datacontract.org/2004/07/Proxy%3CSystemInfo.DTO.IHardwarePartDTO_SystemInfo.DTO_Version=1.0.0' 预计不会。考虑使用 DataContractResolver 或添加任何 已知类型列表中静态未知的类型 - 例如, 通过使用 KnownTypeAttribute 属性或将它们添加到 传递给 DataContractSerializer 的已知类型列表。

【问题讨论】:

  • 您尝试过使用 KnownTypes 吗?这篇文章应该可以帮助您更好地了解 Juval 的 Known Types and the Generic Resolver 发生了什么
  • 谢谢佩塔。我正在看。

标签: c# wcf interface automapper dto


【解决方案1】:

DataContractSerializer 需要了解可能返回的具体类型。一个接口不能被序列化,因为它不能被反序列化(你怎么能创建一个没有具体实现的接口实例)。

简单的解决方法是添加 KnownTypes 属性,如下所示:

[KnownType(typeof(your hardware dto concrete type here))]
public class ComputerDTO
{
    [DataMember]
    public ComputerTypeDTO Type { get; set; }

    [DataMember]
    public string ComputerName { get; set; }

    [DataMember]
    public MonitorDTO Monitor { get; set; }

    [DataMember]
    public List<IHardwarePartDTO> Hardware { get; set; }
}

您可以添加任意数量的已知类型属性。

稍微复杂一点的是 ServiceKnownTypes 属性。这非常相似,但您可以将其添加到您的服务类中。

除此之外,您还可以使用数据合同解析器 - 但这非常复杂,需要一段时间来解释。

编辑:18/02/2013 15:11

您可能还需要查看 Automapper,因为它当前将在您的硬件列表中创建代理 - 并且代理无法序列化。您需要告诉 automapper 将它们序列化为什么 - 例如:

Mapper.CreateMap<Monitor, MonitorDTO>();
Mapper.CreateMap<Monitor, IHardwarePartDTO>().As<MonitorDTO>();

Mapper.CreateMap<Audio, AudioDTO>();
Mapper.CreateMap<Audio, IHardwarePartDTO>().As<AudioDTO>();

Mapper.CreateMap<CDROMDrive, CDROMDriveDTO>();
Mapper.CreateMap<CDROMDrive, IHardwarePartDTO>().As<CDROMDriveDTO>();
//you need entries like these for everythin that implements IHardwarePartDTO

这样,automapper 就知道它需要创建什么。

【讨论】:

  • 嗨,马特。感谢您的回复。当我按照您所说的添加 KnownType 属性时,它会出错。 “属性 'KnownType' 在此声明类型上无效。它仅在 'class, struct' 声明上有效。”
  • 对不起,没有考虑就写了!根据@JohnSaunders 评论修改以显示正确的实施
  • 没关系。实际上,我之前已经在类中添加了 knowntype 属性。没有该列表也可以工作。但我需要那个清单。但它不适用于它。 [DataContract] [KnownType(typeof(CPUDTO))] [KnownType(typeof(AudioDTO))] [KnownType(typeof(CDROMDriveDTO))] [KnownType(typeof(HardDriveDTO))] [KnownType(typeof(MemoryDTO))] [KnownType (typeof(MotherBoardDTO))] [KnownType(typeof(NetworkDTO))] [KnownType(typeof(SCSIDriveDTO))] [KnownType(typeof(USBDTO))] [KnownType(typeof(VideoDTO))] 公共类 ComputerDTO { ... .
  • 您是否使用 DataContract / DataMember 属性标记了所有这些类?
  • 好的,所以我做了另一个编辑,可能会更好地解释它。您基本上需要首先将每个具体硬件类型映射到 IHardwarePartDto 并用作它们的 DTO 对应物。并且还将原始类型分别映射到 DTO 对应项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
相关资源
最近更新 更多