Exemplo n.º 1
0
        /// <summary>
        /// Uses the BulkService class to add a campaign.
        /// </summary>
        private async Task <long?> AddCampaignInBulkAsync(AuthorizationData authorizationData)
        {
            _bulkService = new BulkServiceManager(authorizationData);
            _bulkService.StatusPollIntervalInMilliseconds = 1000;

            var uploadResults = await _bulkService.UploadEntitiesAsync(new EntityUploadParameters
            {
                Entities = new BulkEntity[]
                {
                    new BulkCampaign
                    {
                        AccountId = authorizationData.AccountId,
                        Campaign  = new Campaign
                        {
                            Name        = "Campaign " + DateTime.UtcNow.ToString(CultureInfo.InvariantCulture),
                            BudgetType  = BudgetLimitType.DailyBudgetAccelerated,
                            DailyBudget = 10,
                            TimeZone    = "PacificTimeUSCanadaTijuana"
                        }
                    }
                },
                ResponseMode = ResponseMode.ErrorsAndResults
            });

            var campaign = uploadResults.OfType <BulkCampaign>().Single();

            if (campaign.HasErrors)
            {
                ViewBag.Errors  = string.Format("Bulk Upload Error(s): ");
                ViewBag.Errors += string.Join("; ",
                                              campaign.Errors.Select(e => string.Format("{0}: {1}", e.Number, e.Error)));
            }

            return(campaign.Campaign.Id);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Uploads a list of BulkAdGroupProductPartition objects that must represent
        /// a product partition tree for one ad group. You can include BulkAdGroupProductPartition records for more than one
        /// ad group per upload, however, this code example assumes that only one ad group is in scope.
        /// </summary>
        /// <param name="partitionActions">The list of BulkAdGroupProductPartition objects that must represent
        /// a product partition tree.</param>
        /// <returns>The BulkAdGroupProductPartition upload results.</returns>
        private async Task <IList <BulkAdGroupProductPartition> > ApplyBulkProductPartitionActions(
            IList <BulkAdGroupProductPartition> partitionActions)
        {
            var fileUploadParameters = new FileUploadParameters
            {
                ResultFileDirectory = FileDirectory,
                ResultFileName      = ResultFileName,
                OverwriteResultFile = true,
                UploadFilePath      = FileDirectory + UploadFileName,
                ResponseMode        = ResponseMode.ErrorsAndResults
            };

            Writer = new BulkFileWriter(FileDirectory + UploadFileName);
            foreach (var partitionAction in partitionActions)
            {
                Writer.WriteEntity(partitionAction);
            }
            Writer.Dispose();

            var bulkFilePath =
                await BulkServiceManager.UploadFileAsync(fileUploadParameters);

            Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);

            var downloadEntities = Reader.ReadEntities().ToList();
            var bulkAdGroupProductPartitionResults = downloadEntities.OfType <BulkAdGroupProductPartition>().ToList();

            // Add this output line if you want to view details of each BulkAdGroupProductPartition.
            //OutputBulkAdGroupProductPartitions(bulkAdGroupProductPartitionResults);

            Reader.Dispose();

            return(bulkAdGroupProductPartitionResults);
        }
Exemplo n.º 3
0
        /// <summary>
        /// This example uses the ShareDeprecatedTargets helper method to share a target
        /// with multiple campaigns. Then the underlying criterions are downloaded and
        /// the same file is uploaded with no changes. The Bulk service assigns new criterion identifiers
        /// for all except one of the campaigns that it modifies. The original criterion identifiers
        /// only remain associated to last campaign.
        /// For more details see the Upgrade Targets to Criterions guide.
        /// </summary>
        /// <param name="authorizationData"></param>
        /// <returns></returns>
        private async Task MigrateTargetCriterionsB(AuthorizationData authorizationData)
        {
            IList <long> campaignIds = await ShareDeprecatedTargets(authorizationData).ConfigureAwait(continueOnCapturedContext: false);

            campaignIdKey = campaignIds[0];

            // This example restricts the migration to criterions of the campaign that was added
            // via ShareDeprecatedTargets. To migrate all shared target criterions in the account,
            // you can set CampaignIds = null.
            var bulkFilePath = await DownloadTargetsAsCriterions(campaignIds).ConfigureAwait(continueOnCapturedContext: false);

            var fileUploadParameters = new FileUploadParameters
            {
                ResultFileDirectory = FileDirectory,
                CompressUploadFile  = true,
                ResultFileName      = ResultFileName,
                OverwriteResultFile = true,
                // Unless you have modified the default setting,
                // in this case the upload file path will be 'c:\bulk\download.csv'
                UploadFilePath = bulkFilePath,
                ResponseMode   = ResponseMode.ErrorsAndResults
            };
            await BulkServiceManager.UploadFileAsync(fileUploadParameters).ConfigureAwait(continueOnCapturedContext: false);

            // In the result file we can see that the criterions associated with the first two campaigns (Campaign One and Campaign Two)
            // were migrated and assigned new identifiers.The original criterions (201, 202, and 203) are only associated with
            // Campaign Three. The Bulk service assigns new criterions to the first entities it modifies, and the original criterion
            // identifiers only remain associated to last campaign or ad group.

            // Delete i.e. clean up the entities created in this example.
            OutputStatusMessage("Deleting campaigns and criterions . . .\n");
            await DeleteBulkCampaignsAsync(campaignIds).ConfigureAwait(continueOnCapturedContext: false);

            return;
        }
        /// <summary>
        /// Submit the download request and then use the BulkDownloadOperation result to
        /// track status until the download is complete using GetStatusAsync.
        /// </summary>
        /// <param name="submitDownloadParameters"></param>
        /// <returns></returns>
        private async Task SubmitPollDownloadAsync(
            SubmitDownloadParameters submitDownloadParameters)
        {
            var bulkDownloadOperation = await BulkServiceManager.SubmitDownloadAsync(submitDownloadParameters);

            BulkOperationStatus <DownloadStatus> downloadStatus;
            var waitTime = new TimeSpan(0, 0, 5);

            for (int i = 0; i < 24; i++)
            {
                Thread.Sleep(waitTime);

                downloadStatus = await bulkDownloadOperation.GetStatusAsync();

                if (downloadStatus.Status == DownloadStatus.Completed)
                {
                    break;
                }
            }

            var resultFilePath = await bulkDownloadOperation.DownloadResultFileAsync(
                localResultDirectoryName : FileDirectory,
                localResultFileName : ResultFileName,
                decompress : true,
                overwrite : true // Set this value true if you want to overwrite the same file.
                );

            OutputStatusMessage(string.Format("Download result file: {0}", resultFilePath));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Gets the list of BulkAdGroupProductPartition that represent a product partition tree for the specified ad group.
        /// </summary>
        /// <param name="adGroupId">The identifier of the ad group whose product partition tree you want to get.</param>
        /// <returns>The BulkAdGroupProductPartition download results, filtered by the specified ad group ID.</returns>
        private async Task <IList <BulkAdGroupProductPartition> > GetBulkAdGroupProductPartitionTree(long adGroupId)
        {
            var downloadParameters = new DownloadParameters
            {
                DownloadEntities    = new[] { DownloadEntity.AdGroupProductPartitions },
                ResultFileDirectory = FileDirectory,
                ResultFileName      = DownloadFileName,
                OverwriteResultFile = true,
                LastSyncTimeInUTC   = null
            };

            var bulkFilePath = await BulkServiceManager.DownloadFileAsync(downloadParameters);

            Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType);
            var downloadEntities = Reader.ReadEntities().ToList();
            var bulkAdGroupProductPartitionResults = downloadEntities.OfType <BulkAdGroupProductPartition>().ToList();

            Reader.Dispose();

            IList <BulkAdGroupProductPartition> bulkAdGroupProductPartitions = new List <BulkAdGroupProductPartition>();

            foreach (var bulkAdGroupProductPartitionResult in bulkAdGroupProductPartitionResults)
            {
                if (bulkAdGroupProductPartitionResult.AdGroupCriterion != null &&
                    bulkAdGroupProductPartitionResult.AdGroupCriterion.AdGroupId == adGroupId)
                {
                    bulkAdGroupProductPartitions.Add(bulkAdGroupProductPartitionResult);
                }
            }

            return(bulkAdGroupProductPartitions);
        }
        /// <summary>
        /// Writes the specified entities to a local temporary file prior to upload.
        /// </summary>
        /// <param name="uploadEntities"></param>
        /// <returns></returns>
        protected async Task <List <BulkEntity> > UploadEntitiesAsync(
            IEnumerable <BulkEntity> uploadEntities,
            Progress <BulkOperationProgressInfo> progress)
        {
            // The system temp directory will be used if another working directory is not specified. If you are
            // using a cloud service such as Azure you'll want to ensure you do not exceed the file or directory limits.
            // You can specify a different working directory for each BulkServiceManager instance.

            BulkServiceManager.WorkingDirectory = FileDirectory;

            var entityUploadParameters = new EntityUploadParameters
            {
                Entities            = uploadEntities,
                OverwriteResultFile = true,
                ResultFileDirectory = FileDirectory,
                ResultFileName      = ResultFileName,
                ResponseMode        = ResponseMode.ErrorsAndResults
            };

            // The UploadEntitiesAsync method returns IEnumerable<BulkEntity>, so the result file will not
            // be accessible e.g. for CleanupTempFiles until you iterate over the result e.g. via ToList().

            var resultEntities = (await BulkServiceManager.UploadEntitiesAsync(entityUploadParameters)).ToList();

            // The CleanupTempFiles method removes all files (not sub-directories) within the working directory,
            // whether or not the files were created by this BulkServiceManager instance.

            BulkServiceManager.CleanupTempFiles();

            return(resultEntities);
        }
        /// <summary>
        /// Writes the specified entities to a local temporary file after download.
        /// </summary>
        /// <param name="downloadParameters"></param>
        /// <returns></returns>
        protected async Task <List <BulkEntity> > DownloadEntitiesAsync(
            DownloadParameters downloadParameters,
            Progress <BulkOperationProgressInfo> progress,
            CancellationToken cancellationToken)
        {
            // The system temp directory will be used if another working directory is not specified. If you are
            // using a cloud service such as Azure you'll want to ensure you do not exceed the file or directory limits.
            // You can specify a different working directory for each BulkServiceManager instance.

            BulkServiceManager.WorkingDirectory = FileDirectory;

            // The DownloadEntitiesAsync method returns IEnumerable<BulkEntity>, so the download file will not
            // be accessible e.g. for CleanupTempFiles until you iterate over the result e.g. via ToList().

            var resultEntities = (await BulkServiceManager.DownloadEntitiesAsync(
                                      parameters: downloadParameters,
                                      progress: progress,
                                      cancellationToken: cancellationToken)).ToList();

            // The CleanupTempFiles method removes all files (not sub-directories) within the working directory,
            // whether or not the files were created by this BulkServiceManager instance.

            //BulkServiceManager.CleanupTempFiles();

            return(resultEntities);
        }
        /// <summary>
        /// You can submit a download or upload request and the BulkServiceManager will automatically
        /// return results. The BulkServiceManager abstracts the details of checking for result file
        /// completion, and you don't have to write any code for results polling.
        /// </summary>
        /// <param name="downloadParameters"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        private async Task BackgroundCompletionAsync(
            DownloadParameters downloadParameters,
            Progress <BulkOperationProgressInfo> progress,
            CancellationToken cancellationToken)
        {
            var resultFilePath = await BulkServiceManager.DownloadFileAsync(
                parameters : downloadParameters,
                progress : progress,
                cancellationToken : cancellationToken);

            OutputStatusMessage(string.Format("Download result file: {0}", resultFilePath));
        }
        /// <summary>
        /// You can submit a download or upload request and the BulkServiceManager will automatically
        /// return results. The BulkServiceManager abstracts the details of checking for result file
        /// completion, and you don't have to write any code for results polling.
        /// </summary>
        /// <param name="downloadParameters"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        private async Task BackgroundCompletionAsync(
            DownloadParameters downloadParameters,
            Progress <BulkOperationProgressInfo> progress)
        {
            // You may optionally cancel the DownloadFileAsync operation after a specified time interval.
            var tokenSource = new CancellationTokenSource();

            tokenSource.CancelAfter(TimeoutInMilliseconds);

            var resultFilePath = await BulkServiceManager.DownloadFileAsync(downloadParameters, progress, tokenSource.Token);

            OutputStatusMessage(string.Format("Download result file: {0}\n", resultFilePath));
        }
        /// <summary>
        /// Uploads a list of BulkAdGroupProductPartition objects that must represent
        /// a product partition tree for one ad group. You can include BulkAdGroupProductPartition records for more than one
        /// ad group per upload, however, this code example assumes that only one ad group is in scope.
        /// </summary>
        /// <param name="partitionActions">The list of BulkAdGroupProductPartition objects that must represent
        /// a product partition tree.</param>
        /// <returns>The BulkAdGroupProductPartition upload results.</returns>
        private async Task <IList <BulkAdGroupProductPartition> > ApplyBulkProductPartitionActions(
            IList <BulkAdGroupProductPartition> partitionActions)
        {
            var fileUploadParameters = new FileUploadParameters
            {
                ResultFileDirectory = FileDirectory,
                ResultFileName      = ResultFileName,
                OverwriteResultFile = true,
                UploadFilePath      = FileDirectory + UploadFileName,
                ResponseMode        = ResponseMode.ErrorsAndResults
            };

            var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                    OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                      x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

            var tokenSource = new CancellationTokenSource();

            tokenSource.CancelAfter(TimeoutInMilliseconds);

            Writer = new BulkFileWriter(
                filePath: FileDirectory + UploadFileName);

            foreach (var partitionAction in partitionActions)
            {
                Writer.WriteEntity(partitionAction);
            }
            Writer.Dispose();

            var bulkFilePath = await BulkServiceManager.UploadFileAsync(
                parameters : fileUploadParameters,
                progress : progress,
                cancellationToken : tokenSource.Token);

            Reader = new BulkFileReader(
                filePath: bulkFilePath,
                resultFileType: ResultFileType.Upload,
                fileFormat: FileType);

            OutputStatusMessage("Upload results:");

            var downloadEntities = Reader.ReadEntities().ToList();
            var bulkAdGroupProductPartitionResults = downloadEntities.OfType <BulkAdGroupProductPartition>().ToList();

            OutputBulkAdGroupProductPartitions(bulkAdGroupProductPartitionResults);

            Reader.Dispose();

            return(bulkAdGroupProductPartitionResults);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Downloads all target criterions in the account. You can use this method
        /// to sync criterion identifiers and map them to your campaigns and ad groups.
        /// </summary>
        /// <returns>The string result of the Task is the local path to the downloaded bulk file.</returns>
        private async Task <string> DownloadTargetsAsCriterions(IList <long> campaignIds)
        {
            var downloadParameters = new DownloadParameters
            {
                CampaignIds      = campaignIds,
                DownloadEntities = new List <DownloadEntity> {
                    DownloadEntity.AdGroupTargetCriterions,
                    DownloadEntity.CampaignTargetCriterions
                },
                ResultFileDirectory = FileDirectory,
                ResultFileName      = DownloadFileName,
                OverwriteResultFile = true,
                LastSyncTimeInUTC   = null
            };

            OutputStatusMessage("Downloading targets as criterions . . . \n");
            return(await BulkServiceManager.DownloadFileAsync(downloadParameters).ConfigureAwait(continueOnCapturedContext: false));
        }
        /// <summary>
        /// Submit the download request and then use the BulkDownloadOperation result to
        /// track status until the download is complete using TrackAsync.
        /// </summary>
        /// <param name="submitDownloadParameters"></param>
        /// <returns></returns>
        private async Task SubmitTrackDownloadAsync(
            SubmitDownloadParameters submitDownloadParameters,
            Progress <BulkOperationProgressInfo> progress,
            CancellationToken cancellationToken)
        {
            var bulkDownloadOperation = await BulkServiceManager.SubmitDownloadAsync(submitDownloadParameters);

            BulkOperationStatus <DownloadStatus> downloadStatus = await bulkDownloadOperation.TrackAsync(
                progress : progress,
                cancellationToken : cancellationToken);

            var resultFilePath = await bulkDownloadOperation.DownloadResultFileAsync(
                localResultDirectoryName : FileDirectory,
                localResultFileName : ResultFileName,
                decompress : true,
                overwrite : true // Set this value true if you want to overwrite the same file.
                );

            OutputStatusMessage(string.Format("Download result file: {0}", resultFilePath));
        }
        /// <summary>
        /// Submit the download request and then use the BulkDownloadOperation result to
        /// track status until the download is complete e.g. either using
        /// TrackAsync or GetStatusAsync.
        /// </summary>
        /// <param name="submitDownloadParameters"></param>
        /// <returns></returns>
        private async Task SubmitAndDownloadAsync(SubmitDownloadParameters submitDownloadParameters)
        {
            var bulkDownloadOperation = await BulkServiceManager.SubmitDownloadAsync(submitDownloadParameters);

            // You may optionally cancel the TrackAsync operation after a specified time interval.
            var tokenSource = new CancellationTokenSource();

            tokenSource.CancelAfter(TimeoutInMilliseconds);

            BulkOperationStatus <DownloadStatus> downloadStatus = await bulkDownloadOperation.TrackAsync(null, tokenSource.Token);

            // You can use TrackAsync to poll until complete as shown above,
            // or use custom polling logic with GetStatusAsync as shown below.

            //BulkOperationStatus<DownloadStatus> downloadStatus;
            //var waitTime = new TimeSpan(0, 0, 5);

            //for (int i = 0; i < 24; i++)
            //{
            //    Thread.Sleep(waitTime);

            //    downloadStatus = await bulkDownloadOperation.GetStatusAsync();

            //    if (downloadStatus.Status == DownloadStatus.Completed)
            //    {
            //        break;
            //    }
            //}

            var resultFilePath = await bulkDownloadOperation.DownloadResultFileAsync(
                FileDirectory,
                ResultFileName,
                decompress : true,
                overwrite : true // Set this value true if you want to overwrite the same file.
                );

            OutputStatusMessage(string.Format("Download result file: {0}\n", resultFilePath));
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);
                BulkService.StatusPollIntervalInMilliseconds = 5000;

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                // In this example we will download all ads and keywords in the account.
                var entities = BulkDownloadEntity.Ads |
                    BulkDownloadEntity.Keywords;

                // DownloadParameters is used for Option A below.
                var downloadParameters = new DownloadParameters
                {
                    CampaignIds = null,
                    DataScope = DataScope.EntityData | DataScope.EntityPerformanceData,
                    PerformanceStatsDateRange = new PerformanceStatsDateRange { PredefinedTime = ReportTimePeriod.LastFourWeeks },
                    Entities = entities,
                    FileType = FileType,
                    LastSyncTimeInUTC = null,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = DownloadFileName,
                    OverwriteResultFile = true
                };

                // SubmitDownloadParameters is used for Option B and Option C below.
                var submitDownloadParameters = new SubmitDownloadParameters
                {
                    CampaignIds = null,
                    DataScope = DataScope.EntityData | DataScope.EntityPerformanceData,
                    PerformanceStatsDateRange = new PerformanceStatsDateRange { PredefinedTime = ReportTimePeriod.LastFourWeeks },
                    Entities = entities,
                    FileType = FileType,
                    LastSyncTimeInUTC = null
                };

                // Option A - Background Completion with BulkServiceManager
                // You can submit a download or upload request and the BulkServiceManager will automatically 
                // return results. The BulkServiceManager abstracts the details of checking for result file 
                // completion, and you don't have to write any code for results polling.

                OutputStatusMessage("Awaiting Background Completion . . .");
                await BackgroundCompletionAsync(downloadParameters, progress);

                // Option B - Submit and Download with BulkServiceManager
                // Submit the download request and then use the BulkDownloadOperation result to 
                // track status until the download is complete e.g. either using
                // TrackAsync or GetStatusAsync.

                //OutputStatusMessage("Awaiting Submit and Download . . .");
                //await SubmitAndDownloadAsync(submitDownloadParameters);

                // Option C - Download Results with BulkServiceManager
                // If for any reason you have to resume from a previous application state, 
                // you can use an existing download request identifier and use it 
                // to download the result file. 

                // For example you might have previously retrieved a request ID using SubmitDownloadAsync.
                //var bulkDownloadOperation = await BulkService.SubmitDownloadAsync(submitDownloadParameters);
                //var requestId = bulkDownloadOperation.RequestId;

                // Given the request ID above, you can resume the workflow and download the bulk file.
                // The download request identifier is valid for two days. 
                // If you do not download the bulk file within two days, you must request it again.
                //OutputStatusMessage("Awaiting Download Results . . .");
                //await DownloadResultsAsync(requestId, authorizationData);
                
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(String.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.Errors.Select(error => String.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.OperationErrors.Select(error => String.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(String.Join("; ", ex.Detail.BatchErrors.Select(error => String.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                OutputStatusMessage(String.Format("{0} % Complete", x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                const int appAdExtensionIdKey = -11;
                const int callAdExtensionIdKey = -12;
                const int locationAdExtensionIdKey = -13;
                const int siteLinksAdExtensionIdKey = -14;
                const int campaignIdKey = -123;

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, 
                // and additional elements needed to read from and write to a bulk file. 

                var uploadEntities = new List<BulkEntity>();

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",
                        BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget = 1000.00,
                        TimeZone = "PacificTimeUSCanadaTijuana",
                        Status = CampaignStatus.Paused,

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,

                        // Used with FinalUrls shown in the sitelinks that we will add below.
                        TrackingUrlTemplate =
                            "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}"
                    }
                };

                // Prepare ad extensions for upload

                var bulkAppAdExtension = new BulkAppAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    AppAdExtension = new AppAdExtension
                    {
                        AppPlatform = "Windows",
                        AppStoreId = "AppStoreIdGoesHere",
                        DestinationUrl = "DestinationUrlGoesHere",
                        DisplayText = "Contoso",
                        Id = appAdExtensionIdKey,
                    }
                };

                var bulkCallAdExtension = new BulkCallAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    CallAdExtension = new CallAdExtension
                    {
                        CountryCode = "US",
                        PhoneNumber = "2065550100",
                        IsCallOnly = false,
                        Id = callAdExtensionIdKey
                    }
                };

                var bulkLocationAdExtension = new BulkLocationAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    LocationAdExtension = new LocationAdExtension
                    {
                        Id = locationAdExtensionIdKey,
                        PhoneNumber = "206-555-0100",
                        CompanyName = "Contoso Shoes",
                        IconMediaId = null,
                        ImageMediaId = null,
                        Address = new Address
                        {
                            StreetAddress = "1234 Washington Place",
                            StreetAddress2 = "Suite 1210",
                            CityName = "Woodinville",
                            ProvinceName = "WA",
                            CountryCode = "US",
                            PostalCode = "98608"
                        }
                    }
                };

                // Note that when written to file using the BulkFileWriter, an extra Sitelink Ad Extension record with Deleted
                // status precedes the actual site link record or records that you want to upload. All bulk entities 
                // that are derived from MultiRecordBulkEntiy are preceded with a Deleted record using the BulkFileWriter. 
                // In this example it is a moot point because we are creating a new ad extension. If the specified
                // ad extension Id already exists in your account, the Deleted record effectively deletes the existing
                // extension and replaces it with the SiteLinksAdExtension specified below.

                var bulkSiteLinkAdExtension = new BulkSiteLinkAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    SiteLinksAdExtension = new SiteLinksAdExtension
                    {
                        // Note that if you do not specify a negative Id as reference key, each of SiteLinks items will
                        // be split during upload into separate sitelink ad extensions with unique ad extension identifiers.
                        Id = siteLinksAdExtensionIdKey,
                        SiteLinks = new List<SiteLink>
                                {
                                    new SiteLink
                                        {
                                            DisplayText = "Women's Shoe Sale 1",

                                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                                            // Here is an example of a DestinationUrl you might have used previously. 
                                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                                            // To migrate from DestinationUrl to FinalUrls for existing sitelinks, you can set DestinationUrl
                                            // to an empty string when updating the sitelink. If you are removing DestinationUrl,
                                            // then FinalUrls is required.
                                            // DestinationUrl = "",

                                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                                            // landing page URLs. 
                                            FinalUrls = new[] {
                                                "http://www.contoso.com/womenshoesale"
                                            },
                                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                                            // for mobile devices.
                                            FinalMobileUrls = new[] {
                                                "http://mobile.contoso.com/womenshoesale"
                                            }, 
                                            // You could use a tracking template which would override the campaign level
                                            // tracking template. Tracking templates defined for lower level entities 
                                            // override those set for higher level entities.
                                            // In this example we are using the campaign level tracking template.
                                            TrackingUrlTemplate = null,

                                            // Set custom parameters that are specific to this sitelink, 
                                            // and can be used by the sitelink, ad group, campaign, or account level tracking template. 
                                            // In this example we are using the campaign level tracking template.
                                            UrlCustomParameters = new CustomParameters {
                                                Parameters = new[] {
                                                    new CustomParameter(){
                                                        Key = "promoCode",
                                                        Value = "PROMO1"
                                                    },
                                                    new CustomParameter(){
                                                        Key = "season",
                                                        Value = "summer"
                                                    },
                                                }
                                            },
                                        },
                                    new SiteLink
                                        {
                                            DisplayText = "Women's Shoe Sale 2",

                                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                                            // Here is an example of a DestinationUrl you might have used previously. 
                                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                                            // To migrate from DestinationUrl to FinalUrls for existing sitelinks, you can set DestinationUrl
                                            // to an empty string when updating the sitelink. If you are removing DestinationUrl,
                                            // then FinalUrls is required.
                                            // DestinationUrl = "",

                                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                                            // landing page URLs. 
                                            FinalUrls = new[] {
                                                "http://www.contoso.com/womenshoesale"
                                            },
                                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                                            // for mobile devices.
                                            FinalMobileUrls = new[] {
                                                "http://mobile.contoso.com/womenshoesale"
                                            }, 
                                            // You could use a tracking template which would override the campaign level
                                            // tracking template. Tracking templates defined for lower level entities 
                                            // override those set for higher level entities.
                                            // In this example we are using the campaign level tracking template.
                                            TrackingUrlTemplate = null,

                                            // Set custom parameters that are specific to this sitelink, 
                                            // and can be used by the sitelink, ad group, campaign, or account level tracking template. 
                                            // In this example we are using the campaign level tracking template.
                                            UrlCustomParameters = new CustomParameters {
                                                Parameters = new[] {
                                                    new CustomParameter(){
                                                        Key = "promoCode",
                                                        Value = "PROMO2"
                                                    },
                                                    new CustomParameter(){
                                                        Key = "season",
                                                        Value = "summer"
                                                    },
                                                }
                                            },
                                        }
                                }
                    }
                    // Note that BulkSiteLinkAdExtension.SiteLinks is read only and only 
                    // accessible when reading results from the download or upload results file.
                    // To upload new site links for a new site links ad extension, you should specify
                    // BulkSiteLinkAdExtension.SiteLinksAdExtension.SiteLinks as shown above.
                };

                // Prepare ad extension associations for upload

                var bulkCampaignAppAdExtension = new BulkCampaignAppAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = appAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };

                var bulkCampaignCallAdExtension = new BulkCampaignCallAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = callAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };

                var bulkCampaignLocationAdExtension = new BulkCampaignLocationAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = locationAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };

                var bulkCampaignSiteLinkAdExtension = new BulkCampaignSiteLinkAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = siteLinksAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };


                // Upload the entities created above.
                // Dependent entities such as BulkCampaignCallAdExtension must be written after any dependencies,  
                // for example the BulkCampaign and BulkCallAdExtension. 

                uploadEntities.Add(bulkCampaign);

                uploadEntities.Add(bulkAppAdExtension);
                uploadEntities.Add(bulkCallAdExtension);
                uploadEntities.Add(bulkLocationAdExtension);
                uploadEntities.Add(bulkSiteLinkAdExtension);

                uploadEntities.Add(bulkCampaignAppAdExtension);
                uploadEntities.Add(bulkCampaignCallAdExtension);
                uploadEntities.Add(bulkCampaignLocationAdExtension);
                uploadEntities.Add(bulkCampaignSiteLinkAdExtension);

                OutputStatusMessage("\nAdding campaign, ad extensions, and associations . . .\n");

                // Write the upload output

                var Reader = await UploadEntities(uploadEntities);
                var bulkEntities = Reader.ReadEntities().ToList();

                var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var appAdExtensionResults = bulkEntities.OfType<BulkAppAdExtension>().ToList();
                OutputBulkAppAdExtensions(appAdExtensionResults);

                var callAdExtensionResults = bulkEntities.OfType<BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                var locationAdExtensionResults = bulkEntities.OfType<BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                var siteLinkAdExtensionResults = bulkEntities.OfType<BulkSiteLinkAdExtension>().ToList();
                OutputBulkSiteLinkAdExtensions(siteLinkAdExtensionResults);

                OutputBulkCampaignAppAdExtensions(bulkEntities.OfType<BulkCampaignAppAdExtension>().ToList());
                OutputBulkCampaignCallAdExtensions(bulkEntities.OfType<BulkCampaignCallAdExtension>().ToList());
                OutputBulkCampaignLocationAdExtensions(bulkEntities.OfType<BulkCampaignLocationAdExtension>().ToList());
                OutputBulkCampaignSiteLinkAdExtensions(bulkEntities.OfType<BulkCampaignSiteLinkAdExtension>().ToList());

                Reader.Dispose();

                #endregion Add

                #region Update

                // Update the site links ad extension. 
                // Add an additional site link, and update an existing site link

                // Do not create a BulkSiteLinkAdExtension for update, unless you want to replace all existing SiteLinks
                // with the specified SiteLinks for the specified ad extension. 
                // Instead you should upload one or more site links as a list of BulkSiteLink.

                var siteLinkAdExtensionId = siteLinkAdExtensionResults[0].SiteLinksAdExtension.Id;
                
                var bulkSiteLinks = new List<BulkSiteLink>
                {
                    siteLinkAdExtensionResults[0].SiteLinks[0],
                    new BulkSiteLink 
                    {
                        AccountId = authorizationData.AccountId,
                        AdExtensionId = siteLinkAdExtensionId,
                        Order = 3,
                        SiteLink = new SiteLink
                        {
                            
                            DisplayText = "Women's Shoe Sale 3",

                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                            // Destination URLs are deprecated and will be read-only starting in the 
                            // second calendar quarter of 2016. After Bulk and Campaign Management version 9 APIs 
                            // sunset at the beginning of the third calendar quarter of 2016, you will no longer 
                            // be able to use Destination URLs. 
                            // Here is an example of a DestinationUrl you might have used previously. 
                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this sitelink, 
                            // and can be used by the sitelink, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO3"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        }
                    },
                };

                // To remove a subset of custom parameters, specify the custom parameters that 
                // you want to keep in the Parameters element of the CustomParameters object.
                                
                bulkSiteLinks[0].SiteLink.UrlCustomParameters = new CustomParameters {
                    Parameters = new[] {
                        new CustomParameter(){
                            Key = "promoCode",
                            Value = "updatedpromo"
                        },
                    }
                };

                // Write the new site link and updated site link to the file

                uploadEntities = new List<BulkEntity>();

                foreach (var bulkSiteLink in bulkSiteLinks)
                {
                    uploadEntities.Add(bulkSiteLink);
                }


                OutputStatusMessage("\nUpdating sitelinks . . .\n");

                // Write the upload output

                Reader = await UploadEntities(uploadEntities);
                bulkEntities = Reader.ReadEntities().ToList();
                var siteLinkResults = bulkEntities.OfType<BulkSiteLink>().ToList();
                OutputBulkSiteLinks(siteLinkResults);

                Reader.Dispose();

                #endregion Update

                #region Delete

                // Prepare the bulk entities that you want to delete. You must set the Id field to the corresponding 
                // entity identifier, and the Status field to Deleted. 

                var campaignId = campaignResults[0].Campaign.Id;
                bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id = campaignId,
                        Status = CampaignStatus.Deleted
                    }
                };

                var appAdExtensionId = appAdExtensionResults[0].AppAdExtension.Id;
                bulkAppAdExtension = new BulkAppAdExtension
                {
                    AppAdExtension = new AppAdExtension
                    {
                        Id = appAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                var callAdExtensionId = callAdExtensionResults[0].CallAdExtension.Id;
                bulkCallAdExtension = new BulkCallAdExtension
                {
                    CallAdExtension = new CallAdExtension
                    {
                        Id = callAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                var locationAdExtensionId = locationAdExtensionResults[0].LocationAdExtension.Id;
                bulkLocationAdExtension = new BulkLocationAdExtension
                {
                    LocationAdExtension = new LocationAdExtension
                    {
                        Id = locationAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };


                bulkSiteLinkAdExtension = new BulkSiteLinkAdExtension
                {
                    SiteLinksAdExtension = new SiteLinksAdExtension
                    {
                        Id = siteLinkAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                // Write the entities that you want deleted, to the specified file.
                // Dependent entities such as BulkCampaignCallAdExtension are deleted without being specified explicitly.  
                // For example, if you delete either BulkCampaign or BulkCallAdExtension, then the equivalent of 
                // BulkCampaignCallAdExtension is effectively deleted. 

                uploadEntities = new List<BulkEntity>();

                uploadEntities.Add(bulkCampaign);

                uploadEntities.Add(bulkAppAdExtension);
                uploadEntities.Add(bulkCallAdExtension);
                uploadEntities.Add(bulkLocationAdExtension);
                uploadEntities.Add(bulkSiteLinkAdExtension);

                OutputStatusMessage("\nDeleting campaign and ad extensions . . .\n");

                // Write the upload output

                Reader = await UploadEntities(uploadEntities);
                bulkEntities = Reader.ReadEntities().ToList();

                campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                appAdExtensionResults = bulkEntities.OfType<BulkAppAdExtension>().ToList();
                OutputBulkAppAdExtensions(appAdExtensionResults);

                callAdExtensionResults = bulkEntities.OfType<BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                locationAdExtensionResults = bulkEntities.OfType<BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                siteLinkAdExtensionResults = bulkEntities.OfType<BulkSiteLinkAdExtension>().ToList();
                OutputBulkSiteLinkAdExtensions(siteLinkAdExtensionResults);

                OutputBulkCampaignAppAdExtensions(bulkEntities.OfType<BulkCampaignAppAdExtension>().ToList());
                OutputBulkCampaignCallAdExtensions(bulkEntities.OfType<BulkCampaignCallAdExtension>().ToList());
                OutputBulkCampaignLocationAdExtensions(bulkEntities.OfType<BulkCampaignLocationAdExtension>().ToList());
                OutputBulkCampaignSiteLinkAdExtensions(bulkEntities.OfType<BulkCampaignSiteLinkAdExtension>().ToList());

                Reader.Dispose();

                #endregion Delete

            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, 
                // and additional elements needed to read from and write to a bulk file. 

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new negative keyword in the BulkCampaignNegativeKeyword object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId = null,
                        DailyBudget = 50,
                        BudgetType = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,
                    }
                };

                var bulkCampaignNegativeKeywords = new BulkCampaignNegativeKeyword[] {
                    new BulkCampaignNegativeKeyword {
                        CampaignId = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Phrase,
                            Text = "auto",
                        }
                    },
                    new BulkCampaignNegativeKeyword {
                        CampaignId = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Exact,
                            Text = "auto",
                        }
                    },
                    new BulkCampaignNegativeKeyword {
                        CampaignId = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Phrase,
                            Text = "car",
                        }
                    },
                    new BulkCampaignNegativeKeyword {
                        CampaignId = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Exact,
                            Text = "car",
                        }
                    },
                };

                // Negative keywords can be added and deleted from a shared negative keyword list. The negative keyword list can be shared or associated with multiple campaigns.
                // You can create up to 20 negative keyword lists per account and share or associate them with any campaign in the same account. 
                // To create a negative keyword list, upload a BulkNegativeKeywordList (Negative Keyword List record type). 
                // For each negative keyword that you want to add to the list, upload a BulkSharedNegativeKeyword (Shared Negative Keyword record type). 
                // To associate the negative keyword list with a campaign, also upload a BulkCampaignNegativeKeywordList (Campaign Negative Keyword List Association record type). 
                
                var bulkNegativeKeywordList = new BulkNegativeKeywordList
                {
                    NegativeKeywordList = new NegativeKeywordList
                    {
                        // Since we are adding the list and the negative keywords during the same upload, 
                        // we will use a reference key to the negative keyword list identifier.
                        Id = negativeKeywordListIdKey,
                        Name = "My NKW List",
                    },
                };

                var bulkSharedNegativeKeywords = new BulkSharedNegativeKeyword[] {
                    new BulkSharedNegativeKeyword {
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Phrase,
                            Text = "mobile",
                        },
                        NegativeKeywordListId = negativeKeywordListIdKey,
                    },
                    new BulkSharedNegativeKeyword {
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Exact,
                            Text = "mobile",
                        },
                        NegativeKeywordListId = negativeKeywordListIdKey,
                    },
                };

                var bulkCampaignNegativeKeywordList = new BulkCampaignNegativeKeywordList
                {
                    SharedEntityAssociation = new SharedEntityAssociation
                    {
                        EntityId = campaignIdKey,
                        EntityType = "Campaign",
                        SharedEntityId = negativeKeywordListIdKey,
                        SharedEntityType = "NegativeKeywordList",
                    }
                };
                
                var uploadEntities = new List<BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                foreach (var bulkCampaignNegativeKeyword in bulkCampaignNegativeKeywords)
                {
                    uploadEntities.Add(bulkCampaignNegativeKeyword);
                }

                uploadEntities.Add(bulkNegativeKeywordList);
                foreach (var bulkSharedNegativeKeyword in bulkSharedNegativeKeywords)
                {
                    uploadEntities.Add(bulkSharedNegativeKeyword);
                }
                uploadEntities.Add(bulkCampaignNegativeKeywordList);

                // Upload and write the output

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                var downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var campaignNegativeKeywordResults = downloadEntities.OfType<BulkCampaignNegativeKeyword>().ToList();
                OutputBulkCampaignNegativeKeywords(campaignNegativeKeywordResults);

                var negativeKeywordListResults = downloadEntities.OfType<BulkNegativeKeywordList>().ToList();
                OutputBulkNegativeKeywordLists(negativeKeywordListResults);

                var sharedNegativeKeywordListResults = downloadEntities.OfType<BulkSharedNegativeKeyword>().ToList();
                OutputBulkSharedNegativeKeywords(sharedNegativeKeywordListResults);

                var campaignNegativeKeywordListResults = downloadEntities.OfType<BulkCampaignNegativeKeywordList>().ToList();
                OutputBulkCampaignNegativeKeywordLists(campaignNegativeKeywordListResults);

                Reader.Dispose();

                #endregion Add

                #region CleanUp

                //Delete the campaign and negative keywords that were previously added. 
                //You should remove this region if you want to view the added entities in the 
                //Bing Ads web application or another tool.

                //You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                //When you delete a BulkCampaign, the dependent entities such as BulkCampaignNegativeKeyword 
                //are deleted without being specified explicitly.  
                //When you delete a BulkNegativeKeywordList, the dependent entities such as BulkSharedNegativeKeyword 
                //are deleted without being specified explicitly.

                uploadEntities = new List<BulkEntity>();
                
                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                foreach (var negativeKeywordListResult in negativeKeywordListResults)
                {
                    negativeKeywordListResult.Status = Status.Deleted;
                    uploadEntities.Add(negativeKeywordListResult);
                }

                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign and negative keywords . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType<BulkCampaign>().ToList());
                OutputBulkNegativeKeywordLists(downloadEntities.OfType<BulkNegativeKeywordList>().ToList());
                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
Exemplo n.º 17
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                // You will need to use the Campaign Management service to get the Bing Merchant Center Store Id.
                // This will be used when creating a new Bing Shopping Campaign.
                // For other operations such as adding product conditions,
                // you can manage Bing Shopping Campaigns solely with the Bulk Service.

                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(this.OutputStatusMessage);
                CampaignManagementExampleHelper.CampaignManagementService =
                    new ServiceClient <ICampaignManagementService>(authorizationData, environment);

                BulkServiceManager = new BulkServiceManager(authorizationData, environment);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region CampaignThroughAdGroupSetup

                // Get a list of all Bing Merchant Center stores associated with your CustomerId

                IList <BMCStore> stores = (await CampaignManagementExampleHelper.GetBMCStoresByCustomerIdAsync())?.BMCStores;
                if (stores == null)
                {
                    OutputStatusMessage(
                        string.Format("You do not have any BMC stores registered for CustomerId {0}.\n", authorizationData.CustomerId)
                        );
                    return;
                }

                var uploadEntities = new List <BulkEntity>();

                /* Add a new Bing Shopping campaign that will be associated with a ProductScope criterion.
                 *  - Set the CampaignType element of the Campaign to Shopping.
                 *  - Create a ShoppingSetting instance and set its Priority (0, 1, or 2), SalesCountryCode, and StoreId elements.
                 *    Add this shopping setting to the Settings list of the Campaign.
                 */

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth.
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id
                        // will be used when associating this new campaign with a new campaign product scope in the BulkCampaignProductScope object below.
                        Id           = campaignIdKey,
                        CampaignType = CampaignType.Shopping,
                        Settings     = new[] {
                            new ShoppingSetting()
                            {
                                Priority         = 0,
                                SalesCountryCode = "US",
                                StoreId          = (int)stores[0].Id
                            }
                        },
                        Name        = "Bing Shopping Campaign " + DateTime.UtcNow,
                        Description = "Bing Shopping Campaign Example.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId    = null,
                        DailyBudget = 50,
                        BudgetType  = BudgetLimitType.DailyBudgetStandard,

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // Used with CustomParameters defined in lower level entities such as ad group criterion.
                        TrackingUrlTemplate =
                            "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}"
                    }
                };

                /* Optionally, you can create a ProductScope criterion that will be associated with your Bing Shopping campaign.
                 * Use the product scope criterion to include a subset of your product catalog, for example a specific brand,
                 * category, or product type. A campaign can only be associated with one ProductScope, which contains a list
                 * of up to 7 ProductCondition. You'll also be able to specify more specific product conditions for each ad group.
                 */

                var bulkCampaignProductScope = new BulkCampaignProductScope
                {
                    BiddableCampaignCriterion = new BiddableCampaignCriterion()
                    {
                        CampaignId   = campaignIdKey,
                        CriterionBid = null,  // Not applicable for product scope
                        Criterion    = new ProductScope()
                        {
                            Conditions = new ProductCondition[] {
                                new ProductCondition {
                                    Operand   = "Condition",
                                    Attribute = "New"
                                },
                                new ProductCondition {
                                    Operand   = "CustomLabel0",
                                    Attribute = "MerchantDefinedCustomLabel"
                                },
                            }
                        },
                    },
                    Status = Status.Active,
                };

                // Specify one or more ad groups.

                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup    = new AdGroup
                    {
                        Id        = adGroupIdKey,
                        Name      = "Product Categories",
                        StartDate = null,
                        EndDate   = new Microsoft.BingAds.V12.CampaignManagement.Date
                        {
                            Month = 12,
                            Day   = 31,
                            Year  = DateTime.UtcNow.Year + 1
                        },
                        Language = "English",
                        Status   = AdGroupStatus.Active
                    },
                };

                /*
                 * Create a product ad. You must add at least one product ad to the ad group.
                 * The product ad identifier can be used for reporting analytics.
                 * Use Merchant Promotions if you want tags to appear at the bottom of your product ad
                 * as "special offer" links, helping to increase customer engagement. For details
                 * on Merchant Promotions see https://help.bingads.microsoft.com/#apex/3/en/56805/0.
                 */

                var bulkProductAd = new BulkProductAd
                {
                    AdGroupId = adGroupIdKey,
                    ProductAd = new ProductAd {
                    }
                };

                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkAdGroup);
                uploadEntities.Add(bulkCampaignProductScope);
                uploadEntities.Add(bulkProductAd);

                // Upload and write the output

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var productAdResults = downloadEntities.OfType <BulkProductAd>().ToList();
                OutputBulkProductAds(productAdResults);

                var campaignProductScopeResults = downloadEntities.OfType <BulkCampaignProductScope>().ToList();
                OutputBulkCampaignProductScopes(campaignProductScopeResults);

                Reader.Dispose();

                #endregion CampaignThroughAdGroupSetup

                #region BidAllProducts

                var adGroupId = (long)adGroupResults[0].AdGroup.Id;

                var helper = new ProductPartitionHelper(adGroupId);

                var root = helper.AddUnit(
                    null,
                    new ProductCondition {
                    Operand = "All", Attribute = null
                },
                    0.35,
                    false,
                    "root"
                    );

                OutputStatusMessage("Applying only the root as a Unit with a bid . . . \n");
                var applyBulkProductPartitionActionsResults =
                    await ApplyBulkProductPartitionActions(helper.PartitionActions);

                var productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                OutputStatusMessage("The ad group's product partition only has a tree root node: \n");
                OutputProductPartitions(productPartitions);

                /*
                 * Let's update the bid of the root Unit we just added.
                 */

                var updatedRoot = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root");
                var bid         = new FixedBid
                {
                    Amount = 0.45
                };
                ((BiddableAdGroupCriterion)(updatedRoot.AdGroupCriterion)).CriterionBid = bid;

                helper = new ProductPartitionHelper(adGroupId);
                helper.UpdatePartition(updatedRoot);

                OutputStatusMessage("Updating the bid for the tree root node . . . \n");
                await ApplyBulkProductPartitionActions(helper.PartitionActions);

                productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                OutputStatusMessage("Updated the bid for the tree root node: \n");
                OutputProductPartitions(productPartitions);

                #endregion BidAllProducts

                #region InitializeTree

                /*
                 * Now we will overwrite any existing tree root, and build a product partition group tree structure in multiple steps.
                 * You could build the entire tree in a single call since there are less than 20,000 nodes; however,
                 * we will build it in steps to demonstrate how to use the results from bulk upload to update the tree.
                 *
                 * For a list of validation rules, see the Product Ads technical guide:
                 * https://docs.microsoft.com/en-us/bingads/guides/product-ads
                 */

                helper = new ProductPartitionHelper(adGroupId);

                /*
                 * Check whether a root node exists already.
                 */

                var existingRoot = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root");
                if (existingRoot != null)
                {
                    existingRoot.ClientId = "deletedroot";
                    helper.DeletePartition(existingRoot);
                }

                root = helper.AddSubdivision(
                    null,
                    new ProductCondition {
                    Operand = "All", Attribute = null
                },
                    "root"
                    );

                /*
                 * The direct children of any node must have the same Operand.
                 * For this example we will use CategoryL1 nodes as children of the root.
                 * For a list of valid CategoryL1 through CategoryL5 values, see the Bing Category Taxonomy:
                 * http://go.microsoft.com/fwlink?LinkId=507666
                 */
                var animalsSubdivision = helper.AddSubdivision(
                    root,
                    new ProductCondition {
                    Operand = "CategoryL1", Attribute = "Animals & Pet Supplies"
                },
                    "animalsSubdivision"
                    );

                /*
                 * If you use a CategoryL2 node, it must be a descendant (child or later) of a CategoryL1 node.
                 * In other words you cannot have a CategoryL2 node as parent of a CategoryL1 node.
                 * For this example we will a CategoryL2 node as child of the CategoryL1 Animals & Pet Supplies node.
                 */
                var petSuppliesSubdivision = helper.AddSubdivision(
                    animalsSubdivision,
                    new ProductCondition {
                    Operand = "CategoryL2", Attribute = "Pet Supplies"
                },
                    "petSuppliesSubdivision"
                    );

                var brandA = helper.AddUnit(
                    petSuppliesSubdivision,
                    new ProductCondition {
                    Operand = "Brand", Attribute = "Brand A"
                },
                    0.35,
                    false,
                    "brandA"
                    );

                /*
                 * If you won't bid on Brand B, set the helper method's bidAmount to '0' and isNegative to true.
                 * The helper method will create a NegativeAdGroupCriterion and apply the condition.
                 */
                var brandB = helper.AddUnit(
                    petSuppliesSubdivision,
                    new ProductCondition {
                    Operand = "Brand", Attribute = "Brand B"
                },
                    0,
                    true,
                    "brandB"
                    );

                var otherBrands = helper.AddUnit(
                    petSuppliesSubdivision,
                    new ProductCondition {
                    Operand = "Brand", Attribute = null
                },
                    0.35,
                    false,
                    "otherBrands"
                    );

                var otherPetSupplies = helper.AddUnit(
                    animalsSubdivision,
                    new ProductCondition {
                    Operand = "CategoryL2", Attribute = null
                },
                    0.35,
                    false,
                    "otherPetSupplies"
                    );

                var electronics = helper.AddUnit(
                    root,
                    new ProductCondition {
                    Operand = "CategoryL1", Attribute = "Electronics"
                },
                    0.35,
                    false,
                    "electronics"
                    );

                var otherCategoryL1 = helper.AddUnit(
                    root,
                    new ProductCondition {
                    Operand = "CategoryL1", Attribute = null
                },
                    0.35,
                    false,
                    "otherCategoryL1"
                    );

                OutputStatusMessage("Applying product partitions to the ad group . . . \n");
                applyBulkProductPartitionActionsResults =
                    await ApplyBulkProductPartitionActions(helper.PartitionActions);

                productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                /*
                 * The product partition group tree now has 9 nodes.
                 *
                 * All other (Root Node)
                 |
                 +-- Animals & Pet Supplies (CategoryL1)
                 |    |
                 |    +-- Pet Supplies (CategoryL2)
                 |    |    |
                 |    |    +-- Brand A
                 |    |    |
                 |    |    +-- Brand B
                 |    |    |
                 |    |    +-- All other (Brand)
                 |    |
                 |    +-- All other (CategoryL2)
                 |
                 +-- Electronics (CategoryL1)
                 |
                 +-- All other (CategoryL1)
                 |
                 */

                OutputStatusMessage("The product partition group tree now has 9 nodes: \n");
                OutputProductPartitions(productPartitions);

                #endregion InitializeTree

                #region UpdateTree

                /*
                 * Let's replace the Electronics (CategoryL1) node created above with an Electronics (CategoryL1) node that
                 * has children i.e. Brand C (Brand), Brand D (Brand), and All other (Brand) as follows:
                 *
                 *  Electronics (CategoryL1)
                 |
                 +-- Brand C (Brand)
                 |
                 +-- Brand D (Brand)
                 |
                 +-- All other (Brand)
                 |
                 */

                helper = new ProductPartitionHelper(adGroupId);

                /*
                 * To replace a node we must know its Id and its ParentCriterionId. In this case the parent of the node
                 * we are replacing is All other (Root Node). The node that we are replacing is Electronics (CategoryL1).
                 */
                var rootId = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root").AdGroupCriterion.Id;
                electronics.AdGroupCriterion.Id = GetNodeByClientId(applyBulkProductPartitionActionsResults, "electronics").AdGroupCriterion.Id;
                helper.DeletePartition(electronics);

                var parent = new BulkAdGroupProductPartition
                {
                    AdGroupCriterion = new BiddableAdGroupCriterion()
                    {
                        Id = rootId
                    }
                };

                var electronicsSubdivision = helper.AddSubdivision(
                    parent,
                    new ProductCondition {
                    Operand = "CategoryL1", Attribute = "Electronics"
                },
                    "electronicsSubdivision"
                    );

                var brandC = helper.AddUnit(
                    electronicsSubdivision,
                    new ProductCondition {
                    Operand = "Brand", Attribute = "Brand C"
                },
                    0.35,
                    false,
                    "brandC"
                    );

                var brandD = helper.AddUnit(
                    electronicsSubdivision,
                    new ProductCondition {
                    Operand = "Brand", Attribute = "Brand D"
                },
                    0.35,
                    false,
                    "brandD"
                    );

                var otherElectronicsBrands = helper.AddUnit(
                    electronicsSubdivision,
                    new ProductCondition {
                    Operand = "Brand", Attribute = null
                },
                    0.35,
                    false,
                    "otherElectronicsBrands"
                    );

                OutputStatusMessage(
                    "Updating the product partition group to refine Electronics (CategoryL1) with 3 child nodes . . . \n"
                    );
                applyBulkProductPartitionActionsResults =
                    await ApplyBulkProductPartitionActions(helper.PartitionActions);

                productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                /*
                 * The product partition group tree now has 12 nodes, including the children of Electronics (CategoryL1):
                 *
                 * All other (Root Node)
                 |
                 +-- Animals & Pet Supplies (CategoryL1)
                 |    |
                 |    +-- Pet Supplies (CategoryL2)
                 |    |    |
                 |    |    +-- Brand A
                 |    |    |
                 |    |    +-- Brand B
                 |    |    |
                 |    |    +-- All other (Brand)
                 |    |
                 |    +-- All other (CategoryL2)
                 |
                 +-- Electronics (CategoryL1)
                 |    |
                 |    +-- Brand C (Brand)
                 |    |
                 |    +-- Brand D (Brand)
                 |    |
                 |    +-- All other (Brand)
                 |
                 +-- All other (CategoryL1)
                 |
                 */

                OutputStatusMessage(
                    "The product partition group tree now has 12 nodes, including the children of Electronics (CategoryL1): \n"
                    );
                OutputProductPartitions(productPartitions);

                #endregion UpdateTree

                #region CleanUp

                //Delete the campaign, ad group, criterion, and ad that were previously added.
                //You should remove this region if you want to view the added entities in the
                //Bing Ads web application or another tool.

                //You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                //When you delete a BulkCampaign, the dependent entities such as BulkAdGroup and BulkAdGroupProductPartition
                //are deleted without being specified explicitly.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage(
                    "Deleting the campaign, product conditions, ad group, product partitions, and product ad... \n"
                    );

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());

                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            // Catch Campaign Management service exceptions
            catch (FaultException <Microsoft.BingAds.V12.CampaignManagement.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.CampaignManagement.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 18
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var uploadEntities = new List<BulkEntity>();

                #region Add

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, 
                // and additional elements needed to read from and write to a bulk file. 

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",
                        BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget = 1000.00,
                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,

                        // Used with FinalUrls shown in the text ads that we will add below.
                        TrackingUrlTemplate =
                            "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}"
                    }
                };

                // Specify one or more ad groups.
                
                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup = new AdGroup
                    {
                        Id = adGroupIdKey,
                        Name = "Women's Red Shoe Sale",
                        AdDistribution = AdDistribution.Search,
                        BiddingModel = BiddingModel.Keyword,
                        PricingModel = PricingModel.Cpc,
                        StartDate = null,
                        EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date { Month = 12, Day = 31, Year = 2016 },
                        Language = "English",
                        Status = AdGroupStatus.Active,

                        // You could use a tracking template which would override the campaign level
                        // tracking template. Tracking templates defined for lower level entities 
                        // override those set for higher level entities.
                        // In this example we are using the campaign level tracking template.
                        TrackingUrlTemplate = null,
                    },
                };

                // In this example only the second keyword should succeed. The Text of the first keyword exceeds the limit,
                // and the third keyword is a duplicate of the second keyword. 

                var bulkKeywords = new [] {
                    new BulkKeyword{
                        AdGroupId = adGroupIdKey,
                        Keyword = new Keyword
                        {
                            Bid = new Bid { Amount = 0.47 },
                            Param2 = "10% Off",
                            MatchType = MatchType.Broad,
                            Text = "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes " +
                                   "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes " +
                                   "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes"
                        },
                    },
                    new BulkKeyword{
                        AdGroupId = adGroupIdKey,
                        Keyword = new Keyword
                        {
                            Bid = new Bid { Amount = 0.47 },
                            Param2 = "10% Off",
                            MatchType = MatchType.Phrase,
                            Text = "Brand-A Shoes"
                        },
                    },
                    new BulkKeyword{
                        AdGroupId = adGroupIdKey,
                        Keyword = new Keyword
                        {
                            Bid = new Bid { Amount = 0.47 },
                            Param2 = "10% Off",
                            MatchType = MatchType.Phrase,
                            Text = "Brand-A Shoes"
                        },
                    },
                };

                // In this example only the first 3 ads should succeed. 
                // The Title of the fourth ad is empty and not valid,
                // and the fifth ad is a duplicate of the second ad. 

                var bulkTextAds = new [] {
                    new BulkTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        TextAd = new TextAd 
                        {
                            Title = "Women's Shoe Sale",
                            Text = "Huge Savings on red shoes.",
                            DisplayUrl = "Contoso.com",
                        
                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                            // Here is an example of a DestinationUrl you might have used previously. 
                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                            // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl
                            // to an empty string when updating the ad. If you are removing DestinationUrl,
                            // then FinalUrls is required.
                            // DestinationUrl = "",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale",
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale",
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO1"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            }
                        },
                    },
                    new BulkTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        TextAd = new TextAd 
                        {
                            Title = "Women's Super Shoe Sale",
                            Text = "Huge Savings on red shoes.",
                            DisplayUrl = "Contoso.com",                       
                        
                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                            // Here is an example of a DestinationUrl you might have used previously. 
                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                            // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl
                            // to an empty string when updating the ad. If you are removing DestinationUrl,
                            // then FinalUrls is required.
                            // DestinationUrl = "",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO2"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                    new BulkTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        TextAd = new TextAd 
                        {
                            Title = "Women's Red Shoe Sale",
                            Text = "Huge Savings on red shoes.",
                            DisplayUrl = "Contoso.com",

                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                            // Here is an example of a DestinationUrl you might have used previously. 
                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                            // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl
                            // to an empty string when updating the ad. If you are removing DestinationUrl,
                            // then FinalUrls is required.
                            // DestinationUrl = "",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO3"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                    new BulkTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        TextAd = new TextAd 
                        {
                            Title = "",
                            Text = "Huge Savings on red shoes.",
                            DisplayUrl = "Contoso.com",                       
                        
                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                            // Here is an example of a DestinationUrl you might have used previously. 
                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                            // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl
                            // to an empty string when updating the ad. If you are removing DestinationUrl,
                            // then FinalUrls is required.
                            // DestinationUrl = "",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO4"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                    new BulkTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        TextAd = new TextAd 
                        {
                            Title = "Women's Super Shoe Sale",
                            Text = "Huge Savings on red shoes.",
                            DisplayUrl = "Contoso.com",                       
                        
                            // If you are currently using Destination URLs, you must replace them with Final URLs. 
                            // Here is an example of a DestinationUrl you might have used previously. 
                            // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123",

                            // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl
                            // to an empty string when updating the ad. If you are removing DestinationUrl,
                            // then FinalUrls is required.
                            // DestinationUrl = "",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO5"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                };


                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkAdGroup);

                foreach (var bulkKeyword in bulkKeywords)
                {
                    uploadEntities.Add(bulkKeyword);
                }

                foreach (var bulkTextAd in bulkTextAds)
                {
                    uploadEntities.Add(bulkTextAd);
                }

                // Write the upload output

                var Reader = await UploadEntities(uploadEntities);
                var bulkEntities = Reader.ReadEntities().ToList();

                var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = bulkEntities.OfType<BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var keywordResults = bulkEntities.OfType<BulkKeyword>().ToList();
                OutputBulkKeywords(keywordResults);

                var textAdResults = bulkEntities.OfType<BulkTextAd>().ToList();
                OutputBulkTextAds(textAdResults);

                Reader.Dispose();

                #endregion Add


                #region CleanUp

                /* Delete the campaign, ad group, keywords, and ads that were previously added. 
                 * You should remove this region if you want to view the added entities in the 
                 * Bing Ads web application or another tool.
                 */

                var campaignId = campaignResults[0].Campaign.Id;
                bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id = campaignId,
                        Status = CampaignStatus.Deleted
                    }
                };

                uploadEntities = new List<BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                // Write the upload output

                Reader = await UploadEntities(uploadEntities);
                bulkEntities = Reader.ReadEntities().ToList();
                campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);
                Reader.Dispose();

                OutputStatusMessage(String.Format("Deleted CampaignId {0}\n", campaignResults[0].Campaign.Id));

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
Exemplo n.º 19
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, 
                // and additional elements needed to read from and write to a bulk file. 
                
                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId = null,
                        DailyBudget = 50,
                        BudgetType = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,
                    }
                };

                // You can specify one negative site per BulkCampaignNegativeSite (singular), or multiple negative sites
                // in a BulkCampaignNegativeSites (plural) object.

                var bulkCampaignNegativeSite = new BulkCampaignNegativeSite[] {
                    new BulkCampaignNegativeSite {
                        // CampaignName will be ignored if you specify CampaignId.
                        CampaignName = null,
                        CampaignId = campaignIdKey,
                        Website = "contoso.com/negativesite1"
                    },
                    new BulkCampaignNegativeSite {
                        CampaignId = campaignIdKey,
                        Website = "contoso.com/negativesite2"
                    },
                };

                // If you upload a BulkCampaignNegativeSites bulk entity, then you are effectively replacing any existing 
                // negative sites assigned to the campaign. Thus, when a BulkCampaignNegativeSites entity is written to the 
                // upload file, an extra Campaign Negative Site record is included where the Status is Deleted and the 
                // Website field is empty. 
                // That said, if you include additional BulkCampaignNegativeSite or BulkCampaignNegativeSites in the same upload, 
                // they will be included in the new set of negative sites.
                var bulkCampaignNegativeSites = new BulkCampaignNegativeSites[] {
                    new BulkCampaignNegativeSites {
                        // CampaignName will be ignored if you specify CampaignId.
                        CampaignName = null,
                        CampaignNegativeSites = new CampaignNegativeSites
                        {
                           CampaignId = campaignIdKey,
                           NegativeSites = new string[]
                           {
                               "contoso.com/negativesite3",
                               "contoso.com/negativesite4",
                           }
                        }
                    },
                };

                var uploadEntities = new List<BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                foreach (var campaignNegativeSite in bulkCampaignNegativeSite)
                {
                    uploadEntities.Add(campaignNegativeSite);
                }

                foreach (var campaignNegativeSites in bulkCampaignNegativeSites)
                {
                    uploadEntities.Add(campaignNegativeSites);
                }

                // Upload and write the output

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                var downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                // If you modify the sample to upload only BulkCampaignNegativeSite entities for a campaign, the SDK will abstract  
                // the results file contents as one or more BulkCampaignNegativeSite. If you upload both BulkCampaignNegativeSite 
                // and BulkCampaignNegativeSites as shown above, then the SDK will abstract the results file contents as a 
                // BulkCampaignNegativeSites object containing all of the negative sites for the campaign, 
                // including those uploaded as a BulkCampaignNegativeSite. 

                // Whether you use the SDK to upload the entities, or only use the SDK to read an upload results file,
                // the SDK will abstract the results file as follows:
                // If the file contains an extra Campaign Negative Site record where the Status is Deleted and the 
                // Website field is empty, the SDK returns a BulkCampaignNegativeSites (plural) object.
                // Otherwise the SDK returns one or more BulkCampaignNegativeSite (singlular) objects.

                var campaignNegativeSiteResults = downloadEntities.OfType<BulkCampaignNegativeSite>().ToList();
                OutputBulkCampaignNegativeSite(campaignNegativeSiteResults);
                
                var campaignNegativeSitesResults = downloadEntities.OfType<BulkCampaignNegativeSites>().ToList();
                OutputBulkCampaignNegativeSites(campaignNegativeSitesResults);

                Reader.Dispose();

                #endregion Add

                #region CleanUp

                //Delete the campaign and negative sites that were previously added. 
                //You should remove this region if you want to view the added entities in the 
                //Bing Ads web application or another tool.

                //You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                //When you delete a BulkCampaign, the dependent entities such as BulkCampaignNegativeSite 
                //are deleted without being specified explicitly.  

                uploadEntities = new List<BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign and negative sites . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType<BulkCampaign>().ToList());
                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);
                BulkServiceManager.StatusPollIntervalInMilliseconds = 5000;

                // Track download or upload progress

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                // Some BulkServiceManager operations can be cancelled after a time interval.

                var tokenSource = new CancellationTokenSource();
                tokenSource.CancelAfter(TimeoutInMilliseconds);

                // Download all campaigns, ad groups, and ads in the account.

                var entities = new[] {
                    DownloadEntity.Campaigns,
                    DownloadEntity.AdGroups,
                    DownloadEntity.Ads,
                };

                // DownloadParameters is used for Option A below.
                var downloadParameters = new DownloadParameters
                {
                    CampaignIds         = null,
                    DataScope           = DataScope.EntityData | DataScope.QualityScoreData,
                    DownloadEntities    = entities,
                    FileType            = FileType,
                    LastSyncTimeInUTC   = null,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = DownloadFileName,
                    OverwriteResultFile = true
                };

                // SubmitDownloadParameters is used for Option B and Option C below.
                var submitDownloadParameters = new SubmitDownloadParameters
                {
                    CampaignIds       = null,
                    DataScope         = DataScope.EntityData | DataScope.QualityScoreData,
                    DownloadEntities  = entities,
                    FileType          = FileType,
                    LastSyncTimeInUTC = null
                };

                // Option A - Background Completion with BulkServiceManager
                // You can submit a download or upload request and the BulkServiceManager will automatically
                // return results. The BulkServiceManager abstracts the details of checking for result file
                // completion, and you don't have to write any code for results polling.

                OutputStatusMessage("-----\nAwaiting Background Completion with DownloadFileAsync...");
                await BackgroundCompletionAsync(
                    downloadParameters : downloadParameters,
                    progress : progress,
                    cancellationToken : tokenSource.Token);

                // Alternatively we can use DownloadEntitiesAsync if we want to work with the entities in memory.
                // If you enable this option the result file from BackgroundCompletionAsync will also be deleted
                // if written to the same working directory.
                OutputStatusMessage("-----\nAwaiting Background Completion with DownloadEntitiesAsync...");
                var downloadEntities = await DownloadEntitiesAsync(
                    downloadParameters : downloadParameters,
                    progress : progress,
                    cancellationToken : tokenSource.Token);

                // Option B - Submit and Download with BulkServiceManager
                // Submit the download request and then use the BulkDownloadOperation result to
                // track status until the download is complete e.g. either using
                // TrackAsync or GetStatusAsync.

                OutputStatusMessage("-----\nAwaiting Submit, Track, and Download...");
                await SubmitTrackDownloadAsync(
                    submitDownloadParameters : submitDownloadParameters,
                    progress : progress,
                    cancellationToken : tokenSource.Token);

                // A second variation of Option B.
                // See SubmitTrackDownloadAsync for details.

                OutputStatusMessage("-----\nAwaiting Submit, Poll, and Download...");
                await SubmitTrackDownloadAsync(
                    submitDownloadParameters : submitDownloadParameters,
                    progress : progress,
                    cancellationToken : tokenSource.Token);

                // Option C - Download Results with BulkServiceManager
                // If for any reason you have to resume from a previous application state,
                // you can use an existing download request identifier and use it
                // to download the result file.

                // For example you might have previously retrieved a request ID using SubmitDownloadAsync.

                var bulkDownloadOperation = await BulkServiceManager.SubmitDownloadAsync(
                    parameters : submitDownloadParameters);

                var requestId = bulkDownloadOperation.RequestId;

                // Given the request ID above, you can resume the workflow and download the bulk file.
                // The download request identifier is valid for two days.
                // If you do not download the bulk file within two days, you must request it again.

                OutputStatusMessage("-----\nAwaiting Download Results...");
                await DownloadResultsAsync(
                    requestId : requestId,
                    authorizationData : authorizationData,
                    progress : progress,
                    cancellationToken : tokenSource.Token);
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(String.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                // Used to output the Campaign Management objects within Bulk entities.
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);

                var uploadEntities = new List <BulkEntity>();

                // Add a new campaign and associate it with ad extensions.

                uploadEntities.Add(GetBulkCampaign());

                uploadEntities.Add(GetBulkActionAdExtension());
                uploadEntities.Add(GetBulkAppAdExtension());
                uploadEntities.Add(GetBulkCallAdExtension());
                uploadEntities.Add(GetBulkCalloutAdExtension());
                uploadEntities.Add(GetBulkLocationAdExtension());
                uploadEntities.Add(GetBulkPriceAdExtension());
                uploadEntities.Add(GetBulkReviewAdExtension());
                uploadEntities.Add(GetBulkSitelinkAdExtension());
                uploadEntities.Add(GetBulkStructuredSnippetAdExtension());

                uploadEntities.Add(GetBulkCampaignActionAdExtension());
                uploadEntities.Add(GetBulkCampaignAppAdExtension());
                uploadEntities.Add(GetBulkCampaignCallAdExtension());
                uploadEntities.Add(GetBulkCampaignCalloutAdExtension());
                uploadEntities.Add(GetBulkCampaignLocationAdExtension());
                uploadEntities.Add(GetBulkCampaignPriceAdExtension());
                uploadEntities.Add(GetBulkCampaignReviewAdExtension());
                uploadEntities.Add(GetBulkCampaignSitelinkAdExtension());
                uploadEntities.Add(GetBulkCampaignStructuredSnippetAdExtension());

                OutputStatusMessage("-----\nAdding campaign, ad extensions, and associations...");

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var actionAdExtensionResults = downloadEntities.OfType <BulkActionAdExtension>().ToList();
                OutputBulkActionAdExtensions(actionAdExtensionResults);

                var appAdExtensionResults = downloadEntities.OfType <BulkAppAdExtension>().ToList();
                OutputBulkAppAdExtensions(appAdExtensionResults);

                var callAdExtensionResults = downloadEntities.OfType <BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                var calloutAdExtensionResults = downloadEntities.OfType <BulkCalloutAdExtension>().ToList();
                OutputBulkCalloutAdExtensions(calloutAdExtensionResults);

                var imageAdExtensionResults = downloadEntities.OfType <BulkImageAdExtension>().ToList();
                OutputBulkImageAdExtensions(imageAdExtensionResults);

                var locationAdExtensionResults = downloadEntities.OfType <BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                var priceAdExtensionResults = downloadEntities.OfType <BulkPriceAdExtension>().ToList();
                OutputBulkPriceAdExtensions(priceAdExtensionResults);

                var reviewAdExtensionResults = downloadEntities.OfType <BulkReviewAdExtension>().ToList();
                OutputBulkReviewAdExtensions(reviewAdExtensionResults);

                var structuredSnippetAdExtensionResults = downloadEntities.OfType <BulkStructuredSnippetAdExtension>().ToList();
                OutputBulkStructuredSnippetAdExtensions(structuredSnippetAdExtensionResults);

                var sitelinkAdExtensionResults = downloadEntities.OfType <BulkSitelinkAdExtension>().ToList();
                OutputBulkSitelinkAdExtensions(sitelinkAdExtensionResults);

                OutputBulkCampaignAdExtensionAssociations(downloadEntities.OfType <BulkCampaignAdExtensionAssociation>().ToList());

                Reader.Dispose();


                // Delete the campaign and ad extensions that were previously added.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    if (campaignResult.Campaign != null)
                    {
                        campaignResult.Campaign.Status = CampaignStatus.Deleted;
                        uploadEntities.Add(campaignResult);
                    }
                }

                foreach (var actionAdExtensionResult in actionAdExtensionResults)
                {
                    if (actionAdExtensionResult.ActionAdExtension.Id > 0)
                    {
                        actionAdExtensionResult.ActionAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(actionAdExtensionResult);
                    }
                }

                foreach (var appAdExtensionResult in appAdExtensionResults)
                {
                    //By default the sample does not successfully create any app ad extensions,
                    //because you need to provide details above such as the AppStoreId.
                    if (appAdExtensionResult.AppAdExtension.Id > 0)
                    {
                        appAdExtensionResult.AppAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(appAdExtensionResult);
                    }
                }

                foreach (var callAdExtensionResult in callAdExtensionResults)
                {
                    if (callAdExtensionResult.CallAdExtension.Id > 0)
                    {
                        callAdExtensionResult.CallAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(callAdExtensionResult);
                    }
                }

                foreach (var calloutAdExtensionResult in calloutAdExtensionResults)
                {
                    if (calloutAdExtensionResult.CalloutAdExtension.Id > 0)
                    {
                        calloutAdExtensionResult.CalloutAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(calloutAdExtensionResult);
                    }
                }

                foreach (var imageAdExtensionResult in imageAdExtensionResults)
                {
                    if (imageAdExtensionResult.ImageAdExtension.Id > 0)
                    {
                        imageAdExtensionResult.ImageAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(imageAdExtensionResult);
                    }
                }

                foreach (var locationAdExtensionResult in locationAdExtensionResults)
                {
                    if (locationAdExtensionResult.LocationAdExtension.Id > 0)
                    {
                        locationAdExtensionResult.LocationAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(locationAdExtensionResult);
                    }
                }

                foreach (var priceAdExtensionResult in priceAdExtensionResults)
                {
                    if (priceAdExtensionResult.PriceAdExtension.Id > 0)
                    {
                        priceAdExtensionResult.PriceAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(priceAdExtensionResult);
                    }
                }

                foreach (var reviewAdExtensionResult in reviewAdExtensionResults)
                {
                    if (reviewAdExtensionResult.ReviewAdExtension.Id > 0)
                    {
                        reviewAdExtensionResult.ReviewAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(reviewAdExtensionResult);
                    }
                }

                foreach (var sitelinkAdExtensionResult in sitelinkAdExtensionResults)
                {
                    if (sitelinkAdExtensionResult.SitelinkAdExtension.Id > 0)
                    {
                        sitelinkAdExtensionResult.SitelinkAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(sitelinkAdExtensionResult);
                    }
                }

                foreach (var structuredSnippetAdExtensionResult in structuredSnippetAdExtensionResults)
                {
                    if (structuredSnippetAdExtensionResult.StructuredSnippetAdExtension.Id > 0)
                    {
                        structuredSnippetAdExtensionResult.StructuredSnippetAdExtension.Status = AdExtensionStatus.Deleted;
                        uploadEntities.Add(structuredSnippetAdExtensionResult);
                    }
                }

                // Upload and write the output

                OutputStatusMessage("-----\nDeleting campaign and ad extensions...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());
                OutputBulkActionAdExtensions(downloadEntities.OfType <BulkActionAdExtension>().ToList());
                OutputBulkAppAdExtensions(downloadEntities.OfType <BulkAppAdExtension>().ToList());
                OutputBulkCallAdExtensions(downloadEntities.OfType <BulkCallAdExtension>().ToList());
                OutputBulkCalloutAdExtensions(downloadEntities.OfType <BulkCalloutAdExtension>().ToList());
                OutputBulkImageAdExtensions(downloadEntities.OfType <BulkImageAdExtension>().ToList());
                OutputBulkLocationAdExtensions(downloadEntities.OfType <BulkLocationAdExtension>().ToList());
                OutputBulkPriceAdExtensions(downloadEntities.OfType <BulkPriceAdExtension>().ToList());
                OutputBulkReviewAdExtensions(downloadEntities.OfType <BulkReviewAdExtension>().ToList());
                OutputBulkSitelinkAdExtensions(downloadEntities.OfType <BulkSitelinkAdExtension>().ToList());
                OutputBulkStructuredSnippetAdExtensions(downloadEntities.OfType <BulkStructuredSnippetAdExtension>().ToList());

                Reader.Dispose();
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V13.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V13.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkServiceManager = new BulkServiceManager(authorizationData);
                BulkServiceManager.StatusPollIntervalInMilliseconds = 5000;

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Upload

                // In this example we'll upload a new campaign and then delete it.

                var uploadEntities = new List <BulkEntity>();
                uploadEntities.Add(GetExampleBulkCampaign());

                OutputStatusMessage("Uploading a campaign with UploadEntitiesAsync . . .");
                var resultEntities = await UploadEntitiesAsync(uploadEntities, progress);

                uploadEntities = new List <BulkEntity>();
                foreach (var campaignResult in resultEntities.OfType <BulkCampaign>().ToList())
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                OutputStatusMessage("Deleting a campaign with UploadEntitiesAsync . . .");
                resultEntities = await UploadEntitiesAsync(uploadEntities, progress);

                #endregion Upload

                #region Download

                // In this example we will download all campaigns, ad groups, and ads in the account.
                var entities = new[] {
                    DownloadEntity.Campaigns,
                    DownloadEntity.AdGroups,
                    DownloadEntity.Ads
                };

                // DownloadParameters is used for Option A below.
                var downloadParameters = new DownloadParameters
                {
                    CampaignIds = null,
                    DataScope   = DataScope.EntityData | DataScope.QualityScoreData,
                    PerformanceStatsDateRange = new PerformanceStatsDateRange {
                        PredefinedTime = ReportTimePeriod.LastFourWeeks
                    },
                    DownloadEntities    = entities,
                    FileType            = FileType,
                    LastSyncTimeInUTC   = null,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = DownloadFileName,
                    OverwriteResultFile = true
                };

                // SubmitDownloadParameters is used for Option B and Option C below.
                var submitDownloadParameters = new SubmitDownloadParameters
                {
                    CampaignIds = null,
                    DataScope   = DataScope.EntityData | DataScope.QualityScoreData,
                    PerformanceStatsDateRange = new PerformanceStatsDateRange {
                        PredefinedTime = ReportTimePeriod.LastFourWeeks
                    },
                    DownloadEntities  = entities,
                    FileType          = FileType,
                    LastSyncTimeInUTC = null
                };

                // Option A - Background Completion with BulkServiceManager
                // You can submit a download or upload request and the BulkServiceManager will automatically
                // return results. The BulkServiceManager abstracts the details of checking for result file
                // completion, and you don't have to write any code for results polling.

                OutputStatusMessage("Awaiting Background Completion with DownloadFileAsync . . .");
                await BackgroundCompletionAsync(downloadParameters, progress);

                // Alternatively we can use DownloadEntitiesAsync if we want to work with the entities in memory.
                // If you enable this option the result file from BackgroundCompletionAsync will also be deleted
                // if written to the same working directory.
                OutputStatusMessage("Awaiting Background Completion with DownloadEntitiesAsync . . .");
                var downloadEntities = await DownloadEntitiesAsync(downloadParameters, progress);

                // Option B - Submit and Download with BulkServiceManager
                // Submit the download request and then use the BulkDownloadOperation result to
                // track status until the download is complete e.g. either using
                // TrackAsync or GetStatusAsync.

                //OutputStatusMessage("Awaiting Submit and Download . . .");
                //await SubmitAndDownloadAsync(submitDownloadParameters);

                // Option C - Download Results with BulkServiceManager
                // If for any reason you have to resume from a previous application state,
                // you can use an existing download request identifier and use it
                // to download the result file.

                // For example you might have previously retrieved a request ID using SubmitDownloadAsync.
                //var bulkDownloadOperation = await BulkService.SubmitDownloadAsync(submitDownloadParameters);
                //var requestId = bulkDownloadOperation.RequestId;

                // Given the request ID above, you can resume the workflow and download the bulk file.
                // The download request identifier is valid for two days.
                // If you do not download the bulk file within two days, you must request it again.
                //OutputStatusMessage("Awaiting Download Results . . .");
                //await DownloadResultsAsync(requestId, authorizationData);

                #endregion Download
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(String.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(String.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                CustomerService = new ServiceClient <ICustomerManagementService>(authorizationData);
                BulkService     = new BulkServiceManager(authorizationData);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                Dictionary <long, List <long> > targetToEntities = new Dictionary <long, List <long> >();
                Dictionary <long, List <Dictionary <long, KeyValuePair <long, string> > > > targetToEntities2 = new Dictionary <long, List <Dictionary <long, KeyValuePair <long, string> > > >();

                var downloadParameters = new DownloadParameters
                {
                    CampaignIds = null,
                    Entities    = BulkDownloadEntity.AdGroupTargets |
                                  BulkDownloadEntity.CampaignTargets,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = DownloadFileName,
                    OverwriteResultFile = true,
                    LastSyncTimeInUTC   = null
                };

                // Search for the Bing Ads accounts that the user can access.

                var getUserResponse = await GetUserAsync(null);

                var user     = getUserResponse.User;
                var accounts = await SearchAccountsByUserIdAsync(user.Id);

                foreach (var account in accounts)
                {
                    var linkToUI = string.Format("https://ui.bingads.microsoft.com/Campaign/Campaigns?cid={0}&aid={1}#/customer/{0}/account/{1}/campaign",
                                                 authorizationData.CustomerId,
                                                 account.Id);
                    OutputStatusMessage(string.Format("Downloading targets for account {0} \n", account.Number));
                    OutputStatusMessage(linkToUI);

                    authorizationData.AccountId = (long)account.Id;
                    BulkService = new BulkServiceManager(authorizationData);
                    var downloadEntities = (await BulkService.DownloadEntitiesAsync(downloadParameters)).ToList();

                    var adGroupTargetResults = downloadEntities.OfType <Microsoft.BingAds.V10.Bulk.Entities.BulkAdGroupTarget>().ToList();
                    foreach (var entity in adGroupTargetResults)
                    {
                        MapTargetToEntity(targetToEntities, (long)entity.Target.Id, (long)entity.AdGroupId);
                        MapTargetToEntity2(
                            targetToEntities2,
                            authorizationData.AccountId,
                            (long)entity.Target.Id,
                            (long)entity.AdGroupId,
                            "AdGroup"
                            );
                    }

                    var campaignTargetResults = downloadEntities.OfType <Microsoft.BingAds.V10.Bulk.Entities.BulkCampaignTarget>().ToList();
                    foreach (var entity in campaignTargetResults)
                    {
                        MapTargetToEntity(targetToEntities, (long)entity.Target.Id, (long)entity.CampaignId);
                        MapTargetToEntity2(
                            targetToEntities2,
                            authorizationData.AccountId,
                            (long)entity.Target.Id,
                            (long)entity.CampaignId,
                            "Campaign"
                            );
                    }
                }

                OutputStatusMessage("\nView 1: By Target Id:");

                foreach (var dict in targetToEntities)
                {
                    if (dict.Value.Count() > 1)
                    {
                        OutputStatusMessage(string.Format("\nTargetId {0} is shared by the following entities:", dict.Key));
                        OutputStatusMessage(string.Join("\r\n", dict.Value.Select(id => string.Format("{0}", id))));
                    }
                }

                OutputStatusMessage("\nView 2: With Account Detail:");
                OutputStatusMessage("\nTargetId, AccountId, EntityId, EntityType");

                foreach (var targetDictionary in targetToEntities2)
                {
                    if (targetDictionary.Value.Count() > 1)
                    {
                        foreach (var accountDictionary in targetDictionary.Value)
                        {
                            foreach (var accountIdKey in accountDictionary.Keys)
                            {
                                OutputStatusMessage(
                                    string.Format("{0}, {1}, {2}, {3}",
                                                  targetDictionary.Key,
                                                  accountIdKey,
                                                  accountDictionary[accountIdKey].Key,  // EntityId
                                                  accountDictionary[accountIdKey].Value // EntityType e.g. Campaign or AdGroup
                                                  ));
                            }
                        }
                    }
                }
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                // Used to output the Campaign Management objects within Bulk entities.
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(string.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var uploadEntities = new List<BulkEntity>();

                // Add a search campaign.
                
                var bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        BudgetType = BudgetLimitType.DailyBudgetStandard,
                        DailyBudget = 50,
                        CampaignType = CampaignType.Search,
                        Id = campaignIdKey,
                        Languages = new string[] { "All" },
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        TimeZone = "PacificTimeUSCanadaTijuana",
                    },
                };
                uploadEntities.Add(bulkCampaign);

                // Add an ad group within the campaign.

                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup = new AdGroup
                    {
                        Id = adGroupIdKey,
                        Name = "Women's Red Shoe Sale",
                        StartDate = null,
                        EndDate = new Microsoft.BingAds.V12.CampaignManagement.Date
                        {
                            Month = 12,
                            Day = 31,
                            Year = DateTime.UtcNow.Year + 1
                        },
                        CpcBid = new Bid { Amount = 0.09 },
                    },
                };
                uploadEntities.Add(bulkAdGroup);

                // Add keywords and ads within the ad group.

                var bulkKeyword = new BulkKeyword{
                    AdGroupId = adGroupIdKey,
                    Keyword = new Keyword
                    {
                        Bid = new Bid { Amount = 0.47 },
                        Param2 = "10% Off",
                        MatchType = MatchType.Phrase,
                        Text = "Brand-A Shoes",
                    },                    
                };
                uploadEntities.Add(bulkKeyword);

                var bulkExpandedTextAd = new BulkExpandedTextAd
                {
                    AdGroupId = adGroupIdKey,
                    ExpandedTextAd = new ExpandedTextAd
                    {
                        TitlePart1 = "Contoso",
                        TitlePart2 = "Quick & Easy Setup",
                        TitlePart3 = "Seemless Integration",
                        Text = "Find New Customers & Increase Sales!",
                        TextPart2 = "Start Advertising on Contoso Today.",
                        Path1 = "seattle",
                        Path2 = "shoe sale",
                        FinalUrls = new[] {
                            "http://www.contoso.com/womenshoesale"
                        },
                    },
                };
                uploadEntities.Add(bulkExpandedTextAd);

                // Upload and write the output

                OutputStatusMessage("-----\nAdding campaign, ad group, keyword, and ad...");

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                var downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                var campaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType<BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var keywordResults = downloadEntities.OfType<BulkKeyword>().ToList();
                OutputBulkKeywords(keywordResults);

                var expandedTextAdResults = downloadEntities.OfType<BulkExpandedTextAd>().ToList();
                OutputBulkExpandedTextAds(expandedTextAdResults);

                Reader.Dispose();
                
                // Delete the campaign and everything it contains e.g., ad groups and ads.

                uploadEntities = new List<BulkEntity>();
                
                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }
                
                // Upload and write the output

                OutputStatusMessage("-----\nDeleting the campaign and everything it contains e.g., ad groups and ads...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                campaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                Reader.Dispose();
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                // Used to output the Campaign Management objects within Bulk entities.
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var uploadEntities = new List <BulkEntity>();

                // Define a campaign

                var bulkCampaign = new BulkCampaign
                {
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        Id           = campaignIdKey,
                        BudgetType   = BudgetLimitType.DailyBudgetStandard,
                        DailyBudget  = 50,
                        CampaignType = CampaignType.Search,
                        Languages    = new string[] { "All" },
                        Name         = "Women's Shoes " + DateTime.UtcNow,
                        TimeZone     = "PacificTimeUSCanadaTijuana",
                    }
                };

                uploadEntities.Add(bulkCampaign);

                // Define a set of negative sites that can be applied to the campaign.
                // You can set one negative site via the BulkCampaignNegativeSite (singular) bulk entity,
                // or multiple negative sites via the BulkCampaignNegativeSites (plural) bulk entity.
                //
                // If you upload a BulkCampaignNegativeSites bulk entity, then you are effectively replacing any existing
                // negative sites assigned to the campaign.
                //
                // When the SDK writes a BulkCampaignNegativeSites entity to the bulk upload file,
                // an extra Campaign Negative Site record is included where the Status is Deleted and the
                // Website field is empty. (This is the record that deletes any existing campaign negative sites.)
                //
                // If you include additional BulkCampaignNegativeSite or BulkCampaignNegativeSites in the same upload,
                // they will also be included in the set of negative sites applied to the campaign.

                var bulkCampaignNegativeSite = new BulkCampaignNegativeSite[] {
                    new BulkCampaignNegativeSite {
                        CampaignId = campaignIdKey,
                        Website    = "contoso.com/negativesite1"
                    },
                    new BulkCampaignNegativeSite {
                        CampaignId = campaignIdKey,
                        Website    = "contoso.com/negativesite2"
                    },
                };

                foreach (var campaignNegativeSite in bulkCampaignNegativeSite)
                {
                    uploadEntities.Add(campaignNegativeSite);
                }

                var bulkCampaignNegativeSites = new BulkCampaignNegativeSites {
                    CampaignNegativeSites = new CampaignNegativeSites
                    {
                        CampaignId    = campaignIdKey,
                        NegativeSites = new string[]
                        {
                            "contoso.com/negativesite3",
                            "contoso.com/negativesite4",
                        }
                    }
                };

                uploadEntities.Add(bulkCampaignNegativeSites);

                // Upload and write the output

                OutputStatusMessage("-----\nApplying negative sites to a new campaign...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                // If the upload result file contains a Campaign Negative Site record where the Status is Deleted
                // and the Website field is empty, the SDK represents all negative sites for the campaign
                // via a BulkCampaignNegativeSites (plural) object. Otherwise the SDK represents negative sites
                // for the campaign via one or more BulkCampaignNegativeSite (singlular) objects.

                var campaignNegativeSiteResults = downloadEntities.OfType <BulkCampaignNegativeSite>().ToList();
                OutputBulkCampaignNegativeSite(campaignNegativeSiteResults);

                var campaignNegativeSitesResults = downloadEntities.OfType <BulkCampaignNegativeSites>().ToList();
                OutputBulkCampaignNegativeSites(campaignNegativeSitesResults);

                Reader.Dispose();

                // Delete the campaign and everything it contains e.g., ad groups and ads.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage("-----\nDeleting the campaign and everything it contains e.g., ad groups and ads...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());
                OutputBulkNegativeKeywordLists(downloadEntities.OfType <BulkNegativeKeywordList>().ToList());

                Reader.Dispose();
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V13.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V13.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 26
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                const int targetIdKey = -1;
                const int campaignIdKey = -123;

                var uploadEntities = new List<BulkEntity>();

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, 
                // and additional elements needed to read from and write to a bulk file. 

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",
                        BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget = 1000.00,
                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,
                    }
                };

                // Prepare targets for upload

                var bulkCampaignDayTimeTarget = new BulkCampaignDayTimeTarget
                {
                    CampaignId = campaignIdKey,
                    TargetId = targetIdKey,
                    DayTimeTarget = new DayTimeTarget
                    {
                        Bids = new List<DayTimeTargetBid>
                        {
                            new DayTimeTargetBid
                            {
                                BidAdjustment = 10,
                                Day = Day.Friday,
                                FromHour = 11,
                                FromMinute = Minute.Zero,
                                ToHour = 13,
                                ToMinute = Minute.Fifteen
                            },
                            new DayTimeTargetBid
                            {
                                BidAdjustment = 20,
                                Day = Day.Saturday,
                                FromHour = 11,
                                FromMinute = Minute.Zero,
                                ToHour = 13,
                                ToMinute = Minute.Fifteen
                            }
                        }
                    }
                };

                var bulkCampaignLocationTarget = new BulkCampaignLocationTarget
                {
                    CampaignId = campaignIdKey,
                    TargetId = targetIdKey,

                    IntentOption = IntentOption.PeopleIn,
                    CityTarget = new CityTarget
                    {
                        Bids = new List<CityTargetBid>
                        {
                            new CityTargetBid
                            {
                                BidAdjustment = 15,
                                City = "Toronto, Toronto ON CA",
                                IsExcluded = false
                            }
                        }
                    },
                    CountryTarget = new CountryTarget
                    {
                        Bids = new List<CountryTargetBid>
                        {
                            new CountryTargetBid
                            {
                                BidAdjustment = 15,
                                CountryAndRegion = "CA",
                                IsExcluded = false
                            }
                        }
                    },
                    MetroAreaTarget = new MetroAreaTarget
                    {
                        Bids = new List<MetroAreaTargetBid>
                        {
                            new MetroAreaTargetBid
                            {
                                BidAdjustment = 15,
                                MetroArea = "Seattle-Tacoma, WA, WA US",
                                IsExcluded = false
                            }
                        }
                    },
                    StateTarget = new StateTarget
                    {
                        Bids = new List<StateTargetBid>
                        {
                            new StateTargetBid
                            {
                                BidAdjustment = 15,
                                State = "US-WA",
                                IsExcluded = false
                            }
                        }
                    },
                    PostalCodeTarget = new PostalCodeTarget
                    {
                        Bids = new List<PostalCodeTargetBid>
                        {
                            new PostalCodeTargetBid
                            {
                                // Bid adjustments are not allowed for location exclusions. 
                                // If IsExcluded is true, this element will be ignored.
                                BidAdjustment = 10,
                                PostalCode = "98052, WA US",
                                IsExcluded = false
                            }
                        }
                    }
                };

                var bulkCampaignRadiusTarget = new BulkCampaignRadiusTarget
                {
                    CampaignId = campaignIdKey,
                    TargetId = targetIdKey,

                    RadiusTarget = new RadiusTarget2
                    {
                        Bids = new List<RadiusTargetBid2>
                        {
                            new RadiusTargetBid2
                            {
                                BidAdjustment = 50,
                                LatitudeDegrees = 47.755367,
                                LongitudeDegrees = -122.091827,
                                Radius = 11,
                                RadiusUnit = DistanceUnit.Kilometers,
                                Name = "radius1"
                            },
                            new RadiusTargetBid2
                            {
                                BidAdjustment = 20,
                                LatitudeDegrees = 49.755367,
                                LongitudeDegrees = -129.091827,
                                Radius = 12,
                                RadiusUnit = DistanceUnit.Kilometers,
                                Name = "radius2"
                            }
                        }
                    }
                };


                // Write the entities created above, to the specified file.
                
                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkCampaignDayTimeTarget);
                uploadEntities.Add(bulkCampaignLocationTarget);
                uploadEntities.Add(bulkCampaignRadiusTarget);

                // Write the upload output

                var Reader = await UploadEntities(uploadEntities);
                var bulkEntities = Reader.ReadEntities().ToList();

                var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var campaignDayTimeTargetResults = bulkEntities.OfType<BulkCampaignDayTimeTarget>().ToList();
                OutputBulkCampaignDayTimeTargets(campaignDayTimeTargetResults);
                
                var campaignLocationTargetResults = bulkEntities.OfType<BulkCampaignLocationTarget>().ToList();
                OutputBulkCampaignLocationTargets(campaignLocationTargetResults);

                var campaignRadiusTargetResults = bulkEntities.OfType<BulkCampaignRadiusTarget>().ToList();
                OutputBulkCampaignRadiusTargets(campaignRadiusTargetResults);

                Reader.Dispose();

                #endregion Add
                
                #region Update

                // Update the day and time target. 
                // Do not create a BulkCampaignDayTimeTarget for update, unless you want to replace all existing DayTime target bids
                // with the specified day and time target set for the current bulk upload. 
                // Instead you should upload one or more BulkCampaignDayTimeTargetBid.

                var bulkCampaignDayTimeTargetBids = new List<BulkCampaignDayTimeTargetBid>
                {
                    new BulkCampaignDayTimeTargetBid
                    {
                        CampaignId = campaignDayTimeTargetResults[0].CampaignId,
                        TargetId = campaignDayTimeTargetResults[0].TargetId,
                        DayTimeTargetBid = new DayTimeTargetBid
                        {
                            BidAdjustment = 15,
                            Day = Day.Friday,
                            FromHour = 11,
                            FromMinute = Minute.Zero,
                            ToHour = 13,
                            ToMinute = Minute.Fifteen
                        }
                    }
                };

                // Write the updated target to the file

                uploadEntities = new List<BulkEntity>();

                foreach (var bulkCampaignDayTimeTargetBid in bulkCampaignDayTimeTargetBids)
                {
                    uploadEntities.Add(bulkCampaignDayTimeTargetBid);
                }

                // Write the upload output

                Reader = await UploadEntities(uploadEntities);

                OutputStatusMessage("Upload Results Bulk File Path" + Reader.BulkFilePath + "\n");
                OutputStatusMessage("Updated Entities\n");

                bulkEntities = Reader.ReadEntities().ToList();

                var campaignDayTimeTargetBidResults = bulkEntities.OfType<BulkCampaignDayTimeTargetBid>().ToList();
                OutputBulkCampaignDayTimeTargetBids(campaignDayTimeTargetBidResults);

                Reader.Dispose();
                
                #endregion Update

                #region CleanUp

                /* Delete the campaign and target associations that were previously added. 
                 * Note that the targets are not deleted. Deleting targets is not supported using the
                 * Bulk service. To delete targets you can use the DeleteTargetsFromLibrary operation
                 * via the Campaign Management service.
                 * You should remove this region if you want to view the added entities in the 
                 * Bing Ads web application or another tool.
                 */

                var campaignId = campaignResults[0].Campaign.Id;
                bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id = campaignId,
                        Status = CampaignStatus.Deleted
                    }
                };

                uploadEntities = new List<BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                // Write the upload output

                Reader = await UploadEntities(uploadEntities);
                bulkEntities = Reader.ReadEntities().ToList();
                campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);
                Reader.Dispose();

                OutputStatusMessage(String.Format("Deleted CampaignId {0}\n", campaignResults[0].Campaign.Id));

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                AdInsightExampleHelper AdInsightExampleHelper = new AdInsightExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);
                AdInsightExampleHelper.AdInsightService = new ServiceClient <IAdInsightService>(
                    authorizationData: authorizationData,
                    environment: environment);

                // Used to output the Campaign Management objects within Bulk entities.
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);


                var uploadEntities = new List <BulkEntity>();

                // Setup a page feed that can be associated with one or more campaigns.

                var bulkPageFeed = new BulkFeed
                {
                    CustomAttributes = new[]
                    {
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "Url",
                            Name = "Page Url"
                        },
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "StringList",
                            Name = "Custom Label"
                        }
                    },
                    Id      = feedIdKey,
                    Name    = "My PageFeed " + DateTime.UtcNow,
                    Status  = Status.Active,
                    SubType = "PageFeed"
                };

                uploadEntities.Add(bulkPageFeed);

                var pageFeedItemCustomAttributes = new Dictionary <string, object>();
                pageFeedItemCustomAttributes.Add(
                    "Page Url",
                    "https://" + DOMAIN_NAME + "/3001");
                pageFeedItemCustomAttributes.Add(
                    "Custom Label", new string[] {
                    "Label_1_3001",
                    "Label_1_3002"
                });

                var serializerSettings = new JsonSerializerSettings();
                serializerSettings.NullValueHandling = NullValueHandling.Ignore;
                var pageFeedItemCustomAttributesJson = JsonConvert.SerializeObject(
                    pageFeedItemCustomAttributes, serializerSettings);

                var bulkPageFeedItem = new BulkFeedItem
                {
                    FeedId           = feedIdKey,
                    CustomAttributes = pageFeedItemCustomAttributesJson,
                    Status           = Status.Active
                };

                uploadEntities.Add(bulkPageFeedItem);

                // To get started with dynamic search ads, first you'll need to add a new Campaign
                // with its type set to DynamicSearchAds. When you create the campaign, you'll need to
                // include a DynamicSearchAdsSetting that specifies the target website domain and language.
                // Page feeds can be associated at the campaign level via 'Source' and 'Page Feed Ids'.

                var bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id           = campaignIdKey,
                        BudgetType   = Microsoft.BingAds.V13.CampaignManagement.BudgetLimitType.DailyBudgetStandard,
                        DailyBudget  = 50,
                        CampaignType = CampaignType.DynamicSearchAds,
                        Languages    = new string[] { "All" },
                        Name         = "Women's Shoes " + DateTime.UtcNow,
                        TimeZone     = "PacificTimeUSCanadaTijuana",
                        Settings     = new[] {
                            // Set the target website domain and language.
                            // Be sure to set the Source to AdvertiserSuppliedUrls or All,
                            // otherwise the PageFeedIds will be ignored.
                            new DynamicSearchAdsSetting
                            {
                                DomainName  = DOMAIN_NAME,
                                Language    = LANGUAGE,
                                Source      = DynamicSearchAdsSource.All,
                                PageFeedIds = new [] { feedIdKey }
                            }
                        },
                    },
                };

                uploadEntities.Add(bulkCampaign);

                // Create a new ad group within the dynamic search ads campaign.

                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup    = new AdGroup
                    {
                        Id        = adGroupIdKey,
                        Name      = "Women's Red Shoe Sale",
                        StartDate = null,
                        EndDate   = new Microsoft.BingAds.V13.CampaignManagement.Date
                        {
                            Month = 12,
                            Day   = 31,
                            Year  = DateTime.UtcNow.Year + 1
                        },
                        CpcBid = new Bid {
                            Amount = 0.09
                        },
                    },
                };

                uploadEntities.Add(bulkAdGroup);

                // Create an auto target based on the custom label feed items created above e.g., "Label_1_3001".

                var adGroupWebpagePositiveCustomLabel = new BulkAdGroupDynamicSearchAdTarget
                {
                    BiddableAdGroupCriterion = new BiddableAdGroupCriterion
                    {
                        AdGroupId    = adGroupIdKey,
                        CriterionBid = new FixedBid
                        {
                            Amount = 0.50
                        },
                        Criterion = new Webpage
                        {
                            Parameter = new WebpageParameter
                            {
                                Conditions = new[]
                                {
                                    new WebpageCondition
                                    {
                                        Argument = "Label_1_3001",
                                        Operand  = WebpageConditionOperand.CustomLabel,
                                    },
                                },
                                CriterionName = "Ad Group Webpage Positive Custom Label Criterion"
                            },
                        },
                    }
                };
                uploadEntities.Add(adGroupWebpagePositiveCustomLabel);

                // To discover the categories that you can use for Webpage criterion (positive or negative),
                // use the GetDomainCategories operation with the Ad Insight service.

                OutputStatusMessage("-----\nGetDomainCategories:");
                var getDomainCategoriesResponse = await AdInsightExampleHelper.GetDomainCategoriesAsync(
                    categoryName : null,
                    domainName : DOMAIN_NAME,
                    language : LANGUAGE);

                var categories = getDomainCategoriesResponse.Categories;
                AdInsightExampleHelper.OutputArrayOfDomainCategory(categories);

                // If any categories are available let's use one as a condition.

                if (categories.Count > 0)
                {
                    var adGroupWebpagePositiveCategory = new BulkAdGroupDynamicSearchAdTarget
                    {
                        BiddableAdGroupCriterion = new BiddableAdGroupCriterion
                        {
                            AdGroupId    = adGroupIdKey,
                            CriterionBid = new FixedBid
                            {
                                Amount = 0.50
                            },
                            Criterion = new Webpage
                            {
                                Parameter = new WebpageParameter
                                {
                                    Conditions = new[]
                                    {
                                        new WebpageCondition
                                        {
                                            Argument = categories[0].CategoryName,
                                            Operand  = WebpageConditionOperand.Category,
                                        }
                                    },
                                    CriterionName = "Ad Group Webpage Positive Category Criterion"
                                },
                            }
                        }
                    };
                    uploadEntities.Add(adGroupWebpagePositiveCategory);
                }

                // If you want to exclude certain portions of your website, you can add negative Webpage
                // criterion at the campaign and ad group level.

                var adGroupWebpageNegativeUrl = new BulkAdGroupNegativeDynamicSearchAdTarget
                {
                    NegativeAdGroupCriterion = new NegativeAdGroupCriterion
                    {
                        AdGroupId = adGroupIdKey,
                        Criterion = new Webpage
                        {
                            Parameter = new WebpageParameter
                            {
                                // You can choose whether you want the criterion argument to match partial URLs,
                                // page content, page title, or categories that Bing thinks applies to your website.
                                Conditions = new[]
                                {
                                    new WebpageCondition
                                    {
                                        Argument = "https://" + DOMAIN_NAME + "/3001",
                                        Operand  = WebpageConditionOperand.Url,
                                    }
                                },
                                // If you do not specify any name, then it will be set to a concatenated list of conditions.
                                CriterionName = null
                            }
                        }
                    }
                };
                uploadEntities.Add(adGroupWebpageNegativeUrl);

                // Finally you must add at least one Dynamic Search Ad into the ad group. The ad title and display URL
                // are generated automatically based on the website domain and language that you want to target.

                var bulkDynamicSearchAd = new BulkDynamicSearchAd
                {
                    AdGroupId       = adGroupIdKey,
                    DynamicSearchAd = new DynamicSearchAd
                    {
                        Text      = "Find New Customers & Increase Sales!",
                        TextPart2 = "Start Advertising on Contoso Today.",
                        Path1     = "seattle",
                        Path2     = "shoe sale",
                        // You cannot set FinalUrls for dynamic search ads.
                        // The Final URL will be a dynamically selected landing page.
                        // The final URL is distinct from the path that customers will see and click on in your ad.
                        FinalUrls = null
                    },
                };

                uploadEntities.Add(bulkDynamicSearchAd);

                // Upload and write the output

                OutputStatusMessage("-----\nAdding page feed, campaign, ad group, criterions, and ads...");

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                var feedResults = downloadEntities.OfType <BulkFeed>().ToList();
                OutputBulkFeeds(feedResults);

                var feedItemResults = downloadEntities.OfType <BulkFeedItem>().ToList();
                OutputBulkFeedItems(feedItemResults);

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var adGroupDynamicSearchAdTargetResults = downloadEntities.OfType <BulkAdGroupDynamicSearchAdTarget>().ToList();
                OutputBulkAdGroupDynamicSearchAdTargets(adGroupDynamicSearchAdTargetResults);

                var adGroupNegativeDynamicSearchAdTargetResults = downloadEntities.OfType <BulkAdGroupNegativeDynamicSearchAdTarget>().ToList();
                OutputBulkAdGroupNegativeDynamicSearchAdTargets(adGroupNegativeDynamicSearchAdTargetResults);

                var dynamicSearchAdResults = downloadEntities.OfType <BulkDynamicSearchAd>().ToList();
                OutputBulkDynamicSearchAds(dynamicSearchAdResults);

                Reader.Dispose();

                // Delete the campaign and everything it contains e.g., ad groups and ads.

                uploadEntities = new List <BulkEntity>();

                foreach (var feedResult in feedResults)
                {
                    feedResult.Status = Status.Deleted;
                    uploadEntities.Add(feedResult);
                }

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                OutputStatusMessage("-----\nDeleting page feed, DSA campaign, and all contained entities...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                feedResults = downloadEntities.OfType <BulkFeed>().ToList();
                OutputBulkFeeds(feedResults);

                campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                Reader.Dispose();
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V13.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V13.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 28
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(authorizationData);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var downloadParameters = new DownloadParameters
                {
                    DownloadEntities    = new[] { DownloadEntity.RemarketingLists },
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = DownloadFileName,
                    OverwriteResultFile = true,
                    LastSyncTimeInUTC   = null
                };

                var bulkFilePath = await BulkServiceManager.DownloadFileAsync(downloadParameters);

                OutputStatusMessage("Downloaded all remarketing lists that the current user can associate with ad groups.\n");
                Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType);
                var downloadEntities = Reader.ReadEntities().ToList();

                var remarketingListResults = downloadEntities.OfType <BulkRemarketingList>().ToList();
                OutputBulkRemarketingLists(remarketingListResults);

                Reader.Dispose();

                // You must already have at least one remarketing list.
                if (remarketingListResults.Count < 1)
                {
                    OutputStatusMessage("You do not have any remarketing lists that the current user can associate with ad groups.\n");
                    return;
                }

                var uploadEntities = new List <BulkEntity>();

                #region Add

                // Prepare the bulk entities that you want to upload.

                var bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id          = campaignIdKey,
                        Name        = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId      = null,
                        DailyBudget   = 50,
                        BudgetType    = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        TrackingUrlTemplate = null
                    }
                };

                // Specify one or more ad groups.

                var bulkAdGroup = new BulkAdGroup
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth.
                    ClientId   = "YourClientIdGoesHere",
                    CampaignId = campaignIdKey,
                    AdGroup    = new AdGroup
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkAdGroup, the Id is optional
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the
                        // ad group Id will be used when associating this new ad group with a new ad group remarketing list association
                        // in the BulkAdGroupRemarketingListAssociation object below.
                        Id             = adGroupIdKey,
                        Name           = "Women's Red Shoe Sale",
                        AdDistribution = AdDistribution.Search,
                        BiddingScheme  = new InheritFromParentBiddingScheme(),
                        PricingModel   = PricingModel.Cpc,
                        StartDate      = null,
                        EndDate        = new Microsoft.BingAds.V11.CampaignManagement.Date
                        {
                            Month = 12,
                            Day   = 31,
                            Year  = DateTime.UtcNow.Year + 1
                        },
                        Language            = "English",
                        Status              = AdGroupStatus.Active,
                        TrackingUrlTemplate = null,

                        // Applicable for all remarketing lists that are associated with this ad group. TargetAndBid indicates
                        // that you want to show ads only to people included in the remarketing list, with the option to change
                        // the bid amount. Ads in this ad group will only show to people included in the remarketing list.
                        RemarketingTargetingSetting = RemarketingTargetingSetting.TargetAndBid,
                    },
                };

                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkAdGroup);

                // This example associates all of the remarketing lists with the new ad group.

                foreach (var remarketingList in remarketingListResults)
                {
                    if (remarketingList.RemarketingList != null && remarketingList.RemarketingList.Id != null)
                    {
                        var bulkAdGroupRemarketingListAssociation = new BulkAdGroupRemarketingListAssociation
                        {
                            ClientId = "MyBulkAdGroupRemarketingListAssociation " + remarketingList.RemarketingList.Id,
                            BiddableAdGroupCriterion = new BiddableAdGroupCriterion
                            {
                                AdGroupId = adGroupIdKey,
                                Criterion = new AudienceCriterion
                                {
                                    AudienceId   = (long)remarketingList.RemarketingList.Id,
                                    AudienceType = AudienceType.RemarketingList,
                                },
                                CriterionBid = new BidMultiplier
                                {
                                    Multiplier = 20.00,
                                },
                                Status = AdGroupCriterionStatus.Paused,
                            },
                            // Read-only properties
                            AdGroupName         = null,
                            CampaignName        = null,
                            RemarketingListName = null,
                        };

                        uploadEntities.Add(bulkAdGroupRemarketingListAssociation);
                    }
                }

                // Upload and write the output

                OutputStatusMessage("\nAdding campaign, ad group, and ad group remarketing list associations...\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var adGroupRemarketingListResults = downloadEntities.OfType <BulkAdGroupRemarketingListAssociation>().ToList();
                OutputBulkAdGroupRemarketingListAssociations(adGroupRemarketingListResults);

                Reader.Dispose();

                #endregion Add

                #region CleanUp

                // Delete the campaign, ad group, and ad group remarketing list associations that were previously added.
                // The remarketing lists will not be deleted.
                // You should remove this region if you want to view the added entities in the
                // Bing Ads web application or another tool.

                // You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                // When you delete a BulkCampaign, the dependent entities such as BulkAdGroup and BulkAdGroupRemarketingListAssociation
                // are deleted without being specified explicitly.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign, ad group, and ad group remarketing list associations . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());

                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V11.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V11.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                // Used to output the Campaign Management objects within Bulk entities.
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var uploadEntities = new List <BulkEntity>();

                // Setup an ad customizer feed that can be referenced later in the ad copy.

                var bulkAdCustomizerFeed = new BulkFeed
                {
                    CustomAttributes = new[]
                    {
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "String",
                            Name = "Product"
                        },
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "String",
                            Name = "Materials_Lightweight"
                        },
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "String",
                            Name = "Description_Lightweight"
                        },
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "Int64",
                            Name = "Finishes"
                        },
                        new FeedCustomAttributeContract
                        {
                            FeedAttributeType = "Price",
                            Name = "StartPrice"
                        },
                    },
                    Id      = feedIdKey,
                    Name    = "My AdCustomizerFeed " + DateTime.UtcNow,
                    Status  = Status.Active,
                    SubType = "AdCustomizerFeed",
                };

                uploadEntities.Add(bulkAdCustomizerFeed);

                var adCustomizerFeedItemCustomAttributes = new Dictionary <string, object>();
                adCustomizerFeedItemCustomAttributes.Add("Product", "Contoso 900");
                adCustomizerFeedItemCustomAttributes.Add("Materials_Lightweight", "titanium or acetate");
                adCustomizerFeedItemCustomAttributes.Add("Description_Lightweight", "Stylish, lightweight shades");
                adCustomizerFeedItemCustomAttributes.Add("Finishes", 8);
                adCustomizerFeedItemCustomAttributes.Add("StartPrice", "$24.99");

                var serializerSettings = new JsonSerializerSettings();
                serializerSettings.NullValueHandling = NullValueHandling.Ignore;
                var adCustomizerFeedItemCustomAttributesJson = JsonConvert.SerializeObject(
                    adCustomizerFeedItemCustomAttributes, serializerSettings);

                var bulkAdCustomizerFeedItem = new BulkFeedItem
                {
                    FeedId           = feedIdKey,
                    CustomAttributes = adCustomizerFeedItemCustomAttributesJson,
                    Id            = null,
                    AdGroupName   = null,
                    AudienceId    = null,
                    CampaignName  = null,
                    DayTimeRanges = new[]
                    {
                        new DayTime
                        {
                            Day         = Day.Monday,
                            StartHour   = 9,
                            StartMinute = Minute.Zero,
                            EndHour     = 21,
                            EndMinute   = Minute.Zero,
                        },
                    },
                    EndDate          = null,
                    StartDate        = DateTime.UtcNow,
                    IntentOption     = IntentOption.PeopleIn,
                    Keyword          = "lightweight sunglasses",
                    LocationId       = 190,
                    MatchType        = MatchType.Broad,
                    DevicePreference = null,
                    Status           = Status.Active
                };

                uploadEntities.Add(bulkAdCustomizerFeedItem);

                // Add a search campaign.

                var bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        BudgetType   = BudgetLimitType.DailyBudgetStandard,
                        DailyBudget  = 50,
                        CampaignType = CampaignType.Search,
                        Id           = campaignIdKey,
                        Languages    = new string[] { "All" },
                        Name         = "Summer Sunglasses " + DateTime.UtcNow,
                        TimeZone     = "PacificTimeUSCanadaTijuana",
                    },
                };
                uploadEntities.Add(bulkCampaign);

                // Add an ad group within the campaign.

                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup    = new AdGroup
                    {
                        Id        = adGroupIdKey,
                        Name      = "Sunglasses Sale",
                        StartDate = null,
                        EndDate   = new Microsoft.BingAds.V13.CampaignManagement.Date
                        {
                            Month = 12,
                            Day   = 31,
                            Year  = DateTime.UtcNow.Year + 1
                        },
                        CpcBid = new Bid {
                            Amount = 0.09
                        },
                    },
                };
                uploadEntities.Add(bulkAdGroup);

                // Add keywords and ads within the ad group.

                var bulkKeyword = new BulkKeyword {
                    AdGroupId = adGroupIdKey,
                    Keyword   = new Keyword
                    {
                        Bid = new Bid {
                            Amount = 0.47
                        },
                        Param2    = "10% Off",
                        MatchType = MatchType.Phrase,
                        Text      = "Brand-A Sunglasses",
                    },
                };
                uploadEntities.Add(bulkKeyword);

                var bulkExpandedTextAd = new BulkExpandedTextAd
                {
                    AdGroupId      = adGroupIdKey,
                    ExpandedTextAd = new ExpandedTextAd
                    {
                        TitlePart1 = "The latest {=Sunglasses.Product}s",
                        TitlePart2 = "In {=Sunglasses.Materials_Lightweight}",
                        TitlePart3 = null,
                        Text       = "{=Sunglasses.Description_Lightweight} in {=Sunglasses.Finishes} finishes.",
                        TextPart2  = "Starting at only {=Sunglasses.StartPrice}!",
                        Path1      = "deals",
                        Path2      = null,
                        FinalUrls  = new[] {
                            "https://www.contoso.com"
                        },
                    },
                };
                uploadEntities.Add(bulkExpandedTextAd);

                // Upload and write the output

                OutputStatusMessage("-----\nAdding the ad customizer feed, campaign, ad group, keyword, and ad...");

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                var feedResults = downloadEntities.OfType <BulkFeed>().ToList();
                OutputBulkFeeds(feedResults);

                var feedItemResults = downloadEntities.OfType <BulkFeedItem>().ToList();
                OutputBulkFeedItems(feedItemResults);

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var keywordResults = downloadEntities.OfType <BulkKeyword>().ToList();
                OutputBulkKeywords(keywordResults);

                var expandedTextAdResults = downloadEntities.OfType <BulkExpandedTextAd>().ToList();
                OutputBulkExpandedTextAds(expandedTextAdResults);

                Reader.Dispose();

                // Delete the feed and campaign and everything it contains e.g., ad groups and ads.

                uploadEntities = new List <BulkEntity>();

                foreach (var feedResult in feedResults)
                {
                    feedResult.Status = Status.Deleted;
                    uploadEntities.Add(feedResult);
                }

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage("-----\nDeleting the feed and campaign and everything it contains e.g., ad groups and ads...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                Reader.Dispose();
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V13.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V13.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 30
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(String.Format("{0} % Complete", x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                const int callAdExtensionIdKey      = -12;
                const int locationAdExtensionIdKey  = -13;
                const int siteLinksAdExtensionIdKey = -14;
                const int campaignIdKey             = -123;

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object,
                // and additional elements needed to read from and write to a bulk file.

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth.
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below.
                        Id             = campaignIdKey,
                        Name           = "Women's Shoes " + DateTime.UtcNow,
                        Description    = "Red shoes line.",
                        BudgetType     = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget  = 1000.00,
                        TimeZone       = "PacificTimeUSCanadaTijuana",
                        DaylightSaving = true
                    }
                };

                // Prepare ad extensions for upload

                var bulkCallAdExtension = new BulkCallAdExtension
                {
                    AccountId       = authorizationData.AccountId,
                    CallAdExtension = new CallAdExtension
                    {
                        CountryCode = "US",
                        PhoneNumber = "2065550100",
                        IsCallOnly  = false,
                        Id          = callAdExtensionIdKey
                    }
                };

                var bulkLocationAdExtension = new BulkLocationAdExtension
                {
                    AccountId           = authorizationData.AccountId,
                    LocationAdExtension = new LocationAdExtension
                    {
                        Id           = locationAdExtensionIdKey,
                        PhoneNumber  = "206-555-0100",
                        CompanyName  = "Contoso Shoes",
                        IconMediaId  = null,
                        ImageMediaId = null,
                        Address      = new Address
                        {
                            StreetAddress  = "1234 Washington Place",
                            StreetAddress2 = "Suite 1210",
                            CityName       = "Woodinville",
                            ProvinceName   = "WA",
                            CountryCode    = "US",
                            PostalCode     = "98608"
                        }
                    }
                };

                // Note that when written to file using the BulkFileWriter, an extra Sitelink Ad Extension record with Deleted
                // status precedes the actual site link record or records that you want to upload. All bulk entities
                // that are derived from MultiRecordBulkEntiy are preceded with a Deleted record using the BulkFileWriter.
                // In this example it is a moot point because we are creating a new ad extension. If the specified
                // ad extension Id already exists in your account, the Deleted record effectively deletes the existing
                // extension and replaces it with the SiteLinksAdExtension specified below.

                var bulkSiteLinkAdExtension = new BulkSiteLinkAdExtension
                {
                    AccountId            = authorizationData.AccountId,
                    SiteLinksAdExtension = new SiteLinksAdExtension
                    {
                        // Note that if you do not specify a negative Id as reference key, each of SiteLinks items will
                        // be split during upload into separate sitelink ad extensions with unique ad extension identifiers.
                        Id        = siteLinksAdExtensionIdKey,
                        SiteLinks = new List <SiteLink>
                        {
                            new SiteLink
                            {
                                DestinationUrl = "Contoso.com",
                                DisplayText    = "Women's Shoe Sale 1"
                            },
                            new SiteLink
                            {
                                DestinationUrl = "Contoso.com/WomenShoeSale/2",
                                DisplayText    = "Women's Shoe Sale 2"
                            }
                        }
                    }
                    // Note that BulkSiteLinkAdExtension.SiteLinks is read only and only
                    // accessible when reading results from the download or upload results file.
                    // To upload new site links for a new site links ad extension, you should specify
                    // BulkSiteLinkAdExtension.SiteLinksAdExtension.SiteLinks as shown above.
                };

                // Prepare ad extension associations for upload

                var bulkCampaignCallAdExtension = new BulkCampaignCallAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = callAdExtensionIdKey,
                        EntityId      = campaignIdKey
                    }
                };

                var bulkCampaignLocationAdExtension = new BulkCampaignLocationAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = locationAdExtensionIdKey,
                        EntityId      = campaignIdKey
                    }
                };

                var bulkCampaignSiteLinkAdExtension = new BulkCampaignSiteLinkAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = siteLinksAdExtensionIdKey,
                        EntityId      = campaignIdKey
                    }
                };


                // Write the entities created above, to the specified file.
                // Dependent entities such as BulkCampaignCallAdExtension must be written after any dependencies,
                // for example the BulkCampaign and BulkCallAdExtension.

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                Writer.WriteEntity(bulkCampaign);

                Writer.WriteEntity(bulkCallAdExtension);
                Writer.WriteEntity(bulkLocationAdExtension);
                Writer.WriteEntity(bulkSiteLinkAdExtension);

                Writer.WriteEntity(bulkCampaignCallAdExtension);
                Writer.WriteEntity(bulkCampaignLocationAdExtension);
                Writer.WriteEntity(bulkCampaignSiteLinkAdExtension);


                Writer.Dispose();

                var fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath      = FileDirectory + UploadFileName,
                    ResponseMode        = ResponseMode.ErrorsAndResults
                };

                // UploadFileAsync will upload the file you finished writing and will download the results file

                OutputStatusMessage("Starting UploadFileAsync . . .\n");
                var bulkFilePath = await BulkService.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);

                Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);
                OutputStatusMessage("Upload Results Bulk File Path: " + Reader.BulkFilePath + "\n");
                OutputStatusMessage("Added Entities\n");

                // Write the upload output

                var bulkEntities = Reader.ReadEntities().ToList();

                var campaignResults = bulkEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var callAdExtensionResults = bulkEntities.OfType <BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                var locationAdExtensionResults = bulkEntities.OfType <BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                var siteLinkAdExtensionResults = bulkEntities.OfType <BulkSiteLinkAdExtension>().ToList();
                OutputBulkSiteLinkAdExtensions(siteLinkAdExtensionResults);

                Reader.Dispose();

                #endregion Add

                #region Update

                // Update the site links ad extension.
                // Do not create a BulkSiteLinkAdExtension for update, unless you want to replace all existing SiteLinks
                // with the specified SiteLinks for the specified ad extension.
                // Instead you should upload one or more site links as a list of BulkSiteLink.

                var bulkSiteLinks = new List <BulkSiteLink>
                {
                    new BulkSiteLink
                    {
                        SiteLink = new SiteLink
                        {
                            DestinationUrl = "Contoso.com",
                            DisplayText    = "Red Shoe Sale"
                        }
                    }
                };

                // Add an additional site link, and update an existing site link

                if (siteLinkAdExtensionResults.ToArray().Any() &&
                    siteLinkAdExtensionResults.ToArray()[0].SiteLinks.ToArray().Any())
                {
                    var existingSiteLink = siteLinkAdExtensionResults.ToArray()[0].SiteLinks[0];
                    existingSiteLink.SiteLink.DisplayText = "Red Shoes Super Sale";

                    // Associate the new site links with the identifier of the existing site links ad extension

                    foreach (var bulkSiteLink in bulkSiteLinks)
                    {
                        bulkSiteLink.AdExtensionId = existingSiteLink.AdExtensionId;
                    }

                    bulkSiteLinks.Add(existingSiteLink);
                }

                // Write the new site link and updated site link to the file

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                foreach (var bulkSiteLink in bulkSiteLinks)
                {
                    Writer.WriteEntity(bulkSiteLink);
                }

                Writer.Dispose();

                fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath      = FileDirectory + UploadFileName,
                    ResponseMode        = ResponseMode.ErrorsAndResults
                };

                // UploadFileAsync will upload the file you finished writing and will download the results file

                OutputStatusMessage("Starting UploadFileAsync . . .\n");
                bulkFilePath = await BulkService.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);

                Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);
                OutputStatusMessage("Upload Results Bulk File Path: " + Reader.BulkFilePath + "\n");
                OutputStatusMessage("Updated Entities\n");

                // Write any upload errors

                bulkEntities = Reader.ReadEntities().ToList();
                var siteLinkResults = bulkEntities.OfType <BulkSiteLink>().ToList();
                OutputBulkSiteLinks(siteLinkResults);

                Reader.Dispose();

                #endregion Update

                #region Delete

                // Prepare the bulk entities that you want to delete. You must set the Id field to the corresponding
                // entity identifier, and the Status field to Deleted.

                var campaignId = campaignResults[0].Campaign.Id;
                bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id     = campaignId,
                        Status = CampaignStatus.Deleted
                    }
                };

                var callAdExtensionId = callAdExtensionResults[0].CallAdExtension.Id;
                bulkCallAdExtension = new BulkCallAdExtension
                {
                    CallAdExtension = new CallAdExtension
                    {
                        Id     = callAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                var locationAdExtensionId = locationAdExtensionResults[0].LocationAdExtension.Id;
                bulkLocationAdExtension = new BulkLocationAdExtension
                {
                    LocationAdExtension = new LocationAdExtension
                    {
                        Id     = locationAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };


                var siteLinkAdExtensionId = siteLinkAdExtensionResults[0].SiteLinksAdExtension.Id;
                bulkSiteLinkAdExtension = new BulkSiteLinkAdExtension
                {
                    SiteLinksAdExtension = new SiteLinksAdExtension
                    {
                        Id     = siteLinkAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                // Write the entities that you want deleted, to the specified file.
                // Dependent entities such as BulkCampaignCallAdExtension are deleted without being specified explicitly.
                // For example, if you delete either BulkCampaign or BulkCallAdExtension, then the equivalent of
                // BulkCampaignCallAdExtension is effectively deleted.

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                Writer.WriteEntity(bulkCampaign);

                Writer.WriteEntity(bulkCallAdExtension);
                Writer.WriteEntity(bulkLocationAdExtension);
                Writer.WriteEntity(bulkSiteLinkAdExtension);


                Writer.Dispose();

                fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath      = FileDirectory + UploadFileName,
                    ResponseMode        = ResponseMode.ErrorsAndResults
                };

                // UploadFileAsync will upload the file you finished writing and will download the results file

                OutputStatusMessage("Starting UploadFileAsync . . .\n");
                bulkFilePath = await BulkService.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);

                Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);
                OutputStatusMessage("Upload Results Bulk File Path: " + Reader.BulkFilePath + "\n");
                OutputStatusMessage("Deleted Entities\n");

                // Write the upload output

                bulkEntities = Reader.ReadEntities().ToList();

                campaignResults = bulkEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                callAdExtensionResults = bulkEntities.OfType <BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                locationAdExtensionResults = bulkEntities.OfType <BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                siteLinkAdExtensionResults = bulkEntities.OfType <BulkSiteLinkAdExtension>().ToList();
                OutputBulkSiteLinkAdExtensions(siteLinkAdExtensionResults);

                Reader.Dispose();

                #endregion Delete
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 31
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                AdInsightExampleHelper AdInsightExampleHelper = new AdInsightExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);
                AdInsightExampleHelper.AdInsightService = new ServiceClient <IAdInsightService>(
                    authorizationData: authorizationData,
                    environment: environment);

                // Used to output the Campaign Management objects within Bulk entities.
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(
                    OutputStatusMessageDefault: this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(
                    authorizationData: authorizationData,
                    apiEnvironment: environment);

                var uploadEntities = new List <BulkEntity>();

                // To get started with dynamic search ads, first you'll need to add a new Campaign
                // with its type set to DynamicSearchAds. When you create the campaign, you'll need to
                // include a DynamicSearchAdsSetting that specifies the target website domain and language.

                var bulkCampaign = new BulkCampaign
                {
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        Id           = campaignIdKey,
                        BudgetType   = Microsoft.BingAds.V12.CampaignManagement.BudgetLimitType.DailyBudgetStandard,
                        DailyBudget  = 50,
                        CampaignType = CampaignType.DynamicSearchAds,
                        Languages    = new string[] { "All" },
                        Name         = "Women's Shoes " + DateTime.UtcNow,
                        TimeZone     = "PacificTimeUSCanadaTijuana",
                        Settings     = new[] {
                            new DynamicSearchAdsSetting
                            {
                                DomainName = "contoso.com",
                                Language   = "English"
                            }
                        },
                    },
                };

                uploadEntities.Add(bulkCampaign);

                // Create a new ad group within the dynamic search ads campaign.

                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup    = new AdGroup
                    {
                        Id        = adGroupIdKey,
                        Name      = "Women's Red Shoe Sale",
                        StartDate = null,
                        EndDate   = new Microsoft.BingAds.V12.CampaignManagement.Date
                        {
                            Month = 12,
                            Day   = 31,
                            Year  = DateTime.UtcNow.Year + 1
                        },
                        CpcBid = new Bid {
                            Amount = 0.09
                        },
                    },
                };

                uploadEntities.Add(bulkAdGroup);

                // You can add one or more Webpage criteria to each ad group that helps determine
                // whether or not to serve dynamic search ads.

                var adGroupWebpagePositivePageContent = new BulkAdGroupDynamicSearchAdTarget
                {
                    BiddableAdGroupCriterion = new BiddableAdGroupCriterion
                    {
                        AdGroupId    = adGroupIdKey,
                        CriterionBid = new FixedBid
                        {
                            Amount = 0.50
                        },
                        Criterion = new Webpage
                        {
                            Parameter = new WebpageParameter
                            {
                                Conditions = new[]
                                {
                                    new WebpageCondition
                                    {
                                        Argument = "flowers",
                                        Operand  = WebpageConditionOperand.PageContent,
                                    }
                                },
                                CriterionName = "Ad Group Webpage Positive Page Content Criterion"
                            },
                        },
                    }
                };
                uploadEntities.Add(adGroupWebpagePositivePageContent);

                // To discover the categories that you can use for Webpage criterion (positive or negative),
                // use the GetDomainCategories operation with the Ad Insight service.

                OutputStatusMessage("-----\nGetDomainCategories:");
                var getDomainCategoriesResponse = await AdInsightExampleHelper.GetDomainCategoriesAsync(
                    categoryName : null,
                    domainName : DOMAIN_NAME,
                    language : LANGUAGE);

                var categories = getDomainCategoriesResponse.Categories;
                AdInsightExampleHelper.OutputArrayOfDomainCategory(categories);

                // If any categories are available let's use one as a condition.

                if (categories.Count > 0)
                {
                    var adGroupWebpagePositiveCategory = new BulkAdGroupDynamicSearchAdTarget
                    {
                        BiddableAdGroupCriterion = new BiddableAdGroupCriterion
                        {
                            AdGroupId    = adGroupIdKey,
                            CriterionBid = new FixedBid
                            {
                                Amount = 0.50
                            },
                            Criterion = new Webpage
                            {
                                Parameter = new WebpageParameter
                                {
                                    Conditions = new[]
                                    {
                                        new WebpageCondition
                                        {
                                            Argument = categories[0].CategoryName,
                                            Operand  = WebpageConditionOperand.Category,
                                        }
                                    },
                                    CriterionName = "Ad Group Webpage Positive Category Criterion"
                                },
                            }
                        }
                    };
                    uploadEntities.Add(adGroupWebpagePositiveCategory);
                }

                // If you want to exclude certain portions of your website, you can add negative Webpage
                // criterion at the campaign and ad group level.

                var adGroupWebpageNegativeUrl = new BulkAdGroupNegativeDynamicSearchAdTarget
                {
                    NegativeAdGroupCriterion = new NegativeAdGroupCriterion
                    {
                        AdGroupId = adGroupIdKey,
                        Criterion = new Webpage
                        {
                            Parameter = new WebpageParameter
                            {
                                // You can choose whether you want the criterion argument to match partial URLs,
                                // page content, page title, or categories that Bing thinks applies to your website.
                                Conditions = new[]
                                {
                                    new WebpageCondition
                                    {
                                        Argument = DOMAIN_NAME,
                                        Operand  = WebpageConditionOperand.Url,
                                    }
                                },
                                // If you do not specify any name, then it will be set to a concatenated list of conditions.
                                CriterionName = null
                            }
                        }
                    }
                };
                uploadEntities.Add(adGroupWebpageNegativeUrl);

                // The negative Webpage criterion at the campaign level applies to all ad groups
                // within the campaign; however, if you define ad group level negative Webpage criterion,
                // the campaign criterion is ignored for that ad group.

                var campaignWebpageNegative = new BulkCampaignNegativeDynamicSearchAdTarget
                {
                    NegativeCampaignCriterion = new NegativeCampaignCriterion
                    {
                        CampaignId = campaignIdKey,
                        Criterion  = new Webpage
                        {
                            Parameter = new WebpageParameter
                            {
                                Conditions = new[]
                                {
                                    new WebpageCondition
                                    {
                                        Argument = DOMAIN_NAME + "\\seattle",
                                        Operand  = WebpageConditionOperand.Url,
                                    }
                                },
                                CriterionName = "Campaign Negative Webpage Url Criterion"
                            }
                        }
                    }
                };
                uploadEntities.Add(campaignWebpageNegative);


                // Finally you must add at least one DynamicSearchAd into the ad group. The ad title and display URL
                // are generated automatically based on the website domain and language that you want to target.

                var bulkDynamicSearchAd = new BulkDynamicSearchAd
                {
                    ClientId        = "here",
                    AdGroupId       = adGroupIdKey,
                    DynamicSearchAd = new DynamicSearchAd
                    {
                        Text  = "Find New Customers & Increase Sales! Start Advertising on Contoso Today.",
                        Path1 = "seattle",
                        Path2 = "shoe sale",
                        // You cannot set FinalUrls for dynamic search ads.
                        // The Final URL will be a dynamically selected landing page.
                        // The final URL is distinct from the path that customers will see and click on in your ad.
                        FinalUrls = null,
                    },
                };

                uploadEntities.Add(bulkDynamicSearchAd);

                // Upload and write the output

                OutputStatusMessage("-----\nAdding campaign, ad group, criterions, and ads...");

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var campaignNegativeDynamicSearchAdTargetResults = downloadEntities.OfType <BulkCampaignNegativeDynamicSearchAdTarget>().ToList();
                OutputBulkCampaignNegativeDynamicSearchAdTargets(campaignNegativeDynamicSearchAdTargetResults);

                var adGroupDynamicSearchAdTargetResults = downloadEntities.OfType <BulkAdGroupDynamicSearchAdTarget>().ToList();
                OutputBulkAdGroupDynamicSearchAdTargets(adGroupDynamicSearchAdTargetResults);

                var adGroupNegativeDynamicSearchAdTargetResults = downloadEntities.OfType <BulkAdGroupNegativeDynamicSearchAdTarget>().ToList();
                OutputBulkAdGroupNegativeDynamicSearchAdTargets(adGroupNegativeDynamicSearchAdTargetResults);

                var dynamicSearchAdResults = downloadEntities.OfType <BulkDynamicSearchAd>().ToList();
                OutputBulkDynamicSearchAds(dynamicSearchAdResults);

                Reader.Dispose();

                // Delete the campaign and everything it contains e.g., ad groups and ads.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                OutputStatusMessage("-----\nDeleting DSA campaign, criterions, and ad...");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();

                OutputStatusMessage("Upload results:");

                campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                Reader.Dispose();
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 32
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                const int campaignIdKey = -123;

                var uploadEntities = new List <BulkEntity>();

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object,
                // and additional elements needed to read from and write to a bulk file.

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth.
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below.
                        Id          = campaignIdKey,
                        Name        = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId      = null,
                        DailyBudget   = 50,
                        BudgetType    = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,
                    }
                };

                // Prepare targets for upload

                var bulkCampaignDayTimeTarget = new BulkCampaignDayTimeTarget
                {
                    CampaignId    = campaignIdKey,
                    DayTimeTarget = new DayTimeTarget
                    {
                        Bids = new List <DayTimeTargetBid>
                        {
                            new DayTimeTargetBid
                            {
                                BidAdjustment = 10,
                                Day           = Day.Friday,
                                FromHour      = 11,
                                FromMinute    = Minute.Zero,
                                ToHour        = 13,
                                ToMinute      = Minute.Fifteen
                            },
                            new DayTimeTargetBid
                            {
                                BidAdjustment = 20,
                                Day           = Day.Saturday,
                                FromHour      = 11,
                                FromMinute    = Minute.Zero,
                                ToHour        = 13,
                                ToMinute      = Minute.Fifteen
                            }
                        }
                    }
                };

                var bulkCampaignLocationTarget = new BulkCampaignLocationTarget
                {
                    CampaignId = campaignIdKey,

                    IntentOption = IntentOption.PeopleIn,
                    CityTarget   = new CityTarget
                    {
                        Bids = new List <CityTargetBid>
                        {
                            new CityTargetBid
                            {
                                BidAdjustment = 15,
                                City          = "Toronto, Toronto ON CA",
                                IsExcluded    = false
                            }
                        }
                    },
                    CountryTarget = new CountryTarget
                    {
                        Bids = new List <CountryTargetBid>
                        {
                            new CountryTargetBid
                            {
                                BidAdjustment    = 15,
                                CountryAndRegion = "CA",
                                IsExcluded       = false
                            }
                        }
                    },
                    MetroAreaTarget = new MetroAreaTarget
                    {
                        Bids = new List <MetroAreaTargetBid>
                        {
                            new MetroAreaTargetBid
                            {
                                BidAdjustment = 15,
                                MetroArea     = "Seattle-Tacoma, WA, WA US",
                                IsExcluded    = false
                            }
                        }
                    },
                    StateTarget = new StateTarget
                    {
                        Bids = new List <StateTargetBid>
                        {
                            new StateTargetBid
                            {
                                BidAdjustment = 15,
                                State         = "US-WA",
                                IsExcluded    = false
                            }
                        }
                    },
                    PostalCodeTarget = new PostalCodeTarget
                    {
                        Bids = new List <PostalCodeTargetBid>
                        {
                            new PostalCodeTargetBid
                            {
                                // Bid adjustments are not allowed for location exclusions.
                                // If IsExcluded is true, this element will be ignored.
                                BidAdjustment = 10,
                                PostalCode    = "98052, WA US",
                                IsExcluded    = false
                            }
                        }
                    }
                };

                var bulkCampaignRadiusTarget = new BulkCampaignRadiusTarget
                {
                    CampaignId = campaignIdKey,

                    RadiusTarget = new RadiusTarget
                    {
                        Bids = new List <RadiusTargetBid>
                        {
                            new RadiusTargetBid
                            {
                                BidAdjustment    = 50,
                                LatitudeDegrees  = 47.755367,
                                LongitudeDegrees = -122.091827,
                                Radius           = 11,
                                RadiusUnit       = DistanceUnit.Kilometers,
                                Name             = "radius1"
                            },
                            new RadiusTargetBid
                            {
                                BidAdjustment    = 20,
                                LatitudeDegrees  = 49.755367,
                                LongitudeDegrees = -129.091827,
                                Radius           = 12,
                                RadiusUnit       = DistanceUnit.Kilometers,
                                Name             = "radius2"
                            }
                        }
                    }
                };

                var bulkCampaignDeviceOsTarget = new BulkCampaignDeviceOsTarget
                {
                    CampaignId     = campaignIdKey,
                    DeviceOsTarget = new DeviceOSTarget
                    {
                        Bids = new List <DeviceOSTargetBid>
                        {
                            new DeviceOSTargetBid
                            {
                                BidAdjustment = 20,
                                DeviceName    = "Tablets"
                            },
                        }
                    }
                };

                // Upload the entities created above.

                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkCampaignDayTimeTarget);
                uploadEntities.Add(bulkCampaignLocationTarget);
                uploadEntities.Add(bulkCampaignRadiusTarget);
                uploadEntities.Add(bulkCampaignDeviceOsTarget);

                OutputStatusMessage("\nAdding campaign and targets . . . ");
                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                // Upload and write the output

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var campaignDayTimeTargetResults = downloadEntities.OfType <BulkCampaignDayTimeTarget>().ToList();
                OutputBulkCampaignDayTimeTargets(campaignDayTimeTargetResults);

                var campaignLocationTargetResults = downloadEntities.OfType <BulkCampaignLocationTarget>().ToList();
                OutputBulkCampaignLocationTargets(campaignLocationTargetResults);

                var campaignRadiusTargetResults = downloadEntities.OfType <BulkCampaignRadiusTarget>().ToList();
                OutputBulkCampaignRadiusTargets(campaignRadiusTargetResults);

                var campaignDeviceOsTargetResults = downloadEntities.OfType <BulkCampaignDeviceOsTarget>().ToList();
                OutputBulkCampaignDeviceOsTargets(campaignDeviceOsTargetResults);

                Reader.Dispose();

                #endregion Add

                #region Update

                // If the campaign was successfully added in the previous upload, let's append a new device bid.
                if (campaignResults.Count > 0)
                {
                    // In this example we want to keep the Tablets bid that was uploaded previously, so we will upload the BulkCampaignDeviceOsTargetBid.
                    // Each BulkCampaignDeviceOsTargetBid instance corresponds to one Campaign DeviceOS Target record in the bulk file.
                    // If instead you want to replace all existing device target bids for the specified campaign, then you should upload
                    // a BulkCampaignDeviceOsTarget. If you write a BulkCampaignDeviceOsTarget to the file (for example see the previous upload above),
                    // then an additional Campaign DeviceOS Target record is included automatically with Status set to Deleted.

                    var bulkCampaignDeviceOsTargetBid = new BulkCampaignDeviceOsTargetBid
                    {
                        CampaignId = campaignDayTimeTargetResults[0].CampaignId,
                        // You can specify ClientId for BulkCampaignDeviceOsTargetBid, but not for BulkCampaignDeviceOsTarget.
                        ClientId          = "My BulkCampaignDeviceOsTargetBid",
                        DeviceOsTargetBid = new DeviceOSTargetBid
                        {
                            BidAdjustment = 20,
                            DeviceName    = "Smartphones"
                        }
                    };

                    uploadEntities = new List <BulkEntity>();
                    uploadEntities.Add(bulkCampaignDeviceOsTargetBid);

                    OutputStatusMessage("\nAdding Smartphones device target for campaign . . . ");
                    Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                    downloadEntities = Reader.ReadEntities().ToList();

                    var campaignDeviceOsTargetBidResults = downloadEntities.OfType <BulkCampaignDeviceOsTargetBid>().ToList();
                    OutputBulkCampaignDeviceOsTargetBids(campaignDeviceOsTargetBidResults);

                    Reader.Dispose();
                }

                #endregion Update

                #region CleanUp

                //Delete the campaign and target associations that were previously added.
                //You should remove this region if you want to view the added entities in the
                //Bing Ads web application or another tool.

                //You must set the Id field of the Campaign record that you want to delete, and the Status field to Deleted.
                //In this example the Id is already set i.e. via the upload result captured above.
                //When you delete a BulkCampaign, the dependent entities such as BulkCampaignDeviceOsTarget
                //are deleted without being specified explicitly.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                OutputStatusMessage("\nDeleting campaign and target associations . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());

                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 33
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                OutputStatusMessage(String.Format("{0} % Complete", x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                const int appAdExtensionIdKey = -11;
                const int callAdExtensionIdKey = -12;
                const int locationAdExtensionIdKey = -13;
                const int siteLinksAdExtensionIdKey = -14;
                const int campaignIdKey = -123;

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, 
                // and additional elements needed to read from and write to a bulk file. 

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",
                        BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget = 1000.00,
                        TimeZone = "PacificTimeUSCanadaTijuana",
                    }
                };

                // Prepare ad extensions for upload

                var bulkAppAdExtension = new BulkAppAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    AppAdExtension = new AppAdExtension
                    {
                        AppPlatform = "Windows",
                        AppStoreId = "AppStoreIdGoesHere",
                        DestinationUrl = "DestinationUrlGoesHere",
                        DisplayText = "Contoso",
                        Id = appAdExtensionIdKey,
                    }
                };

                var bulkCallAdExtension = new BulkCallAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    CallAdExtension = new CallAdExtension
                    {
                        CountryCode = "US",
                        PhoneNumber = "2065550100",
                        IsCallOnly = false,
                        Id = callAdExtensionIdKey
                    }
                };

                var bulkLocationAdExtension = new BulkLocationAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    LocationAdExtension = new LocationAdExtension
                    {
                        Id = locationAdExtensionIdKey,
                        PhoneNumber = "206-555-0100",
                        CompanyName = "Contoso Shoes",
                        IconMediaId = null,
                        ImageMediaId = null,
                        Address = new Address
                        {
                            StreetAddress = "1234 Washington Place",
                            StreetAddress2 = "Suite 1210",
                            CityName = "Woodinville",
                            ProvinceName = "WA",
                            CountryCode = "US",
                            PostalCode = "98608"
                        }
                    }
                };

                // Note that when written to file using the BulkFileWriter, an extra Sitelink Ad Extension record with Deleted
                // status precedes the actual site link record or records that you want to upload. All bulk entities 
                // that are derived from MultiRecordBulkEntiy are preceded with a Deleted record using the BulkFileWriter. 
                // In this example it is a moot point because we are creating a new ad extension. If the specified
                // ad extension Id already exists in your account, the Deleted record effectively deletes the existing
                // extension and replaces it with the SiteLinksAdExtension specified below.

                var bulkSiteLinkAdExtension = new BulkSiteLinkAdExtension
                {
                    AccountId = authorizationData.AccountId,
                    SiteLinksAdExtension = new SiteLinksAdExtension
                    {
                        // Note that if you do not specify a negative Id as reference key, each of SiteLinks items will
                        // be split during upload into separate sitelink ad extensions with unique ad extension identifiers.
                        Id = siteLinksAdExtensionIdKey,
                        SiteLinks = new List<SiteLink>
                                {
                                    new SiteLink
                                        {
                                            DestinationUrl = "Contoso.com",
                                            DisplayText = "Women's Shoe Sale 1"
                                        },
                                    new SiteLink
                                        {
                                            DestinationUrl = "Contoso.com/WomenShoeSale/2",
                                            DisplayText = "Women's Shoe Sale 2"
                                        }
                                }
                    }
                    // Note that BulkSiteLinkAdExtension.SiteLinks is read only and only 
                    // accessible when reading results from the download or upload results file.
                    // To upload new site links for a new site links ad extension, you should specify
                    // BulkSiteLinkAdExtension.SiteLinksAdExtension.SiteLinks as shown above.
                };

                // Prepare ad extension associations for upload

                var bulkCampaignAppAdExtension = new BulkCampaignAppAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = appAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };

                var bulkCampaignCallAdExtension = new BulkCampaignCallAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = callAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };

                var bulkCampaignLocationAdExtension = new BulkCampaignLocationAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = locationAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };

                var bulkCampaignSiteLinkAdExtension = new BulkCampaignSiteLinkAdExtension
                {
                    AdExtensionIdToEntityIdAssociation = new AdExtensionIdToEntityIdAssociation
                    {
                        AdExtensionId = siteLinksAdExtensionIdKey,
                        EntityId = campaignIdKey
                    }
                };


                // Write the entities created above, to the specified file.
                // Dependent entities such as BulkCampaignCallAdExtension must be written after any dependencies,  
                // for example the BulkCampaign and BulkCallAdExtension. 

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                Writer.WriteEntity(bulkCampaign);

                Writer.WriteEntity(bulkAppAdExtension);
                Writer.WriteEntity(bulkCallAdExtension);
                Writer.WriteEntity(bulkLocationAdExtension);
                Writer.WriteEntity(bulkSiteLinkAdExtension);

                Writer.WriteEntity(bulkCampaignAppAdExtension);
                Writer.WriteEntity(bulkCampaignCallAdExtension);
                Writer.WriteEntity(bulkCampaignLocationAdExtension);
                Writer.WriteEntity(bulkCampaignSiteLinkAdExtension);


                Writer.Dispose();

                var fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath = FileDirectory + UploadFileName,
                    ResponseMode = ResponseMode.ErrorsAndResults
                };

                // UploadFileAsync will upload the file you finished writing and will download the results file

                OutputStatusMessage("\nAdding campaign, ad extensions, and associations . . .\n");
                var bulkFilePath = await BulkService.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);
                Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);
                OutputStatusMessage("Upload Results Bulk File Path: " + Reader.BulkFilePath + "\n");

                // Write the upload output

                var bulkEntities = Reader.ReadEntities().ToList();

                var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var appAdExtensionResults = bulkEntities.OfType<BulkAppAdExtension>().ToList();
                OutputBulkAppAdExtensions(appAdExtensionResults);

                var callAdExtensionResults = bulkEntities.OfType<BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                var locationAdExtensionResults = bulkEntities.OfType<BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                var siteLinkAdExtensionResults = bulkEntities.OfType<BulkSiteLinkAdExtension>().ToList();
                OutputBulkSiteLinkAdExtensions(siteLinkAdExtensionResults);

                OutputBulkCampaignAppAdExtensions(bulkEntities.OfType<BulkCampaignAppAdExtension>().ToList());
                OutputBulkCampaignCallAdExtensions(bulkEntities.OfType<BulkCampaignCallAdExtension>().ToList());
                OutputBulkCampaignLocationAdExtensions(bulkEntities.OfType<BulkCampaignLocationAdExtension>().ToList());
                OutputBulkCampaignSiteLinkAdExtensions(bulkEntities.OfType<BulkCampaignSiteLinkAdExtension>().ToList());

                Reader.Dispose();

                #endregion Add

                #region Update

                // Update the site links ad extension. 
                // Do not create a BulkSiteLinkAdExtension for update, unless you want to replace all existing SiteLinks
                // with the specified SiteLinks for the specified ad extension. 
                // Instead you should upload one or more site links as a list of BulkSiteLink.

                var bulkSiteLinks = new List<BulkSiteLink>
                    {
                        new BulkSiteLink
                            {
                                SiteLink = new SiteLink
                                    {
                                        DestinationUrl = "Contoso.com",
                                        DisplayText = "Red Shoe Sale"
                                    }
                            }
                    };

                // Add an additional site link, and update an existing site link

                if (siteLinkAdExtensionResults.ToArray().Any() &&
                    siteLinkAdExtensionResults.ToArray()[0].SiteLinks.ToArray().Any())
                {
                    var existingSiteLink = siteLinkAdExtensionResults.ToArray()[0].SiteLinks[0];
                    existingSiteLink.SiteLink.DisplayText = "Red Shoes Super Sale";

                    // Associate the new site links with the identifier of the existing site links ad extension

                    foreach (var bulkSiteLink in bulkSiteLinks)
                    {
                        bulkSiteLink.AdExtensionId = existingSiteLink.AdExtensionId;
                    }

                    bulkSiteLinks.Add(existingSiteLink);
                }

                // Write the new site link and updated site link to the file

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                foreach (var bulkSiteLink in bulkSiteLinks)
                {
                    Writer.WriteEntity(bulkSiteLink);
                }

                Writer.Dispose();

                fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath = FileDirectory + UploadFileName,
                    ResponseMode = ResponseMode.ErrorsAndResults
                };

                // UploadFileAsync will upload the file you finished writing and will download the results file

                OutputStatusMessage("\nUpdating sitelinks . . .\n");
                bulkFilePath = await BulkService.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);
                Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);
                OutputStatusMessage("Upload Results Bulk File Path: " + Reader.BulkFilePath + "\n");

                // Write any upload errors

                bulkEntities = Reader.ReadEntities().ToList();
                var siteLinkResults = bulkEntities.OfType<BulkSiteLink>().ToList();
                OutputBulkSiteLinks(siteLinkResults);

                Reader.Dispose();

                #endregion Update

                #region Delete

                // Prepare the bulk entities that you want to delete. You must set the Id field to the corresponding 
                // entity identifier, and the Status field to Deleted. 

                var campaignId = campaignResults[0].Campaign.Id;
                bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id = campaignId,
                        Status = CampaignStatus.Deleted
                    }
                };

                var appAdExtensionId = appAdExtensionResults[0].AppAdExtension.Id;
                bulkAppAdExtension = new BulkAppAdExtension
                {
                    AppAdExtension = new AppAdExtension
                    {
                        Id = appAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                var callAdExtensionId = callAdExtensionResults[0].CallAdExtension.Id;
                bulkCallAdExtension = new BulkCallAdExtension
                {
                    CallAdExtension = new CallAdExtension
                    {
                        Id = callAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                var locationAdExtensionId = locationAdExtensionResults[0].LocationAdExtension.Id;
                bulkLocationAdExtension = new BulkLocationAdExtension
                {
                    LocationAdExtension = new LocationAdExtension
                    {
                        Id = locationAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };


                var siteLinkAdExtensionId = siteLinkAdExtensionResults[0].SiteLinksAdExtension.Id;
                bulkSiteLinkAdExtension = new BulkSiteLinkAdExtension
                {
                    SiteLinksAdExtension = new SiteLinksAdExtension
                    {
                        Id = siteLinkAdExtensionId,
                        Status = AdExtensionStatus.Deleted
                    }
                };

                // Write the entities that you want deleted, to the specified file.
                // Dependent entities such as BulkCampaignCallAdExtension are deleted without being specified explicitly.  
                // For example, if you delete either BulkCampaign or BulkCallAdExtension, then the equivalent of 
                // BulkCampaignCallAdExtension is effectively deleted. 

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                Writer.WriteEntity(bulkCampaign);

                Writer.WriteEntity(bulkAppAdExtension);
                Writer.WriteEntity(bulkCallAdExtension);
                Writer.WriteEntity(bulkLocationAdExtension);
                Writer.WriteEntity(bulkSiteLinkAdExtension);


                Writer.Dispose();

                fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath = FileDirectory + UploadFileName,
                    ResponseMode = ResponseMode.ErrorsAndResults
                };

                // UploadFileAsync will upload the file you finished writing and will download the results file

                OutputStatusMessage("\nDeleting campaign and ad extensions . . .\n");
                bulkFilePath = await BulkService.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);
                Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType);
                OutputStatusMessage("Upload Results Bulk File Path: " + Reader.BulkFilePath + "\n");

                // Write the upload output

                bulkEntities = Reader.ReadEntities().ToList();

                campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                appAdExtensionResults = bulkEntities.OfType<BulkAppAdExtension>().ToList();
                OutputBulkAppAdExtensions(appAdExtensionResults);

                callAdExtensionResults = bulkEntities.OfType<BulkCallAdExtension>().ToList();
                OutputBulkCallAdExtensions(callAdExtensionResults);

                locationAdExtensionResults = bulkEntities.OfType<BulkLocationAdExtension>().ToList();
                OutputBulkLocationAdExtensions(locationAdExtensionResults);

                siteLinkAdExtensionResults = bulkEntities.OfType<BulkSiteLinkAdExtension>().ToList();
                OutputBulkSiteLinkAdExtensions(siteLinkAdExtensionResults);

                OutputBulkCampaignAppAdExtensions(bulkEntities.OfType<BulkCampaignAppAdExtension>().ToList());
                OutputBulkCampaignCallAdExtensions(bulkEntities.OfType<BulkCampaignCallAdExtension>().ToList());
                OutputBulkCampaignLocationAdExtensions(bulkEntities.OfType<BulkCampaignLocationAdExtension>().ToList());
                OutputBulkCampaignSiteLinkAdExtensions(bulkEntities.OfType<BulkCampaignSiteLinkAdExtension>().ToList());

                Reader.Dispose();

                #endregion Delete

            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
Exemplo n.º 34
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var uploadEntities = new List<BulkEntity>();

                #region Add

                // Let's create a new budget and share it with a new campaign.

                var bulkBudget = new BulkBudget
                {
                    ClientId = "YourClientIdGoesHere",
                    Budget = new Budget
                    {
                        Amount = 50,
                        BudgetType = BudgetLimitType.DailyBudgetStandard,
                        Id = budgetIdKey,
                        Name = "My Shared Budget " + DateTime.UtcNow,
                    }
                };
                
                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. 
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId = budgetIdKey,
                        DailyBudget = null,
                        BudgetType = BudgetLimitType.DailyBudgetStandard,

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,

                        // You can set your campaign bid strategy to Enhanced CPC (EnhancedCpcBiddingScheme) 
                        // and then, at any time, set an individual ad group or keyword bid strategy to 
                        // Manual CPC (ManualCpcBiddingScheme).
                        // For campaigns you can use either of the EnhancedCpcBiddingScheme or ManualCpcBiddingScheme objects. 
                        // If you do not set this element, then ManualCpcBiddingScheme is used by default.
                        BiddingScheme = new EnhancedCpcBiddingScheme { },

                        Status = CampaignStatus.Paused,
                        
                        // Used with FinalUrls shown in the expanded text ads that we will add below.
                        TrackingUrlTemplate =
                            "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}"
                    }
                };

                // Specify one or more ad groups.
                
                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup = new AdGroup
                    {
                        Id = adGroupIdKey,
                        Name = "Women's Red Shoe Sale",
                        AdDistribution = AdDistribution.Search,
                        BiddingModel = BiddingModel.Keyword,
                        PricingModel = PricingModel.Cpc,
                        StartDate = null,
                        EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date
                        {
                            Month = 12,
                            Day = 31,
                            Year = DateTime.UtcNow.Year + 1
                        },
                        Language = "English",
                        Status = AdGroupStatus.Active,

                        // For ad groups you can use either of the InheritFromParentBiddingScheme or ManualCpcBiddingScheme objects. 
                        // If you do not set this element, then InheritFromParentBiddingScheme is used by default.
                        BiddingScheme = new ManualCpcBiddingScheme { },

                        // You could use a tracking template which would override the campaign level
                        // tracking template. Tracking templates defined for lower level entities 
                        // override those set for higher level entities.
                        // In this example we are using the campaign level tracking template.
                        TrackingUrlTemplate = null,
                    },
                };

                // In this example only the second keyword should succeed. The Text of the first keyword exceeds the limit,
                // and the third keyword is a duplicate of the second keyword. 

                var bulkKeywords = new [] {
                    new BulkKeyword{
                        AdGroupId = adGroupIdKey,
                        Keyword = new Keyword
                        {
                            Bid = new Bid { Amount = 0.47 },
                            Param2 = "10% Off",
                            MatchType = MatchType.Broad,
                            Text = "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes " +
                                   "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes " +
                                   "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes",
                            // For keywords you can use either of the InheritFromParentBiddingScheme or ManualCpcBiddingScheme objects. 
                            // If you do not set this element, then InheritFromParentBiddingScheme is used by default.
                            BiddingScheme = new InheritFromParentBiddingScheme { },
                        },
                    },
                    new BulkKeyword{
                        AdGroupId = adGroupIdKey,
                        Keyword = new Keyword
                        {
                            Bid = new Bid { Amount = 0.47 },
                            Param2 = "10% Off",
                            MatchType = MatchType.Phrase,
                            Text = "Brand-A Shoes",
                            // For keywords you can use either of the InheritFromParentBiddingScheme or ManualCpcBiddingScheme objects. 
                            // If you do not set this element, then InheritFromParentBiddingScheme is used by default.
                            BiddingScheme = new InheritFromParentBiddingScheme { },
                        },
                    },
                    new BulkKeyword{
                        AdGroupId = adGroupIdKey,
                        Keyword = new Keyword
                        {
                            Bid = new Bid { Amount = 0.47 },
                            Param2 = "10% Off",
                            MatchType = MatchType.Phrase,
                            Text = "Brand-A Shoes",
                            // For keywords you can use either of the InheritFromParentBiddingScheme or ManualCpcBiddingScheme objects. 
                            // If you do not set this element, then InheritFromParentBiddingScheme is used by default.
                            BiddingScheme = new InheritFromParentBiddingScheme { },
                        },
                    },
                };

                // In this example only the first 3 ads should succeed. 
                // The TitlePart2 of the fourth ad is empty and not valid,
                // and the fifth ad is a duplicate of the second ad. 

                var bulkExpandedTextAds = new [] {
                    new BulkExpandedTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        ExpandedTextAd = new ExpandedTextAd
                        {
                            TitlePart1 = "Contoso",
                            TitlePart2 = "Fast & Easy Setup",
                            Text = "Find New Customers & Increase Sales! Start Advertising on Contoso Today.",
                            Path1 = "seattle",
                            Path2 = "shoe sale",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale",
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale",
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO1"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            }
                        },
                    },
                    new BulkExpandedTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        ExpandedTextAd = new ExpandedTextAd
                        {
                            TitlePart1 = "Contoso",
                            TitlePart2 = "Quick & Easy Setup",
                            Text = "Find New Customers & Increase Sales! Start Advertising on Contoso Today.",
                            Path1 = "seattle",
                            Path2 = "shoe sale",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO2"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                    new BulkExpandedTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        ExpandedTextAd = new ExpandedTextAd
                        {
                            TitlePart1 = "Contoso",
                            TitlePart2 = "Fast & Simple Setup",
                            Text = "Find New Customers & Increase Sales! Start Advertising on Contoso Today.",
                            Path1 = "seattle",
                            Path2 = "shoe sale",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO3"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                    new BulkExpandedTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        ExpandedTextAd = new ExpandedTextAd
                        {
                            TitlePart1 = "Contoso",
                            TitlePart2 = "",
                            Text = "Find New Customers & Increase Sales! Start Advertising on Contoso Today.",
                            Path1 = "seattle",
                            Path2 = "shoe sale",  

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO4"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                    new BulkExpandedTextAd
                    {
                        AdGroupId = adGroupIdKey,
                        ExpandedTextAd = new ExpandedTextAd
                        {
                            TitlePart1 = "Contoso",
                            TitlePart2 = "Quick & Easy Setup",
                            Text = "Find New Customers & Increase Sales! Start Advertising on Contoso Today.",
                            Path1 = "seattle",
                            Path2 = "shoe sale",

                            // With FinalUrls you can separate the tracking template, custom parameters, and 
                            // landing page URLs. 
                            FinalUrls = new[] {
                                "http://www.contoso.com/womenshoesale"
                            },
                            // Final Mobile URLs can also be used if you want to direct the user to a different page 
                            // for mobile devices.
                            FinalMobileUrls = new[] {
                                "http://mobile.contoso.com/womenshoesale"
                            }, 
                            // You could use a tracking template which would override the campaign level
                            // tracking template. Tracking templates defined for lower level entities 
                            // override those set for higher level entities.
                            // In this example we are using the campaign level tracking template.
                            TrackingUrlTemplate = null,

                            // Set custom parameters that are specific to this ad, 
                            // and can be used by the ad, ad group, campaign, or account level tracking template. 
                            // In this example we are using the campaign level tracking template.
                            UrlCustomParameters = new CustomParameters {
                                Parameters = new[] {
                                    new CustomParameter(){
                                        Key = "promoCode",
                                        Value = "PROMO5"
                                    },
                                    new CustomParameter(){
                                        Key = "season",
                                        Value = "summer"
                                    },
                                }
                            },
                        },
                    },
                };

                uploadEntities.Add(bulkBudget);
                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkAdGroup);

                foreach (var bulkKeyword in bulkKeywords)
                {
                    uploadEntities.Add(bulkKeyword);
                }

                foreach (var bulkExpandedTextAd in bulkExpandedTextAds)
                {
                    uploadEntities.Add(bulkExpandedTextAd);
                }

                // Upload and write the output

                OutputStatusMessage("Adding campaign, budget, ad group, ads, and keywords...\n");

                var Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                var downloadEntities = Reader.ReadEntities().ToList();

                var budgetResults = downloadEntities.OfType<BulkBudget>().ToList();
                OutputBulkBudgets(budgetResults);

                var campaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType<BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var keywordResults = downloadEntities.OfType<BulkKeyword>().ToList();
                OutputBulkKeywords(keywordResults);

                var expandedTextAdResults = downloadEntities.OfType<BulkExpandedTextAd>().ToList();
                OutputBulkExpandedTextAds(expandedTextAdResults);

                Reader.Dispose();

                #endregion Add

                #region Update

                // Here is a simple example that updates the campaign budget.
                
                var downloadParameters = new DownloadParameters
                {
                    Entities = BulkDownloadEntity.Budgets | BulkDownloadEntity.Campaigns,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = DownloadFileName,
                    OverwriteResultFile = true,
                    LastSyncTimeInUTC = null
                };

                // Download all campaigns and shared budgets in the account.
                var bulkFilePath = await BulkService.DownloadFileAsync(downloadParameters);
                OutputStatusMessage("\nDownloaded all campaigns and shared budgets in the account.\n");
                Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType);
                downloadEntities = Reader.ReadEntities().ToList();
                var getBudgetResults = downloadEntities.OfType<BulkBudget>().ToList();
                OutputBulkBudgets(getBudgetResults);
                var getCampaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(getCampaignResults);

                uploadEntities = new List<BulkEntity>();

                // If the campaign has a shared budget you cannot update the Campaign budget amount,
                // and you must instead update the amount in the Budget record. If you try to update 
                // the budget amount of a Campaign that has a shared budget, the service will return 
                // the CampaignServiceCannotUpdateSharedBudget error code.

                foreach (var entity in getBudgetResults)
                {
                    if (entity.Budget.Id > 0)
                    {
                        // Increase budget by 20 %
                        entity.Budget.Amount *= 1.2m;
                        uploadEntities.Add(entity);
                    }
                }

                foreach (var entity in getCampaignResults)
                {
                    if (entity.Campaign.BudgetId == null || entity.Campaign.BudgetId <= 0)
                    {
                        // Increase existing budgets by 20%
                        // Monthly budgets are deprecated and there will be a forced migration to daily budgets in calendar year 2017. 
                        // Shared budgets do not support the monthly budget type, so this is only applicable to unshared budgets. 
                        // During the migration all campaign level unshared budgets will be rationalized as daily. 
                        // The formula that will be used to convert monthly to daily budgets is: Monthly budget amount / 30.4.
                        // Moving campaign monthly budget to daily budget is encouraged before monthly budgets are migrated. 

                        if (entity.Campaign.BudgetType == BudgetLimitType.MonthlyBudgetSpendUntilDepleted)
                        {
                            // Increase budget by 20 %
                            entity.Campaign.BudgetType = BudgetLimitType.DailyBudgetStandard;
                            entity.Campaign.DailyBudget = entity.Campaign.MonthlyBudget / 30.4 * 1.2;
                        }
                        else
                        {
                            // Increase budget by 20 %
                            entity.Campaign.DailyBudget *= 1.2;
                        }
                        uploadEntities.Add(entity);
                    }
                }

                Reader.Dispose();

                if (uploadEntities.Count > 0)
                {
                    OutputStatusMessage("\nChanged local campaign budget amounts. Starting upload.\n");

                    Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                    downloadEntities = Reader.ReadEntities().ToList();
                    getBudgetResults = downloadEntities.OfType<BulkBudget>().ToList();
                    OutputBulkBudgets(getBudgetResults);
                    getCampaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                    OutputBulkCampaigns(getCampaignResults);
                    Reader.Dispose();
                }
                else
                {
                    OutputStatusMessage("\nNo campaigns or shared budgets in account.\n");
                }

                #endregion Update

                #region CleanUp

                //Delete the campaign, ad group, ads, and keywords that were previously added. 
                //You should remove this region if you want to view the added entities in the 
                //Bing Ads web application or another tool.

                //You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                //When you delete a BulkCampaign, the dependent entities such as BulkAdGroup, BulkKeyword, 
                //and BulkExpandedTextAd are deleted without being specified explicitly.  

                uploadEntities = new List<BulkEntity>();

                foreach (var budgetResult in budgetResults)
                {
                    budgetResult.Status = Status.Deleted;
                    uploadEntities.Add(budgetResult);
                }

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }
                
                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign, budget, ad group, keywords, and ads . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                downloadEntities = Reader.ReadEntities().ToList();
                getBudgetResults = downloadEntities.OfType<BulkBudget>().ToList();
                OutputBulkBudgets(getBudgetResults);
                getCampaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(getCampaignResults);

                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
Exemplo n.º 35
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(authorizationData, environment);
                BulkServiceManager.StatusPollIntervalInMilliseconds = 5000;

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Download

                // In this example we will download all ad groups in the account.

                var entities = new[] {
                    DownloadEntity.AdGroups,
                };

                // You can limit by specific campaign IDs and request performance data.

                var downloadParameters = new DownloadParameters
                {
                    CampaignIds = null,
                    DataScope   = DataScope.EntityData,
                    PerformanceStatsDateRange = null,
                    DownloadEntities          = entities,
                    FileType            = FileType,
                    LastSyncTimeInUTC   = null,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName      = DownloadFileName,
                    OverwriteResultFile = true
                };

                // You can submit a download or upload request and the BulkServiceManager will automatically
                // return results. The BulkServiceManager abstracts the details of checking for result file
                // completion, and you don't have to write any code for results polling.

                var bulkFilePath = await BulkServiceManager.DownloadFileAsync(downloadParameters);

                OutputStatusMessage("Downloaded all ad groups in the account.\n");

                #endregion Download

                #region Parse

                Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType);
                var bulkAdGroups = Reader.ReadEntities().ToList().OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(bulkAdGroups);

                Writer = new BulkFileWriter(FileDirectory + UploadFileName);

                // We will activate ad groups for one month starting from today as an example.

                var nextMonth = DateTime.UtcNow.AddMonths(1);

                // Within the downloaded records, find all ad groups that you want to update.

                foreach (var bulkAdGroup in bulkAdGroups)
                {
                    var adGroup = bulkAdGroup.AdGroup;
                    if (adGroup != null && bulkAdGroup.IsExpired)
                    {
                        // For best performance, only upload the properties that you want to update.

                        Writer.WriteEntity(new BulkAdGroup
                        {
                            CampaignId = bulkAdGroup.CampaignId,
                            AdGroup    = new AdGroup
                            {
                                Id      = adGroup.Id,
                                EndDate = new Microsoft.BingAds.V12.CampaignManagement.Date
                                {
                                    Month = nextMonth.Month,
                                    Day   = nextMonth.Day,
                                    Year  = nextMonth.Year
                                },
                                Status = AdGroupStatus.Active,
                            }
                        });
                    }
                }

                Reader.Dispose();
                Writer.Dispose();

                #endregion Parse

                #region Upload

                // Upload the local file that we already prepared

                var fileUploadParameters = new FileUploadParameters
                {
                    ResultFileDirectory = FileDirectory,
                    CompressUploadFile  = true,
                    ResultFileName      = ResultFileName,
                    OverwriteResultFile = true,
                    UploadFilePath      = FileDirectory + UploadFileName,
                    ResponseMode        = ResponseMode.ErrorsAndResults
                };

                var resultFilePath = await BulkServiceManager.UploadFileAsync(fileUploadParameters, progress, CancellationToken.None);

                OutputStatusMessage("Updated ad groups.\n");

                Reader       = new BulkFileReader(resultFilePath, ResultFileType.Upload, FileType);
                bulkAdGroups = Reader.ReadEntities().ToList().OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(bulkAdGroups);
                Reader.Dispose();

                #endregion Upload


                #region Entities

                // We can make the same update without explicitly reading or writing a local file.
                // When working with entities a file is downloaded to the temp directory,
                // although you don't need to manage it.

                var downloadEntities = await BulkServiceManager.DownloadEntitiesAsync(downloadParameters);

                OutputStatusMessage("Downloaded all ad groups in the account.\n");
                bulkAdGroups = downloadEntities.ToList().OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(bulkAdGroups);

                var uploadEntities = new List <BulkEntity>();

                foreach (var bulkAdGroup in bulkAdGroups)
                {
                    var adGroup = bulkAdGroup.AdGroup;
                    if (adGroup != null && bulkAdGroup.IsExpired)
                    {
                        // Instead of Writer.WriteEntity, we will add to the in-memory list

                        uploadEntities.Add(new BulkAdGroup
                        {
                            CampaignId = bulkAdGroup.CampaignId,
                            AdGroup    = new AdGroup
                            {
                                Id      = adGroup.Id,
                                EndDate = new Microsoft.BingAds.V12.CampaignManagement.Date
                                {
                                    Month = nextMonth.Month,
                                    Day   = nextMonth.Day,
                                    Year  = nextMonth.Year
                                },
                                Status = AdGroupStatus.Active,
                            }
                        });
                    }
                }

                var entityUploadParameters = new EntityUploadParameters
                {
                    Entities     = uploadEntities,
                    ResponseMode = ResponseMode.ErrorsAndResults,
                };

                var resultEntities = await BulkServiceManager.UploadEntitiesAsync(entityUploadParameters, progress, CancellationToken.None);

                OutputStatusMessage("Updated ad groups.\n");

                bulkAdGroups = resultEntities.ToList().OfType <BulkAdGroup>().ToList();
                OutputBulkAdGroups(bulkAdGroups);

                #endregion Entities
            }
            // Catch authentication exceptions
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
        }
Exemplo n.º 36
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(authorizationData);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object,
                // and additional elements needed to read from and write to a bulk file.

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth.
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id
                        // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below.
                        Id          = campaignIdKey,
                        Name        = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId      = null,
                        DailyBudget   = 50,
                        BudgetType    = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",
                    }
                };

                // You can specify one negative site per BulkCampaignNegativeSite (singular), or multiple negative sites
                // in a BulkCampaignNegativeSites (plural) object.

                var bulkCampaignNegativeSite = new BulkCampaignNegativeSite[] {
                    new BulkCampaignNegativeSite {
                        // CampaignName will be ignored if you specify CampaignId.
                        CampaignName = null,
                        CampaignId   = campaignIdKey,
                        Website      = "contoso.com/negativesite1"
                    },
                    new BulkCampaignNegativeSite {
                        CampaignId = campaignIdKey,
                        Website    = "contoso.com/negativesite2"
                    },
                };

                // If you upload a BulkCampaignNegativeSites bulk entity, then you are effectively replacing any existing
                // negative sites assigned to the campaign. Thus, when a BulkCampaignNegativeSites entity is written to the
                // upload file, an extra Campaign Negative Site record is included where the Status is Deleted and the
                // Website field is empty.
                // That said, if you include additional BulkCampaignNegativeSite or BulkCampaignNegativeSites in the same upload,
                // they will be included in the new set of negative sites.
                var bulkCampaignNegativeSites = new BulkCampaignNegativeSites[] {
                    new BulkCampaignNegativeSites {
                        // CampaignName will be ignored if you specify CampaignId.
                        CampaignName          = null,
                        CampaignNegativeSites = new CampaignNegativeSites
                        {
                            CampaignId    = campaignIdKey,
                            NegativeSites = new string[]
                            {
                                "contoso.com/negativesite3",
                                "contoso.com/negativesite4",
                            }
                        }
                    },
                };

                var uploadEntities = new List <BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                foreach (var campaignNegativeSite in bulkCampaignNegativeSite)
                {
                    uploadEntities.Add(campaignNegativeSite);
                }

                foreach (var campaignNegativeSites in bulkCampaignNegativeSites)
                {
                    uploadEntities.Add(campaignNegativeSites);
                }

                // Upload and write the output

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                // If you modify the sample to upload only BulkCampaignNegativeSite entities for a campaign, the SDK will abstract
                // the results file contents as one or more BulkCampaignNegativeSite. If you upload both BulkCampaignNegativeSite
                // and BulkCampaignNegativeSites as shown above, then the SDK will abstract the results file contents as a
                // BulkCampaignNegativeSites object containing all of the negative sites for the campaign,
                // including those uploaded as a BulkCampaignNegativeSite.

                // Whether you use the SDK to upload the entities, or only use the SDK to read an upload results file,
                // the SDK will abstract the results file as follows:
                // If the file contains an extra Campaign Negative Site record where the Status is Deleted and the
                // Website field is empty, the SDK returns a BulkCampaignNegativeSites (plural) object.
                // Otherwise the SDK returns one or more BulkCampaignNegativeSite (singlular) objects.

                var campaignNegativeSiteResults = downloadEntities.OfType <BulkCampaignNegativeSite>().ToList();
                OutputBulkCampaignNegativeSite(campaignNegativeSiteResults);

                var campaignNegativeSitesResults = downloadEntities.OfType <BulkCampaignNegativeSites>().ToList();
                OutputBulkCampaignNegativeSites(campaignNegativeSitesResults);

                Reader.Dispose();

                #endregion Add

                #region CleanUp

                //Delete the campaign and negative sites that were previously added.
                //You should remove this region if you want to view the added entities in the
                //Bing Ads web application or another tool.

                //You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                //When you delete a BulkCampaign, the dependent entities such as BulkCampaignNegativeSite
                //are deleted without being specified explicitly.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign and negative sites . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());
                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V11.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V11.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
Exemplo n.º 37
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment;

                CampaignManagementExampleHelper = new CampaignManagementExampleHelper(this.OutputStatusMessage);

                BulkServiceManager = new BulkServiceManager(authorizationData, environment);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                #region Add

                // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object,
                // and additional elements needed to read from and write to a bulk file.

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth.
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id
                        // will be used when associating this new campaign with a new negative keyword in the BulkCampaignNegativeKeyword object below.
                        Id          = campaignIdKey,
                        Name        = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId      = null,
                        DailyBudget   = 50,
                        BudgetType    = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",
                    }
                };

                var bulkCampaignNegativeKeywords = new BulkCampaignNegativeKeyword[] {
                    new BulkCampaignNegativeKeyword {
                        CampaignId      = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Phrase,
                            Text      = "auto",
                        }
                    },
                    new BulkCampaignNegativeKeyword {
                        CampaignId      = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Exact,
                            Text      = "auto",
                        }
                    },
                    new BulkCampaignNegativeKeyword {
                        CampaignId      = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Phrase,
                            Text      = "car",
                        }
                    },
                    new BulkCampaignNegativeKeyword {
                        CampaignId      = campaignIdKey,
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Exact,
                            Text      = "car",
                        }
                    },
                };

                // Negative keywords can be added and deleted from a shared negative keyword list. The negative keyword list can be shared or associated with multiple campaigns.
                // You can create up to 20 negative keyword lists per account and share or associate them with any campaign in the same account.
                // To create a negative keyword list, upload a BulkNegativeKeywordList (Negative Keyword List record type).
                // For each negative keyword that you want to add to the list, upload a BulkSharedNegativeKeyword (Shared Negative Keyword record type).
                // To associate the negative keyword list with a campaign, also upload a BulkCampaignNegativeKeywordList (Campaign Negative Keyword List Association record type).

                var bulkNegativeKeywordList = new BulkNegativeKeywordList
                {
                    NegativeKeywordList = new NegativeKeywordList
                    {
                        // Since we are adding the list and the negative keywords during the same upload,
                        // we will use a reference key to the negative keyword list identifier.
                        Id   = negativeKeywordListIdKey,
                        Name = "My NKW List",
                    },
                };

                var bulkSharedNegativeKeywords = new BulkSharedNegativeKeyword[] {
                    new BulkSharedNegativeKeyword {
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Phrase,
                            Text      = "mobile",
                        },
                        NegativeKeywordListId = negativeKeywordListIdKey,
                    },
                    new BulkSharedNegativeKeyword {
                        NegativeKeyword = new NegativeKeyword
                        {
                            MatchType = MatchType.Exact,
                            Text      = "mobile",
                        },
                        NegativeKeywordListId = negativeKeywordListIdKey,
                    },
                };

                var bulkCampaignNegativeKeywordList = new BulkCampaignNegativeKeywordList
                {
                    SharedEntityAssociation = new SharedEntityAssociation
                    {
                        EntityId         = campaignIdKey,
                        EntityType       = "Campaign",
                        SharedEntityId   = negativeKeywordListIdKey,
                        SharedEntityType = "NegativeKeywordList",
                    }
                };

                var uploadEntities = new List <BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                foreach (var bulkCampaignNegativeKeyword in bulkCampaignNegativeKeywords)
                {
                    uploadEntities.Add(bulkCampaignNegativeKeyword);
                }

                uploadEntities.Add(bulkNegativeKeywordList);
                foreach (var bulkSharedNegativeKeyword in bulkSharedNegativeKeywords)
                {
                    uploadEntities.Add(bulkSharedNegativeKeyword);
                }
                uploadEntities.Add(bulkCampaignNegativeKeywordList);

                // Upload and write the output

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                var downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType <BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var campaignNegativeKeywordResults = downloadEntities.OfType <BulkCampaignNegativeKeyword>().ToList();
                OutputBulkCampaignNegativeKeywords(campaignNegativeKeywordResults);

                var negativeKeywordListResults = downloadEntities.OfType <BulkNegativeKeywordList>().ToList();
                OutputBulkNegativeKeywordLists(negativeKeywordListResults);

                var sharedNegativeKeywordListResults = downloadEntities.OfType <BulkSharedNegativeKeyword>().ToList();
                OutputBulkSharedNegativeKeywords(sharedNegativeKeywordListResults);

                var campaignNegativeKeywordListResults = downloadEntities.OfType <BulkCampaignNegativeKeywordList>().ToList();
                OutputBulkCampaignNegativeKeywordLists(campaignNegativeKeywordListResults);

                Reader.Dispose();

                #endregion Add

                #region CleanUp

                //Delete the campaign and negative keywords that were previously added.
                //You should remove this region if you want to view the added entities in the
                //Bing Ads web application or another tool.

                //You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                //When you delete a BulkCampaign, the dependent entities such as BulkCampaignNegativeKeyword
                //are deleted without being specified explicitly.
                //When you delete a BulkNegativeKeywordList, the dependent entities such as BulkSharedNegativeKeyword
                //are deleted without being specified explicitly.

                uploadEntities = new List <BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                foreach (var negativeKeywordListResult in negativeKeywordListResults)
                {
                    negativeKeywordListResult.Status = Status.Deleted;
                    uploadEntities.Add(negativeKeywordListResult);
                }

                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign and negative keywords . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);

                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType <BulkCampaign>().ToList());
                OutputBulkNegativeKeywordLists(downloadEntities.OfType <BulkNegativeKeywordList>().ToList());
                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V12.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V12.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                #region CampaignThroughAdGroupSetup

                // You will need to use the Campaign Management service to get the Bing Merchant Center Store Id. This will be used
                // when creating a new Bing Shopping Campaign.
                // For other operations such as adding product conditions, you can manage Bing Shopping Campaigns solely with the Bulk Service. 

                CampaignService = new ServiceClient<ICampaignManagementService>(authorizationData);

                // Get a list of all Bing Merchant Center stores associated with your CustomerId

                IList<BMCStore> stores = await GetBMCStoresByCustomerIdAsync();
                if (stores == null)
                {
                    OutputStatusMessage(
                        String.Format("You do not have any BMC stores registered for CustomerId {0}.\n", authorizationData.CustomerId)
                    );
                    return;
                }

                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));


                const int campaignIdKey = -123;
                const int adGroupIdKey = -1234;

                var uploadEntities = new List<BulkEntity>();

                /* Add a new Bing Shopping campaign that will be associated with a ProductScope criterion.
                 *  - Set the CampaignType element of the Campaign to Shopping.
                 *  - Create a ShoppingSetting instance and set its Priority (0, 1, or 2), SalesCountryCode, and StoreId elements. 
                 *    Add this shopping setting to the Settings list of the Campaign.
                 */

                var bulkCampaign = new BulkCampaign
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    Campaign = new Campaign
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id 
                        // will be used when associating this new campaign with a new campaign product scope in the BulkCampaignProductScope object below. 
                        Id = campaignIdKey,
                        CampaignType = CampaignType.Shopping,
                        Settings = new[] { 
                            new ShoppingSetting() {
                                Priority = 0,
                                SalesCountryCode = "US",
                                StoreId = (int)stores[0].Id
                            }
                        },
                        Name = "Bing Shopping Campaign " + DateTime.UtcNow,
                        Description = "Bing Shopping Campaign Example.",
                        BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted,
                        MonthlyBudget = 1000.00,
                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,

                    }
                };

                /* Optionally, you can create a ProductScope criterion that will be associated with your Bing Shopping campaign. 
                 * Use the product scope criterion to include a subset of your product catalog, for example a specific brand, 
                 * category, or product type. A campaign can only be associated with one ProductScope, which contains a list 
                 * of up to 7 ProductCondition. You'll also be able to specify more specific product conditions for each ad group.
                 */

                var bulkCampaignProductScope = new BulkCampaignProductScope
                {
                    CampaignCriterion = new CampaignCriterion()
                    {
                        CampaignId = campaignIdKey,
                        BidAdjustment = null,  // Reserved for future use
                        Criterion = new ProductScope()
                        {
                            Conditions = new ProductCondition[] {
                                new ProductCondition {
                                    Operand = "Condition",
                                    Attribute = "New"
                                },
                                new ProductCondition {
                                    Operand = "CustomLabel0",
                                    Attribute = "MerchantDefinedCustomLabel"
                                },
                            }
                        },
                    },
                    Status = Status.Active,
                };

                // Specify one or more ad groups.

                var bulkAdGroup = new BulkAdGroup
                {
                    CampaignId = campaignIdKey,
                    AdGroup = new AdGroup
                    {
                        Id = adGroupIdKey,
                        Name = "Product Categories",
                        AdDistribution = AdDistribution.Search,
                        BiddingModel = BiddingModel.Keyword,
                        PricingModel = PricingModel.Cpc,
                        StartDate = null,
                        EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date { Month = 12, Day = 31, Year = 2016 },
                        Language = "English",
                        Status = AdGroupStatus.Active
                    },
                };

                /*
                 * Create a product ad. You must add at least one ProductAd to the corresponding ad group. 
                 * A ProductAd is not used directly for delivered ad copy. Instead, the delivery engine generates 
                 * product ads from the product details that it finds in your Bing Merchant Center store's product catalog. 
                 * The primary purpose of the ProductAd object is to provide promotional text that the delivery engine 
                 * adds to the product ads that it generates. For example, if the promotional text is set to 
                 * “Free shipping on $99 purchases”, the delivery engine will set the product ad’s description to 
                 * “Free shipping on $99 purchases.”
                 */

                var bulkProductAd = new BulkProductAd
                {
                    AdGroupId = adGroupIdKey,
                    ProductAd = new ProductAd
                    {
                        PromotionalText = "Free shipping on $99 purchases."
                    }
                };

                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkAdGroup);
                uploadEntities.Add(bulkCampaignProductScope);
                uploadEntities.Add(bulkProductAd);

                // Write the upload output

                var Reader = await UploadEntities(uploadEntities);
                var bulkEntities = Reader.ReadEntities().ToList();

                var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = bulkEntities.OfType<BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var productAdResults = bulkEntities.OfType<BulkProductAd>().ToList();
                OutputBulkProductAds(productAdResults);

                var campaignProductScopeResults = bulkEntities.OfType<BulkCampaignProductScope>().ToList();
                OutputBulkCampaignProductScopes(campaignProductScopeResults);

                Reader.Dispose();

                #endregion CampaignThroughAdGroupSetup

                #region BidAllProducts

                var adGroupId = (long)adGroupResults[0].AdGroup.Id;

                var helper = new ProductPartitionHelper(adGroupId);

                var root = helper.AddUnit(
                    null,
                    new ProductCondition { Operand = "All", Attribute = null },
                    0.35,
                    false,
                    "root"
                );

                OutputStatusMessage("Applying only the root as a Unit with a bid . . . \n");
                var applyBulkProductPartitionActionsResults =
                    await ApplyBulkProductPartitionActions(helper.PartitionActions);

                var productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                OutputStatusMessage("The ad group's product partition only has a tree root node: \n");
                OutputProductPartitions(productPartitions);

                /*
                 * Let's update the bid of the root Unit we just added.
                 */

                var updatedRoot = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root");
                var bid = new FixedBid
                {
                    Bid = new Bid
                    {
                        Amount = 0.45
                    }
                };
                ((BiddableAdGroupCriterion)(updatedRoot.AdGroupCriterion)).CriterionBid = bid;

                helper = new ProductPartitionHelper(adGroupId);
                helper.UpdatePartition(updatedRoot);

                OutputStatusMessage("Updating the bid for the tree root node . . . \n");
                await ApplyBulkProductPartitionActions(helper.PartitionActions);

                productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                OutputStatusMessage("Updated the bid for the tree root node: \n");
                OutputProductPartitions(productPartitions);

                #endregion BidAllProducts

                #region InitializeTree

                /*
                 * Now we will overwrite any existing tree root, and build a product partition group tree structure in multiple steps. 
                 * You could build the entire tree in a single call since there are less than 20,000 nodes; however, 
                 * we will build it in steps to demonstrate how to use the results from bulk upload to update the tree. 
                 * 
                 * For a list of validation rules, see the Bing Shopping Campaigns technical guide:
                 * https://msdn.microsoft.com/en-US/library/bing-ads-campaign-management-bing-shopping-campaigns.aspx
                 */

                helper = new ProductPartitionHelper(adGroupId);

                /*
                 * Check whether a root node exists already.
                 */

                var existingRoot = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root");
                if (existingRoot != null)
                {
                    existingRoot.ClientId = "deletedroot";
                    helper.DeletePartition(existingRoot);
                }

                root = helper.AddSubdivision(
                    null,
                    new ProductCondition { Operand = "All", Attribute = null },
                    "root"
                );

                /*
                 * The direct children of any node must have the same Operand. 
                 * For this example we will use CategoryL1 nodes as children of the root. 
                 * For a list of valid CategoryL1 through CategoryL5 values, see the Bing Category Taxonomy:
                 * http://advertise.bingads.microsoft.com/en-us/WWDocs/user/search/en-us/Bing_Category_Taxonomy.txt
                 */
                var animalsSubdivision = helper.AddSubdivision(
                    root,
                    new ProductCondition { Operand = "CategoryL1", Attribute = "Animals & Pet Supplies" },
                    "animalsSubdivision"
                );

                /*
                 * If you use a CategoryL2 node, it must be a descendant (child or later) of a CategoryL1 node. 
                 * In other words you cannot have a CategoryL2 node as parent of a CategoryL1 node. 
                 * For this example we will a CategoryL2 node as child of the CategoryL1 Animals & Pet Supplies node. 
                 */
                var petSuppliesSubdivision = helper.AddSubdivision(
                    animalsSubdivision,
                    new ProductCondition { Operand = "CategoryL2", Attribute = "Pet Supplies" },
                    "petSuppliesSubdivision"
                );

                var brandA = helper.AddUnit(
                    petSuppliesSubdivision,
                    new ProductCondition { Operand = "Brand", Attribute = "Brand A" },
                    0.35,
                    false,
                    "brandA"
                );

                /*
                 * If you won't bid on Brand B, set the helper method's bidAmount to '0' and isNegative to true. 
                 * The helper method will create a NegativeAdGroupCriterion and apply the condition.
                 */
                var brandB = helper.AddUnit(
                    petSuppliesSubdivision,
                    new ProductCondition { Operand = "Brand", Attribute = "Brand B" },
                    0,
                    true,
                    "brandB"
                );

                var otherBrands = helper.AddUnit(
                    petSuppliesSubdivision,
                    new ProductCondition { Operand = "Brand", Attribute = null },
                    0.35,
                    false,
                    "otherBrands"
                );

                var otherPetSupplies = helper.AddUnit(
                    animalsSubdivision,
                    new ProductCondition { Operand = "CategoryL2", Attribute = null },
                    0.35,
                    false,
                    "otherPetSupplies"
                );

                var electronics = helper.AddUnit(
                    root,
                    new ProductCondition { Operand = "CategoryL1", Attribute = "Electronics" },
                    0.35,
                    false,
                    "electronics"
                );

                var otherCategoryL1 = helper.AddUnit(
                    root,
                    new ProductCondition { Operand = "CategoryL1", Attribute = null },
                    0.35,
                    false,
                    "otherCategoryL1"
                );

                OutputStatusMessage("Applying product partitions to the ad group . . . \n");
                applyBulkProductPartitionActionsResults =
                    await ApplyBulkProductPartitionActions(helper.PartitionActions);

                productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                /*
                 * The product partition group tree now has 9 nodes. 
                 
                   All other (Root Node)
                    |
                    +-- Animals & Pet Supplies (CategoryL1)
                    |    |
                    |    +-- Pet Supplies (CategoryL2)
                    |    |    |
                    |    |    +-- Brand A
                    |    |    |    
                    |    |    +-- Brand B
                    |    |    |    
                    |    |    +-- All other (Brand)
                    |    |         
                    |    +-- All other (CategoryL2)
                    |        
                    +-- Electronics (CategoryL1)
                    |   
                    +-- All other (CategoryL1)

                 */

                OutputStatusMessage("The product partition group tree now has 9 nodes: \n");
                OutputProductPartitions(productPartitions);

                #endregion InitializeTree

                #region UpdateTree

                /*
                 * Let's replace the Electronics (CategoryL1) node created above with an Electronics (CategoryL1) node that 
                 * has children i.e. Brand C (Brand), Brand D (Brand), and All other (Brand) as follows: 
                 
                    Electronics (CategoryL1)
                    |
                    +-- Brand C (Brand)
                    |
                    +-- Brand D (Brand)
                    |
                    +-- All other (Brand)
           
                 */

                helper = new ProductPartitionHelper(adGroupId);

                /*
                 * To replace a node we must know its Id and its ParentCriterionId. In this case the parent of the node 
                 * we are replacing is All other (Root Node). The node that we are replacing is Electronics (CategoryL1). 
                 */
                var rootId = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root").AdGroupCriterion.Id;
                electronics.AdGroupCriterion.Id = GetNodeByClientId(applyBulkProductPartitionActionsResults, "electronics").AdGroupCriterion.Id;
                helper.DeletePartition(electronics);

                var parent = new BulkAdGroupProductPartition
                {
                    AdGroupCriterion = new BiddableAdGroupCriterion() { Id = rootId }
                };

                var electronicsSubdivision = helper.AddSubdivision(
                    parent,
                    new ProductCondition { Operand = "CategoryL1", Attribute = "Electronics" },
                    "electronicsSubdivision"
                );

                var brandC = helper.AddUnit(
                    electronicsSubdivision,
                    new ProductCondition { Operand = "Brand", Attribute = "Brand C" },
                    0.35,
                    false,
                    "brandC"
                );

                var brandD = helper.AddUnit(
                    electronicsSubdivision,
                    new ProductCondition { Operand = "Brand", Attribute = "Brand D" },
                    0.35,
                    false,
                    "brandD"
                );

                var otherElectronicsBrands = helper.AddUnit(
                    electronicsSubdivision,
                    new ProductCondition { Operand = "Brand", Attribute = null },
                    0.35,
                    false,
                    "otherElectronicsBrands"
                );

                OutputStatusMessage(
                    "Updating the product partition group to refine Electronics (CategoryL1) with 3 child nodes . . . \n"
                );
                applyBulkProductPartitionActionsResults =
                    await ApplyBulkProductPartitionActions(helper.PartitionActions);

                productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId);

                /*
                 * The product partition group tree now has 12 nodes, including the children of Electronics (CategoryL1):
                 
                   All other (Root Node)
                    |
                    +-- Animals & Pet Supplies (CategoryL1)
                    |    |
                    |    +-- Pet Supplies (CategoryL2)
                    |    |    |
                    |    |    +-- Brand A
                    |    |    |    
                    |    |    +-- Brand B
                    |    |    |    
                    |    |    +-- All other (Brand)
                    |    |         
                    |    +-- All other (CategoryL2)
                    |        
                    +-- Electronics (CategoryL1)
                    |    |
                    |    +-- Brand C (Brand)
                    |    |
                    |    +-- Brand D (Brand)
                    |    |
                    |    +-- All other (Brand)
                    |   
                    +-- All other (CategoryL1)
                 
                 */

                OutputStatusMessage(
                    "The product partition group tree now has 12 nodes, including the children of Electronics (CategoryL1): \n"
                );
                OutputProductPartitions(productPartitions);

                #endregion UpdateTree

                var Service = new ServiceClient<ICampaignManagementService>(authorizationData);
                var getCampaignIds = new List<long>();
                getCampaignIds.Add((long)campaignResults[0].Campaign.Id);
                var request = new GetCampaignsByIdsRequest
                {
                    AccountId = authorizationData.AccountId,
                    CampaignIds = getCampaignIds,
                    CampaignType = CampaignType.Shopping
                };
                await Service.CallAsync((s, r) => s.GetCampaignsByIdsAsync(r), request);

                #region CleanUp

                /* Delete the campaign, ad group, criterion, and ad that were previously added. 
                 * You should remove this region if you want to view the added entities in the 
                 * Bing Ads web application or another tool.
                 */

                var campaignId = campaignResults[0].Campaign.Id;
                bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id = campaignId,
                        Status = CampaignStatus.Deleted
                    }
                };

                uploadEntities = new List<BulkEntity>();
                uploadEntities.Add(bulkCampaign);

                // Write the upload output

                Reader = await UploadEntities(uploadEntities);
                bulkEntities = Reader.ReadEntities().ToList();
                campaignResults = bulkEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);
                Reader.Dispose();

                OutputStatusMessage(String.Format("Deleted CampaignId {0}\n", campaignResults[0].Campaign.Id));

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            // Catch Campaign Management service exceptions
            catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }
Exemplo n.º 39
0
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                CampaignServiceV10 = new ServiceClient <ICampaignManagementServiceV10>(authorizationData);
                CampaignService    = new ServiceClient <ICampaignManagementService>(authorizationData);

                BulkServiceManager    = new BulkServiceManager(authorizationData);
                BulkServiceManagerV10 = new BulkServiceManagerV10(authorizationData);

                var progress = new Progress <BulkOperationProgressInfo>(x =>
                                                                        OutputStatusMessage(string.Format("{0} % Complete",
                                                                                                          x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                OutputStatusMessage("Step through the 'Migration Example A' section of the 'Upgrade Targets to Criterions' guide.\n");
                await MigrateTargetCriterionsA(authorizationData).ConfigureAwait(continueOnCapturedContext: false);

                OutputStatusMessage("Step through the 'Migration Example B' section of the 'Upgrade Targets to Criterions' guide.\n");
                await MigrateTargetCriterionsB(authorizationData).ConfigureAwait(continueOnCapturedContext: false);

                OutputStatusMessage("Step through the 'Sync Criterions' section of the 'Upgrade Targets to Criterions' guide.\n");
                await DownloadTargetsAsCriterions(null).ConfigureAwait(continueOnCapturedContext: false);

                OutputStatusMessage("Step through the 'Add or Update Criterions' section of the 'Upgrade Targets to Criterions' guide.\n");
                await AddUpdateDeleteCriterions().ConfigureAwait(continueOnCapturedContext: false);
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Campaign Management service exceptions
            catch (FaultException <Microsoft.BingAds.V11.CampaignManagement.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V11.CampaignManagement.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            // Catch Bulk service exceptions
            catch (FaultException <Microsoft.BingAds.V11.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException <Microsoft.BingAds.V11.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException <DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException <UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null)
                {
                    Reader.Dispose();
                }
                if (Writer != null)
                {
                    Writer.Dispose();
                }
            }
        }
        public async override Task RunAsync(AuthorizationData authorizationData)
        {
            try
            {
                BulkService = new BulkServiceManager(authorizationData);

                var progress = new Progress<BulkOperationProgressInfo>(x =>
                    OutputStatusMessage(String.Format("{0} % Complete",
                        x.PercentComplete.ToString(CultureInfo.InvariantCulture))));

                var downloadParameters = new DownloadParameters
                {
                    Entities = BulkDownloadEntity.RemarketingLists,
                    ResultFileDirectory = FileDirectory,
                    ResultFileName = DownloadFileName,
                    OverwriteResultFile = true,
                    LastSyncTimeInUTC = null
                };

                var bulkFilePath = await BulkService.DownloadFileAsync(downloadParameters);
                OutputStatusMessage("Downloaded all remarketing lists that the current user can associate with ad groups.\n");
                Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType);
                var downloadEntities = Reader.ReadEntities().ToList();

                var remarketingListResults = downloadEntities.OfType<BulkRemarketingList>().ToList();
                OutputBulkRemarketingLists(remarketingListResults);

                Reader.Dispose();

                // You must already have at least one remarketing list. The Bing Ads API does not support
                // remarketing list add, update, or delete operations.
                if (remarketingListResults.Count < 1)
                {
                    OutputStatusMessage("You do not have any remarketing lists that the current user can associate with ad groups.\n");
                    return;
                }

                var uploadEntities = new List<BulkEntity>();

                #region Add

                // Prepare the bulk entities that you want to upload.  

                var bulkCampaign = new BulkCampaign
                {
                    Campaign = new Campaign
                    {
                        Id = campaignIdKey,
                        Name = "Women's Shoes " + DateTime.UtcNow,
                        Description = "Red shoes line.",

                        // You must choose to set either the shared  budget ID or daily amount.
                        // You can set one or the other, but you may not set both.
                        BudgetId = null,
                        DailyBudget = 50,
                        BudgetType = BudgetLimitType.DailyBudgetStandard,
                        BiddingScheme = new EnhancedCpcBiddingScheme(),

                        TimeZone = "PacificTimeUSCanadaTijuana",

                        // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign,
                        // the value is not written to the Bulk file, and by default DaylightSaving is set to true.
                        DaylightSaving = true,

                        TrackingUrlTemplate = null
                    }
                };

                // Specify one or more ad groups.

                var bulkAdGroup = new BulkAdGroup
                {
                    // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field 
                    // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record.
                    // Note: This bulk file Client Id is not related to an application Client Id for OAuth. 
                    ClientId = "YourClientIdGoesHere",
                    CampaignId = campaignIdKey,
                    AdGroup = new AdGroup
                    {
                        // When using the Campaign Management service, the Id cannot be set. In the context of a BulkAdGroup, the Id is optional 
                        // and may be used as a negative reference key during bulk upload. For example the same negative value set for the  
                        // ad group Id will be used when associating this new ad group with a new ad group remarketing list association
                        // in the BulkAdGroupRemarketingListAssociation object below. 
                        Id = adGroupIdKey,
                        Name = "Women's Red Shoe Sale",
                        AdDistribution = AdDistribution.Search,
                        BiddingModel = BiddingModel.Keyword,
                        BiddingScheme = new InheritFromParentBiddingScheme(),
                        PricingModel = PricingModel.Cpc,
                        StartDate = null,
                        EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date
                        {
                            Month = 12,
                            Day = 31,
                            Year = DateTime.UtcNow.Year + 1
                        },
                        Language = "English",
                        Status = AdGroupStatus.Active,
                        TrackingUrlTemplate = null,

                        // Applicable for all remarketing lists that are associated with this ad group. TargetAndBid indicates 
                        // that you want to show ads only to people included in the remarketing list, with the option to change
                        // the bid amount. Ads in this ad group will only show to people included in the remarketing list.
                        RemarketingTargetingSetting = RemarketingTargetingSetting.TargetAndBid,
                    },
                };

                uploadEntities.Add(bulkCampaign);
                uploadEntities.Add(bulkAdGroup);

                // This example associates all of the remarketing lists with the new ad group.

                foreach (var remarketingList in remarketingListResults)
                {
                    if (remarketingList.RemarketingList != null && remarketingList.RemarketingList.Id != null)
                    {
                        var BulkAdGroupRemarketingListAssociation = new BulkAdGroupRemarketingListAssociation
                        {
                            ClientId = "MyBulkAdGroupRemarketingListAssociation " + remarketingList.RemarketingList.Id,
                            AdGroupRemarketingListAssociation = new AdGroupRemarketingListAssociation
                            {
                                AdGroupId = adGroupIdKey,
                                BidAdjustment = 20.00,
                                RemarketingListId = (long)remarketingList.RemarketingList.Id,
                                Status = AdGroupRemarketingListAssociationStatus.Paused
                            },
                        };

                        uploadEntities.Add(BulkAdGroupRemarketingListAssociation);
                    }
                }

                // Upload and write the output

                OutputStatusMessage("\nAdding campaign, ad group, and ad group remarketing list associations...\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                downloadEntities = Reader.ReadEntities().ToList();

                var campaignResults = downloadEntities.OfType<BulkCampaign>().ToList();
                OutputBulkCampaigns(campaignResults);

                var adGroupResults = downloadEntities.OfType<BulkAdGroup>().ToList();
                OutputBulkAdGroups(adGroupResults);

                var adGroupRemarketingListResults = downloadEntities.OfType<BulkAdGroupRemarketingListAssociation>().ToList();
                OutputBulkAdGroupRemarketingListAssociations(adGroupRemarketingListResults);

                Reader.Dispose();

                #endregion Add

                #region CleanUp

                // Delete the campaign, ad group, and ad group remarketing list associations that were previously added.
                // The remarketing lists will not be deleted. 
                // You should remove this region if you want to view the added entities in the 
                // Bing Ads web application or another tool.

                // You must set the Id field to the corresponding entity identifier, and the Status field to Deleted.

                // When you delete a BulkCampaign, the dependent entities such as BulkAdGroup and BulkAdGroupRemarketingListAssociation 
                // are deleted without being specified explicitly.  

                uploadEntities = new List<BulkEntity>();

                foreach (var campaignResult in campaignResults)
                {
                    campaignResult.Campaign.Status = CampaignStatus.Deleted;
                    uploadEntities.Add(campaignResult);
                }

                // Upload and write the output

                OutputStatusMessage("\nDeleting campaign, ad group, and ad group remarketing list associations . . .\n");

                Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities);
                downloadEntities = Reader.ReadEntities().ToList();
                OutputBulkCampaigns(downloadEntities.OfType<BulkCampaign>().ToList());

                Reader.Dispose();

                #endregion Cleanup
            }
            // Catch Microsoft Account authorization exceptions.
            catch (OAuthTokenRequestException ex)
            {
                OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description));
            }
            // Catch Bulk service exceptions
            catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
                OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationInProgressException ex)
            {
                OutputStatusMessage("The result file for the bulk operation is not yet available for download.");
                OutputStatusMessage(ex.Message);
            }
            catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex)
            {
                OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message))));
            }
            catch (Exception ex)
            {
                OutputStatusMessage(ex.Message);
            }
            finally
            {
                if (Reader != null) { Reader.Dispose(); }
                if (Writer != null) { Writer.Dispose(); }
            }
        }