手动编码的 WCF 客户端中不存在 ServiceKnownTypeAttribute

ServiceKnownTypeAttribute does not exist in manually coded WCF client

我正在制作自定义 WCF 客户端,我想在应用程序启动时动态注册 classes。

我在客户端界面上使用属性 ServiceKnownType

[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
    }

}

但是当我尝试使用 class 时它抛出异常:

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

但是如果我在下面声明一个外部类型的解析器:

[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;
    }
}

然后就可以了?!

我还尝试在代理 class 实现上设置 ServiceKnownType,如下所示:

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

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

        return types;
    }
 }

但是实际的 GetKnownTypes 函数永远不会被调用,代理在尝试使用它时会爆炸,因为它不知道正在发送的合同。

请问我做错了什么,为什么不调用 class 中的静态 GetKnownTypes 函数?

MSDN documentation 对于您正在使用的构造函数重载说:

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

它在定义属性的类型(IVotesCommandService)上寻找"GetMethodNames",而不是在运行时间类型(VotesCommandServiceClient)上寻找。

您需要定义为 [ServiceKnownType("GetKnownTypes", typeof(VotesCommandServiceClient)]