简体   繁体   中英

Serializing a List of Interfaces using the DataContractSerializer

I have a class and there are some nested classes within it. I serialize it and send it to the wcf service using a method with no problems. Here's the class;

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

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

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

Here's the method;

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);
}

But I have also a list of interface to be sent. So I change the code like below and get an error.

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;  }
}

Inside of hardware is getting filled in the project. But if I try to send it, I get this famous error :

Type 'Proxy' with data contract name '_x0030__Culture_x003D_neutral_PublicKeyToken_x003D_null_x003E_: http://schemas.datacontract.org/2004/07/Proxy%3CSystemInfo.DTO.IHardwarePartDTO_SystemInfo.DTO_Version=1.0.0 ' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

The DataContractSerializer needs to know about the concrete types that is might return. An interface cannot be serialized, as it cannot be deserialized (how can you create an instance of an interface without a concrete implementation).

The simple resolution is to add KnownTypes attribute like below:

[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; }
}

You can add as many known type attributes as you like.

Slightly more complex is the ServiceKnownTypes attribute. This is very similar but you would add it to your service class.

Other than that you can use a data contract resolver - but this is very complicated and would take a while to explain.

EDIT: 18/02/2013 15:11

You may also need to look at you Automapper as its currently going to create proxies in your Hardware list - and proxies cannot be serialized. You need to tell automapper what to serialize them to - for example:

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

This way automapper knows what it needs to create.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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