Example #1
0
        /// <summary>
        /// Try to cancel a job.
        /// </summary>
        /// <param name="batchJobId">ID of the batch job to cancel.</param>
        /// <exception cref="AdWordsApiException">Thrown if an API error occurred
        /// when cancelling the job.</exception>
        public void TryToCancelJob(long batchJobId)
        {
            BatchJobService batchJobService =
                (BatchJobService)User.GetService(AdWordsService.v201802.BatchJobService);

            try
            {
                BatchJobOperation batchJobSetOperation = new BatchJobOperation()
                {
                    @operator = Operator.SET,
                    operand   = new ApiBatchJob()
                    {
                        id     = batchJobId,
                        status = BatchJobStatus.CANCELING
                    }
                };

                batchJobService.mutate(new BatchJobOperation[]
                {
                    batchJobSetOperation
                });
            }
            catch (AdWordsApiException)
            {
                // Rethrow the API exception.
                throw;
            }
        }
 /// <summary>Snippet for MutateBatchJob</summary>
 /// <remarks>
 /// This snippet has been automatically generated for illustrative purposes only.
 /// It may require modifications to work in your environment.
 /// </remarks>
 public void MutateBatchJob()
 {
     // Create client
     BatchJobServiceClient batchJobServiceClient = BatchJobServiceClient.Create();
     // Initialize request argument(s)
     string            customerId = "";
     BatchJobOperation operation  = new BatchJobOperation();
     // Make the request
     MutateBatchJobResponse response = batchJobServiceClient.MutateBatchJob(customerId, operation);
 }
        /// <summary>Snippet for MutateBatchJobAsync</summary>
        /// <remarks>
        /// This snippet has been automatically generated for illustrative purposes only.
        /// It may require modifications to work in your environment.
        /// </remarks>
        public async Task MutateBatchJobAsync()
        {
            // Create client
            BatchJobServiceClient batchJobServiceClient = await BatchJobServiceClient.CreateAsync();

            // Initialize request argument(s)
            string            customerId = "";
            BatchJobOperation operation  = new BatchJobOperation();
            // Make the request
            MutateBatchJobResponse response = await batchJobServiceClient.MutateBatchJobAsync(customerId, operation);
        }
        /// <summary>Snippet for MutateBatchJobAsync</summary>
        public async Task MutateBatchJobAsync()
        {
            // Snippet: MutateBatchJobAsync(string, BatchJobOperation, CallSettings)
            // Additional: MutateBatchJobAsync(string, BatchJobOperation, CancellationToken)
            // Create client
            BatchJobServiceClient batchJobServiceClient = await BatchJobServiceClient.CreateAsync();

            // Initialize request argument(s)
            string            customerId = "";
            BatchJobOperation operation  = new BatchJobOperation();
            // Make the request
            MutateBatchJobResponse response = await batchJobServiceClient.MutateBatchJobAsync(customerId, operation);

            // End snippet
        }
        /// <summary>
        /// Creates the batch job.
        /// </summary>
        /// <param name="batchJobService">The batch job service.</param>
        /// <param name="customerId">The Google Ads customer ID for which the call is made.</param>
        /// <returns>The resource name of the created batch job.</returns>
        private static string CreateBatchJob(BatchJobServiceClient batchJobService,
                                             long customerId)
        {
            BatchJobOperation operation = new BatchJobOperation()
            {
                Create = new BatchJob()
                {
                }
            };
            string batchJobResourceName =
                batchJobService.MutateBatchJob(customerId.ToString(), operation).Result.ResourceName;

            Console.WriteLine($"Created a batch job with resource name: " +
                              $"'{batchJobResourceName}'.");

            return(batchJobResourceName);
        }
        /// <summary>
        /// Cancels the job.
        /// </summary>
        /// <param name="batchJobService">The batch job service.</param>
        /// <param name="batchJob">The batch job.</param>
        private BatchJob CancelJob(BatchJobService batchJobService, BatchJob batchJob)
        {
            try {
                batchJob.status = BatchJobStatus.CANCELING;
                BatchJobOperation batchJobSetOperation = new BatchJobOperation()
                {
                    @operator = Operator.SET,
                    operand   = batchJob
                };

                batchJob = batchJobService.mutate(
                    new BatchJobOperation[] { batchJobSetOperation }).value[0];
                Console.WriteLine("Requested cancellation of batch job with ID {0}.", batchJob.id);
            } catch (AdWordsApiException e) {
                ApiException innerException = e.ApiException as ApiException;
                if (innerException == null)
                {
                    // This means that the API call failed, but not due to an error on
                    // the operations. You can still examine the innerException property
                    // of the original exception to get more details.
                    throw new Exception("Failed to retrieve ApiError. See inner exception for more " +
                                        "details.", e);
                }

                // Examine each ApiError received from the server.
                foreach (ApiError apiError in innerException.errors)
                {
                    if (apiError is BatchJobError)
                    {
                        BatchJobError batchJobError = (BatchJobError)apiError;
                        if (batchJobError.reason == BatchJobErrorReason.INVALID_STATE_CHANGE)
                        {
                            Console.WriteLine("Attempt to cancel batch job with ID {0} was rejected because " +
                                              "the job already completed or was canceled.", batchJob.id);
                            continue;
                        }
                    }
                }
                throw;
            }
            return(batchJob);
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        public void Run(AdWordsUser user)
        {
            using (BatchJobService batchJobService =
                       (BatchJobService)user.GetService(AdWordsService.v201806.BatchJobService))
            {
                try
                {
                    // Create a BatchJob.
                    BatchJobOperation addOp = new BatchJobOperation()
                    {
                        @operator = Operator.ADD,
                        operand   = new BatchJob()
                    };

                    BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[]
                    {
                        addOp
                    }).value[0];

                    // Get the upload URL from the new job.
                    string uploadUrl = batchJob.uploadUrl.url;

                    Console.WriteLine(
                        "Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
                        batchJob.id, batchJob.status, batchJob.uploadUrl.url);

                    BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user);

                    // Create a resumable Upload URL to upload the operations.
                    string resumableUploadUrl =
                        batchJobUploadHelper.GetResumableUploadUrl(uploadUrl);

                    BatchUploadProgress uploadProgress =
                        batchJobUploadHelper.BeginStreamUpload(resumableUploadUrl);

                    // Create and add an operation to create a new budget.
                    BudgetOperation budgetOperation = BuildBudgetOperation();

                    uploadProgress = batchJobUploadHelper.StreamUpload(uploadProgress,
                                                                       new List <Operation>()
                    {
                        budgetOperation
                    });

                    // Create and add operations to create new campaigns.
                    List <Operation> campaignOperations = new List <Operation>();
                    campaignOperations.AddRange(
                        BuildCampaignOperations(budgetOperation.operand.budgetId));

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, campaignOperations);

                    // Create and add operations to create new ad groups.
                    List <Operation> adGroupOperations = new List <Operation>();
                    foreach (CampaignOperation campaignOperation in campaignOperations)
                    {
                        adGroupOperations.AddRange(
                            BuildAdGroupOperations(campaignOperation.operand.id));
                    }

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, adGroupOperations);

                    // Create and add operations to create new ad group ads (expanded text ads).
                    List <Operation> adOperations = new List <Operation>();
                    foreach (AdGroupOperation adGroupOperation in adGroupOperations)
                    {
                        adOperations.AddRange(
                            BuildAdGroupAdOperations(adGroupOperation.operand.id));
                    }

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, adOperations);

                    // Create and add operations to create new ad group criteria (keywords).
                    List <Operation> keywordOperations = new List <Operation>();
                    foreach (AdGroupOperation adGroupOperation in adGroupOperations)
                    {
                        keywordOperations.AddRange(
                            BuildAdGroupCriterionOperations(adGroupOperation.operand.id));
                    }

                    uploadProgress =
                        batchJobUploadHelper.StreamUpload(uploadProgress, keywordOperations);

                    // Mark the upload as complete.
                    batchJobUploadHelper.EndStreamUpload(uploadProgress);

                    bool isCompleted = batchJobUploadHelper.WaitForPendingJob(batchJob.id,
                                                                              TIME_TO_WAIT_FOR_COMPLETION,
                                                                              delegate(BatchJob waitBatchJob, long timeElapsed)
                    {
                        Console.WriteLine("[{0} seconds]: Batch job ID {1} has status '{2}'.",
                                          timeElapsed / 1000, waitBatchJob.id, waitBatchJob.status);
                        batchJob = waitBatchJob;
                        return(false);
                    });

                    if (!isCompleted)
                    {
                        throw new TimeoutException(
                                  "Job is still in pending state after waiting for " +
                                  TIME_TO_WAIT_FOR_COMPLETION + " seconds.");
                    }

                    if (batchJob.processingErrors != null)
                    {
                        foreach (BatchJobProcessingError processingError in batchJob
                                 .processingErrors)
                        {
                            Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                                              processingError.ApiErrorType, processingError.trigger,
                                              processingError.errorString, processingError.fieldPath,
                                              processingError.reason);
                        }
                    }

                    if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null)
                    {
                        BatchJobMutateResponse mutateResponse =
                            batchJobUploadHelper.Download(batchJob.downloadUrl.url);
                        Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
                        foreach (MutateResult mutateResult in mutateResponse.rval)
                        {
                            string outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
                            Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index,
                                              outcome);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new System.ApplicationException(
                              "Failed to add campaigns using batch job.", e);
                }
            }
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        /// <param name="adGroupId">Id of the ad groups to which keywords are
        /// added.</param>
        public void Run(AdWordsUser user, long adGroupId)
        {
            using (BatchJobService batchJobService = (BatchJobService)user.GetService(
                       AdWordsService.v201708.BatchJobService)) {
                BatchJobOperation addOp = new BatchJobOperation()
                {
                    @operator = Operator.ADD,
                    operand   = new BatchJob()
                };

                try {
                    BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[] { addOp }).value[0];

                    Console.WriteLine("Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
                                      batchJob.id, batchJob.status, batchJob.uploadUrl.url);

                    List <AdGroupCriterionOperation> operations = CreateOperations(adGroupId);

                    // Create a BatchJobUtilities instance for uploading operations. Use a
                    // chunked upload.
                    BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user, true, CHUNK_SIZE);

                    // Create a resumable Upload URL to upload the operations.
                    string resumableUploadUrl = batchJobUploadHelper.GetResumableUploadUrl(
                        batchJob.uploadUrl.url);

                    // Use the BatchJobUploadHelper to upload all operations.
                    batchJobUploadHelper.Upload(resumableUploadUrl, operations.ToArray());

                    // A flag to determine if the job was requested to be cancelled. This
                    // typically comes from the user.
                    bool wasCancelRequested = false;

                    bool isComplete = batchJobUploadHelper.WaitForPendingJob(batchJob.id,
                                                                             TIME_TO_WAIT_FOR_COMPLETION, delegate(BatchJob waitBatchJob, long timeElapsed) {
                        Console.WriteLine("[{0} seconds]: Batch job ID {1} has status '{2}'.",
                                          timeElapsed / 1000, waitBatchJob.id, waitBatchJob.status);
                        batchJob = waitBatchJob;
                        return(wasCancelRequested);
                    });

                    // Optional: Cancel the job if it has not completed after waiting for
                    // TIME_TO_WAIT_FOR_COMPLETION.
                    bool shouldWaitForCancellation = false;
                    if (!isComplete && wasCancelRequested)
                    {
                        BatchJobError cancellationError = null;
                        try {
                            batchJobUploadHelper.TryToCancelJob(batchJob.id);
                        } catch (AdWordsApiException e) {
                            cancellationError = GetBatchJobError(e);
                        }
                        if (cancellationError == null)
                        {
                            Console.WriteLine("Successfully requested job cancellation.");
                            shouldWaitForCancellation = true;
                        }
                        else
                        {
                            Console.WriteLine("Job cancellation failed. Error says: {0}.",
                                              cancellationError.reason);
                        }

                        if (shouldWaitForCancellation)
                        {
                            isComplete = batchJobUploadHelper.WaitForPendingJob(batchJob.id,
                                                                                TIME_TO_WAIT_FOR_COMPLETION, delegate(BatchJob waitBatchJob, long timeElapsed) {
                                Console.WriteLine("[{0} seconds]: Batch job ID {1} has status '{2}'.",
                                                  timeElapsed / 1000, waitBatchJob.id, waitBatchJob.status);
                                batchJob = waitBatchJob;
                                return(false);
                            });
                        }
                    }

                    if (!isComplete)
                    {
                        throw new TimeoutException("Job is still in pending state after waiting for " +
                                                   TIME_TO_WAIT_FOR_COMPLETION + " seconds.");
                    }

                    if (batchJob.processingErrors != null)
                    {
                        foreach (BatchJobProcessingError processingError in batchJob.processingErrors)
                        {
                            Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                                              processingError.ApiErrorType, processingError.trigger,
                                              processingError.errorString, processingError.fieldPath,
                                              processingError.reason);
                        }
                    }

                    if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null)
                    {
                        BatchJobMutateResponse mutateResponse = batchJobUploadHelper.Download(
                            batchJob.downloadUrl.url);
                        Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
                        foreach (MutateResult mutateResult in mutateResponse.rval)
                        {
                            String outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
                            Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index, outcome);
                        }
                    }
                    else
                    {
                        Console.WriteLine("No results available for download.");
                    }
                } catch (Exception e) {
                    throw new System.ApplicationException("Failed to create keywords using batch job.", e);
                }
            }
        }
Example #9
0
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        public void Run(AdWordsUser user)
        {
            // Get the BatchJobService.
            BatchJobService batchJobService = (BatchJobService)user.GetService(
                AdWordsService.v201509.BatchJobService);

            try {
                // Create a BatchJob.
                BatchJobOperation addOp = new BatchJobOperation()
                {
                    @operator = Operator.ADD,
                    operand   = new BatchJob()
                };

                BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[] { addOp }).value[0];

                // Get the upload URL from the new job.
                string uploadUrl = batchJob.uploadUrl.url;

                Console.WriteLine("Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
                                  batchJob.id, batchJob.status, batchJob.uploadUrl.url);

                // Create the mutate request that will be sent to the upload URL.
                List <Operation> operations = new List <Operation>();

                // Create and add an operation to create a new budget.
                BudgetOperation budgetOperation = BuildBudgetOperation();
                operations.Add(budgetOperation);

                // Create and add operations to create new campaigns.
                List <CampaignOperation> campaignOperations =
                    BuildCampaignOperations(budgetOperation.operand.budgetId);
                operations.AddRange(campaignOperations);

                // Create and add operations to create new ad groups.
                List <AdGroupOperation> adGroupOperations = new List <AdGroupOperation>();
                foreach (CampaignOperation campaignOperation in campaignOperations)
                {
                    adGroupOperations.AddRange(BuildAdGroupOperations(campaignOperation.operand.id));
                }
                operations.AddRange(adGroupOperations);

                // Create and add operations to create new ad group criteria (keywords).
                foreach (AdGroupOperation adGroupOperation in adGroupOperations)
                {
                    operations.AddRange(BuildAdGroupAdOperations(adGroupOperation.operand.id));
                }

                // Create and add operations to create new ad group ads (text ads).
                foreach (AdGroupOperation adGroupOperation in adGroupOperations)
                {
                    operations.AddRange(BuildAdGroupCriterionOperations(adGroupOperation.operand.id));
                }

                BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user);

                // Use the BatchJobUploadHelper to upload all operations.
                batchJobUploadHelper.Upload(uploadUrl, operations.ToArray());

                long pollAttempts = 0;
                bool isPending    = true;
                do
                {
                    int sleepMillis = (int)Math.Pow(2, pollAttempts) *
                                      POLL_INTERVAL_SECONDS_BASE * 1000;
                    Console.WriteLine("Sleeping {0} millis...", sleepMillis);
                    Thread.Sleep(sleepMillis);

                    Selector selector = new Selector()
                    {
                        fields = new string[] { BatchJob.Fields.Id, BatchJob.Fields.Status,
                                                BatchJob.Fields.DownloadUrl, BatchJob.Fields.ProcessingErrors,
                                                BatchJob.Fields.ProgressStats },
                        predicates = new Predicate[] {
                            Predicate.Equals(BatchJob.Fields.Id, batchJob.id)
                        }
                    };
                    batchJob = batchJobService.get(selector).entries[0];

                    Console.WriteLine("Batch job ID {0} has status '{1}'.", batchJob.id, batchJob.status);
                    isPending = PENDING_STATUSES.Contains(batchJob.status);
                } while (isPending && ++pollAttempts <= MAX_RETRIES);

                if (isPending)
                {
                    throw new TimeoutException("Job is still in pending state after polling " +
                                               MAX_RETRIES + " times.");
                }

                if (batchJob.processingErrors != null)
                {
                    foreach (BatchJobProcessingError processingError in batchJob.processingErrors)
                    {
                        Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                                          processingError.ApiErrorType, processingError.trigger,
                                          processingError.errorString, processingError.fieldPath,
                                          processingError.reason);
                    }
                }

                if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null)
                {
                    BatchJobMutateResponse mutateResponse = batchJobUploadHelper.Download(
                        batchJob.downloadUrl.url);
                    Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
                    foreach (MutateResult mutateResult in mutateResponse.rval)
                    {
                        String outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
                        Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index, outcome);
                    }
                }
            } catch (Exception e) {
                throw new System.ApplicationException("Failed to add campaigns using batch job.", e);
            }
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        public void Run(AdWordsUser user)
        {
            // Get the BatchJobService.
              BatchJobService batchJobService = (BatchJobService) user.GetService(
              AdWordsService.v201601.BatchJobService);

              try {
            // Create a BatchJob.
            BatchJobOperation addOp = new BatchJobOperation() {
              @operator = Operator.ADD,
              operand = new BatchJob()
            };

            BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[] { addOp }).value[0];

            // Get the upload URL from the new job.
            string uploadUrl = batchJob.uploadUrl.url;

            Console.WriteLine("Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
            batchJob.id, batchJob.status, batchJob.uploadUrl.url);

            // Create the mutate request that will be sent to the upload URL.
            List<Operation> operations = new List<Operation>();

            // Create and add an operation to create a new budget.
            BudgetOperation budgetOperation = BuildBudgetOperation();
            operations.Add(budgetOperation);

            // Create and add operations to create new campaigns.
            List<CampaignOperation> campaignOperations =
            BuildCampaignOperations(budgetOperation.operand.budgetId);
            operations.AddRange(campaignOperations);

            // Create and add operations to create new ad groups.
            List<AdGroupOperation> adGroupOperations = new List<AdGroupOperation>();
            foreach (CampaignOperation campaignOperation in campaignOperations) {
              adGroupOperations.AddRange(BuildAdGroupOperations(campaignOperation.operand.id));
            }
            operations.AddRange(adGroupOperations);

            // Create and add operations to create new ad group criteria (keywords).
            foreach (AdGroupOperation adGroupOperation in adGroupOperations) {
              operations.AddRange(BuildAdGroupAdOperations(adGroupOperation.operand.id));
            }

            // Create and add operations to create new ad group ads (text ads).
            foreach (AdGroupOperation adGroupOperation in adGroupOperations) {
              operations.AddRange(BuildAdGroupCriterionOperations(adGroupOperation.operand.id));
            }

            BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user);

            // Create a resumable Upload URL to upload the operations.
            string resumableUploadUrl = batchJobUploadHelper.GetResumableUploadUrl(uploadUrl);

            // Use the BatchJobUploadHelper to upload all operations.
            batchJobUploadHelper.Upload(resumableUploadUrl, operations.ToArray());

            long pollAttempts = 0;
            bool isPending = true;
            do {
              int sleepMillis = (int) Math.Pow(2, pollAttempts) *
              POLL_INTERVAL_SECONDS_BASE * 1000;
              Console.WriteLine("Sleeping {0} millis...", sleepMillis);
              Thread.Sleep(sleepMillis);

              Selector selector = new Selector() {
            fields = new string[] { BatchJob.Fields.Id, BatchJob.Fields.Status },
            predicates = new Predicate[] {
              Predicate.Equals(BatchJob.Fields.Id, batchJob.id)
            }
              };
              batchJob = batchJobService.get(selector).entries[0];

              Console.WriteLine("Batch job ID {0} has status '{1}'.", batchJob.id, batchJob.status);
              isPending = PENDING_STATUSES.Contains(batchJob.status);
            } while (isPending && ++pollAttempts <= MAX_RETRIES);

            if (isPending) {
              throw new TimeoutException("Job is still in pending state after polling " +
              MAX_RETRIES + " times.");
            }

            if (batchJob.processingErrors != null) {
              foreach (BatchJobProcessingError processingError in batchJob.processingErrors) {
            Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                processingError.ApiErrorType, processingError.trigger,
                processingError.errorString, processingError.fieldPath,
                processingError.reason);
              }
            }

            if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null) {
              BatchJobMutateResponse mutateResponse = batchJobUploadHelper.Download(
              batchJob.downloadUrl.url);
              Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
              foreach (MutateResult mutateResult in mutateResponse.rval) {
            String outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
            Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index, outcome);
              }
            }
              } catch (Exception e) {
            throw new System.ApplicationException("Failed to add campaigns using batch job.", e);
              }
        }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        /// <param name="adGroupId">Id of the ad groups to which keywords are
        /// added.</param>
        public void Run(AdWordsUser user, long adGroupId)
        {
            // Get the MutateJobService.
            BatchJobService batchJobService = (BatchJobService)user.GetService(
                AdWordsService.v201603.BatchJobService);

            BatchJobOperation addOp = new BatchJobOperation()
            {
                @operator = Operator.ADD,
                operand   = new BatchJob()
            };

            try {
                BatchJob batchJob = batchJobService.mutate(new BatchJobOperation[] { addOp }).value[0];

                Console.WriteLine("Created BatchJob with ID {0}, status '{1}' and upload URL {2}.",
                                  batchJob.id, batchJob.status, batchJob.uploadUrl.url);

                List <AdGroupCriterionOperation> operations = CreateOperations(adGroupId);

                // Create a BatchJobUtilities instance for uploading operations. Use a
                // chunked upload.
                BatchJobUtilities batchJobUploadHelper = new BatchJobUtilities(user, true, CHUNK_SIZE);

                // Create a resumable Upload URL to upload the operations.
                string resumableUploadUrl = batchJobUploadHelper.GetResumableUploadUrl(
                    batchJob.uploadUrl.url);

                // Use the BatchJobUploadHelper to upload all operations.
                batchJobUploadHelper.Upload(resumableUploadUrl, operations.ToArray());

                long pollAttempts = 0;
                bool isPending    = false;
                batchJob = WaitWhileJobIsPending(batchJobService, batchJob, out isPending,
                                                 out pollAttempts);

                // A flag to determine if the job was requested to be cancelled. This
                // typically comes from the user.
                bool wasCancelRequested = false;

                // Optional: Cancel the job if it has not completed after retrying
                // MAX_RETRIES times.
                if (isPending && !wasCancelRequested && pollAttempts == MAX_RETRIES)
                {
                    batchJob = CancelJob(batchJobService, batchJob);
                    batchJob = WaitWhileJobIsPending(batchJobService, batchJob, out isPending,
                                                     out pollAttempts);
                }

                if (isPending)
                {
                    throw new TimeoutException("Job is still in pending state after polling " +
                                               MAX_RETRIES + " times.");
                }

                if (batchJob.processingErrors != null)
                {
                    foreach (BatchJobProcessingError processingError in batchJob.processingErrors)
                    {
                        Console.WriteLine("  Processing error: {0}, {1}, {2}, {3}, {4}",
                                          processingError.ApiErrorType, processingError.trigger,
                                          processingError.errorString, processingError.fieldPath,
                                          processingError.reason);
                    }
                }

                if (batchJob.downloadUrl != null && batchJob.downloadUrl.url != null)
                {
                    BatchJobMutateResponse mutateResponse = batchJobUploadHelper.Download(
                        batchJob.downloadUrl.url);
                    Console.WriteLine("Downloaded results from {0}.", batchJob.downloadUrl.url);
                    foreach (MutateResult mutateResult in mutateResponse.rval)
                    {
                        String outcome = mutateResult.errorList == null ? "SUCCESS" : "FAILURE";
                        Console.WriteLine("  Operation [{0}] - {1}", mutateResult.index, outcome);
                    }
                }
                else
                {
                    Console.WriteLine("No results available for download.");
                }
            } catch (Exception e) {
                throw new System.ApplicationException("Failed to create keywords using batch job.", e);
            }
        }