WCF: Is serialization of common interfaces possible?

I am trying to fulfill a service contract that contains a method that accepts a common interface, and the common interface itself receives an interface parameter. I decorated the ServiceKnownType service interface, I decorated the service implementation with the usual KnownType, and I decorated the datacontract implementation with the usual KnownType:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))] [ServiceKnownType(typeof(Batch<object>))] [ServiceKnownType(typeof(Command))] public interface IActions { [OperationContract] IResponse TakeAction(IBatch<ICommand> commands); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)] [KnownType(typeof(Batch<object>))] [KnownType(typeof(Command))] internal class Actions : IActions { } [DataContract] [KnownType(typeof(Command))] public class Batch<T> : IBatch<T> { } 

For the record, I have Batch, because it seems that you can only specify a known type for a universal type only once - it seems to emit a BatchOfanyType, but I'm not sure how to handle it.

The exception I get is "Add any types that are not statically known to the list of known types, for example, using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the DataContractSerializer."

Is there something obvious I'm doing wrong? Are common interface interfaces simply unsupported? For the record, I am in C # 2.0 and .NET 3.0 for this project.

+6
generics c # serialization wcf
source share
4 answers

You can use interfaces in service contract definitions, if you really want to, as long as you include known types as you do (with a little tweaking, see below).

Apparently, using an interface as a type parameter makes it too big for C # 3.0. I changed the known type attribute to

 [ServiceKnownType(typeof(Batch<Command>))] public interface IActions { } 

It makes it work. Serialization and deserialization will work, but then you came across this exception:

It is not possible to pass an object of type 'Batch`1 [Command]' to enter "IBatch`1 [ICommand]".

For this to work, you need language support for the general type of covariance that was introduced in C # 4.0. For it to work in C # 4.0, however, you need to add a dispersion modifier:

 public interface IBatch<out T> { } 

Then it works fine ... unfortunately you are not using C # 4.0.

The last thing about using interfaces in your service contract: if you create a service link from them, it will enter all the interface parameters as object , because the original type of interface is not part of the metadata. You can share the contracts using the assembly link or manually reorganize the generated proxy server to fix it, but overall, using WCF interfaces is probably more of a problem than it costs.

+12
source share

WCF is a system based on SOA messages β€” it can send anything through a wire in a serial XML format, which can be expressed in an XML schema.

Unfortunately, the XML schema knows nothing about interfaces or generics, so no - you cannot generalize them in general terms - you need to use specific types.

+2
source share

You cannot serialize an interface. The interface simply defines the contract, not the object. I assume the only exception is the ISerializable interface.

+1
source share

Generics can be serialized, but with certain limitations. For example, given a data contract:

 [DataContract] public class Foo<T> { [DataMember] public T Value { get; set; } } 

And a service contract:

 [ServiceContract] public interface IService1 { [OperationContract] Foo<String> GetData(); } 

And the implementation of the service:

 public class Service1 : IService1 { public Foo<string> GetData() { return new Foo<string>() { Value = "My test string" }; } } 

After installing the service link to the above service, this code can be run:

 ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); ServiceReference1.FooOfstring temp = client.GetData(); MessageBox.Show(temp.Value); 

A window will appear with the message "My test string."

Please note that the service itself is not general, but a data contract is used. In addition, the data contract generated on the client side is not a general, but rather a β€œflattened” class that has the value of a row property of the type:

 [System.Runtime.Serialization.DataMemberAttribute()] public string Value { get {...} set {...} } 
+1
source share

All Articles