OlĂ¡ pessoal,
Bom dia!
Neste post eu gostaria de demonstrar para vocĂªs, jĂ¡ que estou (e pretendo continuar) postando vĂ¡rias coisas legais sobre o CLR, como enviar avisos (PRINT) e mensagens de erro (RAISEERROR) para o SQL Server quando suas Stored Procedures compiladas no CLR sĂ£o executadas.
Apesar do post ser pequeno, resolvi criar um post sĂ³ com isso, porque utilizo muito essa classe nas SP’s que vou publicar aqui futuramente, entĂ£o entendo que seja mais fĂ¡cil criar essa referĂªncia do que repostar essa classe vĂ¡rias vezes.
CĂ³digo fonte do arquivo Servidor.cs (prĂ©-requisito)
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 |
using System; using System.Collections.Generic; using System.Data.SqlClient; namespace Bibliotecas.Model { public class ServidorAtual { public string NomeServidor { get; set; } public ServidorAtual() { try { using (var conn = new SqlConnection(Servidor.Context)) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT @@SERVERNAME AS InstanceName"; NomeServidor = (string) cmd.ExecuteScalar(); } var partes = NomeServidor.Split('\\'); if (partes.Length <= 1) return; if (string.Equals(partes[0], partes[1], StringComparison.CurrentCultureIgnoreCase)) NomeServidor = partes[0]; } } catch (Exception ex) { throw ex; } } } public static class Servidor { public static string Ds_Usuario => "Usuario"; public static string Ds_Senha => "Senha"; public static string PRODUCAO => "data source=PRODUCAO;initial catalog=CLR;persist security info=False;Enlist=False;packet size=4096;user id='" + Ds_Usuario + "';password='" + Ds_Senha + "'"; public static string Context => "context connection=true"; public static string Localhost => "data source=LOCALHOST;initial catalog=CLR;persist security info=False;Enlist=False;packet size=4096;user id='" + Ds_Usuario + "';password='" + Ds_Senha + "'"; public static string getLocalhost() { var servidorAtual = new ServidorAtual().NomeServidor; return "data source=" + servidorAtual + ";initial catalog=CLR;persist security info=False;Enlist=False;packet size=4096;user id='" + Ds_Usuario + "';password='" + Ds_Senha + "'"; } public static List<string> Servidores { get { var servidores = new List<string> { PRODUCAO, Localhost }; return servidores; } } } } |
CĂ³digo-fonte da classe Retorno:
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 |
using System; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using Microsoft.SqlServer.Server; namespace Bibliotecas.Model { public static class Retorno { public static void Erro(string erro) { /* IF (OBJECT_ID('CLR.dbo.Log_Erro') IS NOT NULL) DROP TABLE CLR.dbo.Log_Erro CREATE TABLE CLR.dbo.Log_Erro ( Id_Erro INT IDENTITY(1,1), Dt_Erro DATETIME DEFAULT GETDATE(), Nm_Objeto VARCHAR(100), Ds_Erro VARCHAR(MAX), CONSTRAINT [PK_Log_Erro] PRIMARY KEY CLUSTERED (Id_Erro) ) */ using (var conexao = new SqlConnection(Servidor.getLocalhost())) { var comando = new SqlCommand("INSERT INTO dbo.Log_Erro (Nm_Objeto, Ds_Erro) VALUES (@Nm_Objeto, @Ds_Erro)", conexao); var stackTrace = new StackTrace(); var objeto = stackTrace.GetFrame(1).GetMethod().Name; comando.Parameters.Add(new SqlParameter("@Nm_Objeto", SqlDbType.VarChar, 100)).Value = objeto; comando.Parameters.Add(new SqlParameter("@Ds_Erro", SqlDbType.VarChar, 8000)).Value = erro; conexao.Open(); comando.ExecuteNonQuery(); } throw new ApplicationException(erro); } public static void Mensagem(string mensagem) { using (var conexao = new SqlConnection(Servidor.Context)) { var Comando = new SqlCommand("IF ( (512 & @@OPTIONS) = 512 ) select 1 else select 0", conexao); conexao.Open(); if ((int) Comando.ExecuteScalar() != 0) return; var retorno = SqlContext.Pipe; retorno?.Send(mensagem.Length > 4000 ? mensagem.Substring(0, 4000) : mensagem); } } public static void RetornaReader(SqlDataReader dataReader) { var retorno = SqlContext.Pipe; retorno?.Send(dataReader); } } public class Ret : Exception { public Ret(string str) : base(str) { } } } |
Uma vez que essa classe criada no seu projeto CLR, basta importĂ¡-la na sua Stored Procedure e começar a enviar avisos e mensagens de erro, como vou demonstrar abaixo:
SimulaĂ§Ă£o de um erro num mĂ©todo do CLR:
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 |
using Bibliotecas.Model; using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; public partial class StoredProcedures { [Microsoft.SqlServer.Server.SqlProcedure] public static void stpTeste(SqlString Ds_String) { try { if (Ds_String.Value == "ERRO") { // Vou forçar um erro ao tentar inserir dados em uma tabela que nĂ£o existe, causando uma Exception using (var Conexao = new SqlConnection(Servidor.Localhost)) { var Comando = new SqlCommand("INSERT INTO dbo.Erro (Nm_Objeto, Ds_Erro) VALUES (@Nm_Objeto, @Ds_Erro)", Conexao); Comando.Parameters.Add(new SqlParameter("@Nm_Objeto", SqlDbType.VarChar, 100)).Value = "Vai dar erro"; Comando.Parameters.Add(new SqlParameter("@Ds_Erro", SqlDbType.VarChar, 8000)).Value = "DescriĂ§Ă£o do Erro"; Conexao.Open(); Comando.ExecuteNonQuery(); } } Retorno.Mensagem("Alerta enviado para o banco (PRINT)"); } catch(Exception e) { Retorno.Erro("Mensagem de erro (RAISEERROR) gravada. DescriĂ§Ă£o do erro: " + e.Message); } } } |
Consultando o histĂ³rico de erros:
Como vocĂªs devem ter reparado, no mĂ©todo de erro eu coloquei uma instruĂ§Ă£o SQL para gravar o histĂ³rico de quando esse mĂ©todo Ă© chamado, fazendo com que se tenha um log de erros do CLR, facilitando a localizaĂ§Ă£o de possĂveis problemas nas suas procedures CLR.
É isso aĂ, pessoal!
Qualquer dĂºvida, deixem aqui nos comentĂ¡rios.
Abraço.
sql server clr c# csharp enviar avisos mensagens de erro warnings send text print error messages
sql server clr c# csharp enviar avisos mensagens de erro warnings send text print error messages
Bom dia, nĂ£o reconhece o SqlProcedure do [Microsoft.SqlServer.Server.SqlProcedure]. Sabe o que poderia ser ?
Oi Denis,
Beleza ?
VocĂª tem que adicionar referĂªncias a System e System.Data no seu projeto.
Abraço!
No arquivo Servidor.cs, devemos informar o usuario e senha, correto ?
Mesmo informando recebo o erro abaixo:
Erro do .NET Framework durante a execuĂ§Ă£o de rotina definida pelo usuĂ¡rio ou agregaĂ§Ă£o “stpTeste”:
System.Data.SqlClient.SqlException: Falha de logon do usuĂ¡rio ‘leonardo’.
System.Data.SqlClient.SqlException:
em System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
em System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
em System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
em System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
em System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnection owningObject)
em System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(String host, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, Int64 timerStart)
em System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance)
em System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance)
em System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection)
em System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options)
em System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
em System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject…
Me chama no privado pra tentar entender o que estĂ¡ acontecendo
bom dia Estou tentano executar o codigo acima porem estou com um dificuldade poderia me ajudar por favor
ao tentar executar esta informando o seguinte erro na Linha 29 do Codigo
Severity Code Description
Error CS0103 The name ‘Servidor’ does not exist in the current context
Gustavo, bom dia.
Analisei o que vocĂª me falou, e realmente eu esqueci de colocar o cĂ³digo do arquivo Servidor.cs, que vocĂª deve importar para o seu projeto, uma vez que a classe Retorno o referencia. JĂ¡ editei o post e adicionei o cĂ³digo-fonte desse arquivo lĂ¡.
Obrigado!