【问题标题】:WCF Client Inside SQL CLRSQL CLR 中的 WCF 客户端
【发布时间】:2009-01-28 22:40:10
【问题描述】:

我知道它不受支持,而且我知道这甚至不是一个非常好的主意。但是,我希望在 SQL 表值函数内有一个 WCF 客户端。

我(似乎)注册了正确的程序集,但是在运行我的客户端时 - 我收到了 WCF 错误:

消息 6522,第 16 层,状态 1,第 1 行 System.ServiceModel.CommunicationObjectFaultedException: 通信对象,System.ServiceModel.ChannelFactory`1[MyProxy.IMyService], 不能用于通信,因为它处于故障状态。

Sql Server 外部的测试似乎有效 - 我什至没有看到 WCF 客户端尝试建立 TCP 连接。

不确定这是 WCF 还是 SQL CLR 问题,因为我都是新手.....

编辑:我了解所需的 System.ServiceModel 及其无数程序集不在经过审查的 Sql CLR 列表中。不过,

“仍然可以从您的托管存储过程、触发器、用户定义的函数、用户定义的类型和用户定义的聚合中调用不受支持的库。不受支持的库必须首先使用 CREATE 在 SQL Server 数据库中注册ASSEMBLY 语句,然后才能在您的代码中使用。任何在服务器上注册和运行的不受支持的库都应经过审查和测试,以确保安全性和可靠性。"

【问题讨论】:

    标签: .net sql wcf sqlclr


    【解决方案1】:

    本文可能会帮助您找出真正的潜在异常是什么,并了解它的致命性:

    http://jdconley.com/blog/archive/2007/08/22/wcfclientwrapper.aspx(archive.org 复制)

    作为David correctly says,SQL CLR 支持有限的 .NET 程序集子集:

    SQL 2005 Supported .NET Framework Libraries
    SQL 2005 CLR Integration Programming Model Restrictions

    SQL 2008 Supported .NET Framework Libraries
    SQL 2008 CLR Integration Programming Model Restrictions

    如果端点是 WSDL 服务,则支持System.Web.Services,这样可以帮助您摆脱困境吗?或者,您始终可以使用 Web 服务作为您尝试与之通信的任何非 Web 服务 WCF 端点的代理。

    【讨论】:

    • 看起来很有希望......到目前为止,WCF 可调试性并没有给我留下深刻印象,所以我希望这会有所帮助。
    【解决方案2】:

    我不太明白,但Kev's pointer 终于让我进入了工作状态。 WCF 客户端包装器为您提供 actual 异常 - 而不是 VS2008 代理为您提供的 CommunicationObjectFaultedException(如何解决此问题?)。

    那个异常是 FileLoadException,抱怨 System.ServiceModel:

    主机存储中的程序集与 GAC 中的程序集具有不同的签名。 (HRESULT 异常:0x80131050)有关详细信息,请参阅 Microsoft 知识库文章 949080。

    当然,KB 949080 没有任何帮助,因为它仍然指的是 SQL 2005(顺便说一句,我注意到很多 SQL 2008 错误消息,并且仍然指的是 2005 - 你认为它们可以'至少替换了错误消息中的文本)并在更新 .NET FX 后处理了问题 - 这没有发生。

    不过,这确实让我想到了 32 位和 64 位的区别。我的 SQL 2008 服务器是 Server 2008 x64 上的 x64 - 因此,它同时具有 C:\Windows\Microsoft.NET\Framework 和 Framework64 文件夹。由于 SQL Server 是一个 64 位进程,并且我的程序集将在进程中托管 - 我从 Framework64 文件夹加载程序集,并从 Program Files 加载 System.IdentityModel 和 System.IdentityModel.Selectors,而不是 Program Files (x86)。

    所以,我尝试了 x86 程序集 - 但尝试加载 System.Web 会出现相当神秘的错误:

    程序集“System.Web”引用程序集“system.web, version=2.0.0.0,culture=neutral,publickeytoken=b03f5f7f11d50a3a.”,当前数据库中不存在。

    嗯,是的...我猜 System.Web 可能确实引用了 System.Web。原来,StackOverflow already has an answer 解决了这个问题。虽然没有多大意义,但看起来您需要加载 System.Web 的 Framework64 版本,以及其他所有内容的常规 Framework 版本。

    不幸的是,尝试该解决方案让我返回了可怕的 WCF 捕获所有 CommunicationObjectFaultedException。对 WCF 和 IDisposable 的愚蠢感到恼火,我取消了 using 和 Dispose 调用,这样我就可以 - 你知道 - 实际上看到正确的异常:

    var p = new MyServiceClient(new CustomBinding(b), new EndpointAddress(uri));
    var result = p.Execute(); // Don't Dispose proxy or you'll lose the actual exception.
    
    try {
       return result.Values;
    } finally {
       if (p.State != CommunicationState.Closed) {
          if (p.State != CommunicationState.Faulted) {
             p.Close();
          } else {
             p.Abort();
          }
       }
    }
    

    然后我又遇到了另一个 FileLoadException,这次是在 System.Runtime.Serialization 上,再次将我指向无用的 KB 949080。

    认为这是 x64 奇怪的又一个案例,我决定如果要加载 Framework 程序集,我可能还应该加载 Program Files (x86) System.IdentityModel 程序集。

    而且 - 你知道吗……它确实有效。运行时的 IntPtr.Size 为 8 个字节......所以我被加载为 x64。将我的程序集标记为 x64(或 x86)将无法部署 - 它仅适用于 AnyCPU。在加载的程序集上运行 corflags 显示 x86 或 x64 版本的位数没有差异,所以我真的不知道问题是什么。但是,以下 CREATE ASSEMBLIES 有效:

    create assembly [System.Web] 
    from 'C:\Windows\Microsoft.NET\Framework64\v2.0.50727\System.Web.dll'
    with permission_set = UNSAFE
    
    create assembly [System.Messaging] 
    from 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll'
    with permission_set = UNSAFE
    
    create assembly [SMDiagnostics]
    from 'C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\SMDiagnostics.dll'
    with permission_set = UNSAFE
    
    CREATE ASSEMBLY [System.IdentityModel] 
    from 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\System.IdentityModel.dll'
    with permission_set = UNSAFE
    
    CREATE ASSEMBLY [System.IdentityModel.Selectors] 
    from 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\System.IdentityModel.Selectors.dll'
    with permission_set = UNSAFE
    
    CREATE ASSEMBLY [Microsoft.Transactions.Bridge] 
    from 'C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\Microsoft.Transactions.Bridge.dll'
    with permission_set = UNSAFE
    

    然后将我的用户程序集部署为 AnyCPU。 YMMV 可以在 x86 版本的 Sql Server 上。

    男孩 - 我真的开始对这些东西的黄金时间还没有做好准备感到恼火。我几乎怀念 C 的简单日子。

    【讨论】:

    • 我认为造成此类问题的原因之一是对来自 10 个不同地方的知识的假设。 MS 一定知道有很多客户都经历过同样的困境,他们为什么不在 MSDN 文档中记录这样的场景,而不是晦涩难懂的小知识库文章。
    【解决方案3】:

    至少在 SQL Server 2005 中,只有少数支持 SQL CLR 的程序集。我不相信 WCF 是其中之一。我进行了快速搜索,没有任何结果让我得出结论,2008 SQL CLR 发生了很大变化。

    参考: http://support.microsoft.com/kb/922672

    【讨论】:

    • 明白。但是,我不是在寻找“支持”——我在寻找“工作”。否则,我会打电话给 PSS。 ;)
    • 是的......我也是“吸一听”学校的产物 :)
    • 某些程序集永远无法注册为SAFE(由于 CAS 和/或 HPA),因此永远不会被视为“工作”,但这并不意味着它们不能成功使用。
    【解决方案4】:

    我在尝试在 SQL CLR 中调用 WCF Web 服务时遇到了类似的问题。 它从 .NET 加载了如此多的程序集,但我无法让它工作。

    最终,我使用通用 WebClient 向 WCF 服务器发出 HTTP 请求,该服务器运行良好,并且需要将最少的程序集加载到 SQL Server 中。

    【讨论】:

      【解决方案5】:

      我对 System.Runtime.Serialization 程序集有同样的问题。在 x64 窗口上

      解决办法是,在c:\windows\assembly目录下找到System.Runtime.Serialization,复制到其他目录,运行CREATE ASSEMBLY sql命令。

      最好的,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-05
        • 1970-01-01
        • 2016-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多