Reputation: 13
first, I hope I provide enough information to make things clear, if not please ask for more.
I have a working WCF communication using Duplex Channel and OneWay method calls. The ServiceHost is located inside a managed WPF application using NetPipeBinding, the client lives in a AppDomain inside that application. Everything is working as expected as long as all types are primitive (string, DateTime, ...) or specified as known type (List<object>
, List<string>
). But I need to send other types, for which I can´t add a known type attribute because I don´t know them at compile time.
As I read here (http://msdn.microsoft.com/library/ms731923(v=vs.100).aspx) all public types with public properties are supported, and so are types decorated with SerializableAttribute.
I tried to transfer a very simple class:
public class ADT
{
public string Name { get; set; }
}
and as a second try
[Serializable]
public class SerializableADT
{
public string Name { get; set; }
}
and as suggested by Herdo
[DataContract]
public class DataContractADT
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
}
but the deserialization fails for all three types.
There was an error while trying to serialize parameter _http://tempuri.org/:returnValue. The InnerException message was 'Type 'TestLibraries.SeriablizableADT' with data contract name 'SeriablizableADT:_http://schemas.datacontract.org/2004/07/TestLibraries' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
How can I marshal any type that meets the MSDN rules (e.g. decorated with Serializable) without any compile time changes?
Upvotes: 1
Views: 1247
Reputation: 22739
Warning: The NetDataContractSerializer
poses a significant security risk and should be avoided.
public class UseNetDataContractSerializerAttribute : Attribute, IOperationBehavior, IContractBehavior
{
void IOperationBehavior.ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}
void IOperationBehavior.Validate(OperationDescription description)
{
}
void IOperationBehavior.AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
var behavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (behavior != null)
{
description.Behaviors.Remove(behavior);
description.Behaviors.Add(new NetDataContractSerializerOperationBehavior(description));
}
}
void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
foreach (var operation in contractDescription.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
foreach (var operation in contractDescription.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
}
public class NetDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public NetDataContractSerializerOperationBehavior(OperationDescription operation)
: base(operation)
{
}
public NetDataContractSerializerOperationBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormatAttribute)
: base(operation, dataContractFormatAttribute)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new NetDataContractSerializer(name, ns);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new NetDataContractSerializer(name, ns);
}
}
Upvotes: 2
Reputation: 308
I also failed in using unknown types so I went the ugly path: for types unknown at compile time I serialize them manually and transfer the byte stream via WCF.
Edit: After looking into the DataContractResolver, it looks pretty much the same: http://msdn.microsoft.com/de-de/library/dd807504(v=vs.110).aspx
Upvotes: 0