以合理安全的方式使用 sqlclr 和脚本化程序集的 F#

F# with sqlclr in a reasonably safe way and scripted assembly

有一些关于如何在 SQL 服务器中将 F# 与 SQLCLR 一起使用的博客 post 很有帮助:http://richardminerich.com/2015/12/a-safer-way-to-use-f-with-sql-clr/, http://thelastexpression.blogspot.com/2012/04/f-agents-and-sqlclr.html, https://rojepp.wordpress.com/2011/08/03/f_on_sqlclr/, Can the F# core libs be SQLCLR-approved? 对于 C# 方法:http://www.sqlservercentral.com/Authors/Articles/Solomon_Rutzky/294002/

我是 wondering/hoping,随着时间的推移,有一个博客 post 在那里,我还没有找到它或这里的答案,它解决了如何使用带有 SQLCLR 的 F# 这样可以使用 Visual Studio (或其他一些工具)将程序集编写为十六进制,就像使用 C# 部署所做的那样(我无权在服务器上安装代码,除非通过 SQL Server Management Studio),至少比使用 'trustworthy on' 或 'unsafe' 更安全。我以前写过 F# 和很多 T-SQL,我在 Common Lisp 中写的原型(现在必须存在于 SQL 服务器中)会更好地映射到 F#(并且比使用 C# 让我更快乐).

我对您第一个 link ( http://richardminerich.com/2015/12/a-safer-way-to-use-f-with-sql-clr/ ) 中显示的方法表示怀疑,因为它没有直接显示 FSharp.Core 库,因此不清楚作者是否不必设置 TRUSTWORTHY ON 以至少让该部分工作。非常可疑的是,在步骤 5 中,基于非对称密钥的登录被授予了错误的权限:

GRANT EXTERNAL ACCESS ASSEMBLY TO FSHARP_CLR_Login

授予 EXTERNAL ACCESS ASSEMBLY 而不是 允许将程序集设置为 UNSAFE 需要 UNSAFE ASSEMBLY 权限。它 可能 是写入 post 时的复制/粘贴错误,但没有显示 TRUSTWORTHY 当前 TRUSTWORTHY 的证据(即来自 sys.databases) =22=],或者作者的代码在创建该登录名并向其授予该权限之前无法正常工作。

所以,我只是通过安装最新版本的 FSharp.Core – 4.1.2 – 来尝试这个,这是我发现的:

  1. 确认TRUSTWORTHYOFF(即0)通过:

    SELECT [name], is_trustworthy_on FROM sys.databases WHERE [database_id] = DB_ID();
    
  2. 尝试将 FSharp.Core 加载为 SAFE,看看它是否有效:

    USE [TestDB];
    
    CREATE ASSEMBLY [FSharp.Core]
    FROM N'C:\path\to\project\packages\FSharp.Core.4.1.2\lib\net45\FSharp.Core.dll'
    WITH PERMISSION_SET = SAFE;
    

    收到以下错误:

    Msg 6211, Level 16, State 1, Line 32
    CREATE ASSEMBLY failed because type 'Microsoft.FSharp.Collections.FSharpMap`2' in safe assembly 'FSharp.Core' has a static field 'empty'. 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.

  3. 再次尝试加载 FSharp.Core,但显示为 UNSAFE:

    USE [TestDB];
    
    CREATE ASSEMBLY [FSharp.Core]
    FROM N'C:\path\to\project\packages\FSharp.Core.4.1.2\lib\net45\FSharp.Core.dll'
    WITH PERMISSION_SET = UNSAFE;
    

    行得通。但是,我没有将数据库设置为 TRUSTWORTHY ON,也没有创建登录名并授予它 EXTERNAL ACCESS ASSEMBLY 权限。含义:违规可能是通过 运行 时间验证而不是加载时间验证发现的。而且我没有办法测试超出这一部分的内容,但我希望会发生错误。

  4. 如果此程序集的 UNSAFE 权限集确实发生错误,那么您无需设置 TRUSTWORTHY ON 即可处理该错误,但您需要创建一个主证书和基于证书的登录:

    USE [master];
    
    CREATE CERTIFICATE [FSharpCert45]
    FROM EXECUTABLE FILE =
            N'C:\path\to\project\packages\FSharp.Core.4.1.2\lib\net45\FSharp.Core.dll';
    
    CREATE LOGIN [FSharpLogin45] FROM CERTIFICATE [FSharpCert45];
    
    GRANT UNSAFE ASSEMBLY TO [FSharpLogin45];
    
  5. 如果您的程序集也需要标记为 UNSAFE,那么您可以从 master 中的 DLL 创建一个非对称密钥,然后从该非对称密钥,然后授予该基于密钥的登录 UNSAFE ASSEMBLY 权限。 (这假设您的程序集已签名 - 并受密码保护)

  6. 当然,以上所有内容都假设您可以将 DLL 放到服务器上,或者至少放到 SQL 服务器服务帐户可以访问的共享上,而您确实做到了提到想通过十六进制字节部署它。这应该可以通过做:

    1. 在 Visual Studio 中,在 "Solution Explorer" 中的 "References" 下,转到 "Properties" for FSharp.Core并将 Model Aware 设置为 True,将 Permission Set 设置为 Unsafe。这将导致发布过程将 DLL 包含在构建脚本中。
    2. 如果 DLL 已经在您的目标数据库中,那么它可能不会为该程序集生成 CREATE ASSEMBLY 语句,因为发布脚本是增量更改。如果是这种情况,请转到项目属性,并在 项目设置 下,选中 创建脚本(.sql 文件)(如果尚未选中)。这将导致构建过程始终生成 _Create.sql 脚本,并且其中肯定会有 [=127= 的 CREATE ASSEMBLY 语句].
    3. CREATE ASSEMBLY [FSharp.Core] FROM 0x... 语句显然将用于将程序集加载到目标数据库中(即您的程序集也将加载到其中)。
    4. 那个 CREATE ASSEMBLY [FSharp.Core] FROM 0x... 语句将 成为您在 master 中创建对象的门票,如下所示:

      USE [master];
      
      CREATE ASSEMBLY [FSharp.Core]
      FROM 0x4D....
      WITH PERMISSION_SET = UNSAFE;
      
      CREATE CERTIFICATE [FSharpCert45]
      FROM ASSEMBLY [FSharp.Core];
      
      DROP ASSEMBLY [FSharp.Core];
      
      CREATE LOGIN [FSharpLogin45] FROM CERTIFICATE [FSharpCert45];
      
      GRANT UNSAFE ASSEMBLY TO [FSharpLogin45];
      

      这在 SQL Server 2012 上对我有用,唯一的区别是我使用了文件路径而不是十六进制字节。