无法序列化 System.Collections.Generic.Dictionary`2 类型的成员 ...,因为它实现了 IDictionary
Cannot serialize member ... of type System.Collections.Generic.Dictionary`2 because it implements IDictionary
我正在尝试通过 WCF 传递带有字典 属性 的 class,它对一种方法失败但对另一种方法有效。当 class 在 List
中返回时,它起作用了。但是当 class 在 DataTable
中返回时,客户端只是说连接已断开并且没有显示任何错误。
这是导致问题的 class:
[DataContract]
public class DetailLog
{
[DataMember]
public string Name
{
get;
set;
}
[DataMember]
public string SubAction
{
get;
set;
}
[DataMember]
public Dictionary<string, string> Fields
{
get;
set;
}
[DataMember]
public string UserName
{
get;
set;
}
}
我开始创建一个没有问题的方法:
public List<DetailLog> GetDetailLog(List<int> IDs, List<int> actionTypeIds, List<int> userIds, DateTime beginDate, DateTime endDate)
然后我们需要创建一些非常动态的报告,所以我使用了我们之前用于其他动态报告的 DataTable。
但是我需要传递 DetailLog class 所以我创建了一个该类型的 DataTable 列:
public DataTable GetCustomDetailReport(int CustomReportID, List<CustomReportFilter> reportFilters)
{
DataTable data = new DataTable();
...
data.Columns.Add("DetailLog", typeof(DetailLog));
...
}
此方法将在 WCF 主机端正常退出,但客户端会出现连接丢失的错误。我尝试在界面中为 OperationContract 添加 ServiceKnownType 但它没有修复它:
[OperationContract]
[ServiceKnownType(typeof(DetailLog))]
DataTable GetCustomUserAuditReport(int CustomReportID, List<CustomReportFilter> reportFilters);
当方法 returns DataTable 时,我无法真正调试序列化,所以我将此代码添加到 GetCustomDetailReport() 的末尾以捕获错误。
DataContractSerializer ser = new DataContractSerializer(typeof(DataTable), new List<Type> { typeof(DetailLog) });
ser.WriteObject(Stream.Null, data);
当我这样做的时候,我看到了一个异常
Cannot serialize member ... of type System.Collections.Generic.Dictionary`2 because it implements IDictionary.
您的问题如下:
Dictionary<TKey, TValue>
被 data contract serializer used in WCF, as explained in the docs 支持。这就是为什么您的 DetailLog
class 可以通过 WCF 作为根对象成功地通过网络发送。
此序列化程序还支持 IXmlSerializable
以允许类型手动将自身序列化为 XML。
DataTable
实施 IXmlSerializable
.
在内部,DataTable
使用XmlSerializer
序列化非原始条目——一个完全不同的序列化器,使用完全不同的代码基础.
XmlSerializer
does not support dictionaries。因此,当嵌套在 DataTable
.
中时,WCF 无法通过网络发送您的 DetailLog
作为一个无关的问题,还需要给数据设置table名称,不设置的话序列化会抛出异常:
data.TableName = "CustomDetailReport"; // For instance
要解决字典问题,您需要使您的 DetailLog
class 可由两个序列化程序序列化。问题How to serialize/deserialize to Dictionary<int, string>
from custom XML not using XElement?给出了多种序列化其字典属性的方法,包括使用代理数组属性:
[XmlType("KeyValue"), XmlRoot("KeyValue")]
public class SerializableKeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
public static class SerializableKeyValuePairExtensions
{
public static SerializableKeyValuePair<TKey, TValue> ToSerializablePair<TKey, TValue>(this KeyValuePair<TKey, TValue> pair)
{
return new SerializableKeyValuePair<TKey, TValue> { Key = pair.Key, Value = pair.Value };
}
}
[DataContract]
public class DetailLog
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string SubAction { get; set; }
[DataMember]
[XmlIgnore]
public Dictionary<string, string> Fields { get; set; }
[IgnoreDataMember]
[XmlArray("Fields")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public SerializableKeyValuePair<string, string>[] FieldsArray
{
get
{
return Fields == null ? null : Fields.Select(p => p.ToSerializablePair()).ToArray();
}
set
{
Fields = value == null ? null : value.ToDictionary(p => p.Key, p => p.Value);
}
}
[DataMember]
public string UserName { get; set; }
}
WCF 现在应该能够成功地通过网络发送您的 DataTable
。
我正在尝试通过 WCF 传递带有字典 属性 的 class,它对一种方法失败但对另一种方法有效。当 class 在 List
中返回时,它起作用了。但是当 class 在 DataTable
中返回时,客户端只是说连接已断开并且没有显示任何错误。
这是导致问题的 class:
[DataContract]
public class DetailLog
{
[DataMember]
public string Name
{
get;
set;
}
[DataMember]
public string SubAction
{
get;
set;
}
[DataMember]
public Dictionary<string, string> Fields
{
get;
set;
}
[DataMember]
public string UserName
{
get;
set;
}
}
我开始创建一个没有问题的方法:
public List<DetailLog> GetDetailLog(List<int> IDs, List<int> actionTypeIds, List<int> userIds, DateTime beginDate, DateTime endDate)
然后我们需要创建一些非常动态的报告,所以我使用了我们之前用于其他动态报告的 DataTable。
但是我需要传递 DetailLog class 所以我创建了一个该类型的 DataTable 列:
public DataTable GetCustomDetailReport(int CustomReportID, List<CustomReportFilter> reportFilters)
{
DataTable data = new DataTable();
...
data.Columns.Add("DetailLog", typeof(DetailLog));
...
}
此方法将在 WCF 主机端正常退出,但客户端会出现连接丢失的错误。我尝试在界面中为 OperationContract 添加 ServiceKnownType 但它没有修复它:
[OperationContract]
[ServiceKnownType(typeof(DetailLog))]
DataTable GetCustomUserAuditReport(int CustomReportID, List<CustomReportFilter> reportFilters);
当方法 returns DataTable 时,我无法真正调试序列化,所以我将此代码添加到 GetCustomDetailReport() 的末尾以捕获错误。
DataContractSerializer ser = new DataContractSerializer(typeof(DataTable), new List<Type> { typeof(DetailLog) });
ser.WriteObject(Stream.Null, data);
当我这样做的时候,我看到了一个异常
Cannot serialize member ... of type System.Collections.Generic.Dictionary`2 because it implements IDictionary.
您的问题如下:
Dictionary<TKey, TValue>
被 data contract serializer used in WCF, as explained in the docs 支持。这就是为什么您的DetailLog
class 可以通过 WCF 作为根对象成功地通过网络发送。此序列化程序还支持
IXmlSerializable
以允许类型手动将自身序列化为 XML。DataTable
实施IXmlSerializable
.在内部,
DataTable
使用XmlSerializer
序列化非原始条目——一个完全不同的序列化器,使用完全不同的代码基础.XmlSerializer
does not support dictionaries。因此,当嵌套在DataTable
. 中时,WCF 无法通过网络发送您的 作为一个无关的问题,还需要给数据设置table名称,不设置的话序列化会抛出异常:
data.TableName = "CustomDetailReport"; // For instance
DetailLog
要解决字典问题,您需要使您的 DetailLog
class 可由两个序列化程序序列化。问题How to serialize/deserialize to Dictionary<int, string>
from custom XML not using XElement?给出了多种序列化其字典属性的方法,包括使用代理数组属性:
[XmlType("KeyValue"), XmlRoot("KeyValue")]
public class SerializableKeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
public static class SerializableKeyValuePairExtensions
{
public static SerializableKeyValuePair<TKey, TValue> ToSerializablePair<TKey, TValue>(this KeyValuePair<TKey, TValue> pair)
{
return new SerializableKeyValuePair<TKey, TValue> { Key = pair.Key, Value = pair.Value };
}
}
[DataContract]
public class DetailLog
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string SubAction { get; set; }
[DataMember]
[XmlIgnore]
public Dictionary<string, string> Fields { get; set; }
[IgnoreDataMember]
[XmlArray("Fields")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public SerializableKeyValuePair<string, string>[] FieldsArray
{
get
{
return Fields == null ? null : Fields.Select(p => p.ToSerializablePair()).ToArray();
}
set
{
Fields = value == null ? null : value.ToDictionary(p => p.Key, p => p.Value);
}
}
[DataMember]
public string UserName { get; set; }
}
WCF 现在应该能够成功地通过网络发送您的 DataTable
。