public async override Task RunAsync(AuthorizationData authorizationData) { try { ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment; CampaignManagementExampleHelper CampaignManagementExampleHelper = new CampaignManagementExampleHelper(this.OutputStatusMessage); CampaignManagementExampleHelper.CampaignManagementService = new ServiceClient <ICampaignManagementService>(authorizationData, environment); // Add a campaign that will later be associated with negative keywords. var campaigns = new[] { new Campaign { 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", } }; AddCampaignsResponse addCampaignsResponse = await CampaignManagementExampleHelper.AddCampaignsAsync(authorizationData.AccountId, campaigns); long?[] campaignIds = addCampaignsResponse.CampaignIds.ToArray(); BatchError[] campaignErrors = addCampaignsResponse.PartialErrors.ToArray(); CampaignManagementExampleHelper.OutputArrayOfLong(campaignIds); CampaignManagementExampleHelper.OutputArrayOfBatchError(campaignErrors); long campaignId = (long)campaignIds[0]; // You may choose to associate an exclusive set of negative keywords to an individual campaign // or ad group. An exclusive set of negative keywords cannot be shared with other campaigns // or ad groups. This example only associates negative keywords with a campaign. var entityNegativeKeywords = new[] { new EntityNegativeKeyword { EntityId = campaignId, EntityType = "Campaign", NegativeKeywords = new[] { new NegativeKeyword { MatchType = MatchType.Phrase, Text = "auto" }, new NegativeKeyword { MatchType = MatchType.Phrase, Text = "auto" }, } } }; AddNegativeKeywordsToEntitiesResponse addNegativeKeywordsToEntitiesResponse = await CampaignManagementExampleHelper.AddNegativeKeywordsToEntitiesAsync(entityNegativeKeywords); CampaignManagementExampleHelper.OutputArrayOfIdCollection(addNegativeKeywordsToEntitiesResponse.NegativeKeywordIds); CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(addNegativeKeywordsToEntitiesResponse.NestedPartialErrors); if (addNegativeKeywordsToEntitiesResponse.NestedPartialErrors == null || addNegativeKeywordsToEntitiesResponse.NestedPartialErrors.Count == 0) { OutputStatusMessage("Added an exclusive set of negative keywords to the Campaign.\n"); CampaignManagementExampleHelper.OutputArrayOfIdCollection(addNegativeKeywordsToEntitiesResponse.NegativeKeywordIds); } else { CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(addNegativeKeywordsToEntitiesResponse.NestedPartialErrors); } GetNegativeKeywordsByEntityIdsResponse getNegativeKeywordsByEntityIdsResponse = await CampaignManagementExampleHelper.GetNegativeKeywordsByEntityIdsAsync(new[] { campaignId }, "Campaign", authorizationData.AccountId); CampaignManagementExampleHelper.OutputArrayOfEntityNegativeKeyword(getNegativeKeywordsByEntityIdsResponse.EntityNegativeKeywords); CampaignManagementExampleHelper.OutputArrayOfBatchError(getNegativeKeywordsByEntityIdsResponse.PartialErrors); if (getNegativeKeywordsByEntityIdsResponse.PartialErrors == null || getNegativeKeywordsByEntityIdsResponse.PartialErrors.Count == 0) { OutputStatusMessage("Retrieved an exclusive set of negative keywords for the Campaign.\n"); CampaignManagementExampleHelper.OutputArrayOfEntityNegativeKeyword(getNegativeKeywordsByEntityIdsResponse.EntityNegativeKeywords); } else { CampaignManagementExampleHelper.OutputArrayOfBatchError(getNegativeKeywordsByEntityIdsResponse.PartialErrors); } // If you attempt to delete a negative keyword without an identifier the operation will // succeed but will return partial errors corresponding to the index of the negative keyword // that was not deleted. var nestedPartialErrors = (BatchErrorCollection[])(await CampaignManagementExampleHelper.DeleteNegativeKeywordsFromEntitiesAsync(entityNegativeKeywords)).NestedPartialErrors; if (nestedPartialErrors == null || nestedPartialErrors.Length == 0) { OutputStatusMessage("Deleted an exclusive set of negative keywords from the Campaign.\n"); } else { OutputStatusMessage("Attempt to DeleteNegativeKeywordsFromEntities without NegativeKeyword identifier partially fails by design."); CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(nestedPartialErrors); } // Delete the negative keywords with identifiers that were returned above. nestedPartialErrors = (BatchErrorCollection[])(await CampaignManagementExampleHelper.DeleteNegativeKeywordsFromEntitiesAsync( getNegativeKeywordsByEntityIdsResponse.EntityNegativeKeywords)).NestedPartialErrors; if (nestedPartialErrors == null || nestedPartialErrors.Length == 0) { OutputStatusMessage("Deleted an exclusive set of negative keywords from the Campaign.\n"); } else { CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(nestedPartialErrors); } // Negative keywords can also be added and deleted from a shared negative keyword list. // The negative keyword list can be shared or associated with multiple campaigns. // NegativeKeywordList inherits from SharedList which inherits from SharedEntity. var negativeKeywordList = new NegativeKeywordList { Name = "My Negative Keyword List" + DateTime.UtcNow, Type = "NegativeKeywordList" }; SharedListItem[] negativeKeywords = { new NegativeKeyword { Text = "car", Type = "NegativeKeyword", MatchType = MatchType.Exact }, new NegativeKeyword { Text = "car", Type = "NegativeKeyword", MatchType = MatchType.Phrase } }; // You can create a new list for negative keywords with or without negative keywords. var addSharedEntityResponse = await CampaignManagementExampleHelper.AddSharedEntityAsync(negativeKeywordList, negativeKeywords); var sharedEntityId = addSharedEntityResponse.SharedEntityId; long[] listItemIds = addSharedEntityResponse.ListItemIds.ToArray(); OutputStatusMessage(string.Format("NegativeKeywordList successfully added to account library and assigned identifer {0}\n", sharedEntityId)); negativeKeywordList.Id = addSharedEntityResponse.SharedEntityId; CampaignManagementExampleHelper.OutputSharedEntity(negativeKeywordList); CampaignManagementExampleHelper.OutputArrayOfSharedListItem(negativeKeywords.ToList()); CampaignManagementExampleHelper.OutputArrayOfBatchError(addSharedEntityResponse.PartialErrors); OutputStatusMessage("Negative keywords currently in NegativeKeywordList:"); negativeKeywords = (SharedListItem[])(await CampaignManagementExampleHelper.GetListItemsBySharedListAsync(new NegativeKeywordList { Id = sharedEntityId })).ListItems; if (negativeKeywords == null || negativeKeywords.Length == 0) { OutputStatusMessage("None\n"); } else { CampaignManagementExampleHelper.OutputArrayOfNegativeKeyword(negativeKeywords.Cast <NegativeKeyword>().ToList()); } // To update the list of negative keywords, you must either add or remove from the list // using the respective AddListItemsToSharedList or DeleteListItemsFromSharedList operations. // To remove the negative keywords from the list pass the negative keyword identifers // and negative keyword list (SharedEntity) identifer. var partialErrors = (await CampaignManagementExampleHelper.DeleteListItemsFromSharedListAsync(listItemIds, new NegativeKeywordList { Id = sharedEntityId }))?.PartialErrors; if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage("Deleted most recently added negative keywords from negative keyword list.\n"); } else { CampaignManagementExampleHelper.OutputArrayOfBatchError(partialErrors); } OutputStatusMessage("Negative keywords currently in NegativeKeywordList:"); negativeKeywords = (SharedListItem[])(await CampaignManagementExampleHelper.GetListItemsBySharedListAsync(new NegativeKeywordList { Id = sharedEntityId })).ListItems; if (negativeKeywords == null || negativeKeywords.Length == 0) { OutputStatusMessage("None\n"); } else { CampaignManagementExampleHelper.OutputArrayOfNegativeKeyword(negativeKeywords.Cast <NegativeKeyword>().ToList()); } // Whether you created the list with or without negative keywords, more can be added // using the AddListItemsToSharedList operation. negativeKeywords = new SharedListItem[] { new NegativeKeyword { Text = "auto", Type = "NegativeKeyword", MatchType = MatchType.Exact }, new NegativeKeyword { Text = "auto", Type = "NegativeKeyword", MatchType = MatchType.Phrase } }; var addListItemsToSharedListResponse = await CampaignManagementExampleHelper.AddListItemsToSharedListAsync( negativeKeywords, new NegativeKeywordList { Id = sharedEntityId }); listItemIds = addListItemsToSharedListResponse.ListItemIds.ToArray(); CampaignManagementExampleHelper.OutputArrayOfSharedListItem(negativeKeywords.ToList()); CampaignManagementExampleHelper.OutputArrayOfBatchError(addListItemsToSharedListResponse.PartialErrors); OutputStatusMessage("Negative keywords currently in NegativeKeywordList:"); negativeKeywords = (SharedListItem[])(await CampaignManagementExampleHelper.GetListItemsBySharedListAsync(new NegativeKeywordList { Id = sharedEntityId })).ListItems; if (negativeKeywords == null || negativeKeywords.Length == 0) { OutputStatusMessage("None\n"); } else { CampaignManagementExampleHelper.OutputArrayOfNegativeKeyword(negativeKeywords.Cast <NegativeKeyword>().ToList()); } // You can update the name of the negative keyword list. negativeKeywordList = new NegativeKeywordList { Id = sharedEntityId, Name = "My Updated Negative Keyword List", Type = "NegativeKeywordList" }; partialErrors = (await CampaignManagementExampleHelper.UpdateSharedEntitiesAsync(new SharedEntity[] { negativeKeywordList })).PartialErrors; if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage(string.Format("Updated Negative Keyword List Name to {0}.\n", negativeKeywordList.Name)); } else { CampaignManagementExampleHelper.OutputArrayOfBatchError(partialErrors); } // Get and output the negative keyword lists and store the list of identifiers. const string sharedEntityType = "NegativeKeywordList"; var sharedEntities = (await CampaignManagementExampleHelper.GetSharedEntitiesByAccountIdAsync(sharedEntityType)).SharedEntities; CampaignManagementExampleHelper.OutputArrayOfSharedEntity(sharedEntities); var sharedEntityIds = new long[sharedEntities.Count]; for (int index = 0; index < sharedEntities.Count; index++) { if (sharedEntities[index].Id != null) { sharedEntityIds[index] = (long)sharedEntities[index].Id; } } // Negative keywords were added to the negative keyword list above. You can associate the // shared list of negative keywords with a campaign with or without negative keywords. // Shared negative keyword lists cannot be associated with an ad group. An ad group can only // be assigned an exclusive set of negative keywords. var associations = new[] { new SharedEntityAssociation { EntityId = campaignId, EntityType = "Campaign", SharedEntityId = sharedEntityId, SharedEntityType = "NegativeKeywordList" } }; partialErrors = (await CampaignManagementExampleHelper.SetSharedEntityAssociationsAsync(associations)).PartialErrors; if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage(string.Format("Associated CampaignId {0} with Negative Keyword List Id {1}.\n", campaignId, sharedEntityId)); } else { CampaignManagementExampleHelper.OutputArrayOfBatchError(partialErrors); } // Get and output the associations either by Campaign or NegativeKeywordList identifier. GetSharedEntityAssociationsByEntityIdsResponse getSharedEntityAssociationsByEntityIdsResponse = await CampaignManagementExampleHelper.GetSharedEntityAssociationsByEntityIdsAsync(new[] { campaignId }, "Campaign", "NegativeKeywordList"); CampaignManagementExampleHelper.OutputArrayOfSharedEntityAssociation(getSharedEntityAssociationsByEntityIdsResponse.Associations); CampaignManagementExampleHelper.OutputArrayOfBatchError(getSharedEntityAssociationsByEntityIdsResponse.PartialErrors); // Currently the GetSharedEntityAssociationsBySharedEntityIds operation accepts only one shared entity identifier in the list. GetSharedEntityAssociationsBySharedEntityIdsResponse getSharedEntityAssociationsBySharedEntityIdsResponse = await CampaignManagementExampleHelper.GetSharedEntityAssociationsBySharedEntityIdsAsync("Campaign", new[] { sharedEntityIds[sharedEntityIds.Length - 1] }, "NegativeKeywordList"); CampaignManagementExampleHelper.OutputArrayOfSharedEntityAssociation(getSharedEntityAssociationsBySharedEntityIdsResponse.Associations); CampaignManagementExampleHelper.OutputArrayOfBatchError(getSharedEntityAssociationsBySharedEntityIdsResponse.PartialErrors); // Explicitly delete the association between the campaign and the negative keyword list. partialErrors = (await CampaignManagementExampleHelper.DeleteSharedEntityAssociationsAsync(associations)).PartialErrors; if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage("Deleted NegativeKeywordList associations\n"); } else { CampaignManagementExampleHelper.OutputArrayOfBatchError(partialErrors); } // Delete the campaign and any remaining assocations. await CampaignManagementExampleHelper.DeleteCampaignsAsync(authorizationData.AccountId, new[] { campaignId }); OutputStatusMessage(string.Format("Deleted Campaign Id {0}\n", campaignId)); // DeleteCampaigns does not delete the negative keyword list from the account's library. // Call the DeleteSharedEntities operation to delete the shared entities. partialErrors = (await CampaignManagementExampleHelper.DeleteSharedEntitiesAsync(new SharedEntity[] { new NegativeKeywordList { Id = sharedEntityId } }))?.PartialErrors; if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage(string.Format("Deleted Negative Keyword List (SharedEntity) Id {0}\n", sharedEntityId)); } else { CampaignManagementExampleHelper.OutputArrayOfBatchError(partialErrors); } } // 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 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 (FaultException <Microsoft.BingAds.V12.CampaignManagement.EditorialApiFaultDetail> 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 (Exception ex) { OutputStatusMessage(ex.Message); } }
public async override Task RunAsync(AuthorizationData authorizationData) { try { Service = new ServiceClient <ICampaignManagementService>(authorizationData); // Add a campaign that will later be associated with negative keywords. var campaign = new Campaign { Name = "Women's Shoes" + DateTime.UtcNow, Description = "Red shoes line.", BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted, MonthlyBudget = 1000.00, TimeZone = "PacificTimeUSCanadaTijuana", DaylightSaving = true }; var campaignIds = await AddCampaignsAsync(authorizationData.AccountId, new[] { campaign }); // Print the new assigned campaign identifier PrintCampaignIdentifiers(campaignIds); // You may choose to associate an exclusive set of negative keywords to an individual campaign // or ad group. An exclusive set of negative keywords cannot be shared with other campaigns // or ad groups. This example only associates negative keywords with a campaign. var entityNegativeKeywords = new[] { new EntityNegativeKeyword { EntityId = campaignIds[0], EntityType = "Campaign", NegativeKeywords = new[] { new NegativeKeyword { MatchType = MatchType.Phrase, Text = "auto" } } } }; AddNegativeKeywordsToEntitiesResponse addNegativeKeywordsToEntitiesResponse = await AddNegativeKeywordsToEntitiesAsync(entityNegativeKeywords); PrintNegativeKeywordIds(addNegativeKeywordsToEntitiesResponse.NegativeKeywordIds); PrintNestedPartialErrors(addNegativeKeywordsToEntitiesResponse.NestedPartialErrors); if (addNegativeKeywordsToEntitiesResponse.NestedPartialErrors == null || addNegativeKeywordsToEntitiesResponse.NestedPartialErrors.Count == 0) { OutputStatusMessage("Added an exclusive set of negative keywords to the Campaign.\n"); PrintNegativeKeywordIds(addNegativeKeywordsToEntitiesResponse.NegativeKeywordIds); } else { PrintNestedPartialErrors(addNegativeKeywordsToEntitiesResponse.NestedPartialErrors); } GetNegativeKeywordsByEntityIdsResponse getNegativeKeywordsByEntityIdsResponse = await GetNegativeKeywordsByEntityIdsAsync(campaignIds, "Campaign", authorizationData.AccountId); PrintEntityNegativeKeywords(getNegativeKeywordsByEntityIdsResponse.EntityNegativeKeywords); PrintPartialErrors(getNegativeKeywordsByEntityIdsResponse.PartialErrors); if (getNegativeKeywordsByEntityIdsResponse.PartialErrors == null || getNegativeKeywordsByEntityIdsResponse.PartialErrors.Count == 0) { OutputStatusMessage("Retrieved an exclusive set of negative keywords for the Campaign.\n"); PrintEntityNegativeKeywords(getNegativeKeywordsByEntityIdsResponse.EntityNegativeKeywords); } else { PrintPartialErrors(getNegativeKeywordsByEntityIdsResponse.PartialErrors); } // If you attempt to delete a negative keyword without an identifier the operation will // succeed but will return partial errors corresponding to the index of the negative keyword // that was not deleted. var nestedPartialErrors = (BatchErrorCollection[]) await DeleteNegativeKeywordsFromEntitiesAsync(entityNegativeKeywords); if (nestedPartialErrors == null || nestedPartialErrors.Length == 0) { OutputStatusMessage("Deleted an exclusive set of negative keywords from the Campaign.\n"); } else { OutputStatusMessage("Attempt to DeleteNegativeKeywordsFromEntities without NegativeKeyword identifier partially fails by design."); PrintNestedPartialErrors(nestedPartialErrors); } // Delete the negative keywords with identifiers that were returned above. nestedPartialErrors = (BatchErrorCollection[]) await DeleteNegativeKeywordsFromEntitiesAsync( getNegativeKeywordsByEntityIdsResponse.EntityNegativeKeywords); if (nestedPartialErrors == null || nestedPartialErrors.Length == 0) { OutputStatusMessage("Deleted an exclusive set of negative keywords from the Campaign.\n"); } else { PrintNestedPartialErrors(nestedPartialErrors); } // Negative keywords can also be added and deleted from a shared negative keyword list. // The negative keyword list can be shared or associated with multiple campaigns. // NegativeKeywordList inherits from SharedList which inherits from SharedEntity. var negativeKeywordList = new NegativeKeywordList { Name = "My Negative Keyword List" + DateTime.UtcNow, Type = "NegativeKeywordList" }; SharedListItem[] negativeKeywords = { new NegativeKeyword { Text = "car", Type = "NegativeKeyword", MatchType = MatchType.Exact }, new NegativeKeyword { Text = "car", Type = "NegativeKeyword", MatchType = MatchType.Phrase } }; // You can create a new list for negative keywords with or without negative keywords. var addSharedEntityResponse = await AddSharedEntityAsync(negativeKeywordList, negativeKeywords); var sharedEntityId = addSharedEntityResponse.SharedEntityId; long[] listItemIds = addSharedEntityResponse.ListItemIds.ToArray(); OutputStatusMessage(String.Format("NegativeKeywordList successfully added to account library and assigned identifer {0}\n", sharedEntityId)); PrintNegativeKeywordResults( sharedEntityId, negativeKeywords, listItemIds, addSharedEntityResponse.PartialErrors.ToArray()); OutputStatusMessage("Negative keywords currently in NegativeKeywordList:"); negativeKeywords = (SharedListItem[]) await GetListItemsBySharedListAsync(new NegativeKeywordList { Id = sharedEntityId }); if (negativeKeywords == null || negativeKeywords.Length == 0) { OutputStatusMessage("None\n"); } else { PrintNegativeKeywords(negativeKeywords.Cast <NegativeKeyword>()); } // To update the list of negative keywords, you must either add or remove from the list // using the respective AddListItemsToSharedList or DeleteListItemsFromSharedList operations. // To remove the negative keywords from the list pass the negative keyword identifers // and negative keyword list (SharedEntity) identifer. var partialErrors = await DeleteListItemsFromSharedListAsync(listItemIds, new NegativeKeywordList { Id = sharedEntityId }); if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage("Deleted most recently added negative keywords from negative keyword list.\n"); } else { PrintPartialErrors(partialErrors); } OutputStatusMessage("Negative keywords currently in NegativeKeywordList:"); negativeKeywords = (SharedListItem[]) await GetListItemsBySharedListAsync(new NegativeKeywordList { Id = sharedEntityId }); if (negativeKeywords == null || negativeKeywords.Length == 0) { OutputStatusMessage("None\n"); } else { PrintNegativeKeywords(negativeKeywords.Cast <NegativeKeyword>()); } // Whether you created the list with or without negative keywords, more can be added // using the AddListItemsToSharedList operation. negativeKeywords = new SharedListItem[] { new NegativeKeyword { Text = "auto", Type = "NegativeKeyword", MatchType = MatchType.Exact }, new NegativeKeyword { Text = "auto", Type = "NegativeKeyword", MatchType = MatchType.Phrase } }; var addListItemsToSharedListResponse = await AddListItemsToSharedListAsync( negativeKeywords, new NegativeKeywordList { Id = sharedEntityId }); listItemIds = addListItemsToSharedListResponse.ListItemIds.ToArray(); PrintNegativeKeywordResults( sharedEntityId, negativeKeywords, listItemIds, addListItemsToSharedListResponse.PartialErrors.ToArray()); OutputStatusMessage("Negative keywords currently in NegativeKeywordList:"); negativeKeywords = (SharedListItem[]) await GetListItemsBySharedListAsync(new NegativeKeywordList { Id = sharedEntityId }); if (negativeKeywords == null || negativeKeywords.Length == 0) { OutputStatusMessage("None\n"); } else { PrintNegativeKeywords(negativeKeywords.Cast <NegativeKeyword>()); } // You can update the name of the negative keyword list. negativeKeywordList = new NegativeKeywordList { Id = sharedEntityId, Name = "My Updated Negative Keyword List", Type = "NegativeKeywordList" }; partialErrors = await UpdateSharedEntitiesAsync(new SharedEntity[] { negativeKeywordList }); if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage(String.Format("Updated Negative Keyword List Name to {0}.\n", negativeKeywordList.Name)); } else { PrintPartialErrors(partialErrors); } // Get and print the negative keyword lists and return the list of identifiers. const string sharedEntityType = "NegativeKeywordList"; var sharedEntityIds = await GetAndPrintSharedEntityIdentifiersAsync(sharedEntityType); // Negative keywords were added to the negative keyword list above. You can associate the // shared list of negative keywords with a campaign with or without negative keywords. // Shared negative keyword lists cannot be associated with an ad group. An ad group can only // be assigned an exclusive set of negative keywords. var associations = new[] { new SharedEntityAssociation { EntityId = campaignIds[0], EntityType = "Campaign", SharedEntityId = sharedEntityId, SharedEntityType = "NegativeKeywordList" } }; partialErrors = await SetSharedEntityAssociationsAsync(associations); if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage(String.Format("Associated CampaignId {0} with Negative Keyword List Id {1}.\n", campaignIds[0], sharedEntityId)); } else { PrintPartialErrors(partialErrors); } // Get and print the associations either by Campaign or NegativeKeywordList identifier. GetSharedEntityAssociationsByEntityIdsResponse getSharedEntityAssociationsByEntityIdsResponse = await GetSharedEntityAssociationsByEntityIdsAsync(new[] { campaignIds[0] }, "Campaign", "NegativeKeywordList"); PrintSharedEntityAssociations(getSharedEntityAssociationsByEntityIdsResponse.Associations); PrintPartialErrors(getSharedEntityAssociationsByEntityIdsResponse.PartialErrors); // Currently the GetSharedEntityAssociationsBySharedEntityIds operation accepts only one shared entity identifier in the list. GetSharedEntityAssociationsBySharedEntityIdsResponse getSharedEntityAssociationsBySharedEntityIdsResponse = await GetSharedEntityAssociationsBySharedEntityIdsAsync("Campaign", new[] { sharedEntityIds[sharedEntityIds.Count - 1] }, "NegativeKeywordList"); PrintSharedEntityAssociations(getSharedEntityAssociationsBySharedEntityIdsResponse.Associations); PrintPartialErrors(getSharedEntityAssociationsBySharedEntityIdsResponse.PartialErrors); // Explicitly delete the association between the campaign and the negative keyword list. partialErrors = await DeleteSharedEntityAssociationsAsync(associations); if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage("Deleted NegativeKeywordList associations\n"); } else { PrintPartialErrors(partialErrors); } // Delete the campaign and any remaining assocations. DeleteCampaigns(authorizationData.AccountId, new[] { campaignIds[0] }); OutputStatusMessage(String.Format("Deleted CampaignId {0}\n", campaignIds[0])); // DeleteCampaigns does not delete the negative keyword list from the account's library. // Call the DeleteSharedEntities operation to delete the shared entities. partialErrors = await DeleteSharedEntitiesAsync(new SharedEntity[] { new NegativeKeywordList { Id = sharedEntityId } }); if (partialErrors == null || !partialErrors.Any()) { OutputStatusMessage(String.Format("Deleted Negative Keyword List (SharedEntity) Id {0}\n", sharedEntityId)); } else { PrintPartialErrors(partialErrors); } } // 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 Campaign Management service exceptions catch (FaultException <Microsoft.BingAds.CampaignManagement.AdApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (FaultException <Microsoft.BingAds.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 (FaultException <Microsoft.BingAds.CampaignManagement.EditorialApiFaultDetail> 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 (Exception ex) { OutputStatusMessage(ex.Message); } }
public async override Task RunAsync(AuthorizationData authorizationData) { try { ApiEnvironment environment = ((OAuthDesktopMobileAuthCodeGrant)authorizationData.Authentication).Environment; CampaignManagementExampleHelper CampaignManagementExampleHelper = new CampaignManagementExampleHelper( OutputStatusMessageDefault: this.OutputStatusMessage); CampaignManagementExampleHelper.CampaignManagementService = new ServiceClient <ICampaignManagementService>( authorizationData: authorizationData, environment: environment); // Add a campaign that will later be associated with negative keywords. var campaigns = new[] { new Campaign { BudgetType = BudgetLimitType.DailyBudgetStandard, DailyBudget = 50, CampaignType = CampaignType.Search, Description = "Red shoes line.", Languages = new string[] { "All" }, Name = "Women's Shoes " + DateTime.UtcNow, TimeZone = "PacificTimeUSCanadaTijuana", }, }; OutputStatusMessage("-----\nAddCampaigns:"); AddCampaignsResponse addCampaignsResponse = await CampaignManagementExampleHelper.AddCampaignsAsync( accountId : authorizationData.AccountId, campaigns : campaigns, includeDynamicSearchAdsSource : false); long?[] campaignIds = addCampaignsResponse.CampaignIds.ToArray(); BatchError[] campaignErrors = addCampaignsResponse.PartialErrors.ToArray(); OutputStatusMessage("CampaignIds:"); CampaignManagementExampleHelper.OutputArrayOfLong(campaignIds); OutputStatusMessage("PartialErrors:"); CampaignManagementExampleHelper.OutputArrayOfBatchError(campaignErrors); long campaignId = (long)campaignIds[0]; // You may choose to associate an exclusive set of negative keywords to an individual campaign // or ad group. An exclusive set of negative keywords cannot be shared with other campaigns // or ad groups. This example only associates negative keywords with a campaign. var entityNegativeKeywords = new[] { new EntityNegativeKeyword { EntityId = campaignId, EntityType = "Campaign", NegativeKeywords = new[] { new NegativeKeyword { MatchType = MatchType.Phrase, Text = "auto" }, new NegativeKeyword { MatchType = MatchType.Exact, Text = "auto" }, } } }; OutputStatusMessage("-----\nAddNegativeKeywordsToEntities:"); AddNegativeKeywordsToEntitiesResponse addNegativeKeywordsToEntitiesResponse = await CampaignManagementExampleHelper.AddNegativeKeywordsToEntitiesAsync( entityNegativeKeywords : entityNegativeKeywords); OutputStatusMessage("Added an exclusive set of negative keywords to the Campaign"); OutputStatusMessage("NegativeKeywordIds:"); CampaignManagementExampleHelper.OutputArrayOfIdCollection(addNegativeKeywordsToEntitiesResponse.NegativeKeywordIds); OutputStatusMessage("NestedPartialErrors:"); CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(addNegativeKeywordsToEntitiesResponse.NestedPartialErrors); // If you attempt to delete a negative keyword without an identifier the operation will return // partial errors corresponding to the index of the negative keyword that was not deleted. OutputStatusMessage("-----\nDeleteNegativeKeywordsFromEntities:"); BatchErrorCollection[] nestedPartialErrors = (await CampaignManagementExampleHelper.DeleteNegativeKeywordsFromEntitiesAsync( entityNegativeKeywords: entityNegativeKeywords)).NestedPartialErrors.ToArray(); OutputStatusMessage("Attempt to DeleteNegativeKeywordsFromEntities without NegativeKeyword identifier partially fails by design."); CampaignManagementExampleHelper.OutputArrayOfBatchErrorCollection(nestedPartialErrors); // Negative keywords can also be added and deleted from a shared negative keyword list. // The negative keyword list can be shared or associated with multiple campaigns. // NegativeKeywordList inherits from SharedList which inherits from SharedEntity. var negativeKeywordList = new NegativeKeywordList { Name = "My Negative Keyword List" + DateTime.UtcNow, Type = "NegativeKeywordList" }; SharedListItem[] negativeKeywords = { new NegativeKeyword { Text = "car", Type = "NegativeKeyword", MatchType = MatchType.Exact }, new NegativeKeyword { Text = "car", Type = "NegativeKeyword", MatchType = MatchType.Phrase } }; // Add a negative keyword list that can be shared. OutputStatusMessage("-----\nAddSharedEntity:"); var addSharedEntityResponse = await CampaignManagementExampleHelper.AddSharedEntityAsync( sharedEntity : negativeKeywordList, listItems : negativeKeywords); var sharedEntityId = addSharedEntityResponse.SharedEntityId; long[] listItemIds = addSharedEntityResponse.ListItemIds.ToArray(); OutputStatusMessage(string.Format( "NegativeKeywordList added to account library and assigned identifer {0}", sharedEntityId) ); // Negative keywords were added to the negative keyword list above. You can associate the // shared list of negative keywords with a campaign with or without negative keywords. // Shared negative keyword lists cannot be associated with an ad group. An ad group can only // be assigned an exclusive set of negative keywords. var associations = new[] { new SharedEntityAssociation { EntityId = campaignId, EntityType = "Campaign", SharedEntityId = sharedEntityId, SharedEntityType = "NegativeKeywordList" } }; OutputStatusMessage("-----\nSetSharedEntityAssociations:"); var partialErrors = (await CampaignManagementExampleHelper.SetSharedEntityAssociationsAsync( associations: associations)).PartialErrors; OutputStatusMessage(string.Format( "Associated CampaignId {0} with Negative Keyword List Id {1}.", campaignId, sharedEntityId) ); // Delete the campaign and everything it contains e.g., ad groups and ads. OutputStatusMessage("-----\nDeleteCampaigns:"); await CampaignManagementExampleHelper.DeleteCampaignsAsync( accountId : authorizationData.AccountId, campaignIds : new[] { (long)campaignIds[0] }); OutputStatusMessage(string.Format("Deleted Campaign Id {0}", campaignIds[0])); // DeleteCampaigns does not delete the negative keyword list from the account's library. // Call the DeleteSharedEntities operation to delete the negative keyword list. OutputStatusMessage("-----\nDeleteSharedEntities:"); partialErrors = (await CampaignManagementExampleHelper.DeleteSharedEntitiesAsync( sharedEntities: new SharedEntity[] { new NegativeKeywordList { Id = sharedEntityId } }))?.PartialErrors; OutputStatusMessage(string.Format("Deleted Negative Keyword List Id {0}", sharedEntityId)); } // 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 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 (FaultException <Microsoft.BingAds.V12.CampaignManagement.EditorialApiFaultDetail> 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 (Exception ex) { OutputStatusMessage(ex.Message); } }