views:

1687

answers:

3

I have an interface like so:

public interface IDocument : ISerializable
{
    Boolean HasBeenUploaded { get; set; }
    void ISerializable.GetObjectData(SerializationInfo, StreamingContext) { }
}

There are three documents that inherit from this, all of which serialize just fine. But when creating a simple web service, that does nothing, where they can be uploaded to...

public class DCService : System.Web.Services.WebService
{
    [WebMethod]
    public Boolean ReceiveDocument(IDocument document)
    {
        DBIO io = new DBIO();

        return io.InsertIntoDB(document); // does nothing; just returns true
    }
}

I get this when trying to run it: "Cannot serialize interface IDocument"

I'm not quite sure why this would be a problem. I know that some people have had trouble because they didn't want to force subclasses to implement custom serialization but I do, and up to this point it has been successful.

edit> If I create individual webmethods that accept the objects that implement the interface, it works fine, but that weakens the contract between the client/server (and undermines the purpose of having the interface in the first place)

+3  A: 

You may need to use an XmlInclude attribute to your web method. A example can be found here. We have run into this issue before and have added XmlInclude attributes to both our web service proxy class on the client and to certain web service methods.

[WebMethod]
[XmlInclude(typeof(MyDocument))]
public Boolean ReceiveDocument(IDocument document)
{
    DBIO io = new DBIO();

    return io.InsertIntoDB(document); // does nothing; just returns true
}
firedfly
can I have multiple includes like [XmlInclude(typeof(DocType1))] [XmlInclude(typeod(DocType2))] - I'm going to try anyway, but for the next reader...
SnOrfus
Unfortunately, this appears to only work with base types, not interfaces :(
SnOrfus
@SnOrfus - You can have multiple XmlInclude attributes. I was not aware that interfaces would not work with XmlInclude. We've never tried that ourselves.
firedfly
@SnOrfus do you mean the included types to be interfaces? as I said in my answer, you have to point to concrete classes at some point, otherwise asp.net won't be able to tell which one to use
eglasius
+1  A: 

Asp.net must need to be able to tell which specific class it will instantiate when calling that method. This is why it works when defining multiple methods with the specific classes i.e. the call will tell you which class to use.

Consider whether you want the client to send the same set of info for any document, or if you really need to be able to send different info for different documents. With the later, you need the client to know the classes that implement the IDocument, and you do this with the XmlInclude (as firedfly posted).

If you instead want to always send the same info and not now about the specific classes, define a class with that info and that is what you receive in the methods. If you do need to play with IDocument in the rest of the service code, have appropiate logic in the service that gets you an IDocument instance using the data received.

eglasius
+1  A: 

+1 for firedfly, however it should be noted that the XmlInclude attribute may be appended to the web service class rather than to each and every method (or base type, which is also an option). I have tested it and the code is generated well, keeping the inheritance structure.

I got this from the comments section of the same blog he referred to, so credit goes to the OP.

BTW this isn't a comment to firedfly's post because I don't have enough reputation to comment

ohadsc