【问题标题】:WCF Known Type from System.Object in Config来自配置中 System.Object 的 WCF 已知类型
【发布时间】:2010-06-30 16:19:13
【问题描述】:

我正在尝试在我的配置中指定一个已知类型,但我遇到了它派生自 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 消息“属性‘类型’的值无效。错误是:类型 System.Object 不能用作配置中的声明类型。”

有没有办法通过配置来完成这项工作?

【问题讨论】:

    标签: c# .net wcf wcf-configuration known-types


    【解决方案1】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-21
        相关资源
        最近更新 更多