代码之家  ›  专栏  ›  技术社区  ›  Scott J

配置中System.Object的WCF已知类型

  •  8
  • Scott J  · 技术社区  · 14 年前

    我试图在我的配置中指定一个已知的类型,但它是从Object派生的,这一点我遇到了问题。我可以通过属性指定已知类型。但在这种情况下,我需要使它从配置工作。

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

    [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,消息是“属性'type'的值无效。错误为:类型System.Object不能用作配置中声明的类型。“

    是否有任何方法可以通过配置来实现这一点?

    2 回复  |  直到 12 年前
        1
  •  9
  •   Scott J    14 年前

    答案是不可能单独在配置文件中做我想做的事情。上面的配置对应于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; }
    }
    

    包含返回已知类型列表的回调的helper类

    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
  •  2
  •   user543103    14 年前

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