C# WCF-指定已知类型(PCL/.NET标准)

C# WCF-指定已知类型(PCL/.NET标准),c#,android,.net,wcf,xamarin,C#,Android,.net,Wcf,Xamarin,这个问题一再出现。这在.NET和Silverlight上不是问题,但在以后的所有其他平台上,我从未见过一种在不将已知类型实际输入到ServiceContract中的情况下指定已知类型的方法。这意味着此列表不能在运行时动态更改。这是Xamarin、UWP和其他平台的问题。那么,让我们看看这个 最初,在.NET和Silverlight上解决此问题的一种方法是指定一种方法,用于获取ServiceKnownType上的已知类型,如下所示: [ServiceKnownType("GetKnownTypes

这个问题一再出现。这在.NET和Silverlight上不是问题,但在以后的所有其他平台上,我从未见过一种在不将已知类型实际输入到ServiceContract中的情况下指定已知类型的方法。这意味着此列表不能在运行时动态更改。这是Xamarin、UWP和其他平台的问题。那么,让我们看看这个

最初,在.NET和Silverlight上解决此问题的一种方法是指定一种方法,用于获取ServiceKnownType上的已知类型,如下所示:

[ServiceKnownType("GetKnownTypes", typeof(GetTypesHelper))]
这在.NET和Silverlight上一直运行良好,但在UWP或Xamarin上不起作用。我今天试过了,我得到的错误是:

System.InvalidOperationException:ServiceKnownTypeAttribute指定Adapt.XivicClient.WCF.ServiceContracts.GetTypesHelper类型中不存在的方法GetKnownTypes。该方法必须是静态的,并接受ICustomAttributeProvider类型的一个参数

当然,PCL和.NET标准库没有ICCustomAttributeProvider类,因此无法实现这一点。因此,我尝试了另一种可能的解决方案:

这是通过指定服务行为来实现的。但是,PCL和Standard都没有IServiceBehavior类,Android也没有

我尝试了这段代码,因为我认为我可以替换DataContractSerializer,但我在Android上得到了一个NotImplementedException

        dataAccessServiceClient.Endpoint.EndpointBehaviors.Add(new XivicServicBehaviour());

public class XivicServicBehaviour : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

那么,我们有什么选择呢?

我对自己的问题有一个答案。它盯着我的脸看了很长时间,非常简单

我不知道为什么,但我们通常被鼓励使用OperationContract的参数来指定已知类型。大约8年来,我一直认为这是唯一的办法。我一直知道,在使用DataContractSerializer手动序列化/反序列化时,可以指定已知类型,但我不知道如何覆盖WCF的默认功能来实例化我指定的DataContractSerializer

无论如何,还有另一种方法,而且非常简单。只需将列表或检索类型列表的接口传递给代理的构造函数,然后手动将类型添加到操作中,如下所示:

这适用于.NET标准代理(基于任务的操作)

公共类ServiceClientBase:ClientBase、IServiceClient、ICommunicationObject其中T:class
{
#区域构造函数
public ServiceClientBase(绑定绑定,EndpointAddress EndpointAddress,sc.iknowntypeggeter knownTypeGetter):base(绑定,EndpointAddress)
{
foreach(Endpoint.Contract.Operations中的var操作)
{
var knownTypes=knownTypeGetter.GetKnownTypes();
foreach(knownTypes中的变量类型)
{
operation.KnownTypes.Add(类型);
}
}
}
#端区
#区域打开/关闭
公共虚拟任务OpenAsync()
{
var communicationObject=此为ICommunicationObject;
返回Task.Factory.fromsync(communicationObject.BeginOpen(null,null),newaction(communicationObject.endoin));
}
公共虚拟任务CloseAsync()
{
var communicationObject=此为ICommunicationObject;
返回Task.Factory.fromsync(communicationObject.BeginClose(null,null),newaction(communicationObject.EndClose));
}
#端区
}
还有一种味道:

public partial class WCFClientBase<T> : ClientBase<T> where T : class
{
    public WCFClientBase(Binding binding, EndpointAddress endpointAddress, IKnownTypeGetter knownTypeGetter) : base(binding, endpointAddress)
    {
        foreach (var operation in Endpoint.Contract.Operations)
        {
            var knownTypes = knownTypeGetter.GetKnownTypes();

            foreach (var type in knownTypes)
            {
                operation.KnownTypes.Add(type);
            }
        }
    }
}
公共部分类WCFClientBase:ClientBase其中T:class
{
公共WCFClientBase(绑定绑定,EndpointAddress EndpointAddress,IknownTypeggeter KnownTypeggeter):基(绑定,EndpointAddress)
{
foreach(Endpoint.Contract.Operations中的var操作)
{
var knownTypes=knownTypeGetter.GetKnownTypes();
foreach(knownTypes中的变量类型)
{
operation.KnownTypes.Add(类型);
}
}
}
}

我对自己的问题有一个答案。它盯着我的脸看了很长时间,非常简单

我不知道为什么,但我们通常被鼓励使用OperationContract的参数来指定已知类型。大约8年来,我一直认为这是唯一的办法。我一直知道,在使用DataContractSerializer手动序列化/反序列化时,可以指定已知类型,但我不知道如何覆盖WCF的默认功能来实例化我指定的DataContractSerializer

无论如何,还有另一种方法,而且非常简单。只需将列表或检索类型列表的接口传递给代理的构造函数,然后手动将类型添加到操作中,如下所示:

这适用于.NET标准代理(基于任务的操作)

公共类ServiceClientBase:ClientBase、IServiceClient、ICommunicationObject其中T:class
{
#区域构造函数
public ServiceClientBase(绑定绑定,EndpointAddress EndpointAddress,sc.iknowntypeggeter knownTypeGetter):base(绑定,EndpointAddress)
{
foreach(Endpoint.Contract.Operations中的var操作)
{
var knownTypes=knownTypeGetter.GetKnownTypes();
foreach(knownTypes中的变量类型)
{
operation.KnownTypes.Add(类型);
}
}
}
#端区
#区域打开/关闭
公共虚拟任务OpenAsync()
{
var communicationObject=此为ICommunicationObject;
返回Task.Factory.fromsync(communicationObject.BeginOpen(null,null),newaction(communicationObject.endoin));
}
公共虚拟任务CloseAsync()
{
var communicationObject=此为ICommunicationObject;
返回Task.Factory.fromsync(communicationObject.BeginClose(null,null),newaction(communicationObject.EndClose));
}
#端区
}
还有一种味道:

public partial class WCFClientBase<T> : ClientBase<T> where T : class
{
    public WCFClientBase(Binding binding, EndpointAddress endpointAddress, IKnownTypeGetter knownTypeGetter) : base(binding, endpointAddress)
    {
        foreach (var operation in Endpoint.Contract.Operations)
        {
            var knownTypes = knownTypeGetter.GetKnownTypes();

            foreach (var type in knownTypes)
            {
                operation.KnownTypes.Add(type);
            }
        }
    }
}
公共部分类WCFClientBase:ClientBase其中T:class
{