Domanda

Utilizzo ADO.NET per accedere a SQL Server 2005 e vorrei poter accedere dall'interno delle procedure memorizzate T-SQL che sto chiamando.È in qualche modo possibile?

Non riesco a vedere l'output dall'istruzione 'print' quando utilizzo ADO.NET e poiché desidero utilizzare la registrazione solo per il debug, la soluzione ideale sarebbe emettere messaggi su DebugView da SysInternals.

È stato utile?

Soluzione

Ho risolto questo problema scrivendo una procedura SQLCLR come suggerito da Eric Z Beard.L'assembly deve essere firmato con un file di chiavi con nome sicuro.

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

Creata una chiave e un login:

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  

Importato in 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

Quindi sono stato in grado di accedere alle procedure T-SQL utilizzando

exec Debug @message = 'Hello World'

Altri suggerimenti

Penso che scrivere su una tabella di registro sarebbe la mia preferenza.

In alternativa, poiché stai utilizzando 2005, potresti scrivere una semplice procedura SQLCLR per racchiudere EventLog.

Oppure potresti usare xp_logevent se vuoi scrivere nel log SQL

È possibile accedere a una tabella semplicemente inserendo una nuova riga oppure implementare una procedura memorizzata CLR per scrivere su un file.

Fai attenzione quando scrivi su una tabella, perché se l'azione avviene in una transazione e la transazione viene annullata, la tua voce di registro scomparirà.

La registrazione dall'interno di uno sproc SQL sarebbe meglio eseguita sul database stesso.T-SQL può scrivere su file ma non è realmente progettato per questo.

C'è il STAMPA comando, ma preferisco accedere a una tabella in modo da poterla interrogare.

È possibile scrivere righe in una tabella di log dall'interno di una procedura memorizzata.Come altri hanno indicato, potresti fare di tutto per scrivere su qualche file di testo o altro registro con CLR o xp_logevent, ma sembra che tu abbia bisogno di più volume di quanto sarebbe pratico per tali usi.

I casi difficili si verificano (e sono questi per i quali hai davvero bisogno del registro) quando le transazioni falliscono.Poiché qualsiasi registrazione avvenuta durante queste transazioni verrà annullata insieme alla transazione di cui fanno parte, è meglio disporre di un'API di registrazione che i tuoi clienti possano utilizzare per registrare gli errori.Può trattarsi di un semplice DAL che accede allo stesso database o a uno condiviso.

Per quello che vale, ho scoperto che quando non assegno un gestore InfoMessage al mio SqlConnection:

sqlConnection.InfoMessage += new SqlInfoMessageEventHandler(MySqlConnectionInfoMessageHandler);

dove la firma di InfoMessageHandler assomiglia a questa:

MySqlConnectionInfoMessageHandler(object sender, SqlInfoMessageEventArgs e)

quindi le mie istruzioni PRINT nei miei Stored Procs non vengono visualizzate in DbgView.

È possibile utilizzare variabili di output per restituire i messaggi, ma ciò si basa sull'esecuzione del processo senza errori.

create procedure usp_LoggableProc 

@log varchar(max) OUTPUT 

as

-- T-SQL statement here ...

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

E poi nel tuo codice ADO da qualche parte:

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

Puoi utilizzare raiserror per creare i tuoi errori personalizzati con le informazioni di cui hai bisogno e che saranno disponibili tramite la consueta raccolta SqlException Errors nel tuo codice ADO:

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

Hmmm ma sì, non posso fare a meno di sentirmi solo per il debug e nella tua situazione, basta inserire i messaggi varchar in una tabella di errore come gli altri hanno suggerito e selezionare * da essa durante il debug.

Potresti voler controllare Log4TSQL.Fornisce la registrazione del database per procedure memorizzate e trigger in SQL Server 2005-2008.Hai la possibilità di impostare livelli di log separati e indipendenti in base alla procedura/trigger.

- Il seguente DDL SQL ti creerà la tabella per archiviare i dati di registro Utilizzo [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>      
*/  
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top