SQL CLR集成:无需TRUSTWORTHY ON与UNSAFE权限的System.Net.Http使用咨询
我正好碰到过类似的问题,咱们一步步来拆解和解决:
首先,先明确你的核心矛盾:想用SAFE权限替代UNSAFE来遵循安全规范,但官方的System.Net.Http程序集本身不符合SQL CLR对SAFE权限的要求,这就是你报错的根本原因。
先看下你遇到的两个错误对应的问题:
使用v4.0_2.0.0.0__b03f5f7f11d50a3a版本时:Assembly 'System.Net.Http' could not be installed because existing policy would keep it from being used.
使用v4.0_4.0.0.0__b03f5f7f11d50a3a版本时:CREATE ASSEMBLY failed because type 'System.Net.Http.HttpContent' in safe assembly 'System.Net.Http' has a static field 'EncodingsWithBom'. Attributes of static fields in safe assemblies must be marked readonly in Visual C#, ReadOnly in Visual Basic, or initonly in Visual C++ and intermediate language.
第一个错误是因为版本政策冲突,第二个则直接点出了SAFE权限的核心要求:SAFE程序集里的静态字段必须是只读的,而官方System.Net.Http里的EncodingsWithBom是可写的静态字段,所以通不过校验。
接下来给你几个可行的解决方向:
方向一:自行修改并编译符合SAFE要求的System.Net.Http
这是最直接的解决方法,步骤如下:
- 获取对应.NET Framework版本的
System.Net.Http源代码(可以从.NET Framework官方开源仓库获取) - 找到
System.Net.Http.HttpContent类中的EncodingsWithBom静态字段,把它的修饰符改成readonly,同时确保这个字段的初始化是在静态构造函数中完成的(避免后续代码对它进行修改) - 用强名称密钥对签名程序集:
- 打开命令提示符,执行
sn.exe -k CLRKeyPair.snk生成一个密钥对文件 - 在项目属性的“签名”选项卡中,勾选“为程序集签名”,选择刚才生成的密钥文件
- 打开命令提示符,执行
- 编译得到修改后的
System.Net.Http.dll - 最后在SQL Server中加载这个自定义编译的程序集:
CREATE ASSEMBLY [System.Net.Http] AUTHORIZATION dbo FROM 'C:\路径\修改后的System.Net.Http.dll' WITH PERMISSION_SET = SAFE; GO CREATE ASSEMBLY [CLRTest01] AUTHORIZATION dbo FROM 'C:\Windows\CLRTest01.dll' WITH PERMISSION_SET = SAFE; GO
方向二:改用EXTERNAL_ACCESS权限(更贴合实际需求)
这里要提醒你:如果你的CLR存储过程需要用System.Net.Http发起网络请求,SAFE权限本身是不允许访问外部网络资源的——就算你解决了程序集加载的问题,后续执行存储过程还是会报错。
这种情况下,EXTERNAL_ACCESS权限是更合适的选择,它允许程序访问外部资源,同时比UNSAFE更安全,还不需要开启TRUSTWORTHY ON。配置步骤如下:
- 给你自定义的
CLRTest01.dll和修改后的System.Net.Http.dll用同一个强名称密钥签名 - 在SQL Server中创建关联这个密钥的登录并授权:
-- 从程序集提取公钥创建非对称密钥 CREATE ASYMMETRIC KEY CLRTestKey FROM EXECUTABLE FILE = 'C:\Windows\CLRTest01.dll'; -- 创建对应的服务器登录 CREATE LOGIN CLRTestLogin FROM ASYMMETRIC KEY CLRTestKey; -- 授予外部访问权限 GRANT EXTERNAL ACCESS ASSEMBLY TO CLRTestLogin;
- 然后创建程序集时使用EXTERNAL_ACCESS权限:
CREATE ASSEMBLY [System.Net.Http] AUTHORIZATION dbo FROM 'C:\路径\修改后的System.Net.Http.dll' WITH PERMISSION_SET = EXTERNAL_ACCESS; GO CREATE ASSEMBLY [CLRTest01] AUTHORIZATION dbo FROM 'C:\Windows\CLRTest01.dll' WITH PERMISSION_SET = EXTERNAL_ACCESS; GO
关键提醒
官方GAC中的System.Net.Http是为通用.NET应用设计的,并不适配SQL CLR的SAFE权限约束,所以直接加载官方版本肯定会失败。你必须通过自定义编译修改不符合要求的部分,或者选择更贴合实际功能需求的权限级别。
内容的提问来源于stack exchange,提问作者LINQtothepast

