WCF List<string> ошибка сериализации / десериализации
У меня есть следующие классы ServiceContract и DataContract:
[ServiceContract]
public interface IWcfService
{
[OperationContract]
Response GetData();
}
[DataContract]
public class Response
{
[DataMember]
public Dictionary<string, object> Data { get; set; }
}
Когда значение словаря Response.Data имеет тип int, string, double или любые другие "простые" примитивные типы, WCF может успешно сериализовать объект. Но когда значение словаря Response.Data имеет тип List
Message=The formatter threw an exception while trying to deserialize the message:
There was an error while trying to deserialize parameter http://tempuri.org/:GetDataResult.
The InnerException message was 'Error in line 1 position 990.
Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data from a type
that maps to the name 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfstring'.
The deserializer has no knowledge of any type that maps to this name.
Consider using a DataContractResolver or add the type corresponding to 'ArrayOfstring'
to the list of known types - for example, by using the KnownTypeAttribute attribute or
by adding it to the list of known types passed to DataContractSerializer.'.
Я также попытался добавить атрибут KnownType в ServiceContract и DataContract следующим образом:
[ServiceContract]
[ServiceKnownType(typeof(List<string>))]
[ServiceKnownType(typeof(Dictionary<string, string>))]
[ServiceKnownType(typeof(Dictionary<string, List<string>>))]
public interface IWcfService
{
[OperationContract]
[ServiceKnownType(typeof(List<string>))]
[ServiceKnownType(typeof(Dictionary<string, string>))]
[ServiceKnownType(typeof(Dictionary<string, List<string>>))]
Response GetData();
}
[DataContract]
[ServiceKnownType(typeof(List<string>))]
[ServiceKnownType(typeof(Dictionary<string, string>))]
[ServiceKnownType(typeof(Dictionary<string, List<string>>))]
[KnownType(typeof(List<string>))]
[KnownType(typeof(Dictionary<string, string>))]
[KnownType(typeof(Dictionary<string, List<string>>))]
public class Response
{
[DataMember]
public Dictionary<string, object> Data { get; set; }
}
Но ничего из этого не помогло. У кого-нибудь есть идеи по этому поводу?
обновленный
Данные будут выглядеть так:
Data = new new DIctionary<string, object>
{
{"_id", 12344},
{"names", new List<string>{ "John", "Peter", "Jack"}},
{"time", DateTime.Now}
}
Причина, по которой мы использовали Dictionary
3 ответа
Спасибо за вклад каждого. Мне удалось решить проблему, настроив WCF для использования NetDataContractSerializer в качестве сериализатора (по умолчанию используется DataContractSerializer). NETDataContractSerializer будет включать в себя больше информации о типе CLR при выполнении сериализации, хотя он имеет снижение производительности (примерно вдвое больше времени сериализации).
Помните, что ваш контракт данных сериализуется в строки по проводам, поэтому любой передаваемый вами объект должен быть сериализуемым (что object
не является).
Проблема в том, что вы используете объектно-ориентированные шаблоны в сервис-ориентированном контексте - ожидая, что все, что вы передаете в словарном значении, будет полиморфно object
, Я ответил на вопрос с похожими "запахами" здесь: /questions/36359312/vlozhennyie-vnutrennie-klassyi-v-wcf/36359318#36359318.
Эта проблема связана с тем, что WCF настолько хорош в абстрагировании базового канала вашего сервиса, что у вас возникает соблазн забыть, что вы сейчас работаете в контексте "Сервис-ориентированный" (KnownTypes
взломать - дает иллюзию ОО через провод). Контракт данных является частью "открытого" API для вашего сервиса, и поэтому он должен быть четким и ясным представлением данных, предоставляемых вашим сервисом. Наличие структуры данных, которая возвращает "динамические" данные, нарушает это важное правило.
Клиент должен знать, какие данные он возвращает, поэтому, если вы хотите реализовать "динамический" ответ, вы должны реализовать (скажем) различные методы / конечные точки / службы для вариантов ответа. В вашем сервисе нет никаких причин, по которым вы не можете использовать полиморфизм для упрощения вашего кода - но это не должно просачиваться в публичные сервисы / контракты на данные.
Я думаю по умолчанию System.Object
не является Serializable
, Вам необходимо отправить дополнительную информацию, но это все еще не лучшая практика, я рекомендую определить отдельный тип перед использованием вашего словаря.
Обратитесь к ниже:
Служба WCF, возвращающая массив словаря