/// <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); }
/// <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); }
protected virtual void Dispose(bool disposing) { if (disposing) { if (_bulkFileReader != null) { _bulkFileReader.Dispose(); _bulkFileReader = null; } } }
/// <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); }
public BulkFileReaderEnumerable(BulkFileReader bulkFileReader) { _bulkFileReader = bulkFileReader; }
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(); } } }
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(); } } }
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 { 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; // 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 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 } } } }; // Write the entities created above, to the specified file. // Dependent entities such as BulkCampaignLocationTarget must be written after any dependencies, // for example a BulkCampaign. Writer = new BulkFileWriter(FileDirectory + UploadFileName); Writer.WriteEntity(bulkCampaign); Writer.WriteEntity(bulkCampaignDayTimeTarget); Writer.WriteEntity(bulkCampaignLocationTarget); Writer.WriteEntity(bulkCampaignRadiusTarget); 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 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 BulkAdGroupDayTimeTarget 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 bids as a list of BulkCampaignDayTimeTargetBid. var bulkCampaignDayTimeTargetBids = new List <BulkCampaignDayTimeTargetBid> { new BulkCampaignDayTimeTargetBid { CampaignId = campaignDayTimeTargetResults[0].CampaignId, TargetId = targetIdKey, 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 Writer = new BulkFileWriter(FileDirectory + UploadFileName); foreach (var bulkCampaignDayTimeTargetBid in bulkCampaignDayTimeTargetBids) { Writer.WriteEntity(bulkCampaignDayTimeTargetBid); } 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 var campaignDayTimeTargetBidResults = Reader.ReadEntities().OfType <BulkCampaignDayTimeTargetBid>().ToList(); OutputBulkCampaignDayTimeTargetBids(campaignDayTimeTargetBidResults); 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 targetId = campaignDayTimeTargetResults[0].TargetId; bulkCampaignDayTimeTarget = new BulkCampaignDayTimeTarget { Status = Status.Deleted, CampaignId = campaignId, TargetId = targetId }; bulkCampaignLocationTarget = new BulkCampaignLocationTarget { Status = Status.Deleted, CampaignId = campaignId, TargetId = targetId }; bulkCampaignRadiusTarget = new BulkCampaignRadiusTarget { Status = Status.Deleted, CampaignId = campaignId, TargetId = targetId }; // Write the entities that you want deleted, to the specified file. Writer = new BulkFileWriter(FileDirectory + UploadFileName); Writer.WriteEntity(bulkCampaign); Writer.WriteEntity(bulkCampaignDayTimeTarget); Writer.WriteEntity(bulkCampaignLocationTarget); Writer.WriteEntity(bulkCampaignRadiusTarget); 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); campaignDayTimeTargetResults = bulkEntities.OfType <BulkCampaignDayTimeTarget>().ToList(); OutputBulkCampaignDayTimeTargets(campaignDayTimeTargetResults); campaignLocationTargetResults = bulkEntities.OfType <BulkCampaignLocationTarget>().ToList(); OutputBulkCampaignLocationTargets(campaignLocationTargetResults); campaignRadiusTargetResults = bulkEntities.OfType <BulkCampaignRadiusTarget>().ToList(); OutputBulkCampaignRadiusTargets(campaignRadiusTargetResults); 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(); } } }
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(); } } }
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 tokenSource = new CancellationTokenSource(); tokenSource.CancelAfter(TimeoutInMilliseconds); // In this example we will download all ad groups in the account. var downloadParameters = new DownloadParameters { DataScope = DataScope.EntityData, DownloadEntities = new[] { DownloadEntity.AdGroups }, FileType = FileType, LastSyncTimeInUTC = null, ResultFileDirectory = FileDirectory, ResultFileName = DownloadFileName, OverwriteResultFile = true }; OutputStatusMessage("-----\nDownloading all ad groups in the account."); var bulkFilePath = await BulkServiceManager.DownloadFileAsync( parameters : downloadParameters, progress : progress, cancellationToken : tokenSource.Token); OutputStatusMessage("Download results:"); Reader = new BulkFileReader( filePath: bulkFilePath, resultFileType: ResultFileType.FullDownload, fileFormat: 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.AdGroup.Status.ToString().CompareTo("Active") != 0) { // 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.V13.CampaignManagement.Date { Month = nextMonth.Month, Day = nextMonth.Day, Year = nextMonth.Year }, Status = AdGroupStatus.Active, } }); } } Reader.Dispose(); Writer.Dispose(); // 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 }; OutputStatusMessage("-----\nActivating the ad groups..."); var resultFilePath = await BulkServiceManager.UploadFileAsync( parameters : fileUploadParameters, progress : progress, cancellationToken : tokenSource.Token); Reader = new BulkFileReader( filePath: resultFilePath, resultFileType: ResultFileType.Upload, fileFormat: FileType); OutputStatusMessage("Upload results:"); bulkAdGroups = Reader.ReadEntities().ToList().OfType <BulkAdGroup>().ToList(); OutputBulkAdGroups(bulkAdGroups); Reader.Dispose(); } // 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.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); } }
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 tokenSource = new CancellationTokenSource(); tokenSource.CancelAfter(TimeoutInMilliseconds); var downloadParameters = new DownloadParameters { DownloadEntities = new[] { DownloadEntity.RemarketingLists }, ResultFileDirectory = FileDirectory, ResultFileName = DownloadFileName, OverwriteResultFile = true, LastSyncTimeInUTC = null }; OutputStatusMessage("-----\nDownloading all remarketing lists that the current user can associate with ad groups."); var bulkFilePath = await BulkServiceManager.DownloadFileAsync( parameters : downloadParameters, progress : progress, cancellationToken : tokenSource.Token); OutputStatusMessage("Download results:"); Reader = new BulkFileReader( filePath: bulkFilePath, resultFileType: ResultFileType.FullDownload, fileFormat: FileType); var downloadEntities = Reader.ReadEntities().ToList(); var remarketingListResults = downloadEntities.OfType <BulkRemarketingList>().ToList(); OutputBulkRemarketingLists(remarketingListResults); Reader.Dispose(); // You must have at least one remarketing list. if (remarketingListResults.Count < 1) { OutputStatusMessage("There are no remarketing lists in the account."); return; } var uploadEntities = new List <BulkEntity>(); // Add an ad group in a campaign. The ad group will later be associated with remarketing lists. var bulkCampaign = new BulkCampaign { ClientId = "YourClientIdGoesHere", Campaign = new Campaign { Id = campaignIdKey, BudgetType = BudgetLimitType.DailyBudgetStandard, DailyBudget = 50, Languages = new string[] { "All" }, Name = "Women's Shoes " + DateTime.UtcNow, TimeZone = "PacificTimeUSCanadaTijuana", } }; uploadEntities.Add(bulkCampaign); 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 }, // 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. Settings = new[] { new TargetSetting { Details = new [] { new TargetSettingDetail { CriterionTypeGroup = CriterionTypeGroup.Audience, TargetAndBid = true } } } }, }, }; uploadEntities.Add(bulkAdGroup); // For example, associate 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, }, }; uploadEntities.Add(bulkAdGroupRemarketingListAssociation); } } // Upload and write the output OutputStatusMessage("-----\nAdding campaign, ad group, and ad group remarketing list associations..."); Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities); downloadEntities = Reader.ReadEntities().ToList(); OutputStatusMessage("Upload results:"); 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(); // 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(); } } }
/// <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 { Entities = BulkDownloadEntity.AdGroupProductPartitions, ResultFileDirectory = FileDirectory, ResultFileName = ResultFileName, OverwriteResultFile = true, LastSyncTimeInUTC = null }; var bulkFilePath = await BulkService.DownloadFileAsync(downloadParameters); Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType); var bulkEntities = Reader.ReadEntities().ToList(); var bulkAdGroupProductPartitionResults = bulkEntities.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> /// 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 BulkService.UploadFileAsync(fileUploadParameters); Reader = new BulkFileReader(bulkFilePath, ResultFileType.Upload, FileType); var bulkEntities = Reader.ReadEntities().ToList(); var bulkAdGroupProductPartitionResults = bulkEntities.OfType<BulkAdGroupProductPartition>().ToList(); OutputBulkAdGroupProductPartitions(bulkAdGroupProductPartitionResults); Reader.Dispose(); return bulkAdGroupProductPartitionResults; }
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.AdGroupProductPartitions }, ResultFileDirectory = FileDirectory, ResultFileName = DownloadFileName, OverwriteResultFile = true, LastSyncTimeInUTC = null }; // Download all product partitions across all ad groups in the account. var bulkFilePath = await BulkServiceManager.DownloadFileAsync(downloadParameters); OutputStatusMessage("Downloaded all product partitions across all ad groups in the account.\n"); Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType); var bulkAdGroupProductPartitions = Reader.ReadEntities().ToList().OfType <BulkAdGroupProductPartition>().ToList(); OutputBulkAdGroupProductPartitions(bulkAdGroupProductPartitions); var uploadEntities = new List <BulkEntity>(); // Within the downloaded records, find all product partition leaf nodes that have bids. foreach (var bulkAdGroupProductPartition in bulkAdGroupProductPartitions) { var biddableAdGroupCriterion = (bulkAdGroupProductPartition).AdGroupCriterion as BiddableAdGroupCriterion; if (biddableAdGroupCriterion != null && (((ProductPartition)biddableAdGroupCriterion.Criterion).PartitionType == ProductPartitionType.Unit)) { // We will increase all bids by some predetermined amount or percentage as an example. // For best performance, only upload the properties that you want to update. uploadEntities.Add(new BulkAdGroupProductPartition { AdGroupCriterion = new BiddableAdGroupCriterion { AdGroupId = bulkAdGroupProductPartition.AdGroupCriterion.AdGroupId, CriterionBid = new FixedBid { Amount = ((FixedBid)biddableAdGroupCriterion.CriterionBid).Amount + 0.01 }, Id = bulkAdGroupProductPartition.AdGroupCriterion.Id, } }); } } Reader.Dispose(); if (uploadEntities.Count > 0) { OutputStatusMessage("Changed local bid of all product partitions. Starting upload.\n"); Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities); bulkAdGroupProductPartitions = Reader.ReadEntities().ToList().OfType <BulkAdGroupProductPartition>().ToList(); OutputBulkAdGroupProductPartitions(bulkAdGroupProductPartitions); Reader.Dispose(); } else { OutputStatusMessage("No product partitions in account. \n"); } OutputStatusMessage("Program execution completed\n"); } // 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(); } } }
public BulkFileReaderIEnumerator(BulkFileReader bulkFileReader) { _bulkFileReader = bulkFileReader; _readEntities = _bulkFileReader.ReadEntities().GetEnumerator(); }
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); } }
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; // 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 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 } } } }; // Write the entities created above, to the specified file. // Dependent entities such as BulkCampaignLocationTarget must be written after any dependencies, // for example a BulkCampaign. Writer = new BulkFileWriter(FileDirectory + UploadFileName); Writer.WriteEntity(bulkCampaign); Writer.WriteEntity(bulkCampaignDayTimeTarget); Writer.WriteEntity(bulkCampaignLocationTarget); Writer.WriteEntity(bulkCampaignRadiusTarget); 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 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 BulkAdGroupDayTimeTarget 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 bids as a list of BulkCampaignDayTimeTargetBid. var bulkCampaignDayTimeTargetBids = new List<BulkCampaignDayTimeTargetBid> { new BulkCampaignDayTimeTargetBid { CampaignId = campaignDayTimeTargetResults[0].CampaignId, TargetId = targetIdKey, 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 Writer = new BulkFileWriter(FileDirectory + UploadFileName); foreach (var bulkCampaignDayTimeTargetBid in bulkCampaignDayTimeTargetBids) { Writer.WriteEntity(bulkCampaignDayTimeTargetBid); } 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 var campaignDayTimeTargetBidResults = Reader.ReadEntities().OfType<BulkCampaignDayTimeTargetBid>().ToList(); OutputBulkCampaignDayTimeTargetBids(campaignDayTimeTargetBidResults); 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 targetId = campaignDayTimeTargetResults[0].TargetId; bulkCampaignDayTimeTarget = new BulkCampaignDayTimeTarget { Status = Status.Deleted, CampaignId = campaignId, TargetId = targetId }; bulkCampaignLocationTarget = new BulkCampaignLocationTarget { Status = Status.Deleted, CampaignId = campaignId, TargetId = targetId }; bulkCampaignRadiusTarget = new BulkCampaignRadiusTarget { Status = Status.Deleted, CampaignId = campaignId, TargetId = targetId }; // Write the entities that you want deleted, to the specified file. Writer = new BulkFileWriter(FileDirectory + UploadFileName); Writer.WriteEntity(bulkCampaign); Writer.WriteEntity(bulkCampaignDayTimeTarget); Writer.WriteEntity(bulkCampaignLocationTarget); Writer.WriteEntity(bulkCampaignRadiusTarget); 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); campaignDayTimeTargetResults = bulkEntities.OfType<BulkCampaignDayTimeTarget>().ToList(); OutputBulkCampaignDayTimeTargets(campaignDayTimeTargetResults); campaignLocationTargetResults = bulkEntities.OfType<BulkCampaignLocationTarget>().ToList(); OutputBulkCampaignLocationTargets(campaignLocationTargetResults); campaignRadiusTargetResults = bulkEntities.OfType<BulkCampaignRadiusTarget>().ToList(); OutputBulkCampaignRadiusTargets(campaignRadiusTargetResults); 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(); } } }