views:

693

answers:

3

I have a bizarre problem that is doing my head in.

I have the following classes defined in a single project:

public abstract class AbstractUnitModel {

      public void executeRemoteModel(){}

}

//this class also implements a seperate interface, but I dont think that is the issue
public class BlastFurnaceUnitModel : AbstractUnitModel, IUnitModel {}

Now if I try something like this, it works as expected:

class Class1
{

    public void method1() {

        BlastFurnaceUnitModel b = new BlastFurnaceUnitModel();
        method2(b);
    }

    public void method2(AbstractUnitModel a) {}

 }

Now I have another project that exposes a web method. This method takes an AbstractUnitModel and executes it remotely, then sends the results back to the client. So on the server I have this:

 [WebMethod]
 public AbstractUnitModel remotelyExecuteUnitModel(UnitModelWrapperInterface.AbstractUnitModel unitModel)
        {

           unitModel.executeRemoteModel();
           return unitModel;

         }

And on the client I have this:

   public void remoteExecution() {

                var unitModelWebService = new UnitModelRemoteServer.RemoteModelExecutionWebService();
                unitModelWebService.remotelyExecuteUnitModelCompleted += new UnitModelRemoteServer.remotelyExecuteUnitModelCompletedEventHandler(remoteExecutionCompleted);
                unitModelWebService.remotelyExecuteUnitModelAsync(this.remoteBF);
            }

But my project will not compile, and I get these errors: Error 109 The best overloaded method match for 'CalibrationClient.UnitModelRemoteServer.RemoteModelExecutionWebService.remotelyExecuteUnitModelAsync(CalibrationClient.UnitModelRemoteServer.AbstractUnitModel)' has some invalid arguments

Error 110 Argument '1': cannot convert from 'UnitModelWrapperInterface.BlastFurnaceUnitModel' to 'CalibrationClient.UnitModelRemoteServer.AbstractUnitModel'

I can not figure out why this is happening. I have references in the server project to the namespace where AbstractUnitModel is defined. The only thing that looked a little funny to me is that it is using AbstractUnitModel from the 'CalibrationClient' namespace rather than the UnitModelWrapperInterface. It seems when VS generates the proxy for a webservice on the client it creates a partial abstract implementation of AbstractUnitModel. Is this the source of my problem? If so, how might I go about fixing it?

edit for solution: As pointed out, the client needs to know about all classes that could be sent across the wire. I ended up solving this by removing the generated proxy classes and referencing the common library. Not ideal but good enough in this situation.

A: 

You might try [XmlInclude]:

[XmlInclude(typeof(BlastFurnaceUnitModel))]
public abstract class AbstractUnitModel {...}

Worth a try, at least...

(edit) Or at the method level:

[WebMethod(), XmlInclude(typeof(BlastFurnaceUnitModel))]
public AbstractUnitModel remotelyExecuteUnitModel(...) {...}

(less sure about the second)

Marc Gravell
Thanks for your fast response Marc, but this does not seem to have any impact on my issue. I get the same compilation errors.
Alex
+1  A: 

This happens because the WSDL tool creates proxy classes (open the service code file and you'll see them) which are the classes used to instantiate when objects come from the service.

If you want to avoid this, it's best to use WCF. This also deals with the polymorphic returned objects, as webservices also can't deal with polymorphism (so the return type of the remotelyExecuteUnitModel method is always AbstractUnitModel.

Frans Bouma
Ok, I guess this is because the client has no way to determine the nature of the class it has been sent. Using WCF is not an option at this point. Is there a way I can make the derived classes be included in the proxy classes (its not elegant but at this stage I need things to work)? Or is that what Marc's code is supposed to do?
Alex
@Alex: Yes - adding XmlInclude is meant to cause the subclass to be generated in the proxy (client-side) code.
Marc Gravell
I ended up getting this working by removing the proxy class definition and referencing my common library in the reference.cs .
Alex
A: 

The class exposed in your WebService is created in a different namespace inside your service reference.

I usually create a method like

WebServiceReferenceNS.AbstractUnitModel ToWebServiceModel(AbstractUnitModel unitModel)
{
}

to prepare the classes for the WebService. But I'd like to see if there's a more elegant solution.

Filini