Pregunta

Estoy usando ADO.NET para acceder a SQL Server 2005 y me gustaría poder iniciar sesión desde dentro de los procedimientos almacenados de T-SQL a los que estoy llamando.¿Es eso posible de alguna manera?

No puedo ver el resultado de la declaración 'imprimir' cuando uso ADO.NET y como quiero usar el registro solo para depurar, la solución ideal sería emitir mensajes a DebugView desde SysInternals.

¿Fue útil?

Solución

Resolví esto escribiendo un procedimiento SQLCLR como sugirió Eric Z Beard.El ensamblado debe firmarse con un archivo de clave de nombre seguro.

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

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static int Debug(string s)
    {
        System.Diagnostics.Debug.WriteLine(s);
            return 0;
        }
    }
}

Creó una clave y un inicio de sesión:

USE [master]
CREATE ASYMMETRIC KEY DebugProcKey FROM EXECUTABLE FILE =
'C:\..\SqlServerProject1\bin\Debug\SqlServerProject1.dll'

CREATE LOGIN DebugProcLogin FROM ASYMMETRIC KEY DebugProcKey 

GRANT UNSAFE ASSEMBLY TO DebugProcLogin  

Lo importé a SQL Server:

USE [mydb]
CREATE ASSEMBLY SqlServerProject1 FROM
'C:\..\SqlServerProject1\bin\Debug\SqlServerProject1.dll' 
WITH PERMISSION_SET = unsafe

CREATE FUNCTION dbo.Debug( @message as nvarchar(200) )
RETURNS int
AS EXTERNAL NAME SqlServerProject1.[StoredProcedures].Debug

Luego pude iniciar sesión en los procedimientos T-SQL usando

exec Debug @message = 'Hello World'

Otros consejos

Creo que mi preferencia sería escribir en una tabla de registro.

Alternativamente, como está utilizando 2005, puede escribir un procedimiento SQLCLR simple para ajustar el EventLog.

O podrías usar xp_logevent si quisieras escribir en el registro SQL

Puede iniciar sesión en una tabla simplemente insertando una nueva fila o puede implementar un procedimiento almacenado CLR para escribir en un archivo.

Tenga cuidado al escribir en una tabla, porque si la acción ocurre en una transacción y la transacción se revierte, su entrada de registro desaparecerá.

Sería mejor iniciar sesión desde dentro de un proceso SQL en la propia base de datos.T-SQL puede escribir en archivos pero en realidad no está diseñado para ello.

Ahí está el IMPRIMIR comando, pero prefiero iniciar sesión en una tabla para que puedas consultarla.

Puede escribir filas en una tabla de registro desde un procedimiento almacenado.Como han indicado otros, podría hacer todo lo posible para escribir en algún archivo de texto u otro registro con CLR o xp_logevent, pero parece que necesita más volumen del que sería práctico para tales usos.

Los casos difíciles ocurren (y es en estos para los que realmente necesita su registro) cuando las transacciones fallan.Dado que cualquier registro que se produzca durante estas transacciones se revertirá junto con la transacción de la que forman parte, es mejor tener una API de registro que sus clientes puedan usar para registrar errores.Puede ser un DAL simple que se registra en la misma base de datos o en una compartida.

Por si sirve de algo, descubrí que cuando no asigno un controlador de InfoMessage a mi SqlConnection:

sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);

donde la firma de InfoMessageHandler se ve así:

MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)

entonces mis declaraciones PRINT en mis procesos almacenados no aparecen en DbgView.

Podría usar variables de salida para devolver mensajes, pero eso depende de que el proceso se ejecute sin errores.

create procedure usp_LoggableProc 

@log varchar(max) OUTPUT 

as

-- T-SQL statement here ...

select @log = @log + 'X is foo'

Y luego en tu código ADO algo así:

string log = (string)SqlCommand.Parameters["@log"].Value;

Puede utilizar riserror para crear sus propios errores personalizados con la información que necesita y que estará disponible a través de la colección habitual de errores SqlException en su código ADO:

RAISERROR('X is Foo', 10, 1)

Hmmm, pero sí, no puedo evitar sentir que solo necesito depurar y, en su situación, simplemente inserte mensajes varchar en una tabla de error como los demás han sugerido y seleccione * cuando esté depurando.

Quizás quieras comprobar Log4TSQL.Proporciona registro de bases de datos para procedimientos almacenados y activadores en SQL Server 2005 - 2008.Tiene la posibilidad de establecer niveles de registro separados e independientes según el procedimiento/activador.

- El siguiente DDL SQL le creará la tabla para almacenar el uso de datos de registro [DB] GO

/****** Object:  Table [dbo].[tbData_Debug]    Script Date: 02/12/2009 22:30:03 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[tbData_Debug](
    [colTimeStamp] [timestamp] NULL,
    [colNiceTime] [varchar](200) NULL,
    [colDomain_User] [varchar](200) NULL,
    [colMsg] [varchar](4000) NULL,
    [colDebugLevel] [int] NULL,
    [colDebugMsg] [varchar](4000) NULL,
    [colPageName] [varchar](200) NULL,
    [colClassName] [varchar](200) NULL,
    [colMethodName] [varchar](200) NULL,
    [colMethodNameGui] [varchar](4000) NULL,
    [colRet] [int] NULL,
    [colLineNumber] [int] NULL,
    [colLineNumberGui] [int] NULL,
    [colProcedureName] [varchar](200) NULL,
    [colProcedureStep] [varchar](4000) NULL
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO




-- This stored procedure does write to the log table

USE [db]
GO
/****** Object:  StoredProcedure [dbo].[procUtils_AppDebug]    Script Date: 02/12/2009 22:29:24 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[procUtils_AppDebug] (                  

@ret int = null OUT,     
@msgIn varchar(4000) = null ,   -- the msg which the user has seen   
@msgOut varchar(4000) = null OUT ,   -- the msg which the user has seen   
@domain_user varchar(200) = null ,                 -- the domain user echoing the message  
@debugMsgIn varchar(4000) = null  ,   -- the debug msg for internal use  
@debugMsgOut varchar(4000) = null  OUT,   -- the debug msg for internal use  
@pageName varchar(200) = null ,   -- the pageName originator of error  
@className varchar(200) = null ,   -- the class Name orinator of error  
@methodName varchar(200) = null ,   -- the methodName where the last error occured  
@methodNameGui varchar(4000) = null ,   -- the methodNameOfTheGui where the last error occured  
@lineNumber int = null ,  -- the line number of the line issueing the error  
@lineNumberGui int = null,   -- the line number of the line issueing the error               
@procedureName varchar(200) = null , -- the procedureName currently envoked
@procedureStep varchar(4000)  = null -- the steps of the procedure concatenated
)    

AS                  
BEGIN -- proc start                
 SET NOCOUNT ON;                

BEGIN TRY        --begin try      

declare @debugLevel int     
select @debugLevel =  Debug_Level from User_tb where Domain_Name = @domain_user  

/*                  
select * from tbData_Debug    order by 1 desc              
delete from tbData_Debug              
*/    


insert into tbData_Debug ( colNiceTime , colDomain_User , colMsg , colDebugLevel ,   
colDebugMsg , colPageName , colClassName , colMethodName , colMethodNameGui ,   
colRet , colLineNumber , colLineNumberGui , colProcedureName , colProcedureStep) values (
 dbo.funcGetNiceTime() , @domain_user  , @msgIn , @debugLevel ,@debugMsgIn , 
 @pageName , @className , @methodName  ,@MethodNameGui , @ret , 
 @lineNumber , @lineNumberGui , @procedureName , @procedureStep)     

set @debugMsgOut = @debugMsgIn  
set @msgOut = 'Action Registered'  
set @ret = @@ERROR     
return @ret                



END TRY        --end try      

BEGIN CATCH            
 PRINT 'In CATCH block.             
 Error number: ' + CAST(ERROR_NUMBER() AS varchar(10)) + '            
 Error message: ' + ERROR_MESSAGE() + '            
 Error severity: ' + CAST(ERROR_SEVERITY() AS varchar(10)) + '            
 Error state: ' + CAST(ERROR_STATE() AS varchar(10)) + '            
 XACT_STATE: ' + CAST(XACT_STATE() AS varchar(10));            

 set  @debugMsgOut = 'error at [procUtils_AppDebug]--- Error number: ' + CAST(ERROR_NUMBER() AS varchar(10)) + 'Error message: ' + ERROR_MESSAGE() + 'Error severity: ' +   
CAST(ERROR_SEVERITY() AS varchar(10)) + 'Error state: ' + CAST(ERROR_STATE() AS varchar(10)) + 'XACT_STATE: ' + CAST(XACT_STATE() AS varchar(10))            
set @msgIn= 'error while saving application error info into database'  
insert into tbData_Debug ( colMsg ) values ( @msgIn )     

set @debugMsgOut = @debugMsgIn +  @debugMsgOut  
set @msgOut = 'Action Registration failed'  
set @ret = 1           

END CATCH            


return  @ret                       
END --procedure end                 

/*       
<procedureDocumentation>      

<procedurename>procUtils_AppDebug<procedurename>      
<procedureDescription> Records events from the Application Layer </procedureDescription>    
<created>20090121</created>      
<createdby>Yordan Georgiev</createdby>      
<change>      

<changewhen><changewhen>      
<changeDescription></changeDescription>      
<changedBy></changedBy>      
</change>      


<testUsage>    

USE [db]    
GO    

DECLARE @return_value int,    
  @ret int,    
  @msgIn varchar(max),    
  @debugmsg varchar(4000)    

SELECT @ret = 1    
SELECT @msgIn = N'msg'    
SELECT @debugmsg = N'before'    

EXEC @return_value = [dbo].[procUtils_AppDebug]    
  @ret = @ret OUTPUT,    
  @msgIn = @msgIn OUTPUT,    
  @domain_user = N'domain_user',    
  @debugmsg = @debugmsg OUTPUT,    

  @methodName = N'methodName'    

SELECT @ret as N'@ret',    
  @msgIn as N'@msgIn',    
  @debugmsg as N'@debugmsg'    

SELECT 'Return Value' = @return_value    
select * from tbData_Debug order by 1 desc    
GO    

</testUsage>      
</procedureDocumentation>      
*/  
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top