Aggiunta di supporto per il debug in un'attività personalizzataAdding Support for Debugging in a Custom Task

Il motore di runtime di Integration ServicesIntegration Services consente la sospensione di pacchetti, attività e altri tipi di contenitori durante l'esecuzione tramite l'utilizzo di punti di interruzione.The Integration ServicesIntegration Services run-time engine enables packages, tasks, and other types of containers to be suspended during execution by using breakpoints. L'utilizzo di punti di interruzione consente di rivedere e correggere gli errori che impediscono la corretta esecuzione dell'applicazione o delle attività.The use of breakpoints lets you review and correct errors that prevent your application or tasks from running correctly. L'architettura dei punti di interruzione consente al client di valutare il valore di runtime degli oggetti nel pacchetto in determinati punti dell'esecuzione mentre l'elaborazione dell'attività è sospesa.The breakpoint architecture enables the client to evaluate the run-time value of objects in the package at defined points of execution while task processing is suspended.

Gli sviluppatori di attività personalizzate possono utilizzare questa architettura per creare destinazioni di punti di interruzione personalizzati utilizzando l'interfaccia IDTSBreakpointSite e la relativa interfaccia padre IDTSSuspend.Custom task developers can use this architecture to create custom breakpoint targets by using the IDTSBreakpointSite interface, and its parent interface, IDTSSuspend. L'interfaccia IDTSBreakpointSite definisce l'interazione tra il motore di runtime e l'attività per la creazione e la gestione di siti o destinazioni di punti di interruzione personalizzati.The IDTSBreakpointSite interface defines the interaction between the run-time engine and the task for creating and managing custom breakpoint sites or targets. L'interfaccia IDTSSuspend fornisce metodi e proprietà che vengono chiamati dal motore di runtime per notificare all'attività di sospendere o riprendere l'esecuzione.The IDTSSuspend interface provides methods and properties that are called by the run-time engine to notify the task to suspend or resume its execution.

Un sito o una destinazione di punti di interruzione è un punto nell'esecuzione dell'attività in cui l'elaborazione può essere sospesa.A breakpoint site or target is a point in the execution of the task where processing can be suspended. Selezionano gli utenti dai siti di punti di interruzione disponibili nella Imposta punti di interruzione la finestra di dialogo.Users select from available breakpoint sites in the Set Breakpoints dialog box. Ad esempio, oltre alle opzioni predefinite dei punti di interruzione, il contenitore Ciclo Foreach prevede l'opzione "Interrompi all'inizio di ogni iterazione del ciclo".For example, in addition to the default breakpoint options, the Foreach Loop Container offers the "Break at the beginning of every iteration of the loop" option.

Quando un'attività raggiunge la destinazione di un punto di interruzione durante l'esecuzione, la valuta per determinare se il punto di interruzione è abilitato.When a task reaches a breakpoint target during execution, it evaluates the breakpoint target to determine whether a breakpoint is enabled. Ciò indica che l'utente desidera arrestare l'esecuzione in corrispondenza di tale punto di interruzione.This indicates that the user wants execution to stop at that breakpoint. Se il punto di interruzione è abilitato, l'attività genera l'evento OnBreakpointHit per il motore di runtime.If the breakpoint is enabled, the task raises the OnBreakpointHit event to the run-time engine. Il motore di runtime risponde all'evento chiamando il Suspend metodo di ogni attività che è attualmente in esecuzione nel pacchetto.The run-time engine responds to the event by calling the Suspend method of each task that is currently running in the package. L'esecuzione dell'attività riprende quando il runtime chiama il ResumeExecution metodo dell'attività sospesa.Execution of the task resumes when the runtime calls the ResumeExecution method of the suspended task.

Le attività che non utilizzano punti di interruzione devono comunque implementare le interfacce IDTSBreakpointSite e IDTSSuspend.Tasks that do not use breakpoints should still implement the IDTSBreakpointSite and IDTSSuspend interfaces. Ciò assicura che l'attività venga sospesa correttamente quando altri oggetti del pacchetto generano eventi OnBreakpointHit.This ensures that the task is suspended correctly when other objects in the package raise OnBreakpointHit events.

Interfaccia IDTSBreakpointSite e BreakpointManagerIDTSBreakpointSite Interface and BreakpointManager

Le attività creano destinazioni di punti di interruzione chiamando il metodo CreateBreakpointTarget di BreakpointManager, fornendo un ID integer e una stringa descrittiva come parametri.Tasks create breakpoint targets by calling the CreateBreakpointTarget method of the BreakpointManager, providing an integer ID and string description as parameters. Quando l'attività raggiunge il punto del codice che contiene la destinazione del punto di interruzione, la valuta utilizzando il metodo IsBreakpointTargetEnabled per determinare se tale punto di interruzione è abilitato.When the task reaches the point in its code that contains a breakpoint target, it evaluates the breakpoint target by using the IsBreakpointTargetEnabled method to determine whether that breakpoint is enabled. Se true, l'attività di notifica al motore di runtime generando il OnBreakpointHit evento.If true, the task notifies the run-time engine by raising the OnBreakpointHit event.

L'interfaccia IDTSBreakpointSite definisce un singolo metodo, AcceptBreakpointManager, che viene chiamato dal motore di runtime durante la creazione di attività.The IDTSBreakpointSite interface defines a single method, AcceptBreakpointManager, which is called by the run-time engine during task creation. Questo metodo fornisce come parametro l'oggetto BreakpointManager, che viene quindi utilizzato dall'attività per creare e gestire i propri punti di interruzione.This method provides as a parameter the BreakpointManager object, which is then used by the task to create and manage its breakpoints. Le attività devono archiviare il BreakpointManager in locale da utilizzare durante la convalida e Execute metodi.Tasks should store the BreakpointManager locally for use during the Validate and Execute methods.

Nell'esempio di codice seguente viene illustrato come creare una destinazione di punti di interruzione tramite BreakpointManager.The following sample code demonstrates how to create a breakpoint target by using the BreakpointManager. Viene chiamato il metodo OnBreakpointHit per generare l'evento.The sample calls the OnBreakpointHit method to raise the event.

public void AcceptBreakpointManager( BreakpointManager breakPointManager )  
{  
   //   Store the breakpoint manager locally.  
   this.bpm  = breakPointManager;  
}  
public override DTSExecResult Execute( Connections connections,  
  Variables variables, IDTSComponentEvents events,  
  IDTSLogging log, DtsTransaction txn)  
{  
   //   Create a breakpoint.  
   this.bpm.CreateBreakPointTarget( 1 , "A sample breakpoint target." );  
...  
   if( this.bpm.IsBreakpointTargetEnabled( 1 ) == true )  
      events.OnBreakpointHit( this.bpm.GetBreakpointTarget( 1 ) );  
}  
Public Sub AcceptBreakpointManager(ByVal breakPointManager As BreakpointManager)  

   ' Store the breakpoint manager locally.  
   Me.bpm  = breakPointManager  

End Sub  

Public Overrides Function Execute(ByVal connections As Connections, _  
  ByVal variables As Variables, ByVal events As IDTSComponentEvents, _  
  ByVal log As IDTSLogging, ByVal txn As DtsTransaction) As DTSExecResult  

   ' Create a breakpoint.  
   Me.bpm.CreateBreakPointTarget(1 , "A sample breakpoint target.")  

   If Me.bpm.IsBreakpointTargetEnabled(1) = True Then  
      events.OnBreakpointHit(Me.bpm.GetBreakpointTarget(1))  
   End If  

End Function  

Interfaccia IDTSSuspendIDTSSuspend Interface

L'interfaccia IDTSSuspend definisce i metodi che vengono chiamati dal motore di runtime quando sospende o riprende l'esecuzione di un'attività.The IDTSSuspend interface defines the methods that are called by the run-time engine when it pauses or resumes execution of a task. Il IDTSSuspend viene implementata mediante il IDTSBreakpointSite interfaccia e il relativo Suspend e ResumeExecution metodi vengono in genere sottoposti a override dall'attività personalizzata.The IDTSSuspend interface is implemented by the IDTSBreakpointSite interface, and its Suspend and ResumeExecution methods are usually overridden by the custom task. Quando il motore di runtime riceve un OnBreakpointHit evento da un'attività, chiama il Suspend metodo di ogni attività in esecuzione, le attività di sospendere di notifica.When the run-time engine receives an OnBreakpointHit event from a task, it calls the Suspend method of each running task, notifying the tasks to pause. Quando il client riprende l'esecuzione, il motore di runtime chiama il ResumeExecution metodo delle attività che vengono sospesi.When the client resumes execution, the run-time engine calls the ResumeExecution method of the tasks that are suspended.

La sospensione e la ripresa dell'esecuzione di un'attività implica la sospensione e la ripresa del thread di esecuzione dell'attività.Suspending and resuming task execution involves pausing and resuming the task's execution thread. Nel codice gestito, a scopo utilizzare il ManualResetEvent classe System. Threading dello spazio dei nomi di .NET Framework.In managed code, you do this using the ManualResetEvent class in System.Threading namespace of the .NET Framework.

Nell'esempio di codice seguente vengono illustrate la sospensione e la ripresa dell'esecuzione di un'attività.The following code sample demonstrates suspension and resumption of task execution. Si noti che il Execute metodo è stato modificato dal codice di esempio precedente, e il thread di esecuzione viene sospesa quando viene attivato il punto di interruzione.Notice that the Execute method has changed from the previous code sample, and the execution thread is paused when firing the breakpoint.

private ManualResetEvent m_suspended = new ManualResetEvent( true );  
private ManualResetEvent m_canExecute = new ManualResetEvent( true );  
private int   m_suspendRequired = 0;  
private int   m_debugMode = 0;  

public override DTSExecResult Execute( Connections connections, Variables variables, IDTSComponentEvents events, IDTSLogging log, DtsTransaction txn)  
{  
   // While a task is not executing, it is suspended.    
   // Now that we are executing,  
   // change to not suspended.  
   ChangeEvent(m_suspended, false);  

   // Check for a suspend before doing any work,   
   // in case the suspend and execute calls  
   // were initiated at virtually the same time.  
   CheckAndSuspend();  
   CheckAndFireBreakpoint( componentEvents, 1);  
}  
private void CheckAndSuspend()  
{  
   // Loop until we can execute.    
   // The loop is required rather than a simple If  
   // because there is a time between the return from WaitOne and the  
   // reset that we might receive another Suspend call.    
   // Suspend() will see that we are suspended  
   // and return.  So we need to rewait.  
   while (!m_canExecute.WaitOne(0, false))  
   {  
      ChangeEvent(m_suspended, true);  
      m_canExecute.WaitOne();  
      ChangeEvent(m_suspended, false);  
   }  
}  
private void CheckAndFireBreakpoint(IDTSComponentEvents events, int breakpointID)  
{  
   // If the breakpoint is enabled, fire it.  
   if (m_debugMode != 0 &&    this.bpm.IsBreakpointTargetEnabled(breakpointID))  
   {  
      //   Enter a suspend mode before firing the breakpoint.    
      //   Firing the breakpoint will cause the runtime   
      //   to call Suspend on this task.    
      //   Because we are blocked on the breakpoint,   
      //   we are suspended.  
      ChangeEvent(m_suspended, true);  
      events.OnBreakpointHit(this.bpm.GetBreakpointTarget(breakpointID));  
      ChangeEvent(m_suspended, false);  
   }  
   // Check for a suspension for two reasons:   
   //   1. If we are at a point where we could fire a breakpoint,   
   //      we are at a valid suspend point.  Even if we didn't hit a  
   //      breakpoint, the runtime may have called suspend,   
   //      so check for it.       
   //   2. Between the return from OnBreakpointHit   
   //      and the reset of the event, it is possible to have  
   //      received a suspend call from which we returned because   
   //      we were already suspended.  We need to be sure it is okay  
   //      to continue executing now.  
   CheckAndSuspend();  
}  
static void ChangeEvent(ManualResetEvent e, bool shouldSet)  
{  
   bool succeeded;  
   if (shouldSet)  
      succeeded = e.Set();  
   else  
      succeeded = e.Reset();  

   if (!succeeded)  
      throw new Exception("Synchronization object failed.");  

}  
public bool SuspendRequired  
{  
   get   {return m_suspendRequired != 0;}  
   set  
   {  
      // This lock is also taken by Suspend().    
      // Because it is possible for the package to be  
      // suspended and resumed in quick succession,   
      // this property might be set before  
      // the actual Suspend() call.    
      // Without the lock, the Suspend() might reset the canExecute  
      // event after we set it to abort the suspension.  
      lock (this)  
      {  
         Interlocked.Exchange(ref m_suspendRequired, value ? 1 : 0);  
         if (!value)  
            ResumeExecution();  
      }  
   }  
}  
public void ResumeExecution()  
{  
   ChangeEvent( m_canExecute,true );  
}  
public void Suspend()  
{  
   // This lock is also taken by the set SuspendRequired method.    
   // It prevents this call from overriding an   
   // aborted suspension.  See comments in set SuspendRequired.  
   lock (this)  
   {  
      // If a Suspend is required, do it.  
      if (m_suspendRequired != 0)  
         ChangeEvent(m_canExecute, false);  
   }  
   // We can't return from Suspend until the task is "suspended".  
   // This can happen one of two ways:   
   // the m_suspended event occurs, indicating that the execute thread  
   // has suspended, or the canExecute flag is set,   
   // indicating that a suspend is no longer required.  
   WaitHandle [] suspendOperationComplete = {m_suspended, m_canExecute};  
   WaitHandle.WaitAny(suspendOperationComplete);  
}  
Private m_suspended As ManualResetEvent = New ManualResetEvent(True)  
Private m_canExecute As ManualResetEvent = New ManualResetEvent(True)  
Private m_suspendRequired As Integer = 0  
Private m_debugMode As Integer = 0  

Public Overrides Function Execute(ByVal connections As Connections, _  
ByVal variables As Variables, ByVal events As IDTSComponentEvents, _  
ByVal log As IDTSLogging, ByVal txn As DtsTransaction) As DTSExecResult  

   ' While a task is not executing it is suspended.    
   ' Now that we are executing,  
   ' change to not suspended.  
   ChangeEvent(m_suspended, False)  

   ' Check for a suspend before doing any work,   
   ' in case the suspend and execute calls  
   ' were initiated at virtually the same time.  
   CheckAndSuspend()  
   CheckAndFireBreakpoint(componentEvents, 1)  

End Function  

Private Sub CheckAndSuspend()  

   ' Loop until we can execute.    
   ' The loop is required rather than a simple if  
   ' because there is a time between the return from WaitOne and the  
   ' reset that we might receive another Suspend call.    
   ' Suspend() will see that we are suspended  
   ' and return.  So we need to rewait.  
   Do While Not m_canExecute.WaitOne(0, False)  
              ChangeEvent(m_suspended, True)  
              m_canExecute.WaitOne()  
              ChangeEvent(m_suspended, False)  
   Loop  

End Sub  

Private Sub CheckAndFireBreakpoint(ByVal events As IDTSComponentEvents, _  
ByVal breakpointID As Integer)  

   ' If the breakpoint is enabled, fire it.  
   If m_debugMode <> 0 AndAlso Me.bpm.IsBreakpointTargetEnabled(breakpointID) Then  
              '   Enter a suspend mode before firing the breakpoint.    
              '   Firing the breakpoint will cause the runtime   
              '   to call Suspend on this task.    
              '   Because we are blocked on the breakpoint,   
              '   we are suspended.  
              ChangeEvent(m_suspended, True)  
              events.OnBreakpointHit(Me.bpm.GetBreakpointTarget(breakpointID))  
              ChangeEvent(m_suspended, False)  
   End If  

   ' Check for a suspension for two reasons:   
   '   1. If we are at a point where we could fire a breakpoint,   
   '         we are at a valid suspend point.  Even if we didn't hit a  
   '         breakpoint, the runtime may have called suspend,   
   '         so check for it.     
   '   2. Between the return from OnBreakpointHit   
   '         and the reset of the event, it is possible to have  
   '         received a suspend call from which we returned because   
   '         we were already suspended.  We need to be sure it is okay  
   '         to continue executing now.  
   CheckAndSuspend()  

End Sub  

Shared Sub ChangeEvent(ByVal e As ManualResetEvent, ByVal shouldSet As Boolean)  

   Dim succeeded As Boolean  
   If shouldSet Then  
              succeeded = e.Set()  
   Else  
              succeeded = e.Reset()  
   End If  

   If (Not succeeded) Then  
              Throw New Exception("Synchronization object failed.")  
   End If  

End Sub  

Public Property SuspendRequired() As Boolean  
   Get  
               Return m_suspendRequired <> 0  
  End Get  
  Set  
    ' This lock is also taken by Suspend().    
     '   Because it is possible for the package to be  
     '   suspended and resumed in quick succession,   
     '   this property might be set before  
     '   the actual Suspend() call.    
     '   Without the lock, the Suspend() might reset the canExecute  
     '   event after we set it to abort the suspension.  
              SyncLock Me  
                         Interlocked.Exchange(m_suspendRequired,IIf(Value, 1, 0))  
                         If (Not Value) Then  
                                    ResumeExecution()  
                         End If  
              End SyncLock  
   End Set  
End Property  

Public Sub ResumeExecution()  
   ChangeEvent(m_canExecute,True)  
End Sub  

Public Sub Suspend()  

   ' This lock is also taken by the set SuspendRequired method.    
   ' It prevents this call from overriding an   
   ' aborted suspension.  See comments in set SuspendRequired.  
   SyncLock Me  
   ' If a Suspend is required, do it.  
              If m_suspendRequired <> 0 Then  
                         ChangeEvent(m_canExecute, False)  
              End If  
   End SyncLock  
   ' We can't return from Suspend until the task is "suspended".  
   ' This can happen one of two ways:   
   ' the m_suspended event occurs, indicating that the execute thread  
   ' has suspended, or the canExecute flag is set,   
   ' indicating that a suspend is no longer required.  
   Dim suspendOperationComplete As WaitHandle() = {m_suspended, m_canExecute}  
   WaitHandle.WaitAny(suspendOperationComplete)  

End Sub  

Vedere ancheSee Also

Debug del flusso di controlloDebugging Control Flow