Neste artigo
ToggleOlá pessoal,
Bom dia!
Neste post, que será o número 100 do blog, eu gostaria de falar sobre algo que eu particularmente gosto muito no SQL Server, que é a criação de rotinas .NET dentro do banco de dados SQL Server. Sim, estamos falando a CLR (Common Language Runtime).
Introduction
Clique aqui para visualizarEm outras palavras, o CLR permite que você consiga criar rotinas (stored prodecures, functions, triggers, etc) escritas em C#, F# e VB.NET, compilá-las e executá-las no banco de dados nativamente, estendendo as capacidades do SGBD, pois é possível criar uma infinidade de coisas que não seriam possíveis utilizando apenas o Transact-SQL, como manipulação de arquivos, upload e download de arquivos via FTP, funções de agregação, integração com Webservices e muito mais.
Vantagens e desvantagens
Clique aqui para visualizarVantagens do SQL CLR
- Possibilidade de criação de novos recursos, que não seriam possíveis utilizando apenas T-SQL
- Possibilidade de trabalhar com expressões regulares (RegExp) no banco de dados
- Otimização de performance: Uma mesma função escrita em C# no CLR geralmente é executada bem mais rápido que uma função T-SQL, principalmente em casos de looping e cálculos, uma vez que o compilador do .NET é especializado pra esse tipo de operação, enquanto o do T-SQL é para trabalhar com conjuntos. No meu trabalho, já vi vários casos em que a mesma função CLR executou 5x, 10x e algumas até 60x mais rápido que a função T-SQL
- Integração com Webservices via banco de dados
- Segurança: Uma coisa legal que gosto no CLR, é que podemos definir um usuário fixo para a conexão com o banco de dados. Desta forma, podemos liberar acesso pra ele executar SP’s e consultar views e tabelas de sistema e criar funções e SP’s no CLR para isso. Quando um analista precisar utilizar essas SP’s de sistema, basta liberar acesso na SP/View/Function do CLR que terá acesso indireto ao objeto de sistema, sem precisar liberar acesso pra ele no objeto de origem ou criar objetos em bancos de sistema
- Ferramentas de desenvolvimento: A ferramenta utilizada para desenvolver rotinas do CLR é o Visual Studio. O Management Studio é uma IDE muito boa para criação de rotinas Transact-SQL, principalmente como SQL Prompt instalado, mas não se compara o poderoso Visual Studio, principalmente com o ReSharper. A programação é muito mais rápida e prática.
- Versionamento de código-fonte: Por estarmos utilizando o Visual Studio, o código-fonte pode ser facilmente controlado e gerenciado pelo TFS (Team Foundation Server), dando total controle aos códigos criados, ao contrário de Stored Procedures no banco de dados, que não possuem controles como Merge, Diff, etc
- Substituição do xp_cmdshell: Apesar de vir por padrão, desabilitado, muitas pessoas e empresas acabam habilitando o cmdshell em suas instâncias, até mesmo em produção, em virtude que algumas operações não são possíveis de serem realizadas utilizando apenas Transact-SQL, como manipulação de arquivos, por exemplo. Esse recurso é um grande perigo, uma vez que ele simplesmente executa qualquer comando que é enviado para ele, sem qualquer filtro ou restrição. Para isso, recomendo desabilitar esse recurso e a utilização de procedures CLR destinadas exclusivamente para cada finalidade, seja ela uma cópia de arquivos ou até subir uma instância.
- Substituição de OLE Automation: Recurso ainda bastante utilizado e que também vem desabilitado por padrão, procedures OLE Automation são bibliotecas em C++ que permitem utilizar API’s do Windows para realizar diversas operações, como manipulação de arquivos, etc. O grande problema, é que ao habilitar esse recurso, qualquer usuário pode criar qualquer coisa com isso, aliado ao fato que os comandos não são gerenciados e são executados dentro do processo do SQL Server. Em caso de falha, a instância é desligada, pois o processo do SQL Server é fechado automaticamente pelo sistema operacional (!!!!)
- Automação: Com as procedures CLR, você pode automatizar uma infinidade de processos do dia a dia, que antes só poderiam ser automatizados utilizando o Integration Services, que é uma ótima ferramenta, mas acaba se tornando um pouco limitada diante do mundo de possibilidades do CLR, uma vez que no MSIS você conta apenas com os recursos que ferramentas lhe disponibiliza, enquanto no CLR você pode criar qualquer coisa que a plataforma .NET possibilita. Além disso, o resultado do CLR são objetos de bancos de dados, sejam Stored Prodecures, Functions, Triggers, etc, podendo ser utilizados livremente em outras SP’s, Jobs, e qualquer outro objeto do banco, enquanto os Packages só podem ser executados pela ferramenta ou por Jobs. (Obs: CLR E MSIS são ferramentas com objetivos distintos, apenas comparei pois algumas tarefas do Integration Services podem ser substituídas facilmente pelo CLR)
- Conectividade: Possibilidade de utilizar os conectores do .NET Framework e acessar outros SGBD’s e outras instâncias com link direto, sem a necessidade de LinkedServer, que executa o comanndo remotamente
Desvantagens do SQL CLR
- Necessidade de conhecimento em SQL E linguagem de programação (C#, F# ou VB.net)
- Pouca documentação e pessoas com conhecimento sobre o assunto
- Ao publicar uma nova versão, os objetos são removidos e recriados, perdendo as permissões e deixando os objetos indisponíveis durante a publicação
- Caso seja mal desenvolvido e implementado, pode apresentar riscos para o SGBD
- Algumas funções podem necessitar de um alto volume de CPU para processamento
- Não existem parâmetros opcionais para procedures. Todos devem ser preenchidos
Habilitando o CLR na sua instância SQL Server
Clique aqui para visualizar
1 2 3 4 5 6 7 8 |
sp_configure 'clr enabled' GO sp_configure 'clr enabled', 1 GO RECONFIGURE GO sp_configure 'clr enabled' GO |
E teremos o seguinte resultado:
Caso contrário, você irá se deparar com essa mensagem de erro ao tentar utilizar o CLR:
Msg 6263, Level 16, State 1, Line 2
Execution of user code in the .NET Framework is disabled. Enable “clr enabled” configuration option.
Criando seu primeiro projeto SQL CLR no Visual Studio
Clique aqui para visualizarApós isso, abra o Visual Studio e acesso o menu File > New > Project. Selecione o tipo de projeto SQL Server > SQL Server Database Project
E deverá ficar assim inicialmente:
Agora vamos adicionar um novo projeto do tipo Class Library, que irá conter os nossos códigos C#. Para isso, clique com o botão direito na Solution e selecione a opção Add > New Project. Selecione a categoria Visual C# > Windows > Class Library
Após criada, eu geralmente costumo criar diretórios por tipo de objeto na Class Library para melhor organização do código. Isso é recomendável, mas opcional. Você pode querer organizar seu código por assunto ou conforme sua necessidade.
Alguns referências podem ser removidas, pois não serão utilizadas nos exemplos. Clique com o botão direito em “References” do projeto CLR e selecione a opção “Add Reference…”. Na tela que irá abrir, selecione a categoria Projects > Solutions e marque o checkbox do projeto Class Library:
Não se esqueça de definir a permissão do projeto que foi importado, conforme demonstrado na figura abaixo:
O Solution Explorer deverá ficar como o abaixo:
Criando uma stored procedure sem retorno
- Clique com o botão direito no diretório “Procedures” do projeto Bibliotecas (Class Library) e selecione a opção Add > Class… Na tela que foi aberta, digite o nome do arquivo que será criado. Eu costumo colocar o mesmo nome do objeto que será criado no banco de dados. Neste exemplo, irei criar o arquivo stpCopia_Arquivo.cs
- Copie e cole o código abaixo:
C#12345678910using System.IO;public partial class StoredProcedures{[Microsoft.SqlServer.Server.SqlProcedure]public static void stpCopia_Arquivo(string origem, string destino, bool sobrescrever){File.Copy(origem, destino, sobrescrever);}}
Criando uma stored procedure com retorno de um select
- Clique com o botão direito no diretório “Procedures” do projeto Bibliotecas (Class Library) e selecione a opção Add > Class… Na tela que foi aberta, digite o nome do arquivo que será criado. Eu costumo colocar o mesmo nome do objeto que será criado no banco de dados. Neste exemplo, irei criar o arquivo stpImporta_Txt.cs
- Copie e cole o código abaixo:
C#123456789101112131415161718192021222324252627282930313233343536373839404142434445464748using System.Data;using System.Data.SqlTypes;using Microsoft.SqlServer.Server;using System.IO;public partial class StoredProcedures{[Microsoft.SqlServer.Server.SqlProcedure]public static void stpImporta_Txt(SqlString caminho){if (caminho.IsNull) return;using (var sr = new StreamReader(caminho.Value)){// Define um novo objeto de metadados com 2 colunasvar colunas = new SqlMetaData[2];// Define as colunas de retornocolunas[0] = new SqlMetaData("Nr_Linha", SqlDbType.Int);colunas[1] = new SqlMetaData("Ds_Linha", SqlDbType.NVarChar, 1024);var rec = new SqlDataRecord(colunas);// inicia o envio dos dadosSqlContext.Pipe.SendResultsStart(rec);var contador = 1;while (sr.Peek() >= 0){// define as colunasrec.SetInt32(0, contador);rec.SetString(1, sr.ReadLine());// Envia o registro para o banco de dadosSqlContext.Pipe.SendResultsRow(rec);contador++;}// finaliza o envio dos dadosSqlContext.Pipe.SendResultsEnd();}}}
Criando uma função escalar
- Clique com o botão direito no diretório “Functions” > “Scalar Function” do projeto Bibliotecas (Class Library) e selecione a opção Add > Class… Na tela que foi aberta, digite o nome do arquivo que será criado. Eu costumo colocar o mesmo nome do objeto que será criado no banco de dados. Neste exemplo, irei criar o arquivo fncArquivo_Existe.cs
- Copie e cole o código abaixo:
C#1234567891011using System.Data.SqlTypes;using System.IO;public partial class UserDefinedFunctions{[Microsoft.SqlServer.Server.SqlFunction]public static SqlBoolean fncArquivo_Existe(SqlString Ds_Arquivo){return (File.Exists(Ds_Arquivo.ToString()));}} - Repare que, diferentemente das procedures que retornam sempre void, as functions devem retornar dados. No caso do exemplo, retornam dados do tipo SqlBoolean (bit = true/false)
Criando uma table-valued function
- Clique com o botão direito no diretório “Procedures” do projeto Bibliotecas (Class Library) e selecione a opção Add > Class… Na tela que foi aberta, digite o nome do arquivo que será criado. Eu costumo colocar o mesmo nome do objeto que será criado no banco de dados. Neste exemplo, irei criar o arquivo fncArquivo_Ler.cs
- Copie e cole o código abaixo:
C#12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485using System.IO;using System.Collections;using System.Data.SqlTypes;public partial class UserDefinedFunctions{// Classe que irá receber os dados processados através do construtor da Classeprivate class ArquivoLer{public SqlInt32 Nr_Linha;public SqlString Ds_Texto;public ArquivoLer(SqlInt32 nrLinha, SqlString dsTexto){Nr_Linha = nrLinha;Ds_Texto = dsTexto;}}// Definição da função, contendo o método de preenchimento dos registros (FillRow)// e o retorno para o banco de dados[Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "FillRow_Arquivo_Ler",TableDefinition = "Nr_Linha INT, Ds_Texto NVARCHAR(MAX)" /*,DataAccess = DataAccessKind.Read // Caso a função realize consultas no banco*/)]public static IEnumerable fncArquivo_Ler(string Ds_Caminho){var ArquivoLerCollection = new ArrayList();if (string.IsNullOrEmpty(Ds_Caminho))return ArquivoLerCollection;var contador = 1;using (var sr = new StreamReader(Ds_Caminho)){while (sr.Peek() >= 0){ArquivoLerCollection.Add(new ArquivoLer(contador,sr.ReadLine()));contador++;}sr.Close();}return ArquivoLerCollection;}/*Método de preenchimento dos dados. O parâmetro de entrada é sempre o objeto da classecriada no início do código e as variáveis que serão retornadas, todas como OUTPUT, poisseus valores originais serão alterados para o método IEnumerable que controla a função.*/public static void FillRow_Arquivo_Ler(object objArquivoLer, out SqlInt32 nrLinha, out SqlString dsTexto){var ArquivoLer = (ArquivoLer)objArquivoLer;nrLinha = ArquivoLer.Nr_Linha;dsTexto = ArquivoLer.Ds_Texto;}} - Este tipo de objeto é provavelmente o mais trabalhoso de se criar no CLR, uma vez que o seu resultado é uma tabela e para preencher essa tabela, precisamos criar uma classe com os sets/gets com os dados que serão retornados, definir a saída dos dados para o banco e a programação para popular/calcular os dados.
string ou SqlString?
Clique aqui para visualizarExemplos:
o tipo SqlString possui o método de verificação IsNull, para determinar se foi passado por parâmetro um valor NULL. Essa verificação é mais rápida do que usar a string.IsNullOrEmpty. Entretanto, utilizando uma variável string como parâmetro, se a função ou SP for chamada com valor NULL, ela será executada normalmente, sendo tratada ou não futuramente no seu código-fonte. Caso você informe uma valor NULL para uma variável do tipo SqlString e você não tenha feito o tratamento utilizando o método variavel.IsNull, ao recuperar o valor informado utilizando o atributo variavel.Value ou o método variavel.ToString(), será gerada uma exceção de ERRO na sua rotina.
Outro exemplo legal pra ilustrar a diferença é entre o DateTime e o SqlDateTime. Se você passar uma data NULL para o DateTime, será gerado uma exceção de ERRO na sua rotina. Esse tipo de dados não aceita NULL. Caso você precise utilizar algo assim, deverá utilizar os método MinValue (1/1/0001 12:00:00 AM) ou MaxValue (31/12/9999 23:59:59). Já o tipo de dado SqlDateTime aceita valores nulos e possui o método variavel.Null para definir valores nulos.
Minha recomendação é utilizar sempre os tipos de dados para banco de dados (SqlString, SqlInt32, etc) e lembrar SEMPRE de realizar os tratamentos necessários (principalmente o variavel.IsNull).
Qual versão do .NET Framework devo utilizar?
Clique aqui para visualizar– SQL Server 2005: Você só pode utilizar o .NET Framework 1.0 e 2.0
– SQL Server 2008: Suporta até o .NET Framework 3.5
– SQL Server 2012 e 2014: Suportam até o .NET Framework 4.6.1
Você pode definir a versão do .NET Framework ao criar o projeto ou clicando com o botão direito sobre o projeto do Class Library e selecionado a opção “Properties”. Você precisa fazer o mesmo procedimento para o projeto CLR também, que ainda te dá a possibilidade de definir a versão do banco de dados:
Compilando seu projeto e publicando no banco de dados
Clique aqui para visualizarUma vez que o database foi criado, clique com o botão direito no projeto CLR e selecione a opção “Publish…”. Os botões “Build” e “Rebuild” servem para apenas compilar o código-fonte e já validar se existem erros de sintaxe no fonte, enquanto o botão “Clean” elimina os arquivos gerados e o cache do Visual Studio.
Na tela que será aberta, você deve clicar no botão “Edit…” para digitar o servidor e a forma de conexão com o banco de dados.
Você pode criar/carregar perfis para facilitar a publicação em mais de um ambiente. O botão “Generate Scripts” irá gerar um script SQL, que deve ser executado pelo SQLCMD para publicação do CLR e o botão “Publish” irá gerar o script e já executar no banco de dados.
Nível de permissão do assembly
No SQLCLR, existem 3 níveis de permissões dos assemblies criados:
- SAFE: Os métodos do assembly podem fazer mais que os métodos Transact-SQL com a mesma lógica e são executados com as credenciais do usuário que chamou
- EXTERNAL ACCESS: Os métodos podem realizar operações de manipulação de arquivos e I/O pela rede. Os métodos são executados utilizando o service account do SQL Server, herdando seus privilégios do Active Directory
- UNSAFE / UNRESTRICTED: Estende os privilégios do EXTERNAL ACCESS, permitindo o CLR a executar comandos sem qualquer restrição
Caso o assembly necessite de utilizar os níveis de permissão EXTERNAL ACCESS ou UNRESTRICTED, será necessário definir o database em que ele será publicado como TRUSTWORTY:
1 |
ALTER DATABASE [Nome_do_Database] SET TRUSTWORTHY ON |
Permissões necessárias para compilar o CLR
Para que um usuário tenha permissão para publicar um CLR no database, ele precisará atender a um dos requisitos abaixo:
- Membro da role sysadmin
- Caso o nível de permissão do assembly seja SAFE, o usuário necessitará da permissão CREATE ASSEMBLY e DROP ASSEMBLY
- Caso o nível de permissão do assembly seja EXTERNAL ACCESS, o usuário necessitará da permissão CREATE ASSEMBLY, DROP ASSEMBLY e EXTERNAL ACCESS ASSEMBLY
- Caso o nível de permissão do assembly seja UNRESTRICTED, o usuário necessitará da permissão CREATE ASSEMBLY, DROP ASSEMBLY e UNSAFE ASSEMBLY
Resultado final:
Restrições em assemblies: DLL’s Suportadas e Não Suportadas
Clique aqui para visualizarAtributos personalizados não permitidos
Assemblies não podem ser anotados com os seguintes atributos personalizados:
– System.ContextStaticAttribute
– System.MTAThreadAttribute
– System.Runtime.CompilerServices.MethodImplAttribute
– System.Runtime.CompilerServices.CompilationRelaxationsAttribute
– System.Runtime.Remoting.Contexts.ContextAttribute
– System.Runtime.Remoting.Contexts.SynchronizationAttribute
– System.Runtime.InteropServices.DllImportAttribute
– System.Security.Permissions.CodeAccessSecurityAttribute
– System.STAThreadAttribute
– System.ThreadStaticAttribute
Adicionalmente, não podem ser anotados assemblies SAFE e EXTERNAL_ACCESS com os seguintes atributos personalizados:
– System.Security.SuppressUnmanagedCodeSecurityAttribute
– System.Security.UnverifiableCodeAttribute
APIs não permitidas do .NET Framework
Qualquer Microsoft .NET Framework API anotada com uma das proibições HostProtectionAttributes não pode ser chamada dos assemblies SAFE e EXTERNAL_ACCESS.
– eSelfAffectingProcessMgmt
– eSelfAffectingThreading
– eSynchronization
– eSharedState
– eExternalProcessMgmt
– eExternalThreading
– eSecurityInfrastructure
– eMayLeakOnAbort
– eUI
Assemblies .NET Framework suportados
Qualquer assembly referenciado por seu assembly personalizado deve ser carregado no SQL Server usando CREATE ASSEMBLY. Os seguintes assemblies do .NET Framework já estão carregados no SQL Server e, portanto, podem ser consultados por assemblies personalizados sem ter que usar CREATE ASSEMBLY.
– CustomMarshalers.dll
– Microsoft.VisualBasic.dll
– Microsoft.VisualC.dll
– mscorlib.dll
– System.dll
– System.Configuration
– System.Core.dll (suportado a partir do SQL Server 2008)
– System.Data.dll
– System.Data.OracleClient
– System.Data.SqlXml.dll
– System.Deployment
– System.Security.dll
– System.Transactions
– System.Web.Services.dll
– System.Xml.dll
– System.Xml.Linq.dll (suportado a partir do SQL Server 2008)
Views e SP’s do Catálogo
Clique aqui para visualizar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
-- SYS.ASSEMBLIES -- Name, Assembly ID, security and “is_visible” flag SELECT * FROM sys.assemblies -- SYS.ASSEMBLY_FILES -- Assembly ID, name of each file & assembly contents SELECT * FROM sys.assembly_files -- SYS.ASSEMBLY_MODULES -- Sql ObjectID, Assembly ID, name & assembly method SELECT * FROM sys.assembly_modules -- SYS.ASSEMBLY_REFERENCES -- Links between assemblies on Assembly ID SELECT * FROM sys.assembly_references -- SYS.MODULE_ASSEMBLY_USAGES -- Partial duplicate of SYS.ASSEMBLY_MODULES -- Links SQL Object ID to an Assembly ID SELECT * FROM sys.module_assembly_usages -- CLR STORED PROCEDURES SELECT SCHEMA_NAME(sp.schema_id) + '.' + sp.[name] AS [Name], sp.create_date, sp.modify_date, sa.permission_set_desc AS [Access], sp.is_auto_executed FROM sys.procedures AS sp INNER JOIN sys.module_assembly_usages AS sau ON sp.object_id = sau.object_id INNER JOIN sys.assemblies AS sa ON sau.assembly_id = sa.assembly_id WHERE sp.type_desc = N'CLR_STORED_PROCEDURE'; -- CLR TRIGGERS SELECT SCHEMA_NAME(so.schema_id) + '.' + tr.[name] AS [Name], SCHEMA_NAME(so.schema_id) + '.' + OBJECT_NAME(tr.parent_id) AS [Parent], te.type_desc AS [Fired On], te.is_first, te.is_last, tr.create_date, tr.modify_date, sa.permission_set_desc AS [Access], tr.is_disabled, tr.is_not_for_replication, tr.is_instead_of_trigger FROM sys.triggers AS tr INNER JOIN sys.objects AS so ON tr.[object_id] = so.[object_id] INNER JOIN sys.trigger_events AS te ON tr.[object_id] = te.[object_id] INNER JOIN sys.module_assembly_usages AS mau ON tr.object_id = mau.object_id INNER JOIN sys.assemblies AS sa ON mau.assembly_id = sa.assembly_id WHERE tr.type_desc = N'CLR_TRIGGER' -- CLR Scalar Functions SELECT SCHEMA_NAME(so.schema_id) + N'.' + so.[name] AS [Name], so.create_date, so.modify_date, sa.permission_set_desc AS [Access] FROM sys.objects AS so INNER JOIN sys.module_assembly_usages AS sau ON so.object_id = sau.object_id INNER JOIN sys.assemblies AS sa ON sau.assembly_id = sa.assembly_id WHERE so.type_desc = N'CLR_SCALAR_FUNCTION' -- CLR Table-valued Functions SELECT SCHEMA_NAME(so.schema_id) + N'.' + so.[name] AS [Name], so.create_date, so.modify_date, sa.permission_set_desc AS [Access] FROM sys.objects AS so INNER JOIN sys.module_assembly_usages AS sau ON so.object_id = sau.object_id INNER JOIN sys.assemblies AS sa ON sau.assembly_id = sa.assembly_id WHERE so.type_desc = N'CLR_TABLE_VALUED_FUNCTION' -- CLR Aggregate Function SELECT SCHEMA_NAME(so.schema_id) + N'.' + so.[name] AS [Name], so.create_date, so.modify_date, sa.permission_set_desc AS [Access] FROM sys.objects AS so INNER JOIN sys.module_assembly_usages AS mau ON so.object_id = mau.object_id INNER JOIN sys.assemblies AS sa ON mau.assembly_id = sa.assembly_id WHERE so.type_desc = N'AGGREGATE_FUNCTION' EXEC sys.sp_assemblies_rowset N'<AssemblyName>' EXEC sys.sp_assembly_dependencies_rowset <AssemblyID> |
Vídeo – Introdução ao SQLCLR
Quer conversar com a gente sobre SQLCLR?
– Telegram: https://t.me/sqlclr
– Whatsapp: https://chat.whatsapp.com/71JS49CiD12Ct6pR3fjfLu
And that's it, folks!
Até o próximo post!
CLR SQL Server SQLCLR como ativar habilitar como usar how to active enable como criar sp como criar procedure como programar como começar introdução iniciando por onde começar how to code coding programming procedures table-valued functions scalar c# csharp programação banco de dados database programming
CLR SQL Server SQLCLR como ativar habilitar como usar how to active enable como criar sp como criar procedure como programar como começar introdução iniciando por onde começar how to code coding programming procedures table-valued functions scalar c# csharp programação banco de dados database programming
Bom dia,
Excelente explicação. Seria possível fazer conexão com Rest API? Onde podemos encontrar mais documentação.
Obrigado
Vc ja se deparou com o cenario em que se tem base de dados no sas e foi utilizado o clr no sql server para ter acesso as tabelas do SAS? Caso positivo, poderia me dar detalhes?
O artigo é excelente e muito valioso porém atualmente muitas pessoas estão enfrentando problemas na configuração de acesso do usuário. Você teria mais detalhes atualizados para conceder os acessos assembles?
Links:
https://sqlquantumleap.com/2018/02/23/sqlclr-vs-sql-server-2012-2014-2016-part-7-clr-strict-security-the-problem-continues-in-the-past-wait-what/
https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/clr-strict-security?view=sql-server-2017
Vou criar um post específico de segurança do SQLCLR. Aguarde.. rs
Dirceu pode me ajudar. Eu criei uma trigger simples(via clr) que ao inserir dados na tabela no banco ele chama um WS. para consultar essa tabela. porem ao inserir ele gera esse erro.
Mensagem 6522, Nível 16, Estado 1, Procedimento Trg_ChamaWS, Linha 1
Erro do .NET Framework durante a execução de rotina definida pelo usuário ou agregação “Trg_ChamaWS”:
System.InvalidOperationException: Não é possível carregar o conjunto de módulos de serialização gerado dinamicamente. Em alguns ambientes de hospedagem, a funcionalidade de carregamento de conjuntos de módulos é restrita. Considere o uso do serializador pré-gerado. Consulte a exceção interna para obter mais informações. —> System.IO.FileLoadException: LoadFrom(), LoadFile(), Load(byte[]) e LoadModule() foram desabilitados pelo host.
System.IO.FileLoadException:
em System.Reflection.Assembly.nLoadImage(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence evidence, StackCrawlMark& stackMark, Boolean fIntrospection)
em System.Reflection.Assembly.Load(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence securityEvidence)
em Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames)
em Microsoft.CSharp.CSharpCodeGenerator.FromSourceBatch(CompilerParameters options, String[] sources)
em Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSo
…
System.InvalidOperationException:
em System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
em System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
em System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
em System.Xml.Serialization.XmlSerializer.GetSerializersFromCache(XmlMapping[] mappings, Type type)
em System.Xml.Serialization.XmlSerializer.FromMappings(XmlMapping[] mappings, Type type)
em System.Web.Services.Protocols.SoapClientType..ctor(Type type)
em System.Web.Services.Protocols.SoapHttpClientPr…
A instrução foi finalizada.
Dirceu, suas explicações e exemplos tem me sido de grande utilidade, você pode, por gentileza produzir algum exemplo de FTP usando CLR? Desde já agradeço a sua boa vontade.
Oi Luciano, boa noite. Esse será meu próximo post.
Olá Dirceu. Segui as instruções mas na hora da publicação dava o erro abaixo, gerei o script e alterei o TRUSTWORTHY para on, Mesmo assim apenas o assembly bibilotecas foi gerado mas as procedures não, você pode me orientar em como resolver isso. Grato.
reating [Bibliotecas]…
(47,1): SQL72014: .Net SqlClient Data Provider: Msg 10327, Level 14, State 1, Line 1 Falha em CREATE ASSEMBLY do assembly ‘Bibliotecas’ porque o assembly ‘Bibliotecas’ não está autorizado para PERMISSION_SET = UNSAFE. O assembly é autorizado quando uma das seguintes condições é verdadeira: o proprietário do banco de dados (DBO) possui permissão UNSAFE ASSEMBLY e a propriedade TRUSTWORTHY está ativada no banco de dados; ou o assembly está assinado com uma chave assimétrica ou de certificado que possui um logon correspondente com permissão UNSAFE ASSEMBLY.
(47,0): SQL72045: Script execution error. The executed script:
CREATE ASSEMBLY [Bibliotecas]
AUTHORIZATION [dbo]
FROM 0x4D5A9000030…
An error occurred while the batch was being executed.
Ótima introdução ao SQL CLR!
Artigo muito bem organizado!
Parabéns!
Obrigado pelo feedback e espero ter ajudado 🙂
Excelente explicação e intro ao CLR, Dirceu.
Parabéns!