Datacontract and dynamic return type WCF

Amir Rezvani picture Amir Rezvani · Apr 12, 2012 · Viewed 10.3k times · Source

I have a ServiceContract which returns dynamic type and looks like following:

public dynamic LoginViaOpenId(string openIdUrl)

The dynamic return type could be a DataContract that I have defined, or a string. But since I have not used my DataContract on the service, client does not know anything about it and cannot access it.

My DataContract is something like below:

[DataContract]
public enum OpenIdStatus
{
        [EnumMember]
        Authenticated,
        [EnumMember]
        Authenticating,
        [EnumMember]
        Cancelled,
        [EnumMember]
        Failed,
        [EnumMember]
        RedirectToLogon
 }

I know if I had hierarchical types I could have used KnownType to conquer this, but am out of idea for this scenario. Any idea?

Answer

Allon Guralnek picture Allon Guralnek · Apr 12, 2012

A dynamic DataContract is an oxymoron. A DataContract is a predetermined and mutually agreed-upon data structure, and dynamic is an object whose structure is not predetermined and thus cannot be agreed-upon, since it can be anything.

It doesn’t appear you actually need to return a dynamic data type, but rather a varying data type. The difference is that a varying data type is one of a set of fixed data types, whereas a dynamic data type is one which does not have a predetermined structure. Since your return value is one of several knows shapes, there is no need to use the "shapeless" (or "freeform") dynamic type, which isn't supported by WCF.

Instead, you could have the [OperationContract] method return a type with a [DataContract] that will act as a wrapper object that has a single data member of type object, and use [KnownType] on the wrapper object to specify the possible types that may be returned inside the wrapper. Since everything inherits from object, there is already a hierarchy in place.

[DataContract]
[KnownType(typeof(OpenIdStatus))]
[KnownType(typeof(string))]
public class ReturnValue
{
    [DataMember]
    public object Value { get; set; }
}