2

I need invoke webservice operations using standard wsdl, but data objects must be different in client and in the server.

Using interfaces for data objects in a common library, making proxy classes for it in client and in server.

Then, I'm declaring operation contract using the interface, but WCF don't recognize it.

I yet tried use DataContractSerializerBehavior and set knownTypes, no success yet.

Someone can help-me? I've attached a complete solution with more details.

public interface Thing
{
   Guid Id {get;set;}
   String name {get;set;}
   Thing anotherThing {get;set;}
}

[DataContract]
public class ThingAtServer: BsonDocument, Thing // MongoDB persistence
{ 
   [DataMember]
   Guid Id {get;set;}
   //... 
}

[DataContract]
public class ThingAtClient: Thing, INotifyPropertyChanged // WPF bindings
{ 
   [DataMember]
   Guid Id {get;set;}
   //... 
}

[ServiceContract]
public interface MyService
{
  [OperationContract]
  Thing doSomething(Thing input);
}

Click here do see a Sample project on GitHub with TestCases

John Saunders
  • 160,644
  • 26
  • 247
  • 397
thr0w
  • 1,454
  • 3
  • 10
  • 7
  • You're not showing how `Thing` is defined - does it have `[DataContract]`, too? What about `[BsonDocument]`? Typically, you have to define **separate**, elightweight (DTO-style) objects for WCF services - don't inherit from things like a MongoDB base class - you don't need nor want to serialize all this state over your WCF service.... – marc_s Apr 05 '13 at 19:15
  • Also: WCF is a XML-based message passing system - so anything you pass around in WCF must be representable in XML schema (XSD); interfaces are **not** supported by XSD - you need to use **concrete classes** (and generics are not supported either ...) – marc_s Apr 05 '13 at 20:36

2 Answers2

2

I've created WCF Service with contract:

[OperationContract]
CompositeTypeServer GetDataUsingDataContract( CompositeTypeServer composite );

My CompositeTypeServer looks like this:

[DataContract( Namespace = "http://enes.com/" )]
public class CompositeTypeServer
{
    [DataMember]
    public bool BoolValue { get; set; }

    [DataMember]
    public string StringValue { get; set; }
}

Then I've created client project with type CompositeTypeClient:

[DataContract( Namespace = "http://enes.com/" )]
public class CompositeTypeClient
{
    [DataMember]
    public bool BoolValue { get; set; }

    [DataMember]
    public string StringValue { get; set; }
}

Then I've added the reference to my service and selected to reuse types. Everything worked like charm. I was able to use CompositeTypeClient on client side.

So the trick was to specify Namespace for DataContract so they would match on both client and service.

[DataContract( Namespace = "http://enes.com/" )]

PS. I can provide full working VS solution on request.

Enes
  • 1,115
  • 7
  • 12
0

Based on ServiceKnownTypeAttribute (MSDN documentation), I changed what types expected depending on the situation. The main idea is implemented in the class XHelper, responsible to return the correct Type[] according to the situation:

public static class XHelper
{

    public static Boolean? IsClient = null;
    public static Type[] ClientTypes;
    public static Type[] ServerTypes;

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider pProvider)
    {
        if (!IsClient.HasValue)
            throw new Exception("Invalid value");
        if (IsClient.Value)
            return ClientTypes;
        return ServerTypes;
    }
}

You must include the ServiceKnownType tag in the interface that has the ServiceContract to know XHelper class.

[ServiceContract(Namespace = MyProxyProvider.MyNamespace)]
[ServiceKnownType("GetKnownTypes", typeof(XHelper))]
public interface MyService
{
    [OperationContract]
    Thing2 CopyThing(Thing1 input);
}

At the beginning of the test unit, which was informed of the right Type[] for every situation:

    [AssemblyInitialize]
    public static void TestInitialize(TestContext pContext)
    {
        XHelper.ClientTypes = new Type[] { typeof(Thing1ProxyAtClient), typeof(Thing2ProxyAtClient), typeof(Thing2ProxyAtClient) };
        XHelper.ServerTypes = new Type[] { typeof(Thing1ProxyAtServer), typeof(Thing2ProxyAtServer), typeof(ThingNProxyAtServer) };
    }

Click here do see the final code Sample project on GitHub with TestCases

Belchior
  • 1
  • 1