使用 NetDataContractSerializer 将 Guid 传递给 WCF 服务

Passing Guid to WCF service with NetDataContractSerializer

我已经创建了合同

[ServiceContract]
public interface ITestService
{
    [OperationContract]
    [NetDataContract]
    void PassGuid(Guid id);

    [OperationContract]
    [NetDataContract]
    void PassInt(int id);
}

属性 NetDataContractAttribute 描述 here。 当我调用 PassGuid 时出现错误:

Additional information: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:id. The InnerException message was 'XML 'Element' 'http://tempuri.org/:id' does not contain expected attribute 'http://schemas.microsoft.com/2003/10/Serialization/:Type'. The deserializer has no knowledge of which type to deserialize. Check that the type being serialized has the same contract as the type being deserialized.'. Please see InnerException for more details.

但是 PassInt 可以被正确调用。

完整源代码here.

已编辑: 这个问题不是像this one那样发送guid的效率问题,主要是关于NetDataContractSerializer的使用

问题是客户端自动生成的合同(参见文件 WcfClient\Service References\TestService\Reference.cs)没有 [NetDataContract] 属性。

因此在客户端使用DataContractSerializer

为了 NetDataContractSerializer 在客户端和服务器上工作,您需要在客户端有适当的合同定义(通过引用服务器 DLL 或将合同提取到单独的 DLL 中)。然后您将必须创建自己的代理 class(继承自 ClientBase<ITestService>)而不是自动生成的代理(或者只使用 ChannelFactory<ITestService> 而根本没有任何代理 class)。

您正在服务器端使用自定义序列化程序 NetDataContractSerializerNetDataContractSerializerDataContractSerializer 的区别在于序列化添加了类型的附加信息。

例如 DatacontractsSerializer 序列化为:

<Customer xmlns="http://www.contoso.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <FirstName>Zighetti</FirstName>
  <ID>101</ID>
  <LastName>Barbara</LastName>
</Customer>

NetDataContractSerializer 会将同一对象序列化为:

<Customer z:Id="1" z:Type="NetDCS.Person" z:Assembly="NetDCS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://www.contoso.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
  <FirstName z:Id="2">Zighetti</FirstName>
  <ID>101</ID>
  <LastName z:Id="3">Barbara</LastName>
</Customer>

引入更多特定于类型的信息。

在您的情况下,服务器知道 NetDataContractSerializer 但客户端不知道。您必须通过将此行为放入共享代码库中来与客户端共享此行为。然后您可以使用以下代码将此 enw 行为添加到客户端:

       using (var client = new TestServiceClient())
        {
            // Get the channel factory
            var factory = client.ChannelFactory;

            // Attach the behavior
            foreach (OperationDescription desc in factory.Endpoint.Contract.Operations)
            {
                DataContractSerializerOperationBehavior dcsOperationBehavior = desc.Behaviors.Find<DataContractSerializerOperationBehavior>();
                if (dcsOperationBehavior != null)
                {
                    int idx = desc.Behaviors.IndexOf(dcsOperationBehavior);
                    desc.Behaviors.Remove(dcsOperationBehavior);
                    desc.Behaviors.Insert(idx, new WcfClient.NetDataContractAttribute.NetDataContractSerializerOperationBehavior(desc));
                    //return true;

                }
            }

            // pass
            client.PassInt(0);
            // fail
            client.PassGuid(Guid.NewGuid());
            client.Close();
        }

您也可以通过配置文件使用附加行为。