2010-06-30 24 views
8

Próbuję określić znany typ w mojej konfiguracji, ale mam problem z tym, że pochodzi on z Object. Mogę sprawić, żeby działało określając znany typ za pomocą atrybutu. Ale w tym przypadku muszę sprawić, by działał z poziomu konfiguracji.Znany typ WCF z System.Object w Config

Oto przykład. Poniższe działa poprawnie:

[ServiceContract] 
[ServiceKnownType(typeof(MyData))] 
public interface IContract 
{ 
    [OperationContract] 
    void Send(object data); 
} 

[DataContract] 
public class MyData 
{ 
    [DataMember] 
    public string Message { get; set; } 
} 

Ale jeśli usunąć atrybut ServiceKnownType i umieścić następującą informację w config:

<system.runtime.serialization> 
    <dataContractSerializer> 
    <declaredTypes> 
     <add type="System.Object, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> 
     <knownType type="WpfApplication1.MyData, WpfApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </add> 
    </declaredTypes> 
    </dataContractSerializer> 
</system.runtime.serialization> 

dostaję ConfigurationErrorsException z komunikatem „wartości dla własności«typ» jest niepoprawny. Błąd jest następujący: Typ System.Object nie może być używany jako zadeklarowany typ w konfiguracji. "

Czy jest mimo to wykonanie tej pracy przez config?

Odpowiedz

9

Odpowiedź okazuje się być niemożliwe, aby zrobić to, co chcę zrobić w pliku konfiguracyjnym sam. Powyższa konfiguracja odpowiada atrybutowi [KnownType] używanemu w DataContracts. Wydaje się, że nie ma sposobu na wdrożenie [ServiceKnownType] w konfiguracji.

Alternatywnym podejściem jest użycie atrybutu [ServiceKnownType (methodName, type)] z sekcją konfiguracji niestandardowej. Nowy config wygląda następująco:

<configuration> 
    <configSections> 
    <section 
     name="serviceKnownTypes" 
     type="WpfApplication1.ServiceKnownTypesSection, WpfApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
    </configSections> 
    <serviceKnownTypes> 
    <declaredServices> 
     <serviceContract type="WpfApplication1.IContract, WpfApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> 
     <knownTypes> 
      <knownType type="WpfApplication1.MyData, WpfApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </knownTypes> 
     </serviceContract> 
    </declaredServices> 
    </serviceKnownTypes> 
</configuration> 

Kontrakty:

[ServiceContract] 
[ServiceKnownType("GetServiceKnownTypes", typeof(KnownTypeHelper))] 
public interface IContract 
{ 
    [OperationContract] 
    void Send(object data); 
} 

[DataContract] 
public class MyData 
{ 
    [DataMember] 
    public string Message { get; set; } 
} 

Klasa pomocnika, który zawiera wywołania zwrotnego, która zwraca listę znanych typów

public static class KnownTypeHelper 
{ 
    public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider) 
    { 
     List<Type> result = new List<Type>(); 

     ServiceKnownTypesSection serviceKnownTypes = (ServiceKnownTypesSection)ConfigurationManager.GetSection("serviceKnownTypes"); 
     DeclaredServiceElement service = serviceKnownTypes.Services[((Type)(provider)).AssemblyQualifiedName]; 

     foreach (ServiceKnownTypeElement knownType in service.KnownTypes) 
     { 
      result.Add(knownType.Type); 
     } 

     return result; 
    } 
} 

informacji na temat tworzenia niestandardowych config sekcje można znaleźć tutaj:

http://msdn.microsoft.com/en-us/library/2tw134k3.aspx

http://msdn.microsoft.com/en-us/library/system.configuration.configurationcollectionattribute.aspx

2

Nie jestem pewien, czy to jest zgodne z projektem, ale KnownTypeHelper poniżej nie wygeneruje błąd, jeśli nie zostały uznane za umowę o świadczenie usług ze znanymi typami. (tj. opcjonalne dodawanie znanych typów do umów o świadczenie usług).

using System; 
using System.Collections.Generic; 
using System.Configuration; 
using System.Reflection; 

/// <summary> 
/// Helper for finding the known types for Wcf Services from a configuration file. 
/// </summary> 
public static class KnownTypeHelper 
{ 
    /// <summary> 
    /// Gets the known types for the service from a configuration file. 
    /// </summary> 
    /// <param name="provider"> 
    /// The provider. 
    /// </param> 
    /// <returns> 
    /// The known types for the service from a configuration file. 
    /// </returns> 
    public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider) 
    { 
     var result = new List<Type>(); 

     var serviceKnownTypes = (ServiceKnownTypesSection)ConfigurationManager.GetSection("serviceKnownTypes"); 
     if (serviceKnownTypes != null) 
     { 
      var service = serviceKnownTypes.Services[((Type)provider).AssemblyQualifiedName]; 

      if (service != null) 
      { 
       foreach (ServiceKnownTypeElement knownType in service.KnownTypes) 
       { 
        result.Add(knownType.Type); 
       } 
      } 
     } 

     return result; 
    } 
} 

Aby zapisać ktoś inny problem tworzenia klas konfiguracyjnych

Uwaga: Nie ma walidację kwalifikowanych nazw typów montażu. Jeśli ktoś chce dodać do tego odpowiednie atrybuty, zrób to.

using System.Configuration; 

/// <summary> 
/// Section for configuration known types for services. 
/// </summary> 
public class ServiceKnownTypesSection : ConfigurationSection 
{ 
    /// <summary> 
    /// Gets services. 
    /// </summary> 
    [ConfigurationProperty("declaredServices", IsDefaultCollection = false)] 
    [ConfigurationCollection(typeof(DeclaredServiceElement), AddItemName = "serviceContract", CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)] 
    public DeclaredServiceElementCollection Services 
    { 
     get 
     { 
      return (DeclaredServiceElementCollection)base["declaredServices"]; 
     } 
    } 
} 

/// <summary> 
/// Collection of declared service elements. 
/// </summary> 
public class DeclaredServiceElementCollection : ConfigurationElementCollection 
{ 
    /// <summary> 
    /// Gets the service for which known types have been declared for. 
    /// </summary> 
    /// <param name="key"> 
    /// The key of the service. 
    /// </param> 
    public new DeclaredServiceElement this[string key] 
    { 
     get 
     { 
      return (DeclaredServiceElement)BaseGet(key); 
     } 

     set 
     { 
      var element = BaseGet(key); 
      var index = this.BaseIndexOf(element); 
      if (BaseGet(index) != null) 
      { 
       BaseRemoveAt(index); 
      } 

      BaseAdd(index, value); 
     } 
    } 

    /// <summary> 
    /// When overridden in a derived class, creates a new <see cref="T:System.Configuration.ConfigurationElement"/>. 
    /// </summary> 
    /// <returns> 
    /// A new <see cref="T:System.Configuration.ConfigurationElement"/>. 
    /// </returns> 
    protected override ConfigurationElement CreateNewElement() 
    { 
     return new DeclaredServiceElement(); 
    } 

    /// <summary> 
    /// Gets the element key for a specified configuration element when overridden in a derived class. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Object"/> that acts as the key for the specified <see cref="T:System.Configuration.ConfigurationElement"/>. 
    /// </returns> 
    /// <param name="element"> 
    /// The <see cref="T:System.Configuration.ConfigurationElement"/> to return the key for. 
    /// </param> 
    protected override object GetElementKey(ConfigurationElement element) 
    { 
     return ((DeclaredServiceElement)element).Type; 
    } 
} 

/// <summary> 
/// The service for which known types are being declared for. 
/// </summary> 
public class DeclaredServiceElement : ConfigurationElement 
{ 
    /// <summary> 
    /// Gets or sets Type. 
    /// </summary> 
    [ConfigurationProperty("type", IsRequired = true, IsKey = true)] 
    public string Type 
    { 
     get 
     { 
      return (string) this["type"]; 
     } 

     set 
     { 
      this["type"] = value; 
     } 
    } 

    /// <summary> 
    /// Gets KnownTypes. 
    /// </summary> 
    [ConfigurationProperty("knownTypes", IsDefaultCollection = false)] 
    [ConfigurationCollection(typeof(DeclaredServiceElement), AddItemName = "knownType", CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)] 
    public ServiceKnownTypeElementCollection KnownTypes 
    { 
     get 
     { 
      return (ServiceKnownTypeElementCollection)base["knownTypes"]; 
     } 
    } 
} 

/// <summary> 
/// A collection of known type elements. 
/// </summary> 
public class ServiceKnownTypeElementCollection : ConfigurationElementCollection 
{ 
    /// <summary> 
    /// Gets an known type with the specified key. 
    /// </summary> 
    /// <param name="key"> 
    /// The key of the known type. 
    /// </param> 
    public new ServiceKnownTypeElement this[string key] 
    { 
     get 
     { 
      return (ServiceKnownTypeElement)BaseGet(key); 
     } 

     set 
     { 
      var element = BaseGet(key); 
      var index = this.BaseIndexOf(element); 
      if (BaseGet(index) != null) 
      { 
       BaseRemoveAt(index); 
      } 

      BaseAdd(index, value); 
     } 
    } 

    /// <summary> 
    /// When overridden in a derived class, creates a new <see cref="T:System.Configuration.ConfigurationElement"/>. 
    /// </summary> 
    /// <returns> 
    /// A new <see cref="T:System.Configuration.ConfigurationElement"/>. 
    /// </returns> 
    protected override ConfigurationElement CreateNewElement() 
    { 
     return new ServiceKnownTypeElement(); 
    } 

    /// <summary> 
    /// Gets the element key for a specified configuration element when overridden in a derived class. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Object"/> that acts as the key for the specified <see cref="T:System.Configuration.ConfigurationElement"/>. 
    /// </returns> 
    /// <param name="element"> 
    /// The <see cref="T:System.Configuration.ConfigurationElement"/> to return the key for. 
    /// </param> 
    protected override object GetElementKey(ConfigurationElement element) 
    { 
     return ((ServiceKnownTypeElement)element).Type; 
    } 
} 

/// <summary> 
/// Configuration element for a known type to associate with a service. 
/// </summary> 
public class ServiceKnownTypeElement : ConfigurationElement 
{ 
    /// <summary> 
    /// Gets or sets TypeString. 
    /// </summary> 
    [ConfigurationProperty("type", IsRequired = true, IsKey = true)] 
    public string TypeString 
    { 
     get 
     { 
      return (string)this["type"]; 
     } 

     set 
     { 
      this["type"] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets Type. 
    /// </summary> 
    public Type Type 
    { 
     get 
     { 
      return Type.GetType(this.TypeString); 
     } 

     set 
     { 
      this["type"] = value.AssemblyQualifiedName; 
     } 
    } 
}