tags:

views:

52

answers:

2

Hi guys, I'm trying to build out a WCF service but I've run into a blocking issue. I've been Googling around but I haven't been able to make any progress. Hopefully I'll have more luck here.

Let's say I have a job class defined as such:

[DataContract]
public class Job : IJob
{
    public Job(...)
    {
    }

    [DataMember]

    public string Example
    {
        get { return m_example; }
        set { m_example = value; }
    }
}

Now, what I do is something like this

public void DoSomething()
{
    ExampleServiceProxy.ExampleClient proxy = new ExampleServiceProxy.ExampleClient();
    proxy.DoSomething(job);
}

Inside of my Reference.cs I've added some ServiceKnownTypeAttribute as follows:

...
[System.ServiceModel.ServiceKnownTypeAttribute(typeof(Job))]
void DoSomething(object job);

My service code is as follows:

[ServiceContract]
public interface IExample
{
    [OperationContract]
    void DoSomething(IJob);
}

public class Example : IExample
{
    public void DoSomething(IJob job)
    {
        ...
    }
}

Do I need to put further ServiceKnownTypeAttributes somewhere? Do I need to reimplement the object on the service side?

A: 

Is there any reason you are using the interface IJob? I have never seen WCF implemented in that way.

When ever I implement WCF I always use the DataContract, ie Job. I do that because the DataContract is the contract between the two parties, and has no behavior. Where as the Service does have behavior so using an interface is a good idea.

Also the DataContract needs to be defined on the Service side. So if you were to move Job to the Service library, remove IJob, delete the existing reference in the Client and regenerate it, it will work fine.

Here is the service code:

[ServiceContract]
public interface IExample
{
    [OperationContract]
    void DoSomething(Job);
}

[DataContract]
public class Job 
{
    public Job(...)
    {
    }

    [DataMember]

    public string Example
    {
        get { return m_example; }
        set { m_example = value; }
    }
}

public class Example : IExample
{
    public void DoSomething(Job job)
    {
        ...
    }
}
Iain
Would it really make any difference (doesn't know at all) since Job is an implementation of the IJob interface.
kkshin
Good point, "Don't do that" is bad form.
Iain
It's bad form to answer a question with "Don't do that", without even attempting to answer the question. If you really want to say it, then wait until you have enough rep to add a comment.
Andrew Shepherd
@kkshin - It will work that way. The only difference is you need to edit the generated Reference.cs, something I personally would avoid. In either case, Andrews suggestion of creating a new library is the best solution, as when the Service receives the WCF message it needs a concrete class to deserialize it into.
Iain
@kkshin - I made a mistake, if you use the DataContract as I suggested and move it into the Service library then when you generate your client using Add Service Reference (are you doing that?), it will generate a definition of Job for the client for you. Hence you don't need to move Job into another library. I'll fix my answer to say that
Iain
+1  A: 

You have to put the ServiceKnownType attribute on the Service Contract interface.

[ServiceContract] 
public interface IExample 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(Job))]
    void DoSomething(IJob); 
} 

public class Example : IExample 
{ 
    public void DoSomething(IJob job) 
    { 
        ... 
    } 
} 
Andrew Shepherd
I tried to do this earlier, but I get an error that it would introduce a circular dependency. This is because Job.cs is in another assembly and I would have to include it in the WCF project (I think).
kkshin
OK. You have no choice but to refactor your libraries to remove the circular dependencies. Have the ServiceContract, IJob and Job definitions all in one libary. Then have the server implementation in another executable or library, and the client in another executable. When you're programming in WCF, you get used to creating lots of libraries.
Andrew Shepherd
Thanks, I did that and it worked fine.
kkshin