这个问题专门针对加载不在Supported .NET Framework Libraries集中的 .Net Framework 程序集,因此我将重点关注 Microsoft 提供的 DLL 而不是任何随机 DLL 的上下文。
“支持”列表中的程序集和不在列表中的程序集之间的区别归结为支持的程序集“已经过测试,以确保它们符合与 SQL Server 交互的可靠性和安全标准”(如上面链接的“支持的库”页面)。主要问题是“可靠性”而不是“安全性”。支持列表中的程序集已经过验证,其行为与预期一致,没有任何错误或奇怪的副作用。该功能已经过测试,可以使用各种语言和排序规则等。
一些不在支持列表中的 .Net Framework 程序集可以加载PERMISSION_SET
为SAFE
. 但是,这并不能保证所需的行为。并且有些可以加载为UNSAFE
不一定说明会有问题。
作为不保证行为的示例:我已加载System.Drawing
以进行一些简单的图像处理。当图像直接通过byte[]
/VARBINARY(MAX)
提供时以及由文件路径提供并从磁盘读取时,我测试了操作。一切都按预期工作。我把它发给了德国的某个人,他的 Windows 和 SQL Server 都设置为“德语”作为语言。直接提供图像时,他能够得到预期的结果。但是当他提供文件路径时它不起作用。
对于不希望的行为,SQL Server 将显示程序集无法加载的原因SAFE
或EXTERNAL_ACCESS
当您尝试加载时。例如:
CREATE ASSEMBLY [System.Drawing]
AUTHORIZATION [dbo]
FROM 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.dll'
WITH PERMISSION_SET = SAFE;
结果是:
警告:Microsoft .NET Framework 程序集 'system.drawing,version=4.0.0.0,culture=neutral,publickeytoken=b03f5f7f11d50a3a,processorarchitecture=msil。' 您注册的内容未在 SQL Server 托管环境中进行全面测试,因此不受支持。将来,如果您升级或维修此程序集或 .NET Framework,您的 CLR 集成例程可能会停止工作。有关详细信息,请参阅 SQL Server 联机丛书。
消息 6218,级别 16,状态 2,第 1 行为
程序集“System.Drawing”创建程序集失败,因为程序集“System.Drawing”验证失败。检查引用的程序集是否是最新的并且受信任(对于 external_access 或不安全)以在数据库中执行。如果有任何 CLR 验证程序错误消息将跟随此消息
[ : System.Drawing.BufferedGraphicsContext::bFillColorTable][mdToken=0x600013c][offset 0x00000053][found address of Byte] 堆栈上的预期数字类型。
[ : System.Drawing.BufferedGraphicsContext::bFillColorTable][mdToken=0x600013c][offset 0x00000043][found Native Int][expected address of Byte] 堆栈上的意外类型。
[ : System.Drawing.BufferedGraphicsContext::bFillColorTable][mdToken=0x600013c][offset 0x00000027][found Native Int][expected address of Byte] 堆栈上的意外类型。
[ : System.Drawing.Icon::ToBitmap][mdToken=0x6000349][offset 0x00000084][found unmanaged pointer][expected unmanaged pointer] 堆栈上的意外类型。
[ : System.Drawing.Icon::ToBitmap][mdToken=0x6000349][offset 0x000000E4] 非托管指针不是可验证的类型。
[ : System.Drawing.Icon::GetShort][mdToken=0x6000356][offset 0x00000002] 非托管指针不是可验证的类型。
...
如果您不打算使用任何这些方法或类型,那么您可能不会遇到任何问题。没有办法将“安全”的东西与“不安全”的物品分开。
另一个关联内疚的例子,但甚至更远,是:
CREATE ASSEMBLY [System.Web]
AUTHORIZATION [dbo]
FROM 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Web.dll'
WITH PERMISSION_SET = SAFE;
结果是:
警告:Microsoft .NET Framework 程序集 'system.web,version=4.0.0.0,culture=neutral,publickeytoken=b03f5f7f11d50a3a,processorarchitecture=x86。' 您注册的内容未在 SQL Server 托管环境中进行全面测试,因此不受支持。将来,如果您升级或维修此程序集或 .NET Framework,您的 CLR 集成例程可能会停止工作。有关详细信息,请参阅 SQL Server 联机丛书。
警告:Microsoft .NET Framework 程序集 'microsoft.build.framework,version=4.0.0.0,culture=neutral,publickeytoken=b03f5f7f11d50a3a,processorarchitecture=msil。' 您注册的内容未在 SQL Server 托管环境中进行全面测试,因此不受支持。将来,如果您升级或维修此程序集或 .NET Framework,您的 CLR 集成例程可能会停止工作。有关详细信息,请参阅 SQL Server 联机丛书。
警告:Microsoft .NET Framework 程序集 'system.xaml,version=4.0.0.0,culture=neutral,publickeytoken=b77a5c561934e089,processorarchitecture=msil。' 您注册的内容未在 SQL Server 托管环境中进行全面测试,因此不受支持。将来,如果您升级或维修此程序集或 .NET Framework,您的 CLR 集成例程可能会停止工作。有关详细信息,请参阅 SQL Server 联机丛书。
消息 6212,级别 16,状态 1,第 1 行
CREATE ASSEMBLY 失败,因为安全程序集“System.Xaml”中类型“System.Windows.Markup.ValueSerializer”的方法“TypeDescriptorRefreshed”正在存储到静态字段。在安全程序集中不允许存储到静态字段。
如您所见,System.Web
实际上,它本身就很好SAFE
,但它具有依赖程序集并且正在自动加载。第一个依赖程序集microsoft.build.framework
也没有问题(至少不能验证,尽管有可能不允许SAFE
是否存在但只能在运行时捕获)。但是第二个依赖程序集确实有一个可以在加载程序集时验证的问题:它“存储到静态字段”。这是一个可靠性问题而不是安全性问题,因为类被实例化一次(嗯,每个应用程序域,意味着:每个数据库,每个所有者)并在 SPID 之间共享以供使用(这就是为什么在 SQLCLR 中只能访问静态方法的原因) . 因此,静态类级变量在技术上是在会话(即 SPID)之间共享信息,这很容易导致意外行为。但同时,如果您只想使用HtmlString.ToHtmlString()
,那么您可能没有使用System.Xaml
. 那么为什么它不只是加载System.Web
asSAFE
和System.Xaml
asUNSAFE
呢?可能是因为代码在SAFE
程序集不允许调用程序集中的代码UNSAFE
(至少在 SQLCLR 中不允许)。
结论
那么加载UNSAFE
.Net Framework 程序集可以吗?这真的应该归结为测试。大量的测试(不仅仅是你的开发箱上的一个线程,而是真正的测试)。如果一切都按预期运行,那么你应该没问题。但是,如果某些行为与预期不符,那么它不是可以报告给 Microsoft 的错误,因为它已被声明为不受支持。
编辑:
这里是这个问题的更正式的答案,其中列出了可能出现问题的几种情况:SQL Server CLR-hosted environment 中未经测试的 .NET Framework 程序集的支持策略