sql-server – TSQL – 执行CLR权限

我从CLR(.net Assembly)获得了一个sql过程,当执行时返回错误

Msg 6522, Level 16, State 1, Procedure sp_HelloWorld, Line 0
A .NET Framework error occurred during execution of user defined routine or aggregate 'sp_HelloWorld': 
System.Security.SecurityException: Request for the permission of type 'System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
System.Security.SecurityException: 
   at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
   at System.Security.PermissionSet.Demand()
   at System.Data.Common.DbConnectionOptions.DemandPermission()
   at System.Data.SqlClient.SqlConnection.PermissionDemand()
   at System.Data.SqlClient.SqlConnectionFactory.PermissionDemand(DbConnection outerConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()
   at HelloWorld.SQLCLR.HelloWorld()

这是我的SQL脚本

go
drop procedure HelloWorld
drop assembly HelloWorld
GO

create assembly HelloWorld from 'F:\HelloWorld.dll'
with permission_set = safe
Go
create procedure sp_HelloWorld
as external name HelloWorld.[HelloWorld.SQLCLR].HelloWorld
go
exec sp_HelloWorld

这是我的班级(大会)

using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Security.Permissions;
using System.Data;

namespace HelloWorld
{
    public class SQLCLR
    {
        [Microsoft.SqlServer.Server.SqlProcedure]
        public static void HelloWorld()
        {
            string connectString1 = @"Data Source=localhost;Initial Catalog=ItemData;Integrated Security=True";

            SqlClientPermission permission = new SqlClientPermission(PermissionState.None);
            permission.Add(connectString1, "", KeyRestrictionBehavior.AllowOnly);
            permission.PermitOnly();
            SqlConnection sqlcon = new SqlConnection(connectString1);
            sqlcon.Open();
            SqlCommand sqlcmd = new SqlCommand("SELECT Top 1 * FROM ItemData.dbo.Item", sqlcon);
            SqlDataReader reader = sqlcmd.ExecuteReader();
            SqlContext.Pipe.Send(reader);
            sqlcon.Close();
        }
    }
}

最佳答案 问题只是您尝试访问标记为SAFE的程序集中的外部资源.访问外部资源需要将程序集设置为至少EXTERNAL_ACCESS(在某些情况下为UNSAFE).但是,查看代码时,您只是尝试连接到本地实例,在这种情况下,有一种更容易(更快)的方法:使用“Context Connection = true;”作为ConnectionString.

Context Connection是与当前进程/会话的直接连接,有时也称为进程内连接.使用Context Connection的好处是:

>可以在标记为SAFE的程序集中完成
>访问本地临时对象(临时表和临时过程,名称以#开头,而不是双##)
>访问SET CONTEXT_INFO和CONTEXT_INFO()
>没有连接启动开销

也:

>无论您是使用进程内,上下文连接还是常规/外部连接,您都不需要使用SqlClientPermission正式请求权限
>您应该始终通过调用Dispose()方法来清理外部资源.并非所有对象都具有此功能,但SqlConnection,SqlCommand和SqlDataReader当然可以.人们通常将一次性对象包装在using()块中,因为它是一个扩展为try / finally结构的编译器宏,该结构调用finally中的Dispose()方法以确保它被调用,即使出现错误发生.
>许多/大多数一次性对象的Dispose()方法自动处理对Close()的调用,因此您通常不需要显式调用Close().

您的代码应如下所示:

[Microsoft.SqlServer.Server.SqlProcedure]
public static void HelloWorld()
{
  using (SqlConnection sqlcon = new SqlConnection("Context Connection = true;")
  {
    using (SqlCommand sqlcmd = new SqlCommand("SELECT Top 1 * FROM ItemData.dbo.Item",
               sqlcon))
    {
      sqlcon.Open();

      using (SqlDataReader reader = sqlcmd.ExecuteReader())
      {
        SqlContext.Pipe.Send(reader);
      }
    }
  }
}
点赞