views:

4559

answers:

3

In a WCF service, I have two classes with the [DataContract] attribute. One of these classes has an "is-a" relationship with the other - so class B can inherit from class A. However, when I configure inheritance between these two classes, both denoted with a [DataContract] attribute, the metadata fails to load when testing the services.

Is this possible in WCF? Am I missing another attribute?

[DataContract]
public class A
{        
    [DataMember]
    public MyCustomType AValue1{ get; set; }

    [DataMember]
    public MyCustomType AValue2 { get; set; }
}

[DataContract]
public class B: A
{    
   [DataMember]
   public double BValue1{ get; set; }

   [DataMember]
   public double BValue2 { get; set; }
}

NOTE: The custom types are also defined using data contracts.

UPDATE: Below is the error:

Error: Cannot obtain Metadata from http://localhost:8002/GISDataServices/mex If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange Error URI: http://localhost:8002/GISDataServices/mex Metadata contains a reference that cannot be resolved: 'http://localhost:8002/GISDataServices/mex'. Receivera:InternalServiceFaultThe server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.HTTP GET Error URI: http://localhost:8002/GISDataServices/mex There was an error downloading 'http://localhost:8002/GISDataServices/mex'. The request failed with HTTP status 400: Bad Request.

UPDATE 2: See my answer below.

+6  A: 

Yes, but you need to decorate the base class with the [KnownTypeAttribute] constructing it with the derived class's type. For instance:

[DataContract]
[KnownType(typeof(B))]
public class A
{
   [DataMember]
   public string Value { get; set; }
}

[DataContract]
public class B : A
{
   [DataMember]
   public string OtherValue { get; set; }
}
David Morton
This doesn't seem to work. I still get an error when loading the metadata.
j0rd4n
What is the error you are seeing?
Andrew Hare
Great question. Can you post your exact error?
David Morton
The error is posted. I'm doing some reading on the KnownType stuff in my "Programming WCF Services" book. Everything looks correct...very strange.
j0rd4n
How should I define the parameter via the interface? Should I use the base class or the subclass. Ideally, I would use the subclass - is that okay?
j0rd4n
BTW, these types are going to be returned from service method calls (not inputs).
j0rd4n
@David: I'm going to give you the answer because you technically answered the question I originally asked.
j0rd4n
Is this interoperability? what happens if other side know nothing about inheritance?
mt_serg
A: 

Based on this test it should work fine. Do both classes have Default Constructors? Are you using Auto-Properties. Note, In this basic sample the Attributes aren't required. Also, as David Morton mentioned you depending on which element you're returning you may need the KnownType attribute, I'm not 100% but the known type might have to go on the operation contract.

class Program
{
    static void Main(string[] args)
    {
        var serializer = new DataContractSerializer(typeof(Employee));

        var employee = new Employee() { Name="Joe", Salary=100000  };
        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, employee);

            ms.Position = 0;

            var newEmployee = serializer.ReadObject(ms) as Employee;
        }

        Console.ReadKey();

    }
}

[DataContract]
public class Employee : Person
{
    [DataMember]
    public decimal Salary { get; set; }
}

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

[ServiceContract]
interface IEmployeeService
{
    [OperationContract]
    Person GetPerson();

    [OperationContract]
    Employee GetEmployee();

    [OperationContract]
    [KnownType(typeof(Employee))]
    Person GetEmployeeAsPerson();
}
bendewey
I am using auto-properties but those work fine when I remove the inheritance construct.
j0rd4n
Neither class uses an explicit constructor.
j0rd4n
Can you update your post with the problem inheritance construct?
bendewey
Whats the return type of your service A or B or both?
bendewey
It can return both depending on the service method called.
j0rd4n
updated my post about knowntype attribute
bendewey
A: 

Okay, I figured out the question. The answer is...I'm an idiot. It had nothing to do with inheritance. In the base class, I had a data contract member without a 'set' property clause - only a 'get'. Doh!!! Putting in a 'set' clause made it work like a charm.

Sorry for the confusion.

j0rd4n