TSQL - выполнение разрешения CLR - PullRequest
4 голосов
/ 05 ноября 2010

Я получил sql-процедуру из CLR (.net Assembly), которая при выполнении возвращает ошибку

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();
        }
    }
}

Ответы [ 3 ]

6 голосов
/ 02 сентября 2015

Проблема заключается в том, что вы пытаетесь получить доступ к внешнему ресурсу в сборке, которая помечена как SAFE.Для доступа к внешним ресурсам требуется установить сборку как минимум EXTERNAL_ACCESS (а в некоторых случаях UNSAFE).Однако, глядя на ваш код, вы просто пытаетесь подключиться к локальному экземпляру, и в этом случае есть гораздо более простой (и более быстрый) способ сделать это: использовать "Context Connection = true;" в качестве ConnectionString.

Контекстное соединение - это прямое соединение с текущим процессом / сеансом, и его иногда называют внутрипроцессным соединением.Преимущества использования Context Connection:

  • может быть сделано в сборках, помеченных как SAFE
  • доступ к локальным временным объектам (временные таблицы и временные процедуры, начинающиеся с именс одним # вместо двойного ##)
  • доступ к SET CONTEXT_INFO и CONTEXT_INFO()
  • без накладных расходов при запуске соединения

Также:

  • независимо от того, используете ли вы внутрипроцессное, контекстное или обычное / внешнее подключение, вам не нужно формально запрашивать разрешение, используя SqlClientPermission
  • , вы всегда должны очищать внешние ресурсывызвав их Dispose() метод.Не все объекты имеют это, но SqlConnection, SqlCommand и SqlDataReader, безусловно, имеют.Обычно люди заключают одноразовые объекты в блок using(), так как это макрос компилятора, который расширяется до структуры try / finally, которая вызывает метод Dispose() в finally, чтобы обеспечить его вызов, даже есливозникает ошибка.
  • Метод 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);
      }
    }
  }
}
0 голосов
/ 19 июня 2012

Я просто хотел добавить к этому два моих чувства.Я делаю что-то очень похожее, и я получаю ту же ошибку.Вот что я нашел, однако, поскольку у меня нет такого уровня доступа к БД, я не могу его протестировать.

Самое простое (хотя MSDN не рекомендуется использовать только для запуска процесса CLR) - установить уровень разрешений External_Access ...

Наборы разрешений уровня политики хоста SQL Server Наборразрешений безопасности доступа к коду, предоставленных сборкам на уровне политики хоста SQL Server, определяется набором разрешений, указанным при создании сборки.Существует три набора разрешений: SAFE, EXTERNAL_ACCESS и UNSAFE.

Уровень разрешений задается на страницах свойств проекта CLR, вкладка «База данных» - задайте уровень доступа-внешний, задайте Aassembly Owner-dbo и выполните tsql.'ALTER DATABASE DataBaseName SET TRUSTWORTHY ON' Это сделает работу ЗАВЕРШЕНО!- и SmtpClient будет работать нормально ... Тогда сделайте это правильно и подпишите Assenbly с помощью файла ключа с сильным именем ...

Полный пост здесь ...

0 голосов
/ 07 ноября 2010

Вы установили для своей БД значение Trusrtworth ON и включили clr?

Попробуйте это

sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

ALTER DATABASE [YourDatabase] SET TRUSTWORTHY ON
GO

У меня есть руководство здесь о том, как использовать хранимые процедуры CLR, которые могут помочь.

...