jambodev
jambodev

Reputation: 351

Passing an object using DataContract in WCF

[EDIT] I have now edited the D with constructor and calling code in the client and OnDeserializing() and OnDeserialized() methods.

I have a WCF service (over namedpipe), and a client. I need to pass an object (and preferably a ref of that object) as an argument of my OperationContract.

[DataContract]
public class D
{
    [DataMember] 
    public int Id;

    [DataMember] 
    public string StrId;

    //...


    public D(int id, string strid)
    {
        Id = id;
        StrId = strid;
        //...
    }

    [OnDeserialized]
    void OnDeserialized(StreamingContext strmCtx)
    {
    } // breakpoint here (1)

    [OnDeserializing]
    void OnDeserializing(StreamingContext strmCtx)
    {
    } // breakpoint here (2)

}

and this is the service contract:

[ServiceContract]
public interface ICalc
{
    [OperationContract]
    int Calculate(string date, int count);

    // d is input of this method, and count and array are outputs.
    [OperationContract]
    int getArray(ref int count, ref int[] array, D d);
}

This is my client code where getArray is being called:

proxy.getArray(ref myCount, ref myIntArray, new D(source))

I have also tried this:

D d = new D(source)
proxy.getArray(ref myCount, ref myIntArray, d)

Obviously that doesn't change anything, in both cases when I receive d in the service code (code of getArray method) , all its fields are null. Why is that? Is there something that I am missing?

I know that (using enabling traces and looking at the messages at the transport layer) at the transport layer value of the fields are being correctly transported on the wire. I have also added the OnDeserialized() and OnDeserializing() methods to the object so that I can put a breakpoint there, at the breakpoints (1) and (2) all the fields are null ?!! in fact object setters are not being called at all!!

I am running out of ideas here....

Upvotes: 1

Views: 18856

Answers (4)

Slion
Slion

Reputation: 3048

I had that same issue after grouping some parameters into a DataContract class.

I actually had two clients, one using a shared interface assembly with the server was working just fine. The other client using a code copy of the ServiceContract and DataContract was not working and all members of my DataContract parameter server side were 0 or null as described above.

The problem appears to be due to the namespace in which I put my DataContract in my client. I took care of putting my DataContract in the same namespace than the one from the master client assembly and that fixed my issue. In fact I put all my contract classes in the same namespace except the Callback one. So maybe it was not just an issue with the DataContract. Though is was working fine when not using DataContract so I guess that was the only one causing problem.

Hope it makes sense.

Upvotes: 0

Jocke
Jocke

Reputation: 2284

WCF is data oriented (serialized xml) and not object oriented. That won't work!

Your service operation:

[OperationContract]
int getArray(ref int count, ref int[] array, D d);

will return an data value of int. If you want to get the int value and the array value I would recommend that you create a [DataContract] for it, containing both values. In that way they will be passes as data to the client.

Calling the service operation with (ref int[]) will not make a difference.

Update with some code: Sorry but I cant spot your error. Here is small example (that works) that you can compare with. If you still can't fix the bug I suggest you post you entire code and config.

using System.Runtime.Serialization;
using System.ServiceModel;

namespace WcfService2
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(InputData value);
    }

    [DataContract]
    public class InputData
    {
        [DataMember]
        public int[] Array { get; set; }
        [DataMember]
        public D SomeStuff { get; set; }
    }

    [DataContract]
    public class D
    {
        [DataMember]
        public int Id { get; set; }
    }
}

using System;

namespace WcfService2
{
    public class Service1 : IService1
    {
        public string GetData(InputData data)
        {
            if (data.Array == null || data.SomeStuff == null)
                throw new NullReferenceException();
            return "OK!";
        }
    }
}

using ConsoleApplication9.ServiceReference;
using System;

namespace ConsoleApplication9
{
    class Program
    {
        static void Main(string[] args)
        {
            var proxy = new Service1Client();
            var request = new InputData
                {
                    Array = new int[] {1, 2, 3},
                    SomeStuff = new D {Id = 42}
                };
            Console.WriteLine(proxy.GetData(request));
            Console.ReadKey();
        }
    }
}

Upvotes: 5

jambodev
jambodev

Reputation: 351

Thanks for all your helps and responses. Finally, I resolved this. As soon as I put D, in its own assembly and referenced to it both from Service and client, it all started to work.

Upvotes: 0

Dominic Zukiewicz
Dominic Zukiewicz

Reputation: 8444

Have you got a default constructor, as WCF won't understand it if it doesn't.

Also - ref int[] array - arrays are passed as reference types anyway.

Upvotes: 1

Related Questions