views:

468

answers:

3

I need to return a complex type from a webservice and had constructed the class MyComplexType which implements the interface IMyComplexType. Now in my webservice I have a method that should return an object that implements IMyComplexType like so:

[WebMethod]
public IMyComplexType GetMyComplexType()
{
   IMyComplexType myCt = new MyComplexType();
   ...
   return myCt; 
}

Everything compiles ok but when I run the webservice it throws an exception as follows:

System.NotSupportedException: Cannot serialize interface MyWebService.IMyComplexType.

Is this by design or am I missing something. Can I decorate my class or interface somehow to allow this? Do I have to eliminate all interfaces and only work with concrete and perhaps abstract base-classes to be able to do this with .net webservices?

Edit:

this is the interface I am trying to serialize:

public interface ICustomer
{
     long Id {get; set;}
     string Name {get; set;}
     string EmailAddress {get; set;}
}
A: 

It's been a while, but I believe you need only make your interfaces extend ISerializable and all should be good.

Allain Lalonde
This in turns requires me to implement the ISerializable interface in all my classes -- whereas I was hoping to be able to serialize without having to do that. I just need the public properties. Eliminating the interfaces and just using the concrete classes works fine but is that a best-practice??
Fadeproof
+1  A: 

You don't need to implement ISerializable - simply marking the interface with the Serializable attribute should be all you need to do. If you want to implement the interface, by all means go ahead - it will give you fine-grained control over how the interface is serialized. But I would imagine that the default implementation should be ok. Also check to make sure that all the interface members are serializable as well.

[Edit] I wasn't even thinking straight - there is no way that you will be able to implement ISerializable as you are trying to serialize an iterface anyway. The place where ISerializable would be appropriate would be on custom types that need custom serialization that are exposed by the interface.

Andrew Hare
Can't put Serializable attribute on interfaces - only on classes, enums etc. I gave that a try but no luck. Anything else you suggest?I don't have any custom serialization needs. I am just trying to expose things properly - through interfaces and not concrete types. Is that impossible with .net ws?
Fadeproof
it sounds like one of the types in your interface is not serializable - can you edit your post and add the code for the interface?
Andrew Hare
Ok. Added the interface. Is there a way to do this without implementing ISerializable as I just want this to be serialized as-is and no custom needs?
Fadeproof
+1  A: 

Short answer is no, you can't return an interface through a WebService.

Long answer is that you can kind of get the behaviour you want, but it's a bit hacky. The solution is to use binary serialization. So you serialize your type to bytes, have the web method return a series of bytes and then on the other side you would deserialize the bytes back to your complex type.

For example

[WebMethod]
public byte[] GetMyComplexType()
{

   IMyComplexType myCt = new MyComplexType();
   ...

   MemoryStream stream = new MemoryStream();
   IFormatter fmt = new BinaryFormatter();
   fmt.Serialize(stream, myCt);
   stream.Flush();
   byte[] bytes = stream.ToArray();
   stream.Close();

   return bytes;
}

You'll need to convert everything back at the other end.

byte[] bytes = service.GetMyComplexType();
MemoryStream stream = new MemoryStream(bytes);
BinaryFormatter fmt = new BinaryFomatter();
MyComplexType myCt = fmt.DeSerialize(stream);

You can probably clean the deserialization up by creating a generic method. I should add, that you'll need to make sure you can reference the complex type on the client.

Alternatively, if they are your interfaces then you could turn them into Abstract Classes. However, this won't work if you want the class to implement multiple interfaces (or you already inherit from another class) as you can only inherit one class. If you need some polymorphic behaviour on the client, you'll need to use the XmlInclude attribute.

Martin Clarke