Question

Je suis en train de spécifier un type connu dans ma config, mais je vais avoir des problèmes avec le fait qu'il dérive de l'objet. Je peux le faire fonctionner en spécifiant le type connu via l'attribut. Mais dans ce cas, je dois faire fonctionner à partir de la configuration.

Voici un exemple. Les travaux suivants fin:

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

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

Mais si je supprime l'attribut ServiceKnownType et mettre ce qui suit dans la 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>

Je reçois ConfigurationErrorsException avec le message « La valeur de la propriété « type » est pas valide L'erreur est:.. Le System.Object type ne peut pas être utilisé comme un type déclaré dans la configuration »

Y at-il de toute façon de faire ce travail via config?

Était-ce utile?

La solution

La réponse se révèle être il est impossible de faire ce que je veux faire dans le fichier de configuration seul. La configuration ci-dessus correspond à l'attribut [KnownType] utilisé sur DataContracts. Il semble y avoir aucun moyen de mettre en œuvre [ServiceKnownType] dans la configuration.

Une autre approche consiste à utiliser [ServiceKnownType (methodName, type)] attribut avec une section de configuration personnalisée. La nouvelle ressemble à cette config:

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

Les contrats:

[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 d'aide qui contient le rappel qui renvoie la liste des types connus

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

Informations sur la création de sections de configuration personnalisée peut être trouvée ici:

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

http://msdn.microsoft.com/en- nous / bibliothèque / system.configuration.configurationcollectionattribute.aspx

Autres conseils

Je ne suis pas sûr que ce soit par la conception, mais le KnownTypeHelper ci-dessous ne lancera pas d'erreur si vous ne l'avez pas déclaré un contrat de service avec des types connus. (À savoir son option pour ajouter des types connus de contrats de services).

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

Pour sauver quelqu'un d'autre la peine de créer des classes de configuration,

Note: Il n'y a pas de validation des noms de type assemblage qualifiés. Si quelqu'un veut ajouter des attributs à approprié au niveau cela, s'il vous plaît faire.

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;
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top