2

I have the following structure:

public class DerivedClass : List<BaseClass>
{
   //Some helper methods used against the List of BaseClass properties

   //Methods
   public  List<BaseClass> GetListOfBaseClasses()
   {
       return (List<BaseClass>)this;
   }
}

My WCF service knows about the BaseClass object, but the client derived it as a generic list, now when I try to call the service, like this:

DerivedClass classD;
FillData(classD)
List<BaseClass> baseClassList = classD.GetListOfBaseClasses();

using (IService myService = ObjectFactory.GetMyService())
{
      myService.DoSomething(baseClassList); //Method is expecting "List<BaseClass>"
}

I get the following exception:

Type 'DerivedClass' with data contract name '[some URI text]' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

I tried adding these attributes to my class in various combinations but still no luck:

[Serializable]
[KnownType(typeof(List<BaseClass>))]
[XmlInclude(typeof(List<BaseClass>))]
[KnownType(typeof(BaseClass))]
[XmlInclude(typeof(BaseClass))]
public class DerivedClass : List<BaseClass>
{
  /// ...
}

PS- Sheehs, am I the only one that thinks the entry fields are funky on this site? Things keep moving around as I try to format... :| great site regardless of my inability to get the idea of entering text as I want.

Moe Howard
  • 498
  • 7
  • 12

2 Answers2

4

You have to a ServiceKnownTypeAttribute to your service interface:

[ServiceKnownType(typeof(DerivedClass))]
public interface IService
{
    // Service declaration
}
Mathias Becher
  • 703
  • 8
  • 20
  • 1
    not sure if that is the best approach as that will tighly couple client code to the service interface. The service just knows about List and don't think it should care how clients send that in. Say that another client wants to subclass DerivedClass, then the server needs to have another attribute added. don't think that is very good for software maintenance. All the derived class is to function as is a wrapper to the List so it could manipulate the list elements useing the generic List<> built in operators/methods. – Moe Howard Nov 17 '12 at 05:09
  • That is a valid concern when you have no control over the service code. – Mathias Becher Nov 17 '12 at 11:30
0

There are a few ways to register known types. But first please study the articles concerning DataContracts and the types supported by the DataContractSerializer.

Note that you didn't add the DataContract attribute on the DerivedClass BaseClass. Although classes marked with the Serializable attribute are valid and can be exposed in WSDL, the DataContractAttibute has serialization rules designed for interoperability and it is the preferred serialization mechanism for WCF.

If you decide to register known types on the data contract then this should be enough:

[DataContract]    
public class DerivedClass : List<BaseClass>
{
  /// ...
}

[DataContract]
[KnownType(typeof(DerivedClass))]
public clas BaseClass
{
    //Add the DataMemberAttribute to the properties you want serialized.
}

If you want to register the known types on the service contract level you add the ServiceKnownType attribute on the ServiceContract.

Panos Rontogiannis
  • 4,154
  • 1
  • 24
  • 29
  • BaseClass is defined as you have noted. The Client simply derived from that class to take advantage of the generic List<> operators/methods; The implementation would work if the client simply went the has-a approach rather than a is-a approach; that is, if the client didn't derive from List but rather made it a property. But this would look clunky. Is it necessary for the serivce to know about derived implementations of List? Seems not, the client needs to send the List over; the client derived clss should be hidden from serivce – Moe Howard Nov 17 '12 at 05:21
  • You do not have to add it at the service contract AND the data contract level. One is enough. Another alternative is the configuration file or using the KnownTypeAttbibute .ctor that takes as parameter the name of a helper method returning an IEnumerable of known types. Anyway I can't see the point of your derived class. It makes your design harder to understand without any benefits (visible from your example and comments). Remove the derived class and use IList or IEnumerable in your service operations. This way you encapsulate the collection type and have simple maintainable code. – Panos Rontogiannis Nov 17 '12 at 09:16
  • The derived class is purely to operate on the List and that is it. Just helper functions. Like functions that operate on the List; for example, Set all item properties of the list to a value given some conditions and to calculate some values against the List. Basically, all the data and operations is contained in DerivedClass rather than having a seperate "Helper" class that we need to create each time we need to perform a common tasks. Now if you are to say that having two classes (Derived and Helper) is a good design, I disagree. – Moe Howard Nov 17 '12 at 15:06