Sql 2005 CLR集成 - 是否支持动态程序集加载?

时间:2009-11-12 16:14:34

标签: sql-server-2005 sqlclr

我有一个静态类,它动态加载.NET程序集(使用Assembly.LoadFile方法) 我收到以下错误消息:

Msg 6522, Level 16, State 2, Line 3
A .NET Framework error occurred during execution of user-defined routine or aggregate "MySQLCLRUDFFunction": 
System.TypeInitializationException: The type initializer for 'MyClassName' threw an exception. ---> System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed

当我尝试使用此声明分配CAS安全性时

[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]

我反而得到此异常

Msg 6522, Level 16, State 2, Line 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "MySQLCLRUDFFunction": 
System.TypeInitializationException: The type initializer for 'MyClassName' threw an exception. ---> System.Security.SecurityException: Request failed.

注意:我已将SQL Server服务帐户“完全访问”提供给磁盘上的动态组件文件。我使用语法复制了我的dyamic程序集:

create Assembly TestAssembly
    From 'C:\MyTestAssembly.dll';
--Alter Assembly to copy dynamic assembly file
Alter Assembly TestAssembly add file from 'C:\mydynamicassembly.dll';

转动TRUSTWORTHY ON并设置PERMISSION_SET = UNSAFE后,我现在得到此异常

Msg 6522, Level 16, State 2, Line 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "MySQLCLRUDFFunction": 
System.TypeInitializationException: The type initializer for 'MyClassName' threw an exception. ---> System.IO.FileLoadException: LoadFrom(), LoadFile(), Load(byte[]) and LoadModule() have been disabled by the host.

4 个答案:

答案 0 :(得分:2)

正如错误消息所述,SQL Server完全禁止动态程序集加载 - 即使在不安全的情况下也是如此。 Assembly.Load调用成功的唯一方法是,程序集已经通过CREATE ASSEMBLY或GAC和list of supported ("blessed") assemblies加载到数据库中。 sqlclr blog上还有另一篇文章。

答案 1 :(得分:1)

我知道这是一个非常古老的问题,但我最近找到了实现你想要的方法。当您尝试在SQL CLR托管程序集中使用Assembly.Load(...)时,它将明确失败,这是设计使然,即使使用PERMISSION_SET = UNSAFE也是如此。这是为了确保数据库服务器的稳定性。

加载动态程序集的技术是首先注册它们,然后使用传递完全限定类型名称的Type.GetType(...)来解析类型(包括程序集版本信息。

以下是步骤:

1.编译类型,并在磁盘上完成(即不要创建内存中的程序集)。 CompilerResults类型将具有CompiledAssembly属性和PathToCompiledAssembly属性。使用后者,因为访问CompiledAssembly属性将尝试使用Assembly.Load

2.使用路径,我从我的代码中调用存储过程(使用new SqlConnection("Context Connection = true")),我传递了程序集的名称(我预先确定)和编译的程序集路径:

CREATE PROCEDURE re.CreateAssembly
    @name VARCHAR(100),
    @path VARCHAR(1000)
AS
BEGIN
    DECLARE @sql NVARCHAR(2000)
    SET @sql = N'CREATE ASSEMBLY [' + @name + '] AUTHORIZATION [DatabaseUser] FROM ''' + @path + ''' WITH PERMISSION_SET + SAFE';
    EXEC sp_executesql @sql;
END
GO

3.使用您的预定名称,您可以使用Type.GetType(...),例如:

string typeName = "MyCompiledAssembly.MyClass, MyCompiledAssembly, Version=0.0.0.0, Culture=Neutral, PublicKeyToken=null, ProcessorArchitecture=MSIL";
Type type = Type.GetType(typeName);

当SQLCLR尝试解析该类型时,它应该找到它,因为在步骤2中您已经使用Sql Server注册了程序集。

答案 2 :(得分:0)

我猜你在创建组件时已经将PERMISSION_SET设置为SAFE(如果你没有指定它,这将是默认设置)。如果你想这样做,你需要将它改为EXTERNAL_ACCESS或UNSAFE。

http://msdn.microsoft.com/en-us/library/ms189524.aspx

答案 3 :(得分:0)

我是一名致力于SQL-CLR集成的开发人员@微软,所以我可以提供帮助。

要实现您的目标,您需要做两件事:

  1. 将数据库标记为TRUSTWORTHY
  2. 将程序集标记为UNSAFE(数据库必须值得信赖)
  3. 运行SQL Server的帐户必须具有访问文件系统上的文件的权限。通常,文件位于网络共享上,但SQL Server在没有访问网络权限的本地帐户下运行,因此这通常是个问题。默认情况下,SQL Express默认安装没有C:。
  4. 的权限

    请注意,做所有这些事情有几个负面的副作用:

    1. 严重的安全隐患 - 您实际上已将对实例的控制权交给不安全程序集中的代码,因为它现在可以使用原始指针来访问/更改引擎中的任何内容。
    2. 稳定性 - 出于同样的原因,你也放弃了稳定性保证。
    3. 可移植性和灾难恢复 - 如果您的数据库必须移动到其他位置以进行负载平衡,或者在计算机出现故障后从备份恢复,则您将无法在新计算机上安装mydynamicassembly.dll。
    4. 如果可能,请考虑重新设计您的应用,以便将所有需要的程序集预先加载到数据库本身。

      [编辑:如果上述任何一项都无法在MSDN论坛上提出最佳建议]。