views:

556

answers:

4

Is possible in WCF service: method return IList when object can be Person class?

Ex: in IServiceContract.cs

[ServiceContract]
public interface IDAS
{
    [OperationContract]
    void DoWork();

    [OperationContract]
    List<object> GetAnyClass();

}

And class:

public class DAS : IDAS
{
    public void DoWork()
    {
    }

    public List<object> GetAnyClass()
    {
        List<Person> a = new List<Person>();
        a.Add(new Person());
        return a;
    }
}

The problem at runtime is:

System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error

A: 

Theoretically yes, although you need to tell the service that it might be expecting a Person object using the KnownTypeAttribute on your method.

[OperationContract]
[KnownType(typeof(Person))]
List<object> GetAnyClass();

I would really think twice about doing this in practice though - instead declare different method signatures for the objects you're expecting to return:

[OperationContract]
IList<Person> GetPeople();

[OperationContract]
Person GetPerson();

[OperationContract]
IList<Book> GetBooks();

[OperationContract]
Book GetBook();

etc.

It's supposed to be a contract, i.e. concrete, so if you suddenly change the type of class you return it can really mess the clients up.

Also in your example you were returning a concrete List class - this should be avoided, instead use either IList<> or Collection<>.

Andy Shellam
ok. but when:return null;or IList<object> a = null;return null;The problem do not exist.It's really necesary to implement one method for each class?I have 50 tables and 50 class DTO mapping.So, Need I 50 methods?I try to make a RIA silverlight application.Sorry for my bad english.Your comment has helped me a lot.
Cheva
The issue is that WCF is thinking it's getting an object when in fact it's getting a Person, and it doesn't know anything about Person. When you return null, it knows about null, so it's OK. Add the KnownType attribute to your method and [DataContract] on your Person class. Trust me - it will help to separate out your methods and it will make more sense to other people (and yourself) reading your code to know exactly what you're getting.
Andy Shellam
A: 
  1. Yes it is possible, you need to update the reference in Visual Studio (or whatever you are using to generate the proxy class with) and change the collection type returned. There is an option in 'Configure Service Reference' and you can select Generic.List in there (right click your WCF service reference).
  2. The mismatch is because you have changed your service on the server end and not got a new proxy. So change it to return a Generic.List and then regenerate using the steps in 1.

Hope that helps

Ryan

Ryan ONeill
A: 

You can return an IList but it's definitly not a good approach to take.

When you expose your services you need people at the other end of the service to know what they are getting.

IList<Person> would be clearer for everybody that use the services or that code in the services.

If you need a method that can return different type of object just split them out in multiple operations.

IList<Person> GetPersons(...)
IList<Animal> GetAnimals(...)

My 2 cents.

NPayette
ok but, when I to know a set of classes like, person animal, customers, etc. and need fill a IList<T>?It's the same task, again and again. Is very wrong with one method to fill the lists of entities?I share your opinion. So everything is more structured and clear.But, With the class name or class type, I obtain the table name and access with ado.net to BD and DataReader, then I can use a unique method.It's so wrong?Thanks for your opinion.
Cheva
A: 

Cheva (et al),

There is nothing stopping you from calling a single method to fill in the collection(s) you return from the service calls.

IList<Person> GetPersons(...)
IList<Animal> GetAnimals(...)

Both GetPersons() and GetAnimals() can certainly call an internal method e.g.

  IList<Animal> GetAnimals(...)
  {
    // get list of objects of a given type
    internalIList<Object> genericResults = GetItems( 
        ItemType.Persons|ItemType.Animals );

    ...

    IList<Animal> results;

    // convert to specific type
    results = new IList<Animal>(genericResults);

    return results;
  }

That should work, but I didn't test it or anything. YMMV. ; )

-Scott

Scott K. Fraley