CREATE ASSEMBLY失败,"无法解析令牌"

时间:2016-06-26 04:38:32

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

我正在尝试将一些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 Data Provider: Msg 6218, Level 16, State 2,
Line 1 CREATE ASSEMBLY for assembly 'A' failed because assembly 'A' failed
verification. Check if the referenced assemblies are up-to-date and trusted
(for external_access or unsafe) to execute in the database. CLR Verifier error
messages if any will follow this message
[ : A.Class1::Method1][mdToken=0x6000010][offset 0x00000001] Unable to resolve token.
[ : A.Class2::Method2][mdToken=0x6000014][offset 0x0000004C] Unable to resolve token.
[ : A.Class3::Method3][mdToken=0x6000017][offset 0x00000001] Unable to resolve token.
[ : A.Class4::Method4][mdToken=0x6000021][offset 0x0000000C] Unable to resolve token.
(276,0): SQL72045: Script execution error.  The executed script:
CREATE ASSEMBLY [A]
    AUTHORIZATION [dbo]
    FROM 0x4D5A9...002A0

我花了一天时间研究这个话题并没有找到任何有用的东西。所以任何想法都会非常感激。

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

关于服务器和开发机器上的.NET版本。 Dev机器是Win 10. SQL Server在WinServer 2012 R2 Standard Core上的VM中运行。两者都安装了所有最新更新。服务器上安装的.NET版本(使用此代码段https://stackoverflow.com/a/3495491/664178):

PSChildName           Version               Release    Product
-----------           -------               -------    -------
Client                4.6.01055              394271    4.6.1
Full                  4.6.01055              394271    4.6.1
Client                4.0.0.0

在开发机器上:

PSChildName                        Version          Release  Product
-----------                        -------          -------  -------
v2.0.50727                         2.0.50727.4927
v3.0                               3.0.30729.4926
Windows Communication Foundation   3.0.4506.4926
Windows Presentation Foundation    3.0.6920.4902
v3.5                               3.5.30729.4926
Client                             4.6.01038        394254   4.6.1
Full                               4.6.01038        394254   4.6.1
Client                             4.0.0.0

我似乎无法将dev计算机上的.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也不会影响这种情况。

1 个答案:

答案 0 :(得分: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,而在类库中,如果引用的版本为#,{{ 1}}隐含为Version Specific。在这种情况下,可能有助于将引用显式设置为true

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

我相信这也解释了为什么它在大会注册为Specific Version = false时起作用:很可能是特定版本信息和隐含的PERMISSION_SET = UNSAFE属性是对CLR的推荐当程序集为Specific Version = trueSAFE时,但将其设置为EXTERNAL_ACCESS可以绕过指定的首选项。

P.S。我不确定这是否重要,但与我通常做的另一个区别是,在 AssemblyInfo.cs 文件中,UNSAFE属性正在使用AssemblyVersion建立#。我没有发现这是一个复杂的因素,但如果在从引用中删除特定于版本的信息后仍有问题,请尝试用静态值替换*。原因是如果版本#需要“特定”,那么它可能无助于在每个版本上更改版本#的一部分; - )。

有关测试等的详细信息,请参阅discussion