morleyc
morleyc

Reputation: 2431

ServiceKnownTypeAttribute does not exist in manually coded WCF client

I am making a custom WCF client which I want to register the classes dynamically at application startup.

I am using the attribute ServiceKnownType on the client interface:

[ServiceContract(Namespace = "http://example.com/schema/commandservice/v1.0", ConfigurationName = "WcfProxies.IVotesCommandService")]
    [ServiceKnownType("GetKnownTypes")]
    public interface IVotesCommandService
    {
        [OperationContract(Action = "http://example.com/schema/commandservice/v1.0/VotesCommandService/Execute", ReplyAction = "http://example.com/schema/commandservice/v1.0/VotesCommandService/ExecuteResponse")]
        void Execute(object command);

        [OperationContract(Action = "http://example.com/schema/commandservice/v1.0/VotesCommandService/Execute", ReplyAction = "http://example.com/schema/commandservice/v1.0/VotesCommandService/ExecuteResponse")]
        Task ExecuteAsync(object command);
    }
}

public class VotesCommandServiceClient : ClientBase<IVotesCommandService>, IVotesCommandService
{

    public VotesCommandServiceClient()
    {
    }

    public VotesCommandServiceClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }

    public VotesCommandServiceClient(string endpointConfigurationName, string remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public VotesCommandServiceClient(string endpointConfigurationName, EndpointAddress remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public VotesCommandServiceClient(Binding binding, EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    {
    }

    public void Execute(object command)
    {
        Channel.Execute(command);
    }

    public Task ExecuteAsync(object command)
    {
        return Channel.ExecuteAsync(command);
    }

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider) 
    {
        var types = new[]
        {
            typeof (UserVotedOnTopicCommand)
        };

        return types;

        // collect and pass back the list of known types
    }

}

But when I try and use the class it throws an exception:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.dll. Additional information: ServiceKnownTypeAttribute in MyApp.Votes.WinSvc.Test.WcfProxies.IVotesCommandService refers to a method GetKnownTypes that does not exist in type MyApp.Votes.WinSvc.Test.WcfProxies.IVotesCommandService

But if i declare an externally typed resolver below:

[ServiceKnownType("GetKnownTypes", typeof(Helper))]
public interface IVotesCommandService
.... snip...

static class Helper
{
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        var types = new[]
        {
            typeof (UserVotedOnTopicCommand)
        };

        return types;
    }
}

Then it works?!

I have also tried setting ServiceKnownType on the proxy class implementation as below:

[ServiceKnownType("GetKnownTypes")]
public class VotesCommandServiceClient : ClientBase<IVotesCommandService>, IVotesCommandService
{
    ... snip ...

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        var types = new[]
        {
            typeof (UserVotedOnTopicCommand)
        };

        return types;
    }
 }

But then the actual GetKnownTypes function is never called and the proxy bombs out when trying to use it as it doesn't know the contract being sent.

What am I doing wrong please and why isn't the static GetKnownTypes function inside the class being called?

Upvotes: 1

Views: 878

Answers (1)

Eren Ers&#246;nmez
Eren Ers&#246;nmez

Reputation: 39085

MSDN documentation for the constructor overload you're using says:

Use this constructor when applying the ServiceKnownTypeAttribute to a class that contains methods that return known types.

It is looking for "GetMethodNames" on the type that the attribute is defined (IVotesCommandService), not on the run-time type (VotesCommandServiceClient).

You would need to define as [ServiceKnownType("GetKnownTypes", typeof(VotesCommandServiceClient)].

Upvotes: 2

Related Questions