How do you configure WCF known types programmatically?

Solution 1:

Add [ServiceKnownType] to your [ServiceContract] interface:

[ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]

then create a class called KnownTypesProvider:

internal static class KnownTypesProvider
{
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
         // collect and pass back the list of known types
    }
}

and then you can pass back whatever types you need.

Solution 2:

There are 2 additional ways to solve your problem:

I. Use KnownTypeAttribute(string):

[DataContract]
[KnownType("GetKnownTypes")]
public abstract class MyParent
{
    static IEnumerable<Type> GetKnownTypes()
    {
        return new Type[] { typeof(MyChild1), typeof(MyChild2), typeof(MyChild3) };
    }
}

II. Use constructor DataContractSerializer

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | 
                AttributeTargets.Interface)]
public class MyHierarchyKnownTypeAttribute : Attribute, IOperationBehavior, IServiceBehavior, IContractBehavior
{
    private void IOperationBehavior.AddBindingParameters(
            OperationDescription description, 
            BindingParameterCollection parameters)
    {
    }

    void IOperationBehavior.ApplyClientBehavior(
            OperationDescription description, 
            ClientOperation proxy)
    {
        ReplaceDataContractSerializerOperationBehavior(description);
    }

    private void IOperationBehavior.ApplyDispatchBehavior(
            OperationDescription description, 
            DispatchOperation dispatch)
    {
        ReplaceDataContractSerializerOperationBehavior(description);
    }

    private void IOperationBehavior.Validate(OperationDescription description)
    {
    }

    private void IServiceBehavior.AddBindingParameters(
          ServiceDescription serviceDescription,
          ServiceHostBase serviceHostBase,
          System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
          BindingParameterCollection bindingParameters)
    {
        ReplaceDataContractSerializerOperationBehavior(serviceDescription);
    }

    private void IServiceBehavior.ApplyDispatchBehavior(
            ServiceDescription serviceDescription, 
            ServiceHostBase serviceHostBase)
    {
        ReplaceDataContractSerializerOperationBehavior(serviceDescription);
    }

    private void IServiceBehavior.Validate(ServiceDescription serviceDescription,
            ServiceHostBase serviceHostBase)
    {
    }

    private void IContractBehavior.AddBindingParameters(
            ContractDescription contractDescription,
            ServiceEndpoint endpoint, 
            BindingParameterCollection bindingParameters)
    {
    }

    private void IContractBehavior.ApplyClientBehavior(
            ContractDescription contractDescription,
            ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        ReplaceDataContractSerializerOperationBehavior(contractDescription);
    }

    private void IContractBehavior.ApplyDispatchBehavior(
            ContractDescription contractDescription,
            ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
        ReplaceDataContractSerializerOperationBehavior(contractDescription);
    }

    private void IContractBehavior.Validate(ContractDescription contractDescription,
            ServiceEndpoint endpoint)
    {
    }    

    private static void ReplaceDataContractSerializerOperationBehavior(
            ServiceDescription description)
    {
        foreach (var endpoint in description.Endpoints)
        {
            ReplaceDataContractSerializerOperationBehavior(endpoint);
        }
    }

    private static void ReplaceDataContractSerializerOperationBehavior(
            ContractDescription description)
    {
        foreach (var operation in description.Operations)
        {
            ReplaceDataContractSerializerOperationBehavior(operation);
        }
    }

    private static void ReplaceDataContractSerializerOperationBehavior(
            ServiceEndpoint endpoint)
    {
        // ignore mex
        if (endpoint.Contract.ContractType == typeof(IMetadataExchange))
        {
            return;
        }
        ReplaceDataContractSerializerOperationBehavior(endpoint.Contract);
    }

    private static void ReplaceDataContractSerializerOperationBehavior(
            OperationDescription description)
    {
        var behavior = 
         description.Behaviors.Find<DataContractSerializerOperationBehavior>();
        if (behavior != null)
        {
            description.Behaviors.Remove(behavior);
            description.Behaviors.Add(
                new ShapeDataContractSerializerOperationBehavior(description));
        }
    }

    public class ShapeDataContractSerializerOperationBehavior 
            : DataContractSerializerOperationBehavior
    {
        public ShapeDataContractSerializerOperationBehavior(
                OperationDescription description)
            : base(description) { }

        public override XmlObjectSerializer CreateSerializer(Type type, 
                string name, string ns, IList<Type> knownTypes)
        {
            var shapeKnownTypes = 
                new List<Type> { typeof(Circle), typeof(Square) };
            return new DataContractSerializer(type, name, ns, shapeKnownTypes);
        }

        public override XmlObjectSerializer CreateSerializer(Type type, 
                XmlDictionaryString name, XmlDictionaryString ns, 
                IList<Type> knownTypes)
        {
            //All magic here!
            var knownTypes = 
                new List<Type> { typeof(MyChild1), typeof(MyChild2), typeof(MyChild3) };
            return new DataContractSerializer(type, name, ns, knownTypes);
        }
    }
}

[ServiceContract()]
[MyHierarchyKnownTypeAttribute]
public interface IService {...}

NOTE: You must use this attribute on both sides: client side and service side!