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

Sql server 2005 Sql 2005 CLR集成-是否支持动态程序集加载?,sql-server-2005,sqlclr,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 init

我有一个静态类,它动态加载.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.
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.
注意:我已授予我的SQL Server服务帐户“完全访问”磁盘上的动态资产文件。我使用以下语法复制了动态程序集:

create Assembly TestAssembly
    From 'C:\MyTestAssembly.dll';
--Alter Assembly to copy dynamic assembly file
Alter Assembly TestAssembly add file from 'C:\mydynamicassembly.dll';
在打开“可信”并设置“权限”\u 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.Security.SecurityException: Request failed.
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.

我猜在创建程序集时,您已经将权限设置为SAFE(如果您没有指定它,这将是默认设置)。如果要这样做,您需要将其更改为外部访问或不安全


我是从事SQL-CLR集成的@Microsoft开发人员之一,因此我可能会提供帮助

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

  • 将数据库标记为可信的
  • 将程序集标记为不安全(数据库必须可靠)
  • 运行SQL Server的帐户必须具有访问文件系统上文件的权限。通常情况下,文件位于网络共享上,但SQL Server在本地帐户下运行,该帐户没有访问网络的权限,因此这通常是一个问题。默认安装中的SQL Express无权访问C:
  • 请注意,做所有这些事情都会产生一些负面的副作用:

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


    [编辑:如果以上任何一项都没有帮助,最好在MSDN论坛上提问]。

    如错误消息所述,SQL Server完全不允许动态程序集加载-即使在不安全的情况下也是如此。Assembly.Load调用成功的唯一方法是,如果程序集已通过CREATE Assembly加载到数据库中,或加载到GAC和上。上还有一篇关于这个问题的帖子。

    我知道这是一个非常古老的问题,但我最近找到了一种方法来实现你想要的。当您尝试在SQL CLR托管的程序集中使用
    Assembly.Load(…)
    时,它将显式失败,这是出于设计考虑,即使在
    权限设置=不安全的情况下也是如此。这是为了确保数据库服务器的稳定性

    加载动态程序集的技术是首先注册它们,然后使用
    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注册了程序集。

    @Greg Beech和@DenNukem-感谢您的想法。我尝试了权限更改,但仍然得到了最后一个异常-我已编辑了原始问题的详细信息。异常似乎是表示程序集的动态加载已禁用…嗯,这听起来很有说服力;如果SQL Server已显式禁用它,则听起来您将无法动态加载程序集。即使在不安全模式下,我也不知道这是一个限制。有趣的方法。只是出于好奇:您何时需要使用类似的方法?什么情况需要动态加载,并且不知道提前加载什么?@srutzky在撰写本文时,.NET 3.5仍在等待-我已经将我的OOS项目RazorEngine向后移植到.NET 3.5,以便我可以将其安装到Sql Server中,以便在数据库级错误报告机制上使用在SQL中创建一组表(因为DB是每个其他系统之间的公分母),它将触发一封限制错误电子邮件。Razor用于控制电子邮件模板。由于RazorEngine为每个模板生成唯一的DLL,因此必须加载它们才能执行。