我正在尝试在我的配置中指定已知类型,但是我对它从对象派生的事实存在问题。我可以使它起作用,通过属性指定已知类型。但是在这种情况下,我需要使其从配置工作。

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

[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不能用作配置中的声明类型。”

无论如何,是否有通过配置进行这项工作?

有帮助吗?

解决方案

答案证明是不可能单独在配置文件中做我想做的事情。上面的配置对应于数据合同上使用的[newtype]属性。似乎没有办法在配置中实现[ServiceNonningType]。

另一种方法是使用自定义配置部分使用[ServiceNonningType(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

其他提示

我不确定是否是设计,但是如果您没有声明已知类型的服务合同,则下面的知名人士不会丢失错误。 (即它的可选为服务合同添加已知类型)。

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;
        }
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top