Как настроить программные типы WCF?

В моем приложении клиент / сервер используется WCF для связи, что было замечательно. Однако один недостаток текущей архитектуры заключается в том, что я должен использовать известную конфигурацию типа для определенных передаваемых типов. Я использую внутренний механизм Pub / Sub, и это требование неизбежно.

Проблема в том, что легко забыть добавить известный тип, и если вы это сделаете, WCF сработает без малейших подсказок относительно того, что происходит не так.

В моем приложении я знаю набор типов, которые будут отправлены. Я хотел бы выполнить конфигурацию программно, а не декларативно через файл App.config который в настоящее время содержит что-то вроде этого:

              

Вместо этого я хотел бы сделать что-то вроде этого:

 foreach (Type type in _transmittedTypes) { // How would I write this method? AddKnownType(typeof(MyParent), type); } 

Может кто-нибудь объяснить, как я могу это сделать?

EDIT Пожалуйста, поймите, что я пытаюсь установить известные типы динамически во время выполнения, а не декларативно в конфигурации или используя атрибуты в исходном коде.

Это в основном вопрос о API WCF, а не вопрос стиля.

EDIT 2 На этой странице страницы MSDN указано:

Вы также можете добавлять типы в ReadOnlyCollection, доступ к которым осуществляется через свойство KnownTypes DataContractSerializer.

К сожалению, это все, что сказано, и это не имеет особого смысла, учитывая, что KnownTypes является свойством readonly, а значение свойства – ReadOnlyCollection .

Добавьте [ServiceKnownType] в ваш интерфейс [ServiceContract] :

 [ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))] 

затем создайте class под названием KnownTypesProvider :

 internal static class KnownTypesProvider { public static IEnumerable GetKnownTypes(ICustomAttributeProvider provider) { // collect and pass back the list of known types } } 

и затем вы можете передать все типы, которые вам нужны.

Есть еще 2 способа решить вашу проблему:

I. Использование KnownTypeAttribute (строка):

 [DataContract] [KnownType("GetKnownTypes")] public abstract class MyParent { static IEnumerable GetKnownTypes() { return new Type[] { typeof(MyChild1), typeof(MyChild2), typeof(MyChild3) }; } } 

II. Использовать конструктор DataContractSerializer

 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)] public class MyHierarchyKnownTypeAttribute : Attribute, IOperationBehavior, IServiceBehavior, IContractBehavior { private void IOperationBehavior.AddBindingParameters( OperationDescription description, BindingParameterCollection parameters) { } void IOperationBehavior.ApplyClientBehavior( OperationDescription description, ClientOperation proxy) { ReplaceDataContractSerializerOperationBehavior(description); } private void IOperationBehavior.ApplyDispatchBehavior( OperationDescription description, DispatchOperation dispatch) { ReplaceDataContractSerializerOperationBehavior(description); } private void IOperationBehavior.Validate(OperationDescription description) { } private void IServiceBehavior.AddBindingParameters( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection endpoints, BindingParameterCollection bindingParameters) { ReplaceDataContractSerializerOperationBehavior(serviceDescription); } private void IServiceBehavior.ApplyDispatchBehavior( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { ReplaceDataContractSerializerOperationBehavior(serviceDescription); } private void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } private void IContractBehavior.AddBindingParameters( ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } private void IContractBehavior.ApplyClientBehavior( ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { ReplaceDataContractSerializerOperationBehavior(contractDescription); } private void IContractBehavior.ApplyDispatchBehavior( ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { ReplaceDataContractSerializerOperationBehavior(contractDescription); } private void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { } private static void ReplaceDataContractSerializerOperationBehavior( ServiceDescription description) { foreach (var endpoint in description.Endpoints) { ReplaceDataContractSerializerOperationBehavior(endpoint); } } private static void ReplaceDataContractSerializerOperationBehavior( ContractDescription description) { foreach (var operation in description.Operations) { ReplaceDataContractSerializerOperationBehavior(operation); } } private static void ReplaceDataContractSerializerOperationBehavior( ServiceEndpoint endpoint) { // ignore mex if (endpoint.Contract.ContractType == typeof(IMetadataExchange)) { return; } ReplaceDataContractSerializerOperationBehavior(endpoint.Contract); } private static void ReplaceDataContractSerializerOperationBehavior( OperationDescription description) { var behavior = description.Behaviors.Find(); if (behavior != null) { description.Behaviors.Remove(behavior); description.Behaviors.Add( new ShapeDataContractSerializerOperationBehavior(description)); } } public class ShapeDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior { public ShapeDataContractSerializerOperationBehavior( OperationDescription description) : base(description) { } public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList knownTypes) { var shapeKnownTypes = new List { typeof(Circle), typeof(Square) }; return new DataContractSerializer(type, name, ns, shapeKnownTypes); } public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList knownTypes) { //All magic here! var knownTypes = new List { typeof(MyChild1), typeof(MyChild2), typeof(MyChild3) }; return new DataContractSerializer(type, name, ns, knownTypes); } } } [ServiceContract()] [MyHierarchyKnownTypeAttribute] public interface IService {...} 

ПРИМЕЧАНИЕ. Вы должны использовать этот атрибут с обеих сторон: на стороне клиента и на стороне обслуживания!

Мне нужно было сделать это, чтобы позволить наследованию работать правильно. Я не хотел поддерживать список производных типов.

  [KnownType("GetKnownTypes")] public abstract class BaseOperationResponse { public static Type[] GetKnownTypes() { Type thisType = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType; return thisType.Assembly.GetTypes().Where(t => t.IsSubclassOf(thisType)).ToArray(); } 

Я знаю, что первая строка функции переполнена, но это просто означает, что я могу вставить ее в любой базовый class без изменений.

Web .Config

      a.AOrder,a b.BOrder,b c.COrder,c     

 static class Helper { public static IEnumerable GetKnownTypes(ICustomAttributeProvider provider) { System.Collections.Generic.List knownTypes = new System.Collections.Generic.List(); // Add any types to include here. Properties.Settings.Default.KnowTypes.Cast().ToList().ForEach(type => { knownTypes.Add(Type.GetType(type)); }); return knownTypes; } } [ServiceContract] [ServiceKnownType("GetKnownTypes", typeof(Helper))] public interface IOrderProcessor { [OperationContract] string ProcessOrder(Order order); } 

Заказ представляет собой абстрактный базовый class


 [DataContract] public abstract class Order { public Order() { OrderDate = DateTime.Now; } [DataMember] public string OrderID { get; set; } [DataMember] public DateTime OrderDate { get; set; } [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } } 

немного перебор, но работает и является своего рода будущим доказательством

 var knownTypes = AppDomain.CurrentDomain .GetAssemblies() .Where(a => { var companyAttribute = a.GetCustomAttribute(); if (companyAttribute == null) return false; return companyAttribute.Company.ToLower().Contains("[YOUR COMPANY NAME]"); }) .SelectMany(a => a.GetTypes()).Where(t => t.IsSerializable && !t.IsGenericTypeDefinition); var serializer = new DataContractSerializer(type, knownTypes); 
Давайте будем гением компьютера.