生成的 WCF 客户端尝试序列化 Dynamics 365 中的私有成员

generated WCF client tries to serialize private members in Dynamics 365

我写了几个调用相同网络服务的 CRM 插件。所有这些插件共享相同的生成服务参考代码。代码存储在库中,然后与插件 DLL 合并。这适用于旧的本地 CRM。

我们现在正在将相关的本地 CRM 系统迁移到 Dynamics 365,这会引入一个问题:使用生成的 *Client class 调用服务会引发此异常:

System.Security.SecurityException: The data contract type 'MyNamespace.MyDataContract' cannot be serialized in partial trust because the member 'MyDataMemberField' is not public. ---> System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

异常的重要部分是 MyDataMemberField

生成的代码如下所示:

[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "urn:sap-com:document:sap:rfc:functions")]
public class MyDataContract
{
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
    public string MyDataMember
    {
        get { return MyDataMemberField; }
        set { MyDataMemberField = value; }
    }

    private string MyDataMemberField;
}

(请注意,我将 XmlTypeAttribute 中的命名空间保持不变,以防这会产生我不知道的差异。)

您可以看到,通过异常判断存在试图序列化私有成员字段的尝试,我不知道为什么会这样。我在控制台应用程序中使用了相同的生成代码,它能够很好地调用 Web 服务。我还有其他 CRM 插件,它们调用其他 Web 服务(使用其他生成的服务参考代码),它们也能正常工作。我还尝试更改插件使用的 URL 所以它应该引发 404 只是为了确保网络服务不会引发错误,并且它仍然引发相同的异常,所以它必须是客户端例外。我很茫然。

我唯一能想到的是,拥有多个具有相同 public 类型的插件程序集可能会导致这种情况,但恕我直言,这太随机了。

有人知道这里发生了什么吗?

这里要了解的主要事情是 Dynamics 365 Online 将以部分信任的方式执行您的代码(在 D365 中也称为 Sandbox),这将对您在插件中可以执行的操作添加一些限制。出于这个原因,您使用控制台应用程序(完全信任)进行的测试不具有代表性,它会像您提到的那样正常工作。

我建议您查看 Partial Trust Best Practices and Partial Trust Feature Compatibility WCF 文档。快速查看服务参考代码显示 class 标记为 [System.SerializableAttribute()],这在部分信任环境中不受支持,并且 [DataContract] 未用于显式声明 class 可序列化。从外观上看,您将必须更新合同以使其 partial-trust 兼容。

原来有一些逻辑决定是使用XmlSerializer还是DataContractSerializer,看这里:

Add Service Reference is ALWAYS generating xmlserializer and not DataContractSerializer

我的情况是,我们的承包商向我提供了一个 WSDL 文件,其中包含我需要从 CRM 发送到 WCF 的数据类型。我使用 svcutil 生成 C# 代码。此生成的代码没有任何 DataContractDataMember 属性。在 WCF 中使用这些类型会导致那些 *Field 成员显示在 WSDL 的类型中。它还导致 CRM 插件尝试使用那些 *Field 成员进行序列化,而这些成员是私有的,这又导致了上述错误。

在生成的代码中添加 DataContractDataMember 属性解决了这两个问题。