Partager via


Sample: Bulk delete exported records

 

Applies To: Dynamics CRM 2013

This sample code is for Microsoft Dynamics CRM 2013 and Microsoft Dynamics CRM Online. Download the Microsoft Dynamics CRM SDK package. It can be found in the following location in the download package:

SampleCode\CS\DataManagement\BulkDelete\BulkDeleteBackup.cs
SampleCode\VB\DataManagement\BulkDelete\BulkDeleteBackup.vb

Requirements

For more information about the requirements for running the sample code provided in this SDK, see Use the sample and helper code.

Demonstrates

This sample shows how to perform a bulk deletion of records that were previously exported from Microsoft Dynamics CRM by using the Export to Excel option.

Example


using System;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;

namespace Microsoft.Crm.Sdk.Samples
{
    /// <summary>
    /// This sample shows how to perform a bulk delete asynchronous 
    /// operation on the records that have been manually exported 
    /// from Microsoft Dynamics CRM by using Export to Excel in a grid's view.
    /// </summary>
    public class BulkDeleteBackup
    {
        #region Class Level Members
        private OrganizationServiceProxy _serviceProxy;
        private BulkDeleteResponse _bulkDeleteResponse;
        private Guid? _asyncOperationId;
        private Guid? _bulkDeleteOperationId;
        #endregion

        #region How To Sample Code

        /// <summary>
        /// Run the sample.
        /// </summary>
        /// <param name="serverConfig">configuration for the server.</param>
        /// <param name="promptToDelete">
        /// whether or not to prompt the user to delete created records.
        /// </param>
        public void Run(ServerConnection.Configuration serverConfig, bool promptToDelete)
        {
            using (_serviceProxy = ServerConnection.GetOrganizationProxy(serverConfig))
            {
                // This statement is required to enable early-bound type support.
                _serviceProxy.EnableProxyTypes();

                PerformBulkDeleteBackup();
                DeleteRequiredRecords(promptToDelete);
            }
        }

        /// <summary>
        /// Performs the main operation of the sample - performs a bulk delete on inactive
        /// opportunities and activities to remove them from the system.
        /// </summary>
        private void PerformBulkDeleteBackup()
        {
            try
            {
                // Query for a system user to send an email to after the bulk delete
                // operation completes.
                var userRequest = new WhoAmIRequest();
                var userResponse = (WhoAmIResponse)_serviceProxy.Execute(userRequest);
                Guid currentUserId = userResponse.UserId;

                // Create a condition for a bulk delete request.
                // NOTE: This sample uses very specific queries for deleting records
                // that have been manually exported in order to free space.
                QueryExpression opportunitiesQuery = BuildOpportunityQuery();

                // Create the bulk delete request.
                BulkDeleteRequest bulkDeleteRequest = new BulkDeleteRequest();

                // Set the request properties.
                bulkDeleteRequest.JobName = "Backup Bulk Delete";

                // Querying activities
                bulkDeleteRequest.QuerySet = new QueryExpression[]
                {
                    opportunitiesQuery,
                    BuildActivityQuery(Task.EntityLogicalName),
                    BuildActivityQuery(Fax.EntityLogicalName),
                    BuildActivityQuery(PhoneCall.EntityLogicalName),
                    BuildActivityQuery(Email.EntityLogicalName),
                    BuildActivityQuery(Letter.EntityLogicalName),
                    BuildActivityQuery(Appointment.EntityLogicalName),
                    BuildActivityQuery(ServiceAppointment.EntityLogicalName),
                    BuildActivityQuery(CampaignResponse.EntityLogicalName),
                    BuildActivityQuery(RecurringAppointmentMaster.EntityLogicalName)
                };

                // Set the start time for the bulk delete.
                bulkDeleteRequest.StartDateTime = DateTime.Now;

                // Set the required recurrence pattern.
                bulkDeleteRequest.RecurrencePattern = String.Empty;

                // Set email activity properties.
                bulkDeleteRequest.SendEmailNotification = false;
                bulkDeleteRequest.ToRecipients = new Guid[] { currentUserId };
                bulkDeleteRequest.CCRecipients = new Guid[] { };

                // Submit the bulk delete job.
                // NOTE: Because this is an asynchronous operation, the response will be immediate.
                _bulkDeleteResponse =
                    (BulkDeleteResponse)_serviceProxy.Execute(bulkDeleteRequest);
                Console.WriteLine("The bulk delete operation has been requested.");

                CheckSuccess();
            }
            catch (System.Web.Services.Protocols.SoapException)
            {
                // Perform error handling here.
                throw;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// This method will query for the BulkDeleteOperation until it has been
        /// completed or until the designated time runs out.  It then checks to see if
        /// the operation was successful.
        /// </summary>
        private void CheckSuccess()
        {
            // Query for bulk delete operation and check for status.
            QueryByAttribute bulkQuery = new QueryByAttribute(
                BulkDeleteOperation.EntityLogicalName);
            bulkQuery.ColumnSet = new ColumnSet(true);

            // NOTE: When the bulk delete operation was submitted, the GUID that was
            // returned was the asyncoperationid, not the bulkdeleteoperationid.
            bulkQuery.Attributes.Add("asyncoperationid");
            _asyncOperationId = _bulkDeleteResponse.JobId;
            bulkQuery.Values.Add(_asyncOperationId);

            // With only the asyncoperationid at this point, a RetrieveMultiple is
            // required to get the
            // bulk delete operation created above.
            EntityCollection entityCollection = _serviceProxy.RetrieveMultiple(bulkQuery);
            BulkDeleteOperation createdBulkDeleteOperation = null;

            // Monitor the async operation via polling until it is complete or max
            // polling time expires.
            const int ARBITRARY_MAX_POLLING_TIME = 60;
            int secondsTicker = ARBITRARY_MAX_POLLING_TIME;
            while (secondsTicker > 0)
            {
                // Make sure the async operation was retrieved.
                if (entityCollection.Entities.Count > 0)
                {
                    // Grab the one bulk operation that has been created.
                    createdBulkDeleteOperation = (BulkDeleteOperation)entityCollection.Entities[0];

                    // Check the operation's state.
                    if (createdBulkDeleteOperation.StateCode.Value != BulkDeleteOperationState.Completed)
                    {
                        // The operation has not yet completed.  Wait a second for the
                        // status to change.
                        System.Threading.Thread.Sleep(1000);
                        secondsTicker--;

                        // Retrieve a fresh version of the bulk delete operation.
                        entityCollection = _serviceProxy.RetrieveMultiple(bulkQuery);
                    }
                    else
                    {
                        // Stop polling as the operation's state is now complete.
                        secondsTicker = 0;
                    }
                }
                else
                {
                    // Wait a second for async operation to activate.
                    System.Threading.Thread.Sleep(1000);
                    secondsTicker--;

                    // Retrieve the entity again.
                    entityCollection = _serviceProxy.RetrieveMultiple(bulkQuery);
                }
            }

            // Validate that the operation was completed.
            if (createdBulkDeleteOperation != null)
            {
                _bulkDeleteOperationId = createdBulkDeleteOperation.BulkDeleteOperationId;
                if (createdBulkDeleteOperation.StateCode.Value != BulkDeleteOperationState.Completed)
                {
                    Console.WriteLine(
                        "Polling for the BulkDeleteOperation took longer than allowed ({0} seconds).",
                        ARBITRARY_MAX_POLLING_TIME);
                }
                else
                {
                    Console.WriteLine("The BulkDeleteOperation succeeded.\r\n  Successes: {0}, Failures: {1}",
                        createdBulkDeleteOperation.SuccessCount,
                        createdBulkDeleteOperation.FailureCount);
                }
            }
            else
            {
                Console.WriteLine("The BulkDeleteOperation could not be retrieved.");
            }
        }

        /// <summary>
        /// Builds a query that matches all opportunities that are not in the open state.
        /// </summary>
        private static QueryExpression BuildOpportunityQuery()
        {
            // Create a query that will match all opportunities that do not have a state
            // of open.
            var closedCondition = new ConditionExpression(
                "statecode", ConditionOperator.NotEqual, (int)OpportunityState.Open);

            // Create a filter expression for a bulk delete request.
            var closedFilter = new FilterExpression();
            closedFilter.Conditions.Add(closedCondition);

            var queryExpression = new QueryExpression();

            queryExpression.EntityName = Opportunity.EntityLogicalName;
            queryExpression.Criteria = closedFilter;

            // Return all records
            queryExpression.Distinct = false;

            return queryExpression;
        }

        /// <summary>
        /// Builds a query which will match all activities that are in the canceled or
        /// completed state.
        /// </summary>
        private static QueryExpression BuildActivityQuery(String entityName)
        {
            var canceledCondition = new ConditionExpression(
                "statecode", ConditionOperator.Equal, (int)ActivityPointerState.Canceled);
            var completedCondition = new ConditionExpression(
                "statecode", ConditionOperator.Equal, (int)ActivityPointerState.Completed);

            var closedFilter = new FilterExpression(LogicalOperator.Or);
            closedFilter.Conditions.AddRange(canceledCondition, completedCondition);

            var queryExpression = new QueryExpression();

            queryExpression.EntityName = entityName;
            queryExpression.Criteria = closedFilter;

            queryExpression.Distinct = false;

            return queryExpression;
        }

        /// <summary>
        /// This method deletes the AsyncOperation and BulkDeleteOperation that were
        /// created in the database, if the user confirms that deleting these is
        /// desired.
        /// </summary>
        private void DeleteRequiredRecords(bool promptToDelete)
        {
            var toBeDeleted = true;
            if (promptToDelete)
            {
                // Ask the user if the created entities should be deleted.
                Console.Write("\nDo you want these entity records deleted? (y/n) [y]: ");
                String answer = Console.ReadLine();
                if (answer.StartsWith("y") ||
                    answer.StartsWith("Y") ||
                    answer == String.Empty)
                {
                    toBeDeleted = true;
                }
                else
                {
                    toBeDeleted = false;
                }
            }

            if (toBeDeleted)
            {
                // Delete the bulk delete operation so that it won't clutter the
                // database.
                if (_bulkDeleteOperationId.HasValue)
                {
                    _serviceProxy.Delete(
                        BulkDeleteOperation.EntityLogicalName,
                        _bulkDeleteOperationId.Value);
                }

                if (_asyncOperationId.HasValue)
                {
                    _serviceProxy.Delete(
                        AsyncOperation.EntityLogicalName, _asyncOperationId.Value);
                }

                Console.WriteLine("The AsyncOperation and BulkDeleteOperation have been deleted.");
            }
        }

        #endregion How To Sample Code

        #region Main method

        /// <summary>
        /// Standard Main() method used by most SDK samples.
        /// </summary>
        /// <param name="args"></param>
        static public void Main(string[] args)
        {
            try
            {
                // Obtain the target organization's Web address and client logon 
                // credentials from the user.
                ServerConnection serverConnect = new ServerConnection();
                ServerConnection.Configuration config = serverConnect.GetServerConfiguration();

                var app = new BulkDeleteBackup();
                app.Run(config, true);
            }
            catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
            {
                Console.WriteLine("The application terminated with an error.");
                Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp);
                Console.WriteLine("Code: {0}", ex.Detail.ErrorCode);
                Console.WriteLine("Message: {0}", ex.Detail.Message);
                Console.WriteLine("Plugin Trace: {0}", ex.Detail.TraceText);
                Console.WriteLine("Inner Fault: {0}",
                    null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
            }
            catch (System.TimeoutException ex)
            {
                Console.WriteLine("The application terminated with an error.");
                Console.WriteLine("Message: {0}", ex.Message);
                Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
                Console.WriteLine("Inner Fault: {0}",
                    null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("The application terminated with an error.");
                Console.WriteLine(ex.Message);

                // Display the details of the inner exception.
                if (ex.InnerException != null)
                {
                    Console.WriteLine(ex.InnerException.Message);

                    FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException
                        as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>;
                    if (fe != null)
                    {
                        Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp);
                        Console.WriteLine("Code: {0}", fe.Detail.ErrorCode);
                        Console.WriteLine("Message: {0}", fe.Detail.Message);
                        Console.WriteLine("Plugin Trace: {0}", fe.Detail.TraceText);
                        Console.WriteLine("Inner Fault: {0}",
                            null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
                    }
                }
            }
            // Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
            // SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.

            finally
            {
                Console.WriteLine("Press <Enter> to exit.");
                Console.ReadLine();
            }
        }
        #endregion Main method
    }
}

Imports Microsoft.VisualBasic
Imports System
Imports System.ServiceModel
Imports Microsoft.Crm.Sdk.Messages
Imports Microsoft.Xrm.Sdk
Imports Microsoft.Xrm.Sdk.Client
Imports Microsoft.Xrm.Sdk.Query

Namespace Microsoft.Crm.Sdk.Samples
    ''' <summary>
    ''' This sample shows how to perform a bulk delete asynchronous 
    ''' operation on the records that have been manually exported 
    ''' from Microsoft Dynamics CRM by using Export to Excel in a grid's view.
    ''' </summary>
    Public Class BulkDeleteBackup
        #Region "Class Level Members"
        Private _serviceProxy As OrganizationServiceProxy
        Private _bulkDeleteResponse As BulkDeleteResponse
        Private _asyncOperationId? As Guid
        Private _bulkDeleteOperationId? As Guid
        #End Region

        #Region "How To Sample Code"

        ''' <summary>
        ''' Run the sample.
        ''' </summary>
        ''' <param name="serverConfig">configuration for the server.</param>
        ''' <param name="promptToDelete">
        ''' whether or not to prompt the user to delete created records.
        ''' </param>
        Public Sub Run(ByVal serverConfig As ServerConnection.Configuration,
                       ByVal promptToDelete As Boolean)
            _serviceProxy = ServerConnection.GetOrganizationProxy(serverConfig)
            Using _serviceProxy
                ' This statement is required to enable early-bound type support.
                _serviceProxy.EnableProxyTypes()

                PerformBulkDeleteBackup()
                DeleteRequiredRecords(promptToDelete)
            End Using
        End Sub

        ''' <summary>
        ''' Performs the main operation of the sample - performs a bulk delete on inactive
        ''' opportunities and activities to remove them from the system.
        ''' </summary>
        Private Sub PerformBulkDeleteBackup()
            Try
                ' Query for a system user to send an email to after the bulk delete
                ' operation completes.
                Dim userRequest = New WhoAmIRequest()
                Dim userResponse = CType(_serviceProxy.Execute(userRequest), 
                    WhoAmIResponse)
                Dim currentUserId As Guid = userResponse.UserId

                ' Create a condition for a bulk delete request.
                ' NOTE: This sample uses very specific queries for deleting records
                ' that have been manually exported in order to free space.
                Dim opportunitiesQuery As QueryExpression = BuildOpportunityQuery()

                ' Create the bulk delete request.
                Dim bulkDeleteRequest As New BulkDeleteRequest()

                ' Set the request properties.
                bulkDeleteRequest.JobName = "Backup Bulk Delete"

                ' Querying activities
                bulkDeleteRequest.QuerySet = New QueryExpression() {
                    opportunitiesQuery,
                    BuildActivityQuery(Task.EntityLogicalName),
                    BuildActivityQuery(Fax.EntityLogicalName),
                    BuildActivityQuery(PhoneCall.EntityLogicalName),
                    BuildActivityQuery(Email.EntityLogicalName),
                    BuildActivityQuery(Letter.EntityLogicalName),
                    BuildActivityQuery(Appointment.EntityLogicalName),
                    BuildActivityQuery(ServiceAppointment.EntityLogicalName),
                    BuildActivityQuery(CampaignResponse.EntityLogicalName),
                    BuildActivityQuery(RecurringAppointmentMaster.EntityLogicalName)
                }

                ' Set the start time for the bulk delete.
                bulkDeleteRequest.StartDateTime = Date.Now

                ' Set the required recurrence pattern.
                bulkDeleteRequest.RecurrencePattern = String.Empty

                ' Set email activity properties.
                bulkDeleteRequest.SendEmailNotification = False
                bulkDeleteRequest.ToRecipients = New Guid() { currentUserId }
                bulkDeleteRequest.CCRecipients = New Guid() { }

                ' Submit the bulk delete job.
                ' NOTE: Because this is an asynchronous operation, the response will be immediate.
                _bulkDeleteResponse = CType(_serviceProxy.Execute(bulkDeleteRequest), 
                    BulkDeleteResponse)
                Console.WriteLine("The bulk delete operation has been requested.")

                CheckSuccess()
            Catch e1 As System.Web.Services.Protocols.SoapException
                ' Perform error handling here.
                Throw
            Catch e2 As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' This method will query for the BulkDeleteOperation until it has been
        ''' completed or until the designated time runs out.  It then checks to see if
        ''' the operation was successful.
        ''' </summary>
        Private Sub CheckSuccess()
            ' Query for bulk delete operation and check for status.
            Dim bulkQuery As New QueryByAttribute(BulkDeleteOperation.EntityLogicalName)
            bulkQuery.ColumnSet = New ColumnSet(True)

            ' NOTE: When the bulk delete operation was submitted, the GUID that was
            ' returned was the asyncoperationid, not the bulkdeleteoperationid.
            bulkQuery.Attributes.Add("asyncoperationid")
            _asyncOperationId = _bulkDeleteResponse.JobId
            bulkQuery.Values.Add(_asyncOperationId)

            ' With only the asyncoperationid at this point, a RetrieveMultiple is
            ' required to get the
            ' bulk delete operation created above.
            Dim entityCollection As EntityCollection =
                _serviceProxy.RetrieveMultiple(bulkQuery)
            Dim createdBulkDeleteOperation As BulkDeleteOperation = Nothing

            ' Monitor the async operation via polling until it is complete or max
            ' polling time expires.
            Const ARBITRARY_MAX_POLLING_TIME As Integer = 60
            Dim secondsTicker As Integer = ARBITRARY_MAX_POLLING_TIME
            Do While secondsTicker > 0
                ' Make sure the async operation was retrieved.
                If entityCollection.Entities.Count > 0 Then
                    ' Grab the one bulk operation that has been created.
                    createdBulkDeleteOperation = CType(entityCollection.Entities(0), 
                        BulkDeleteOperation)

                    ' Check the operation's state.
                    If createdBulkDeleteOperation.StateCode.Value <>
                        BulkDeleteOperationState.Completed Then
                        ' The operation has not yet completed.  Wait a second for the
                        ' status to change.
                        System.Threading.Thread.Sleep(1000)
                        secondsTicker -= 1

                        ' Retrieve a fresh version of the bulk delete operation.
                        entityCollection = _serviceProxy.RetrieveMultiple(bulkQuery)
                    Else
                        ' Stop polling as the operation's state is now complete.
                        secondsTicker = 0
                    End If
                Else
                    ' Wait a second for async operation to activate.
                    System.Threading.Thread.Sleep(1000)
                    secondsTicker -= 1

                    ' Retrieve the entity again.
                    entityCollection = _serviceProxy.RetrieveMultiple(bulkQuery)
                End If
            Loop

            ' Validate that the operation was completed.
            If createdBulkDeleteOperation IsNot Nothing Then
                _bulkDeleteOperationId = createdBulkDeleteOperation.BulkDeleteOperationId
                If createdBulkDeleteOperation.StateCode.Value <>
                    BulkDeleteOperationState.Completed Then
                    Console.WriteLine("Polling for the BulkDeleteOperation took longer than allowed ({0} seconds).",
                                      ARBITRARY_MAX_POLLING_TIME)
                Else
                    Console.WriteLine("The BulkDeleteOperation succeeded." _
                                      &amp; vbCrLf &amp; "  Successes: {0}, Failures: {1}",
                                      createdBulkDeleteOperation.SuccessCount,
                                      createdBulkDeleteOperation.FailureCount)
                End If
            Else
                Console.WriteLine("The BulkDeleteOperation could not be retrieved.")
            End If
        End Sub

        ''' <summary>
        ''' Builds a query that matches all opportunities that are not in the open state.
        ''' </summary>
        Private Shared Function BuildOpportunityQuery() As QueryExpression
            ' Create a query that will match all opportunities that do not have a state
            ' of open.
            Dim closedCondition = New ConditionExpression("statecode",
                                                          ConditionOperator.NotEqual,
                                                          CInt(Fix(OpportunityState.Open)))

            ' Create a filter expression for a bulk delete request.
            Dim closedFilter = New FilterExpression()
            closedFilter.Conditions.Add(closedCondition)

            Dim queryExpression = New QueryExpression()

            queryExpression.EntityName = Opportunity.EntityLogicalName
            queryExpression.Criteria = closedFilter

            ' Return all records
            queryExpression.Distinct = False

            Return queryExpression
        End Function

        ''' <summary>
        ''' Builds a query which will match all activities that are in the canceled or
        ''' completed state.
        ''' </summary>
        Private Shared Function BuildActivityQuery(ByVal entityName As String) As QueryExpression
            Dim canceledCondition =
                New ConditionExpression("statecode",
                                        ConditionOperator.Equal,
                                        CInt(Fix(ActivityPointerState.Canceled)))
            Dim completedCondition =
                New ConditionExpression("statecode",
                                        ConditionOperator.Equal,
                                        CInt(Fix(ActivityPointerState.Completed)))

            Dim closedFilter = New FilterExpression(LogicalOperator.Or)
            closedFilter.Conditions.AddRange(canceledCondition, completedCondition)

            Dim queryExpression = New QueryExpression()

            queryExpression.EntityName = entityName
            queryExpression.Criteria = closedFilter

            queryExpression.Distinct = False

            Return queryExpression
        End Function

        ''' <summary>
        ''' This method deletes the AsyncOperation and BulkDeleteOperation that were
        ''' created in the database, if the user confirms that deleting these is
        ''' desired.
        ''' </summary>
        Private Sub DeleteRequiredRecords(ByVal promptToDelete As Boolean)
            Dim toBeDeleted = True
            If promptToDelete Then
                ' Ask the user if the created entities should be deleted.
                Console.Write(vbLf &amp; "Do you want these entity records deleted? (y/n) [y]: ")
                Dim answer As String = Console.ReadLine()
                If answer.StartsWith("y") OrElse
                    answer.StartsWith("Y") OrElse
                    answer = String.Empty Then
                    toBeDeleted = True
                Else
                    toBeDeleted = False
                End If
            End If

            If toBeDeleted Then
                ' Delete the bulk delete operation so that it won't clutter the
                ' database.
                If _bulkDeleteOperationId.HasValue Then
                    _serviceProxy.Delete(BulkDeleteOperation.EntityLogicalName,
                                         _bulkDeleteOperationId.Value)
                End If

                If _asyncOperationId.HasValue Then
                    _serviceProxy.Delete(AsyncOperation.EntityLogicalName,
                                         _asyncOperationId.Value)
                End If

                Console.WriteLine("The AsyncOperation and BulkDeleteOperation have been deleted.")
            End If
        End Sub

        #End Region ' How To Sample Code

        #Region "Main method"

        ''' <summary>
        ''' Standard Main() method used by most SDK samples.
        ''' </summary>
        ''' <param name="args"></param>
        Public Shared Sub Main(ByVal args() As String)
            Try
                ' Obtain the target organization's Web address and client logon 
                ' credentials from the user.
                Dim serverConnect As New ServerConnection()
                Dim config As ServerConnection.Configuration =
                    serverConnect.GetServerConfiguration()

                Dim app = New BulkDeleteBackup()
                app.Run(config, True)
            Catch ex As FaultException(Of Microsoft.Xrm.Sdk.OrganizationServiceFault)
                Console.WriteLine("The application terminated with an error.")
                Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp)
                Console.WriteLine("Code: {0}", ex.Detail.ErrorCode)
                Console.WriteLine("Message: {0}", ex.Detail.Message)
                Console.WriteLine("Plugin Trace: {0}", ex.Detail.TraceText)
                Console.WriteLine("Inner Fault: {0}",
                                  If(Nothing Is ex.Detail.InnerFault, "No Inner Fault", "Has Inner Fault"))
            Catch ex As System.TimeoutException
                Console.WriteLine("The application terminated with an error.")
                Console.WriteLine("Message: {0}", ex.Message)
                Console.WriteLine("Stack Trace: {0}", ex.StackTrace)
                Console.WriteLine("Inner Fault: {0}",
                                  If(Nothing Is ex.InnerException.Message, "No Inner Fault", ex.InnerException.Message))
            Catch ex As System.Exception
                Console.WriteLine("The application terminated with an error.")
                Console.WriteLine(ex.Message)

                ' Display the details of the inner exception.
                If ex.InnerException IsNot Nothing Then
                    Console.WriteLine(ex.InnerException.Message)

                    Dim fe As FaultException(Of Microsoft.Xrm.Sdk.OrganizationServiceFault) =
                        TryCast(ex.InnerException, 
                            FaultException(Of Microsoft.Xrm.Sdk.OrganizationServiceFault))
                    If fe IsNot Nothing Then
                        Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp)
                        Console.WriteLine("Code: {0}", fe.Detail.ErrorCode)
                        Console.WriteLine("Message: {0}", fe.Detail.Message)
                        Console.WriteLine("Plugin Trace: {0}", fe.Detail.TraceText)
                        Console.WriteLine("Inner Fault: {0}",
                                          If(Nothing Is fe.Detail.InnerFault, "No Inner Fault", "Has Inner Fault"))
                    End If
                End If
            ' Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
            ' SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.

            Finally
                Console.WriteLine("Press <Enter> to exit.")
                Console.ReadLine()
            End Try
        End Sub
        #End Region ' Main method
    End Class
End Namespace

See Also

BulkDeleteRequest
Delete data in bulk
Run bulk delete
Recurrence pattern in asynchronous job execution
Sample: Bulk delete records that match common criteria