WCF не может сериализовать для объекта (System.Byte [*] Type) - PullRequest
2 голосов
/ 15 марта 2012

Все

По сути, моей службе WCF необходимо подключиться к серверу DCOM и получить структуру, содержащую поле «VARIANT», а затем передать ее моему клиенту службы WCF.

Это мой контракт данных WCF для этой структуры, полученный от собственной службы DCOM

[DataContract]
[ComVisible(true)]
[StructLayout(LayoutKind.Sequential)]
public struct tagProcReadAns
{
    [DataMember]
    [MarshalAs(UnmanagedType.Struct)]
    public object vItemValue;           //VARIANT: marshalled as object in C# 
    [DataMember]
    public ushort wQuality;
    [DataMember]
    public Int32 Error;}            

так как я ожидал, что этот контракт данных может быть зарегистрирован как объект COM и снова перенесен в код C ++, поэтому у меня есть части [ComVisible] и [MarshalAs]

В любом случае, vItemValue - это объект VARIANT, который я успешно получил с сервера DCOM (я проверил содержимое). Однако, когда я столкнулся с исключениями, когда я попытался передать его через WCF.

Я ожидал, что данные, содержащиеся в vItemValue VARIANT, имеют "тип байтового массива", так как я увидел, что значение VARIANT.vt равно "VTUI1 | VT_ARRAY", поэтому я изменяю DataContract следующим образом

[DataContract]
[KnownType(TypeOf(byte[])]  //new 
[ComVisible(true)]
[StructLayout(LayoutKind.Sequential)]
public struct tagProcReadAns
{
    [DataMember]
    [MarshalAs(UnmanagedType.Struct)]
    public object vItemValue;           //VARIANT: marshalled as object in C# 
    [DataMember]
    public ushort wQuality;
    [DataMember]
    public Int32 Error;} 

Однако, когда я снова запускаю код, я все еще обнаружил исключение, добавив трассировку, у меня появляются следующие сообщения об ошибках

There was an error while trying to serialize parameter http://tempuri.org/:aryAns. The InnerException message was 'Type 'System.Byte[*]' with data contract name 'ArrayOfunsignedByte:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 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.'.  Please see InnerException for more details.

Кажется, что тип данных - это не byte [], а byte [*] ?? Что-то не так я сделал? и, как предполагает исключение, я могу использовать DataContractResolver, чтобы как-то решить эту проблему, можете ли вы предложить какие-либо решения?

спасибо

Ответы [ 2 ]

1 голос
/ 16 марта 2012

Я выясняю, как избежать упомянутой выше проблемы с сериализацией.

В основном то, что я делал раньше, - это непосредственное назначение vItemValue , которое я получил из кода C ++, а затем передаю его службе WCF длясериализации.

Следуя предложению @Marc Gravell, я выяснил, что контракт данных должен быть определен следующим образом: VARIANT с типом VT_ARRAY | VT _ * по умолчанию будет маршалироваться доУправляемый код как Object с типом System.Array (byte) вместо System.Byte [] и т. Д.

    [DataContract]
[KnownType(typeof(string))]    
[KnownType(typeof(byte))]
[KnownType(typeof(uint))]
[KnownType(typeof(UInt16))]
[KnownType(typeof(UInt64))]
[KnownType(typeof(ulong))]
[KnownType(typeof(System.Array))]  //here !!!!! for System.Byte[*]
[KnownType(typeof(byte[]))]
[ComVisible(true)]
[StructLayout(LayoutKind.Sequential)]
public struct tagProcReadAns
{
    [DataMember]
    [MarshalAs(UnmanagedType.Struct)]
    public object vItemValue;           //VARIANT type has to be carefully marshalled 
    [DataMember]
    public ushort wQuality;
    [DataMember]
    public Int32 Error;         
}

Кроме того, при передаче объекта VARIANT, полученного из кода C ++, и прохождения через границу WCF, ясделал

System.Array result = System.Array.CreateInstance(typeof(byte), ((System.Array)ans[i].vItemValue).Length);
((System.Array)ans[i].vItemValue).CopyTo(result, 0);

вместо непосредственного присвоения результата ans [i] .vItemValue

, выполнив это, я смог передать объект через границу WCF ...

спасибо Марку за предложения!

0 голосов
/ 15 марта 2012

byte[*] (или, точнее, любой T[*]) - это одномерный массив, который явно не является вектором (вектор - это особая категория массива, основанная на нуле, одномерная).Ссылка на тип для такого типа довольно сложна, поскольку он не существует непосредственно в C # как языке (вам нужно использовать Array для общения с не векторным одномерным массивом).

Мой совет: ввести специальное DTO здесь.Попытка использовать существующую объектную модель для сериализации часто является хорошей отправной точкой, но когда она становится сложной: используйте DTO.Я добавил бы следующее и сопоставил бы это вручную до , идущего где-нибудь рядом с WCF:

[DataContract]
public class TagAnswer // or whatever this is
{
    [DataMember]
    public byte[] Data {get;set;}
    [DataMember]
    public ushort Quality {get;set;}
    [DataMember]
    public Int32 ErrorCode {get;set;}
}

Ваш COM / структура в порядке, когда общается с COM, но не имеет никакого места награница обслуживания.

...