2010-06-30 20 views
8

我想在我的配置中指定一個已知的類型,但我遇到了它從Object派生的事實的問題。我可以使它通過屬性指定已知的類型。但在這種情況下,我需要使它從配置工作。從配置中的System.Object的WCF已知類型

下面是一個例子。以下工作正常:

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

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

但如果我刪除ServiceKnownType屬性,把下面的配置:

<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> 

我得到消息「的屬性‘類型’的值ConfigurationErrorsException錯誤是:類型System.Object不能用作配置中的聲明類型。「

有無論如何通過配置使這項工作?

回答

9

答案原來是不可能的,我只想在配置文件中做我想做的事情。上面的配置對應於DataContracts上使用的[KnownType]屬性。似乎沒有辦法在配置中實現[ServiceKnownType]。

另一種方法是在自定義配置節中使用[ServiceKnownType(methodName,type)]屬性。新的配置是這樣的:

<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> 

的合同:

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

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

包含返回上創建自定義配置已知類型

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; 
    } 
} 

信息列表回調的輔助類部分可以在這裏找到:

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

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

2

我不知道,如果它是由設計,但下面KnownTypeHelper如果你沒有聲明具有已知類型的服務合同將不會引發錯誤。 (即可選擇將已知類型添加到服務合同中)。

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; 
    } 
} 

爲了節省別人創建配置類的麻煩,

注:沒有裝配合格的類型名稱的驗證。如果有人想添加適當的屬性來做到這一點,請做。

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; 
     } 
    } 
}