2010-06-30 14 views
8

Sto cercando di specificare un tipo noto nella mia configurazione, ma sto riscontrando problemi con il fatto che derivi da Object. Posso farlo funzionare specificando il tipo noto tramite l'attributo. Ma in questo caso ho bisogno di farlo funzionare dalla configurazione.WCF di tipo noto da System.Object in Config

Ecco un esempio. Le seguenti opere di bene:

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

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

Ma se rimuovere l'attributo ServiceKnownType e mettere quanto segue nella configurazione:

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

ottengo un ConfigurationErrorsException con il messaggio "Il valore per il 'tipo' di proprietà non è valido. L'errore è: il tipo System.Object non può essere utilizzato come un tipo dichiarato in config. "

Esiste comunque la possibilità di farlo funzionare via config?

risposta

9

La risposta risulta essere che non è possibile eseguire ciò che voglio fare nel solo file di configurazione. La configurazione sopra corrisponde all'attributo [KnownType] utilizzato su DataContracts. Sembra che non ci sia modo di implementare [ServiceKnownType] nella configurazione.

Un approccio alternativo consiste nell'utilizzare l'attributo [ServiceKnownType (methodName, type)] con una sezione di configurazione personalizzata. La nuova configurazione appare così:

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

I contratti:

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

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

La classe di supporto che contiene il callback che restituisce l'elenco dei tipi conosciuti

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

informazioni sulla creazione di configurazione personalizzato le sezioni possono essere trovate qui:

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

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

2

io non sono sicuro se è in base alla progettazione, ma il KnownTypeHelper seguito non genera un errore se non hai dichiarato un contratto di servizio con i tipi noti. (ad esempio, è facoltativo aggiungere tipi noti ai contratti di servizio).

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

Per salvare qualcun altro la briga di creare le classi di configurazione,

Nota: Non v'è alcuna convalida dei nomi dei tipi di montaggio qualificati. Se qualcuno vuole aggiungere gli attributi appropriati per farlo, per favore fallo.

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