【问题标题】:CREATE ASSEMBLY fails with "Unable to resolve token"CREATE ASSEMBLY 失败并显示“无法解析令牌”
【发布时间】:2016-10-28 08:42:48
【问题描述】:

我正在尝试将一些 CLR 代码上传到 SQL Server 2016(开发人员版)实例。总的来说,结构是这样的:

  • 一个 CLR UDF 依赖于程序集 A
  • 另一个 CLR UDF 依赖于程序集 B
  • AB 都依赖于程序集 C

.sqlproj 的目标框架是 4.0。程序集 AB 是针对 .net4.0 构建的。程序集C 是针对 .net2.0 构建的。所有程序集都设置为Model Aware: TruePermission Set: Safe。所有程序集均未签名。

当我将 .sqlproj 发布到数据库服务器时,程序集 CB 运行良好,但程序集 A 失败:

(276,1):SQL72014:.Net SqlClient 数据提供者:消息 6218,级别 16,状态 2, 第 1 行为程序集“A”创建程序集失败,因为程序集“A”失败 确认。检查引用的程序集是否是最新的和受信任的 (对于 external_access 或 unsafe)在数据库中执行。 CLR 验证程序错误 消息(如果有的话)将跟随此消息 [ : A.Class1::Method1][mdToken=0x6000010][offset 0x00000001] 无法解析令牌。 [ : A.Class2::Method2][mdToken=0x6000014][offset 0x0000004C] 无法解析令牌。 [ : A.Class3::Method3][mdToken=0x6000017][offset 0x00000001] 无法解析令牌。 [ : A.Class4::Method4][mdToken=0x6000021][offset 0x0000000C] 无法解析令牌。 (276,0):SQL72045:脚本执行错误。执行的脚本: 创建程序集 [A] 授权 [dbo] 从 0x4D5A9...002A0

我花了大约一天时间研究这个主题,但没有找到任何有用的东西。因此,任何想法都将不胜感激。

更新1:设置所有程序集的Permission Set 属性并将数据库trustworthy 属性设置为ON 工作,程序集现在已成功部署。但是,现在我无法调用 UDF,因为它们不受信任 :) 我敢肯定,这是可以解决的,但这不是问题的真正解决方案。而且我仍然不明白为什么它不适用于Permission Set: Safe

关于服务器和开发机器上的 .NET 版本。开发机器是 Win 10。SQL Server 在 WinServer 2012 R2 标准核心上的 VM 中运行。两者都安装了所有最新更新。服务器上安装的 .NET 版本是(使用这个 sn -p https://stackoverflow.com/a/3495491/664178):

PSChildName 版本发布产品 ----------- ------- ------- -------- 客户端 4.6.01055 394271 4.6.1 满 4.6.01055 394271 4.6.1 客户端 4.0.0.0

在开发机器上:

PSChildName 版本发布产品 ----------- ------- ------- -------- v2.0.50727 2.0.50727.4927 v3.0 3.0.30729.4926 Windows 通信基础 3.0.4506.4926 Windows 演示基础 3.0.6920.4902 v3.5 3.5.30729.4926 客户端 4.6.01038 394254 4.6.1 满 4.6.01038 394254 4.6.1 客户端 4.0.0.0

我似乎无法将开发机器上的 .NET 更新到与服务器相同的版本。可能是因为开发机器的 Windows 设置为延迟更新......但是这个版本不匹配会成为麻烦的根源吗?

更新 2: 显然,这些 .NET 版本是各自平台的最新版本 (https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx)

更新 3:我尝试了一些进一步的事情。

将数据库项目部署到本地 SQL Server 2016 Express 数据库会产生相同的结果,因此看起来开发和服务器盒上的 .NET 版本不匹配不是问题。

此外,在部署到 LocalDB v12.0(SQL Server 2014 引擎)时观察到完全相同的行为,因此问题可能不在于 SQL Server 2016 .

在 Windows Server (Install-WindowsFeature NET-Framework-Core) 上安装 .NET 3.5 也没有影响这种情况。

【问题讨论】:

  • 程序集“A”使用什么PERMISSION_SET?你的大会签署了吗?您是否尝试在 SQL Server 的早期版本上加载这些程序集
  • @srutzky 我在帖子中添加了此信息。所有程序集都是PERMSSION_SET = SAFE,没有一个程序集签名。我无权访问 SQL Server 2014,所以我没有尝试。但我可能会开始准备一个带有 MSSQL2014 的 VM 来测试它。
  • 好的。您能否测试将它们设置为UNSAFE,虽然我不建议将其用于生产用途,但为了更快/更轻松的测试,请将数据库设置为TRUSTWORTHY = ON
  • 另外,SQL Server 2016 实例是否在您的开发盒上运行?如果不是,它是否与您的开发盒处于同一级别的 .NET Framework 补丁?
  • @srutzky 用更多信息更新了问题!

标签: .net sql-server .net-assembly sqlclr sql-server-2016


【解决方案1】:

我的测试表明这里的问题是如何指定对 BigInteger 类库的引用。查看 PaillierExt.csproj 文件,它显示参考包括版本信息:

<Reference Include="BigInteger, Version=1.0.4.36383, Culture=neutral, processorArchitecture=MSIL">

但是,ElGamalExt.csproj 文件将引用(对于同一个 DLL)显示为只是 DLL 的名称:

<Reference Include="BigInteger">

似乎数据库项目中引用的默认行为是引用,如果给定版本号,则隐含Version Specific = false,而在类库中,如果给定版本号,Version Specific 是隐含为true。在这种情况下,显式设置对Specific Version = false 的引用可能会有所帮助。

通过将源代码(不起作用的原始代码,而不是移动内容的更新代码)复制到 3 个新创建的类库项目中,我能够成功构建和加载所有 3 个项目。我将项目 GUID 和引用等内容复制到新的 .csproj 文件中,但没有复制该特定引用的特定版本信息。然后,我能够创建引用 PaillierExtElGamalExt 方法的数据库项目和 SQLCLR 对象。一切都按预期进行。

我相信这也解释了为什么它在程序集注册为 PERMISSION_SET = UNSAFE 时起作用:很可能是特定版本信息和隐含的 Specific Version = true 属性是对 CLR 的建议,当程序集是SAFEEXTERNAL_ACCESS,但将它们设置为 UNSAFE 允许绕过该声明的偏好。

附:我不确定这是否重要,但与我通常所做的另一个不同之处在于,在 AssemblyInfo.cs 文件中,AssemblyVersion 属性使用* 作为构建号。我没有发现这是一个复杂的因素,但如果有人在从参考中删除版本特定信息后仍然有问题,那么尝试用静态值替换 *。原因是,如果版本号需要“特定”,那么在每次构建时更改版本号的一部分可能无济于事;-)。

有关测试等的详细信息可以在discussion中找到。

【讨论】:

  • 非常感谢您的帮助和为解决此问题付出的所有努力。真的很感激!
猜你喜欢
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 2016-11-25
  • 2013-03-23
  • 2021-07-06
  • 2023-03-27
  • 2019-02-15
相关资源
最近更新 更多