Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF returning Objects to Client

I am trying to play around with WCF and I think I've hit a block. My issue is that I am able to call Add(double,double) and getPerson() from the "Client". However, I am not able to call any methods of Person object. I've stripped down the classes with bare methods. Here are my code snippets, please let me know what I am doing wrong..

Server Code

  namespace Test.WebSvc{
  [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Sample")]
  public interface ICalculator
  {
    [OperationContract]
    double Add(double n1, double n2);
    [OperationContract]
    Person getPerson();
  }


 public class CalculatorService : ICalculator
 {
    public double Add(double n1, double n2) { return n1+n2 ; }
    public Person getPerson(){ 
    Person tempPerson = new Person();
    return tempPerson; 
    }
 }

 [DataContract]
 public class Person{
 [OperationContractAttribute]
 public string toString(){
 return "This is a Person Object";
 }

Client Code

ServiceRef1.CalculatorClient client = ServiceRef1.CalculatorClient();//works
Console.WriteLine(client.Add(1.0,2.0)); //this too works   
ServiceRef1.Person p = client.getPerson(); // this is OK., but is not doing what I wanted it to do
Console.WriteLine(p.toString()); // I do not get "This is Person Object"

I am guessing something's wrong with my Person class' declaration.. but dint get a clue what should I do or what I am missing..

Thanks!

like image 877
Sekhar Avatar asked Nov 06 '10 06:11

Sekhar


2 Answers

Yes, you've hit a barrier - WCF is a message-based system which only exchanges serialized data, either as XML or JSON, in text or binary format. It does not however pass around "full" .NET objects with their full capabilities like methods and all that (how should it?? It's designed to be interoperable, and I don't see how a Ruby or PHP client could call a method on a .NET object).

WCF is not designed to make it possible to remotely access objects - it just passes messages between client and server. Therefore, anything you can express in XML schema (atomic types, anything like inheritance and composition) can be serialized and sent between the two parties.

Anything that cannot be modelled in XML schema - like generics, interfaces, methods/code - cannot be passed between client and server.

There are ways and tricks to get around this if you control both ends of the communication and both of them are .NET based. Basically, you would have to put your service contract and all your data contracts (all your classes) into a separate assembly, which you then reference from both the server (implementing the service contract), and from the client calling the contract. You can tell WCF to re-use types that already exist in referenced assemblies, and in this case, the client will re-use the ready-made Person class (with all its .NET goodness) from your common shared assembly instead of re-creating a client-side data proxy. With this trick, you can have WCF send serialized messages across the wire, yet on the client side, you're re-creating a full-fledged .NET object with all its methods and all.

Again: this works great as long as you control both ends of the communication, and both ends are using .NET. Any interoperability is out the window with this approach.

like image 50
marc_s Avatar answered Sep 18 '22 17:09

marc_s


You are mixing up two concepts with your Person type -- what you're doing will not work.

You've put a DataContract attribute on the Person type. This is correct, because you have a service that is returning a Person. The Person object will be serialized and returned to your service client (CalculatorClient in this case).

You should define Person like this:

[DataContract]
public class Person
{
    [DataMember]
    public string Description { get; set; }
}

And in your calculator service:

public Person getPerson()
{ 
    Person tempPerson = new Person();
    tempPerson.Description = "This is a Person Object";
    return tempPerson; 
}

This is because your Person object's job is to hold data, and carry it from server to client. It is not its job to define methods / operations, which should instead be done in your Service classes (eg CalculatorService). Adding the OperationContract attribute does not magically turn the Data Transfer Object into a Service.

like image 36
Nader Shirazie Avatar answered Sep 20 '22 17:09

Nader Shirazie