WCF Известный тип из System.Object в конфиге
-
01-10-2019 - |
Вопрос
Я пытаюсь указать известный тип в моем конфиге, но у меня проблемы с тем, что оно происходит от объекта. Я могу заставить его работать, указывая известный тип через атрибут. Но в этом случае мне нужно сделать его работать с конфига.
Вот пример. Следующие работает нормально:
[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 с сообщением «Значение для типа свойства» недействительно. Ошибка: система типа .Object нельзя использовать в качестве объявленного типа в конфигуре. "
Есть ли в любом случае, чтобы сделать эту работу по конфигурации?
Решение
Ответ оказывается, что невозможно делать то, что я хочу сделать в одном файле конфигурации. Вышеуказанное config соответствует атрибуту [sevedtype], используемым на datacontracts. Похоже, что нет способа реализовать [Serviceknowntype] на конфиге.
Альтернативный подход состоит в том, чтобы использовать атрибут [Serviceknowntype (MedistName, 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;
}
}
Информация о создании пользовательских секций Config Config можно найти здесь:
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;
}
}
}