Utilisation de sorties d'erreur dans un composant de flux de données

Il est possible d'ajouter des objets IDTSOutput100 spéciaux appelés sorties d'erreur à des composants afin de permettre à un composant de rediriger les lignes qu'il ne parvient pas à traiter pendant l'exécution. Les problèmes qu'un composant peut rencontrer sont en général classés en tant qu'erreurs ou troncations et sont propres à chaque composant. Les composants qui fournissent des sorties d'erreur offrent à leurs utilisateurs la flexibilité de gérer les conditions d'erreur en filtrant les lignes d'erreur du jeu de résultats, en provoquant l'échec du composant lorsqu'un problème se produit ou en ignorant des erreurs afin de continuer.

Pour implémenter et prendre en charge les sorties d'erreur dans un composant, vous devez d'abord attribuer à la propriété UsesDispositions du composant la valeur true. Ensuite, vous devez ajouter une sortie au composant dont la propriété IsErrorOut a pour valeur true. Enfin, le composant doit contenir un code qui redirige les lignes vers la sortie d'erreur lorsque des erreurs ou troncations se produisent. Cette rubrique couvre ces trois étapes et explique les différences entre les sorties d'erreur synchrones et asynchrones.

Création d'une sortie d'erreur

Vous créez une sortie d'erreur en appelant la méthode New de la propriété OutputCollection, puis en attribuant à la propriété IsErrorOut de la nouvelle sortie la valeur true. Si la sortie est asynchrone, vous n'avez rien d'autre à lui faire. Si la sortie est synchrone, et qu'il existe une autre sortie synchrone avec la même entrée, vous devez également définir les propriétés ExclusionGroup et SynchronousInputID. Ces deux propriétés doivent avoir les mêmes valeurs que l'autre sortie synchrone avec la même entrée. Si ces propriétés ne sont pas définies sur une valeur différente de zéro, les lignes fournies par l'entrée sont envoyées aux deux sorties synchrones avec l'entrée.

Lorsqu'un composant rencontre une erreur ou troncation pendant l'exécution, il continue selon les paramètres des propriétés ErrorRowDisposition et TruncationRowDisposition de l'entrée ou la sortie, ou de l'entrée ou la colonne de sortie, dans laquelle l'erreur s'est produite. La valeur de ces propriétés doit être définie par défaut sur RD_NotUsed. Lorsque la sortie d'erreur du composant est connectée à un composant en aval, cette propriété est définie par l'utilisateur du composant et permet à l'utilisateur de contrôler la manière dont le composant gère l'erreur ou la troncation.

Remplissage de colonnes d'erreur

Lorsqu'une sortie d'erreur est créée, la tâche de flux de données ajoute automatiquement deux colonnes à la collection de colonnes de sortie. Ces colonnes sont utilisées par les composants pour spécifier l'ID de la colonne qui a provoqué l'erreur ou la troncation, puis pour fournir le code d'erreur spécifique au composant. Ces colonnes sont générées automatiquement, mais les valeurs qu'elles contiennent doivent être définies par le composant.

La méthode utilisée pour définir les valeurs de ces colonnes varie selon que la sortie d'erreur est synchrone ou asynchrone. Les composants avec des sorties synchrones appellent la méthode DirectErrorRow, décrite de manière plus approfondie dans la section suivante, puis fournissent le code d'erreur et les valeurs de colonnes d'erreur en tant que paramètres. Les composants avec des sorties asynchrones ont deux possibilités pour définir les valeurs de ces colonnes. Ils peuvent soit appeler la méthode SetErrorInfo du tampon de sortie et fournir les valeurs, soit localiser les colonnes d'erreur dans le tampon à l'aide de la méthode FindColumnByLineageID et définir directement les valeurs des colonnes. Toutefois, puisque les noms des colonnes ou leur emplacement dans la collection de colonnes de sortie peuvent avoir été modifiés, la seconde méthode risque de ne pas être fiable. La méthode SetErrorInfo définit automatiquement les valeurs dans ces colonnes d'erreur sans avoir à les localiser manuellement.

Si vous devez obtenir la description d'erreur qui correspond à un code d'erreur spécifique, vous pouvez utiliser la méthode GetErrorDescription de l'interface IDTSComponentMetaData100, disponible via la propriété ComponentMetaData du composant.

Les exemples de code suivants présentent un composant qui possède une entrée et deux sorties, dont une sortie d'erreur. Le premier exemple indique comment créer une sortie d'erreur synchrone avec l'entrée. Le second exemple indique comment créer une sortie d'erreur asynchrone.

public override void ProvideComponentProperties()
{
    // Specify that the component has an error output.
    ComponentMetaData.UsesDispositions = true;
    // Create the input.
    IDTSInput100 input = ComponentMetaData.InputCollection.New();
    input.Name = "Input";
    input.ErrorRowDisposition = DTSRowDisposition.RD_NotUsed;
    input.ErrorOrTruncationOperation = "A string describing the possible error or truncation that may occur during execution.";

    // Create the default output.
    IDTSOutput100 output = ComponentMetaData.OutputCollection.New();
    output.Name = "Output";
    output.SynchronousInputID = input.ID;
    output.ExclusionGroup = 1;

    // Create the error output.
    IDTSOutput100 errorOutput = ComponentMetaData.OutputCollection.New();
    errorOutput.IsErrorOut = true;
    errorOutput.Name = "ErrorOutput";
    errorOutput.SynchronousInputID = input.ID;
    errorOutput.ExclusionGroup = 1;

}
Public  Overrides Sub ProvideComponentProperties() 

 ' Specify that the component has an error output.
 ComponentMetaData.UsesDispositions = True 

 Dim input As IDTSInput100 = ComponentMetaData.InputCollection.New 

 ' Create the input.
 input.Name = "Input" 
 input.ErrorRowDisposition = DTSRowDisposition.RD_NotUsed 
 input.ErrorOrTruncationOperation = "A string describing the possible error or truncation that may occur during execution." 

 ' Create the default output.
 Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection.New 
 output.Name = "Output" 
 output.SynchronousInputID = input.ID 
 output.ExclusionGroup = 1 

 ' Create the error output.
 Dim errorOutput As IDTSOutput100 = ComponentMetaData.OutputCollection.New 
 errorOutput.IsErrorOut = True 
 errorOutput.Name = "ErrorOutput" 
 errorOutput.SynchronousInputID = input.ID 
 errorOutput.ExclusionGroup = 1 

End Sub

L'exemple de code suivant crée une sortie d'erreur asynchrone.

public override void ProvideComponentProperties()
{
    // Specify that the component has an error output.
    ComponentMetaData.UsesDispositions = true;

    // Create the input.
    IDTSInput100 input = ComponentMetaData.InputCollection.New();
    input.Name = "Input";
    input.ErrorRowDisposition = DTSRowDisposition.RD_NotUsed;
    input.ErrorOrTruncationOperation = "A string describing the possible error or truncation that may occur during execution.";

    // Create the default output.
    IDTSOutput100 output = ComponentMetaData.OutputCollection.New();
    output.Name = "Output";

    // Create the error output.
    IDTSOutput100 errorOutput = ComponentMetaData.OutputCollection.New();
    errorOutput.Name = "ErrorOutput";
    errorOutput.IsErrorOut = true;
}
Public  Overrides Sub ProvideComponentProperties() 

 ' Specify that the component has an error output.
 ComponentMetaData.UsesDispositions = True 

 ' Create the input.
 Dim input As IDTSInput100 = ComponentMetaData.InputCollection.New 

 ' Create the default output.
 input.Name = "Input" 
 input.ErrorRowDisposition = DTSRowDisposition.RD_NotUsed 
 input.ErrorOrTruncationOperation = "A string describing the possible error or truncation that may occur during execution." 

 ' Create the error output.
 Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection.New 
 output.Name = "Output" 
 Dim errorOutput As IDTSOutput100 = ComponentMetaData.OutputCollection.New 
 errorOutput.Name = "ErrorOutput" 
 errorOutput.IsErrorOut = True 

End Sub

Redirection d'une ligne vers une sortie d'erreur

Après avoir ajouté une sortie d'erreur à un composant, vous devez fournir un code qui gère les conditions d'erreur ou de troncation propres au composant et qui redirige les lignes d'erreur ou de troncation vers la sortie d'erreur. Vous pouvez procéder de deux manières pour cela, selon que la sortie d'erreur est synchrone ou asynchrone.

Redirection d'une ligne avec des sorties synchrones

Les lignes sont envoyées aux sorties synchrones en appelant la méthode DirectErrorRow de la classe PipelineBuffer. L'appel de méthode inclut en tant que paramètres l'ID de la sortie d'erreur, le code d'erreur défini par le composant et l'index de la colonne que le composant n'a pas pu traiter.

L'exemple de code suivant montre comment diriger une ligne dans un tampon vers une sortie d'erreur synchrone à l'aide de la méthode DirectErrorRow.

public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
        IDTSInput100 input = ComponentMetaData.InputCollection.GetObjectByID(inputID);

        // This code sample assumes the component has two outputs, one the default,
        // the other the error output. If the errorOutputIndex returned from GetErrorOutputInfo
        // is 0, then the default output is the second output in the collection.
        int defaultOutputID = -1;
        int errorOutputID = -1;
        int errorOutputIndex = -1;

        GetErrorOutputInfo(ref errorOutputID,ref errorOutputIndex);

        if (errorOutputIndex == 0)
            defaultOutputID = ComponentMetaData.OutputCollection[1].ID;
        else
            defaultOutputID = ComponentMetaData.OutputCollection[0].ID;

        while (buffer.NextRow())
        {
            try
            {
                // TODO: Implement code to process the columns in the buffer row.

                // Ideally, your code should detect potential exceptions before they occur, rather
                // than having a generic try/catch block such as this. 
                // However, because the error or truncation implementation is specific to each component,
                // this sample focuses on actually directing the row, and not a single error or truncation.

                // Unless an exception occurs, direct the row to the default 
                buffer.DirectRow(defaultOutputID);
            }
            catch
            {
                // Yes, has the user specified to redirect the row?
                if (input.ErrorRowDisposition == DTSRowDisposition.RD_RedirectRow)
                {
                    // Yes, direct the row to the error output.
                    // TODO: Add code to include the errorColumnIndex.
                    buffer.DirectErrorRow(errorOutputID, 0, errorColumnIndex);
                }
                else if (input.ErrorRowDisposition == DTSRowDisposition.RD_FailComponent || input.ErrorRowDisposition == DTSRowDisposition.RD_NotUsed)
                {
                    // No, the user specified to fail the component, or the error row disposition was not set.
                    throw new Exception("An error occurred, and the DTSRowDisposition is either not set, or is set to fail component.");
                }
                else
                {
                    // No, the user specified to ignore the failure so 
                    // direct the row to the default output.
                    buffer.DirectRow(defaultOutputID);
                }

            }
        }
}
Public  Overrides Sub ProcessInput(ByVal inputID As Integer, ByVal buffer As PipelineBuffer) 
   Dim input As IDTSInput100 = ComponentMetaData.InputCollection.GetObjectByID(inputID) 

   ' This code sample assumes the component has two outputs, one the default,
   ' the other the error output. If the errorOutputIndex returned from GetErrorOutputInfo
   ' is 0, then the default output is the second output in the collection.
   Dim defaultOutputID As Integer = -1 
   Dim errorOutputID As Integer = -1 
   Dim errorOutputIndex As Integer = -1 

   GetErrorOutputInfo(errorOutputID, errorOutputIndex) 

   If errorOutputIndex = 0 Then 
     defaultOutputID = ComponentMetaData.OutputCollection(1).ID 
   Else 
     defaultOutputID = ComponentMetaData.OutputCollection(0).ID 
   End If 

   While buffer.NextRow 
     Try 
       ' TODO: Implement code to process the columns in the buffer row.

       ' Ideally, your code should detect potential exceptions before they occur, rather
       ' than having a generic try/catch block such as this. 
       ' However, because the error or truncation implementation is specific to each component,
       ' this sample focuses on actually directing the row, and not a single error or truncation.

       ' Unless an exception occurs, direct the row to the default 
       buffer.DirectRow(defaultOutputID) 
     Catch 
       ' Yes, has the user specified to redirect the row?
       If input.ErrorRowDisposition = DTSRowDisposition.RD_RedirectRow Then 
         ' Yes, direct the row to the error output.
         ' TODO: Add code to include the errorColumnIndex.
         buffer.DirectErrorRow(errorOutputID, 0, errorColumnIndex) 
       Else 
         If input.ErrorRowDisposition = DTSRowDisposition.RD_FailComponent OrElse input.ErrorRowDisposition = DTSRowDisposition.RD_NotUsed Then 
           ' No, the user specified to fail the component, or the error row disposition was not set.
           Throw New Exception("An error occurred, and the DTSRowDisposition is either not set, or is set to fail component.") 
         Else 
           ' No, the user specified to ignore the failure so 
           ' direct the row to the default output.
           buffer.DirectRow(defaultOutputID) 
         End If 
       End If 
     End Try 
   End While 
End Sub

Redirection d'une ligne avec des sorties asynchrones

Au lieu de diriger des lignes vers une sortie, comme cela est fait avec des sorties d'erreur synchrones, les composants avec des sorties asynchrones envoient une ligne vers une sortie d'erreur en ajoutant explicitement une ligne à la sortie PipelineBuffer. L'implémentation d'un composant qui utilise des sorties d'erreur asynchrones implique d'ajouter à la sortie d'erreur des colonnes fournies aux composants en aval et de mettre en cache le tampon de sortie pour la sortie d'erreur fournie au composant pendant la méthode PrimeOutput. Les détails de l'implémentation d'un composant avec des sorties asynchrones sont présentés dans la rubrique Développement d'un composant de transformation personnalisé à sorties asynchrones. Si les colonnes ne sont pas ajoutées explicitement à la sortie d'erreur, la ligne du tampon ajoutée au tampon de sortie contient uniquement les deux colonnes d'erreur.

Pour envoyer une ligne vers une sortie d'erreur asynchrone, vous devez ajouter une ligne au tampon de sortie d'erreur. Parfois, une ligne peut avoir déjà été ajoutée au tampon de sortie sans erreur et vous devez la supprimer en utilisant la méthode RemoveRow. Ensuite, vous définissez les valeurs des colonnes du tampon de sortie, et enfin, vous appelez la méthode SetErrorInfo pour fournir le code d'erreur propre au composant et la valeur de la colonne d'erreur.

L'exemple suivant montre comment utiliser une sortie d'erreur pour un composant avec des sorties asynchrones. Lorsque l'erreur simulée se produit, le composant ajoute une ligne au tampon de sortie d'erreur, copie les valeurs ajoutées précédemment au tampon de sortie sans erreur vers le tampon de sortie d'erreur, supprime la ligne ajoutée au tampon de sortie sans erreur et, enfin, définit le code d'erreur et les valeurs des colonnes d'erreur en appelant la méthode SetErrorInfo.

int []columnIndex;
int errorOutputID = -1;
int errorOutputIndex = -1;

public override void PreExecute()
{
    IDTSOutput100 defaultOutput = null;

    this.GetErrorOutputInfo(ref errorOutputID, ref errorOutputIndex);
    foreach (IDTSOutput100 output in ComponentMetaData.OutputCollection)
    {
        if (output.ID != errorOutputID)
            defaultOutput = output;
    }

    columnIndex = new int[defaultOutput.OutputColumnCollection.Count];

    for(int col =0 ; col < defaultOutput.OutputColumnCollection.Count; col++)
    {
        IDTSOutputColumn100 column = defaultOutput.OutputColumnCollection[col];
        columnIndex[col] = BufferManager.FindColumnByLineageID(defaultOutput.Buffer, column.LineageID);
    }
}

public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)
{
    for( int x=0; x < outputs; x++ )
    {
        if (outputIDs[x] == errorOutputID)
            this.errorBuffer = buffers[x];
        else
            this.defaultBuffer = buffers[x];
    }

    int rows = 100;

    Random random = new Random(System.DateTime.Now.Millisecond);

    for (int row = 0; row < rows; row++)
    {
        try
        {
            defaultBuffer.AddRow();

            for (int x = 0; x < columnIndex.Length; x++)
                defaultBuffer[columnIndex[x]] = random.Next();

            // Simulate an error.
            if ((row % 2) == 0)
                throw new Exception("A simulated error.");
        }
        catch
        {
            // Add a row to the error buffer.
            errorBuffer.AddRow();

            // Get the values from the default buffer
            // and copy them to the error buffer.
            for (int x = 0; x < columnIndex.Length; x++)
                errorBuffer[columnIndex[x]] = defaultBuffer[columnIndex[x]];

            // Set the error information.
            errorBuffer.SetErrorInfo(errorOutputID, 1, 0);

            // Remove the row that was added to the default buffer.
            defaultBuffer.RemoveRow();
        }
    }

    if (defaultBuffer != null)
        defaultBuffer.SetEndOfRowset();

    if (errorBuffer != null)
        errorBuffer.SetEndOfRowset();
}
Private columnIndex As Integer() 
Private errorOutputID As Integer = -1 
Private errorOutputIndex As Integer = -1 

Public  Overrides Sub PreExecute() 
 Dim defaultOutput As IDTSOutput100 = Nothing 
 Me.GetErrorOutputInfo(errorOutputID, errorOutputIndex) 
 For Each output As IDTSOutput100 In ComponentMetaData.OutputCollection 
   If Not (output.ID = errorOutputID) Then 
     defaultOutput = output 
   End If 
 Next 
 columnIndex = New Integer(defaultOutput.OutputColumnCollection.Count) {} 
 Dim col As Integer = 0 
 While col < defaultOutput.OutputColumnCollection.Count 
   Dim column As IDTSOutputColumn100 = defaultOutput.OutputColumnCollection(col) 
   columnIndex(col) = BufferManager.FindColumnByLineageID(defaultOutput.Buffer, column.LineageID) 
   System.Math.Min(System.Threading.Interlocked.Increment(col),col-1) 
 End While 
End Sub 

Public  Overrides Sub PrimeOutput(ByVal outputs As Integer, ByVal outputIDs As Integer(), ByVal buffers As PipelineBuffer()) 
 Dim x As Integer = 0 
 While x < outputs 
   If outputIDs(x) = errorOutputID Then 
     Me.errorBuffer = buffers(x) 
   Else 
     Me.defaultBuffer = buffers(x) 
   End If 
   System.Math.Min(System.Threading.Interlocked.Increment(x),x-1) 
 End While 
 Dim rows As Integer = 100 
 Dim random As Random = New Random(System.DateTime.Now.Millisecond) 
 Dim row As Integer = 0 
 While row < rows 
   Try 
     defaultBuffer.AddRow 
     Dim x As Integer = 0 
     While x < columnIndex.Length 
       defaultBuffer(columnIndex(x)) = random.Next 
       System.Math.Min(System.Threading.Interlocked.Increment(x),x-1) 
     End While 
     ' Simulate an error.
     If (row Mod 2) = 0 Then 
       Throw New Exception("A simulated error.") 
     End If 
   Catch 
     ' Add a row to the error buffer.
     errorBuffer.AddRow 
     ' Get the values from the default buffer
     ' and copy them to the error buffer.
     Dim x As Integer = 0 
     While x < columnIndex.Length 
       errorBuffer(columnIndex(x)) = defaultBuffer(columnIndex(x)) 
       System.Math.Min(System.Threading.Interlocked.Increment(x),x-1) 
     End While 
     ' Set the error information.
     errorBuffer.SetErrorInfo(errorOutputID, 1, 0) 
     ' Remove the row that was added to the default buffer.
     defaultBuffer.RemoveRow 
   End Try 
   System.Math.Min(System.Threading.Interlocked.Increment(row),row-1) 
 End While 
 If Not (defaultBuffer Is Nothing) Then 
   defaultBuffer.SetEndOfRowset 
 End If 
 If Not (errorBuffer Is Nothing) Then 
   errorBuffer.SetEndOfRowset 
 End If 
End Sub
Icône Integration Services (petite) Rester à jour avec Integration Services

Pour obtenir les derniers téléchargements, articles, exemples et vidéos de Microsoft, ainsi que des solutions sélectionnées par la communauté, visitez la page Integration Services sur MSDN ou TechNet :

Pour recevoir une notification automatique de ces mises à jour, abonnez-vous aux flux RSS disponibles sur la page.