Dre*_*kes 52 .net wcf wcf-configuration known-types
我的客户端/服务器应用程序正在使用WCF进行通信,这非常棒.然而,当前架构的一个缺点是我必须对某些传输类型使用已知类型配置.我正在使用内部的Pub/Sub机制,这个要求是不可避免的.
问题是很容易忘记添加已知类型,如果你这样做,WCF会无声地失败,只有很少的线索可以解决出错的问题.
在我的应用程序中,我知道将要发送的类型集.我想以编程方式执行配置,而不是声明性地通过App.config当前包含这样的内容的文件:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyProject.MyParent, MyProjectAssembly">
<knownType type="MyProject.MyChild1, MyProjectAssembly"/>
<knownType type="MyProject.MyChild2, MyProjectAssembly"/>
<knownType type="MyProject.MyChild3, MyProjectAssembly"/>
<knownType type="MyProject.MyChild4, MyProjectAssembly"/>
<knownType type="MyProject.MyChild5, MyProjectAssembly"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Run Code Online (Sandbox Code Playgroud)
相反,我想做这样的事情:
foreach (Type type in _transmittedTypes)
{
// How would I write this method?
AddKnownType(typeof(MyParent), type);
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释一下我怎么做这个吗?
编辑请理解我正在尝试在运行时动态设置已知类型,而不是在配置中使用声明或使用源代码中的属性.
这基本上是关于WCF API的问题,而不是样式问题.
编辑2 此MSDN页面指出:
您还可以向ReadOnlyCollection添加类型,通过DataContractSerializer的KnownTypes属性访问.
不幸的是,只要KnownTypes是一个只读属性,并且属性的值是a,它就会说并且它没有多大意义ReadOnlyCollection.
Mik*_*tts 69
添加[ServiceKnownType]到您的[ServiceContract]界面:
[ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]
Run Code Online (Sandbox Code Playgroud)
然后创建一个名为的类KnownTypesProvider:
internal static class KnownTypesProvider
{
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
// collect and pass back the list of known types
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以传回你需要的任何类型.
Ser*_*kov 17
还有2种方法可以解决您的问题:
I.使用KnownTypeAttribute(string):
[DataContract]
[KnownType("GetKnownTypes")]
public abstract class MyParent
{
static IEnumerable<Type> GetKnownTypes()
{
return new Type[] { typeof(MyChild1), typeof(MyChild2), typeof(MyChild3) };
}
}
Run Code Online (Sandbox Code Playgroud)
II.使用构造函数DataContractSerializer
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class |
AttributeTargets.Interface)]
public class MyHierarchyKnownTypeAttribute : Attribute, IOperationBehavior, IServiceBehavior, IContractBehavior
{
private void IOperationBehavior.AddBindingParameters(
OperationDescription description,
BindingParameterCollection parameters)
{
}
void IOperationBehavior.ApplyClientBehavior(
OperationDescription description,
ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
private void IOperationBehavior.ApplyDispatchBehavior(
OperationDescription description,
DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
private void IOperationBehavior.Validate(OperationDescription description)
{
}
private void IServiceBehavior.AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
ReplaceDataContractSerializerOperationBehavior(serviceDescription);
}
private void IServiceBehavior.ApplyDispatchBehavior(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
ReplaceDataContractSerializerOperationBehavior(serviceDescription);
}
private void IServiceBehavior.Validate(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
}
private void IContractBehavior.AddBindingParameters(
ContractDescription contractDescription,
ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{
}
private void IContractBehavior.ApplyClientBehavior(
ContractDescription contractDescription,
ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
ReplaceDataContractSerializerOperationBehavior(contractDescription);
}
private void IContractBehavior.ApplyDispatchBehavior(
ContractDescription contractDescription,
ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
ReplaceDataContractSerializerOperationBehavior(contractDescription);
}
private void IContractBehavior.Validate(ContractDescription contractDescription,
ServiceEndpoint endpoint)
{
}
private static void ReplaceDataContractSerializerOperationBehavior(
ServiceDescription description)
{
foreach (var endpoint in description.Endpoints)
{
ReplaceDataContractSerializerOperationBehavior(endpoint);
}
}
private static void ReplaceDataContractSerializerOperationBehavior(
ContractDescription description)
{
foreach (var operation in description.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
private static void ReplaceDataContractSerializerOperationBehavior(
ServiceEndpoint endpoint)
{
// ignore mex
if (endpoint.Contract.ContractType == typeof(IMetadataExchange))
{
return;
}
ReplaceDataContractSerializerOperationBehavior(endpoint.Contract);
}
private static void ReplaceDataContractSerializerOperationBehavior(
OperationDescription description)
{
var behavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (behavior != null)
{
description.Behaviors.Remove(behavior);
description.Behaviors.Add(
new ShapeDataContractSerializerOperationBehavior(description));
}
}
public class ShapeDataContractSerializerOperationBehavior
: DataContractSerializerOperationBehavior
{
public ShapeDataContractSerializerOperationBehavior(
OperationDescription description)
: base(description) { }
public override XmlObjectSerializer CreateSerializer(Type type,
string name, string ns, IList<Type> knownTypes)
{
var shapeKnownTypes =
new List<Type> { typeof(Circle), typeof(Square) };
return new DataContractSerializer(type, name, ns, shapeKnownTypes);
}
public override XmlObjectSerializer CreateSerializer(Type type,
XmlDictionaryString name, XmlDictionaryString ns,
IList<Type> knownTypes)
{
//All magic here!
var knownTypes =
new List<Type> { typeof(MyChild1), typeof(MyChild2), typeof(MyChild3) };
return new DataContractSerializer(type, name, ns, knownTypes);
}
}
}
[ServiceContract()]
[MyHierarchyKnownTypeAttribute]
public interface IService {...}
Run Code Online (Sandbox Code Playgroud)
注意:您必须在双方使用此属性:客户端和服务端!
小智 13
我需要这样做才能让继承正常工作.我不想要维护派生类型列表.
[KnownType("GetKnownTypes")]
public abstract class BaseOperationResponse
{
public static Type[] GetKnownTypes()
{
Type thisType = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;
return thisType.Assembly.GetTypes().Where(t => t.IsSubclassOf(thisType)).ToArray();
}
Run Code Online (Sandbox Code Playgroud)
我知道函数的第一行是矫枉过正,但它只是意味着我可以将其粘贴到任何基类中而无需修改.