2010-11-05 4 views
4

Я получил процедуру SQL из CLR (сборки .NET), который при выполнении возвращает ошибкуTSQL - Выполнение CLR Разрешение

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

Juvil, если вы все еще заинтересованы, я добавил [ответ] (http://stackoverflow.com/a/32341040/577765), что объясняет проблему и исправляет код для лучших практик. Я также объяснил, почему другие ответы не работают (в комментариях к этим ответам). –

ответ

-3

Установлен ли ваш набор БД в Trusrtworth ON и включен clr?

Попробуйте

sp_configure 'clr enabled', 1 
GO 
RECONFIGURE 
GO 

ALTER DATABASE [YourDatabase] SET TRUSTWORTHY ON 
GO 

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

+0

Это не помогло исправить это для меня. – Ryan

+0

@ Райан и Раймунд: эти шаги не помогут. Если CLR еще не был включен, попытка выполнить любой код SQLCLR приведет к ошибке, указав, что интеграция CLR не включена. Установка DB на TRUSTWORTHY ON, а также быстрое и простое и обычно помогает для сборок EXTERNAL_ACCESS или UNSAFE, обычно это не нужно, так как представляет угрозу безопасности. Проблема здесь в том, что сборка установлена ​​в SAFE, которая запрещает любые внешние запросы. Шаг 1: установить Assembly на EXTERNAL_ACCESS, но есть еще лучший вариант, как показано в моем [ответе] (http://stackoverflow.com/a/32341040/577765). –

+0

Я согласен, что на самом деле это не так. Проблема заключается в разрешениях. Другой комментарий и другой ответ доходят до сути дела. –

0

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

Самый простой (хотя и не рекомендуется MSDN только Jet A CLR Proc для запуска) должен установить уровень разрешения EXTERNAL_ACCESS ...

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

Уровень permision устанавливается на свойства страниц проекта CLR , вкладка базы данных - набор разрешений Level-External, установите Aassembly Владелец-DBO и запустите TSQL 'ALTER DATABASE Databasename SET TRUSTWORTHY ON' Это позволит получить работа СОВЕРШЕНА! - и SmtpClient Wiill работают нормально ... Тогда сделайте это прямо и Подпишите Assenbly с сильным именем Key файл ...

Full Post Here...

+1

Учитывая, что желание подключиться к локальному экземпляру, это, безусловно, не самый простой или даже лучший подход. И установка базы данных в TRUSTWORTHY ON, будучи быстрым и легким, является плохим подходом, который обычно не нужен. Правда, последнее утверждение говорит «тогда сделайте это правильно ...», но если кто-то заработает его с «TRUSTWORTHY ON», то есть очень мало шансов, что они вернутся, чтобы сделать это прямо позже. В любом случае, я объясню реальную проблему в своем [ответе] (http://stackoverflow.com/a/32341040/577765). –

5

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

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

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

также:

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

Отличная информация ... это имеет смысл иметь это. Но! Еще одна важная вещь, в которой нам нужно: проверить, где-бы-мы-бегуем, выбирать между этой и обычной строкой, чтобы мы могли использовать типичную строку соединения во время разработки. Как мы тестируем, есть ли у нас этот «sql-серверный контекст»? –

+0

Просто нашел точно ответ ... также написанный вами :). Возможно, вы могли бы добавить ссылку ... https://stackoverflow.com/a/31279625/1518460 –

Смежные вопросы