How to use inherited classes in web method?

I have two classes as below:
public class BaseClass 

  public BaseClass()  {  } 

  public BaseClass(string name)
  {
   this._name = name;
  }

  private string _name = "BaseClass";
  public string Name
  {
   get
   {
     return _name;
   }
   set
   {
     _name = value;
   }
  }
   
}

public class InheritedClass : BaseClass
{
  public InheritedClass(string name)
   : base(name)
  {
  }
}

then i write a webmethod to use the classes.
public class MyServices : WebService
{
[WebMethod]
public BaseClass HelloWorld()
{
  return new InheritedClass("FirstClass");
}
}
now I get an error:
System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type InheritedClass was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
 at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write2_BaseClass(String n, String ns, BaseClass o, Boolean isNullable, Boolean needType)
 at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_BaseClass(Object o)
 at Microsoft.Xml.Serialization.GeneratedAssembly.BaseClassSerializer.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
 at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
 --- End of inner exception stack trace ---
 at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
 at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o)
 at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
 at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
 at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
 at System.Web.Services.Protocols.WebServiceHandler.Invoke()

I know I can solve the problem by adding this line before the MyServices
[XmlInclude(typeof(InheritedClass))]

But I can't confirm how many "inherited classes" there are in my code, so it seems not fit for me.

Could you show me another way Thank you.





Answer this question

How to use inherited classes in web method?

  • Stevehat

    I'm running into a similar problem to the one posted orginally. The difference is that I'm using an inherited type on the client side. For instance the web service I'm using exposes a user type. I've inherited from this type on the client side to additional methods to it. The web service has web methods which take this base user class as an argument. I can cast down to User fine, but the problem pops up when I try and pass my downcasted user to the webmethod as an argument. When I do that I get the following at runtime:

    The type UserProxy was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

    The UserProxy class is the class I'm using on the client side which is inheriting from the base user class exposed in the API. I've written the following code to see if I could figure out what is going on:

    baseUser = new User();
    baseUser = (API.User)this;
    Type test = baseUser.GetType();

    What is odd is that when I first instantiate the baseUser its type is API.User however after I downcast the userproxy and assign it to that variable the type of baseUser changes to UserProxy which, I think, is what is causing the error I'm seeing. Has anyone run into this or can anyone suggest a fix

    Thanks,

    - Matt

  • CzechMate

    if I use XmlInclude Attribute, I should know all the inherited types and add them here during disign time. When I generate a new inherited type, I also should come back to the web services and modify the include list. It's not convient and not a good design I think.

  • Al Hancq

    Web Service will always have the type info in the metadata associated with the live assembly in production there, either ngen cached or jit compiled.
    Now the client is referencing this through the proxy reference it has, which in turn uses the WSDl supplied info. So the point here is that if u can change teh web service, u can support this at server side of the service, with automatic discovery of the inherited classes base parent chain and then traversing a stipulated depth.

    Do i make sense


  • dmkelly10

    I worked on it a bit..and found that there is no other way..if we are passing non static information from a web service we need to use XMLInclude/SOAPInclude in webmethod or for the entire web service..

    I can't exactly get why you can't have inherited classes information..

    Cheers


  • atif ahmed

    I believe the reason is this: The way XML serialization works is that we generate serialization code on the fly - that is, we actually construct serialization/deserialization code in C# behind the scenes, compile it into a serialization assembly, and use it to serialize/deserialize types. All this generation/compilation happens on the first call to the web service. After the first call, we do not regenerate this code. Thus, if we cannot allow the passing of arbitrarty derived types on every call, since the serialization code for them simply hasn't been generated. [XmlInclude] lets us know which types serialization code should be generated for.
    I may be wrong about the reason (haven't looked into it too deeply), but the fact that you should use XmlInclude is correct.


  • Tom_HDi

    Thanks for your advice.

    But i still get the error as before. If I use the code.
    [WebMethod(EnableSession=true)]
    [XmlInclude(typeof(BaseClass))]
    public BaseClass HelloWorld()
    {
      return new InheritedClass("FirstClass");
    }
    }


    And if use
    [WebMethod(EnableSession=true)]
    [XmlInclude(typeof(InheritedClass))]
    public BaseClass HelloWorld()
    {
      return new InheritedClass("FirstClass");
    }
    }

    it works fine.but it doesn't fit for me as I said before.

  • Sandyee

    To derive your class from base u need to use WebServiceBinding and point to your class


    [SoapRpcService]
    [WebServiceBinding("binding name", "namespace", "wsdl location")]

    public class MyServices : WebService

       [WebMethod] 
        [SoapRpcMethod("binding name")]
        public BaseClass HelloWorld()
        { 
             return new InheritedClass("FirstClass"); 
        }
    }

     



  • OneStrayCat

    You'll live a longer and happier life if you understand that Web Services isn't about types, inherited or otherwise; it's about XML, described by XML schema referenced by a WSDL. So, as the old joke says, "don't do that".



  • Fabricio11

    If you add a new inherited types and wants to return it through one of your webmethod in webservice..you will add the code for it in web service..any how you would be modifying your web service. At that time you have to modify the include list as well for the newly created type.
  • Spardeous

    Hi,
     try

    [WebMethod(EnableSession=true)]
    [XmlInclude(typeof(BaseClass))]
    public BaseClass HelloWorld()
    {
      return new InheritedClass("FirstClass");
    }
    }

    The XmlInclude, will return the xml for the class type...

    regards,
    abhi



  • rwin

    Hi,
    I had the same problem. (I got "...Use the XmlInclude or SoapInclude attribute to specify types that are not known statically" exception). After I implemented IXmlSerializable in the base class, everything worked fine.
    There are some drawbacks, but it could help you..
    Pepa


  • How to use inherited classes in web method?