Каков стандартизированный способ передачи сложных типов в WCF?
-
03-07-2019 - |
Вопрос
Я новичок в WCF, в настоящее время я разрабатываю службу TCP WCF, и я не уверен, правильно я понимаю передачу параметров или нет, поэтому я рекомендую вам прокомментировать и дать стандартизированный способ.
Чтобы прояснить ситуацию, я разработал небольшой сервис для тестирования, который имеет один метод и зависит от внешнего .Net dll, который предоставляет один класс.Код сервисного контракта
[ServiceContract]
public interface IMyService
{
[OperationContract]
int Test1(actionType at, calculationType ct, action a);
[OperationContract]
int Test2(DataSeries s);
}
Где actionType
,calculationType
,action
объявлены ли перечисления внутри внешней библиотеки dll
и DataSeries
это класс, объявленный внутри библиотеки dll.
Исходное определение для DataSeries
класс в библиотеке dll помечен символом [Serializable]
только и всего [DataMember]
о его членах.
Я использую 3-ю библиотеку dll на стороне клиента и сервера, моим удивлением было то, что оба приложения работали нормально, не помещая [DataContract]
в классе DataSeries и без использования каких-либо [EnumMember]
внутренние перечисления, [DataMember]
внутри класса.
Так что же все-таки происходит?
Еще Один эксперимент:
Удаление третьей стороны со стороны клиента и использование сервиса как есть
Я обнаружил, что vs2008 генерирует перечисления и DataSeries
класс и помечает их соответствующими атрибутами?Нравится
[System.CodeDom.Compiler.GeneratedCodeAttribute ("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="actionType", Namespace="http://schemas.datacontract.org/2004/07/DBInterface")]
public enum actionType : int {
[System.Runtime.Serialization.EnumMemberAttribute()]
All = 0,
[System.Runtime.Serialization.EnumMemberAttribute()]
Buy = 1,
[System.Runtime.Serialization.EnumMemberAttribute()]
Sell = 2,
}
Решение
DataContract , DataMember и EnumMember используются DataContractSerializer (обычно basicHttpBinding или wsHttpBinding ). Если вы предоставляете конечной точке привязку TCP ( netTcpBinding ) требуется только SerializableAttribute . Обратите внимание, что с помощью DataContractSerializer вы можете добавить только SerializableAttribute к своим классам, и он автоматически сериализует все поля.
Я бы порекомендовал вам следующее: если вы хотите, чтобы ваш сервис был совместимым, используйте basicHttpBinding и пометьте ваши классы атрибутами DataContract и DataMember. Если ваш клиент является приложением .NET, используйте netTcpBinding и пометьте ваши классы с помощью SerializableAttribute. Р>
Вы также можете прочитать эту запись для сравнения между разные привязки.
Другие советы
Но без использования DataContract или каких-либо атрибутов я обнаружил, что клиентская сторона работает корректно
Да, это правда - если используемые вами типы данных не помечены [DataContract], WCF попытается использовать для них сериализатор SOAP по умолчанию и просто сериализует все, что является общедоступным (все общедоступные свойства).
Это работает, но это может быть не то, что вы хотите / ожидаете, поэтому я бы поддержал мнение дарина - просто всегда используйте явные атрибуты [DataContract] для ваших типов.Чем яснее вы сформулируете свое намерение для себя (или других программистов, которым позже понадобится поддерживать ваш код), тем лучше.Эти "магические трюки", которые происходят за кулисами, иногда приводят к путанице - вам лучше уйти нет слишком полагаться на них
Марк
Поэтому для меня я использую [DataContract] s, передаю один параметр и возвращаю контракт данных обратно.
Это дает больше гибкости, так как я могу расширить контракт данных новыми необязательными атрибутами для контракта данных, не нарушая существующих клиентов.
Перечисления, для которых я также создаю контакты данных; потому что тогда я могу сделать то же самое, расширяя перечисление, ничего не нарушая, и я могу контролировать пространство имен.
[DataContract(Namespace = "http://namespace.mydomain.com/2009/05", Name = "ReferenceTypeData")]
public enum GenderEnum
{
[EnumMember()]
Unknown = 0,
[EnumMember()]
Male = 1,
[EnumMember()]
Female = 2
}
Затем вы должны пометить договор на обслуживание с помощью
[ServiceKnownType(typeof(GenderEnum))]
public interface IServiceContract
{
....
}