public async override Task RunAsync(AuthorizationData authorizationData) { try { BulkService = new BulkServiceManager(authorizationData); var progress = new Progress<BulkOperationProgressInfo>(x => OutputStatusMessage(String.Format("{0} % Complete", x.PercentComplete.ToString(CultureInfo.InvariantCulture)))); var uploadEntities = new List<BulkEntity>(); #region Add // Prepare the bulk entities that you want to upload. Each bulk entity contains the corresponding campaign management object, // and additional elements needed to read from and write to a bulk file. var bulkCampaign = new BulkCampaign { // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record. // Note: This bulk file Client Id is not related to an application Client Id for OAuth. ClientId = "YourClientIdGoesHere", Campaign = new Campaign { // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id // will be used when associating this new campaign with a new call ad extension in the BulkCampaignCallAdExtension object below. Id = campaignIdKey, Name = "Women's Shoes " + DateTime.UtcNow, Description = "Red shoes line.", BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted, MonthlyBudget = 1000.00, TimeZone = "PacificTimeUSCanadaTijuana", // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign, // the value is not written to the Bulk file, and by default DaylightSaving is set to true. DaylightSaving = true, // Used with FinalUrls shown in the text ads that we will add below. TrackingUrlTemplate = "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}" } }; // Specify one or more ad groups. var bulkAdGroup = new BulkAdGroup { CampaignId = campaignIdKey, AdGroup = new AdGroup { Id = adGroupIdKey, Name = "Women's Red Shoe Sale", AdDistribution = AdDistribution.Search, BiddingModel = BiddingModel.Keyword, PricingModel = PricingModel.Cpc, StartDate = null, EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date { Month = 12, Day = 31, Year = 2016 }, Language = "English", Status = AdGroupStatus.Active, // You could use a tracking template which would override the campaign level // tracking template. Tracking templates defined for lower level entities // override those set for higher level entities. // In this example we are using the campaign level tracking template. TrackingUrlTemplate = null, }, }; // In this example only the second keyword should succeed. The Text of the first keyword exceeds the limit, // and the third keyword is a duplicate of the second keyword. var bulkKeywords = new [] { new BulkKeyword{ AdGroupId = adGroupIdKey, Keyword = new Keyword { Bid = new Bid { Amount = 0.47 }, Param2 = "10% Off", MatchType = MatchType.Broad, Text = "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes " + "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes " + "Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes Brand-A Shoes" }, }, new BulkKeyword{ AdGroupId = adGroupIdKey, Keyword = new Keyword { Bid = new Bid { Amount = 0.47 }, Param2 = "10% Off", MatchType = MatchType.Phrase, Text = "Brand-A Shoes" }, }, new BulkKeyword{ AdGroupId = adGroupIdKey, Keyword = new Keyword { Bid = new Bid { Amount = 0.47 }, Param2 = "10% Off", MatchType = MatchType.Phrase, Text = "Brand-A Shoes" }, }, }; // In this example only the first 3 ads should succeed. // The Title of the fourth ad is empty and not valid, // and the fifth ad is a duplicate of the second ad. var bulkTextAds = new [] { new BulkTextAd { AdGroupId = adGroupIdKey, TextAd = new TextAd { Title = "Women's Shoe Sale", Text = "Huge Savings on red shoes.", DisplayUrl = "Contoso.com", // If you are currently using Destination URLs, you must replace them with Final URLs. // Here is an example of a DestinationUrl you might have used previously. // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123", // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl // to an empty string when updating the ad. If you are removing DestinationUrl, // then FinalUrls is required. // DestinationUrl = "", // With FinalUrls you can separate the tracking template, custom parameters, and // landing page URLs. FinalUrls = new[] { "http://www.contoso.com/womenshoesale", }, // Final Mobile URLs can also be used if you want to direct the user to a different page // for mobile devices. FinalMobileUrls = new[] { "http://mobile.contoso.com/womenshoesale", }, // You could use a tracking template which would override the campaign level // tracking template. Tracking templates defined for lower level entities // override those set for higher level entities. // In this example we are using the campaign level tracking template. TrackingUrlTemplate = null, // Set custom parameters that are specific to this ad, // and can be used by the ad, ad group, campaign, or account level tracking template. // In this example we are using the campaign level tracking template. UrlCustomParameters = new CustomParameters { Parameters = new[] { new CustomParameter(){ Key = "promoCode", Value = "PROMO1" }, new CustomParameter(){ Key = "season", Value = "summer" }, } } }, }, new BulkTextAd { AdGroupId = adGroupIdKey, TextAd = new TextAd { Title = "Women's Super Shoe Sale", Text = "Huge Savings on red shoes.", DisplayUrl = "Contoso.com", // If you are currently using Destination URLs, you must replace them with Final URLs. // Here is an example of a DestinationUrl you might have used previously. // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123", // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl // to an empty string when updating the ad. If you are removing DestinationUrl, // then FinalUrls is required. // DestinationUrl = "", // With FinalUrls you can separate the tracking template, custom parameters, and // landing page URLs. FinalUrls = new[] { "http://www.contoso.com/womenshoesale" }, // Final Mobile URLs can also be used if you want to direct the user to a different page // for mobile devices. FinalMobileUrls = new[] { "http://mobile.contoso.com/womenshoesale" }, // You could use a tracking template which would override the campaign level // tracking template. Tracking templates defined for lower level entities // override those set for higher level entities. // In this example we are using the campaign level tracking template. TrackingUrlTemplate = null, // Set custom parameters that are specific to this ad, // and can be used by the ad, ad group, campaign, or account level tracking template. // In this example we are using the campaign level tracking template. UrlCustomParameters = new CustomParameters { Parameters = new[] { new CustomParameter(){ Key = "promoCode", Value = "PROMO2" }, new CustomParameter(){ Key = "season", Value = "summer" }, } }, }, }, new BulkTextAd { AdGroupId = adGroupIdKey, TextAd = new TextAd { Title = "Women's Red Shoe Sale", Text = "Huge Savings on red shoes.", DisplayUrl = "Contoso.com", // If you are currently using Destination URLs, you must replace them with Final URLs. // Here is an example of a DestinationUrl you might have used previously. // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123", // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl // to an empty string when updating the ad. If you are removing DestinationUrl, // then FinalUrls is required. // DestinationUrl = "", // With FinalUrls you can separate the tracking template, custom parameters, and // landing page URLs. FinalUrls = new[] { "http://www.contoso.com/womenshoesale" }, // Final Mobile URLs can also be used if you want to direct the user to a different page // for mobile devices. FinalMobileUrls = new[] { "http://mobile.contoso.com/womenshoesale" }, // You could use a tracking template which would override the campaign level // tracking template. Tracking templates defined for lower level entities // override those set for higher level entities. // In this example we are using the campaign level tracking template. TrackingUrlTemplate = null, // Set custom parameters that are specific to this ad, // and can be used by the ad, ad group, campaign, or account level tracking template. // In this example we are using the campaign level tracking template. UrlCustomParameters = new CustomParameters { Parameters = new[] { new CustomParameter(){ Key = "promoCode", Value = "PROMO3" }, new CustomParameter(){ Key = "season", Value = "summer" }, } }, }, }, new BulkTextAd { AdGroupId = adGroupIdKey, TextAd = new TextAd { Title = "", Text = "Huge Savings on red shoes.", DisplayUrl = "Contoso.com", // If you are currently using Destination URLs, you must replace them with Final URLs. // Here is an example of a DestinationUrl you might have used previously. // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123", // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl // to an empty string when updating the ad. If you are removing DestinationUrl, // then FinalUrls is required. // DestinationUrl = "", // With FinalUrls you can separate the tracking template, custom parameters, and // landing page URLs. FinalUrls = new[] { "http://www.contoso.com/womenshoesale" }, // Final Mobile URLs can also be used if you want to direct the user to a different page // for mobile devices. FinalMobileUrls = new[] { "http://mobile.contoso.com/womenshoesale" }, // You could use a tracking template which would override the campaign level // tracking template. Tracking templates defined for lower level entities // override those set for higher level entities. // In this example we are using the campaign level tracking template. TrackingUrlTemplate = null, // Set custom parameters that are specific to this ad, // and can be used by the ad, ad group, campaign, or account level tracking template. // In this example we are using the campaign level tracking template. UrlCustomParameters = new CustomParameters { Parameters = new[] { new CustomParameter(){ Key = "promoCode", Value = "PROMO4" }, new CustomParameter(){ Key = "season", Value = "summer" }, } }, }, }, new BulkTextAd { AdGroupId = adGroupIdKey, TextAd = new TextAd { Title = "Women's Super Shoe Sale", Text = "Huge Savings on red shoes.", DisplayUrl = "Contoso.com", // If you are currently using Destination URLs, you must replace them with Final URLs. // Here is an example of a DestinationUrl you might have used previously. // DestinationUrl = "http://www.contoso.com/womenshoesale/?season=spring&promocode=PROMO123", // To migrate from DestinationUrl to FinalUrls for existing ads, you can set DestinationUrl // to an empty string when updating the ad. If you are removing DestinationUrl, // then FinalUrls is required. // DestinationUrl = "", // With FinalUrls you can separate the tracking template, custom parameters, and // landing page URLs. FinalUrls = new[] { "http://www.contoso.com/womenshoesale" }, // Final Mobile URLs can also be used if you want to direct the user to a different page // for mobile devices. FinalMobileUrls = new[] { "http://mobile.contoso.com/womenshoesale" }, // You could use a tracking template which would override the campaign level // tracking template. Tracking templates defined for lower level entities // override those set for higher level entities. // In this example we are using the campaign level tracking template. TrackingUrlTemplate = null, // Set custom parameters that are specific to this ad, // and can be used by the ad, ad group, campaign, or account level tracking template. // In this example we are using the campaign level tracking template. UrlCustomParameters = new CustomParameters { Parameters = new[] { new CustomParameter(){ Key = "promoCode", Value = "PROMO5" }, new CustomParameter(){ Key = "season", Value = "summer" }, } }, }, }, }; uploadEntities.Add(bulkCampaign); uploadEntities.Add(bulkAdGroup); foreach (var bulkKeyword in bulkKeywords) { uploadEntities.Add(bulkKeyword); } foreach (var bulkTextAd in bulkTextAds) { uploadEntities.Add(bulkTextAd); } // Write the upload output var Reader = await UploadEntities(uploadEntities); var bulkEntities = Reader.ReadEntities().ToList(); var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList(); OutputBulkCampaigns(campaignResults); var adGroupResults = bulkEntities.OfType<BulkAdGroup>().ToList(); OutputBulkAdGroups(adGroupResults); var keywordResults = bulkEntities.OfType<BulkKeyword>().ToList(); OutputBulkKeywords(keywordResults); var textAdResults = bulkEntities.OfType<BulkTextAd>().ToList(); OutputBulkTextAds(textAdResults); Reader.Dispose(); #endregion Add #region CleanUp /* Delete the campaign, ad group, keywords, and ads that were previously added. * You should remove this region if you want to view the added entities in the * Bing Ads web application or another tool. */ var campaignId = campaignResults[0].Campaign.Id; bulkCampaign = new BulkCampaign { Campaign = new Campaign { Id = campaignId, Status = CampaignStatus.Deleted } }; uploadEntities = new List<BulkEntity>(); uploadEntities.Add(bulkCampaign); // Write the upload output Reader = await UploadEntities(uploadEntities); bulkEntities = Reader.ReadEntities().ToList(); campaignResults = bulkEntities.OfType<BulkCampaign>().ToList(); OutputBulkCampaigns(campaignResults); Reader.Dispose(); OutputStatusMessage(String.Format("Deleted CampaignId {0}\n", campaignResults[0].Campaign.Id)); #endregion Cleanup } // Catch Microsoft Account authorization exceptions. catch (OAuthTokenRequestException ex) { OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description)); } // Catch Bulk service exceptions catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (BulkOperationInProgressException ex) { OutputStatusMessage("The result file for the bulk operation is not yet available for download."); OutputStatusMessage(ex.Message); } catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex) { OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex) { OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (Exception ex) { OutputStatusMessage(ex.Message); } finally { if (Reader != null) { Reader.Dispose(); } if (Writer != null) { Writer.Dispose(); } } }
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 { #region CampaignThroughAdGroupSetup // You will need to use the Campaign Management service to get the Bing Merchant Center Store Id. This will be used // when creating a new Bing Shopping Campaign. // For other operations such as adding product conditions, you can manage Bing Shopping Campaigns solely with the Bulk Service. CampaignService = new ServiceClient<ICampaignManagementService>(authorizationData); // Get a list of all Bing Merchant Center stores associated with your CustomerId IList<BMCStore> stores = await GetBMCStoresByCustomerIdAsync(); if (stores == null) { OutputStatusMessage( String.Format("You do not have any BMC stores registered for CustomerId {0}.\n", authorizationData.CustomerId) ); return; } BulkService = new BulkServiceManager(authorizationData); var progress = new Progress<BulkOperationProgressInfo>(x => OutputStatusMessage(String.Format("{0} % Complete", x.PercentComplete.ToString(CultureInfo.InvariantCulture)))); const int campaignIdKey = -123; const int adGroupIdKey = -1234; var uploadEntities = new List<BulkEntity>(); /* Add a new Bing Shopping campaign that will be associated with a ProductScope criterion. * - Set the CampaignType element of the Campaign to Shopping. * - Create a ShoppingSetting instance and set its Priority (0, 1, or 2), SalesCountryCode, and StoreId elements. * Add this shopping setting to the Settings list of the Campaign. */ var bulkCampaign = new BulkCampaign { // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record. // Note: This bulk file Client Id is not related to an application Client Id for OAuth. ClientId = "YourClientIdGoesHere", Campaign = new Campaign { // When using the Campaign Management service, the Id cannot be set. In the context of a BulkCampaign, the Id is optional // and may be used as a negative reference key during bulk upload. For example the same negative value set for the campaign Id // will be used when associating this new campaign with a new campaign product scope in the BulkCampaignProductScope object below. Id = campaignIdKey, CampaignType = CampaignType.Shopping, Settings = new[] { new ShoppingSetting() { Priority = 0, SalesCountryCode = "US", StoreId = (int)stores[0].Id } }, Name = "Bing Shopping Campaign " + DateTime.UtcNow, Description = "Bing Shopping Campaign Example.", BudgetType = BudgetLimitType.MonthlyBudgetSpendUntilDepleted, MonthlyBudget = 1000.00, TimeZone = "PacificTimeUSCanadaTijuana", // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign, // the value is not written to the Bulk file, and by default DaylightSaving is set to true. DaylightSaving = true, } }; /* Optionally, you can create a ProductScope criterion that will be associated with your Bing Shopping campaign. * Use the product scope criterion to include a subset of your product catalog, for example a specific brand, * category, or product type. A campaign can only be associated with one ProductScope, which contains a list * of up to 7 ProductCondition. You'll also be able to specify more specific product conditions for each ad group. */ var bulkCampaignProductScope = new BulkCampaignProductScope { CampaignCriterion = new CampaignCriterion() { CampaignId = campaignIdKey, BidAdjustment = null, // Reserved for future use Criterion = new ProductScope() { Conditions = new ProductCondition[] { new ProductCondition { Operand = "Condition", Attribute = "New" }, new ProductCondition { Operand = "CustomLabel0", Attribute = "MerchantDefinedCustomLabel" }, } }, }, Status = Status.Active, }; // Specify one or more ad groups. var bulkAdGroup = new BulkAdGroup { CampaignId = campaignIdKey, AdGroup = new AdGroup { Id = adGroupIdKey, Name = "Product Categories", AdDistribution = AdDistribution.Search, BiddingModel = BiddingModel.Keyword, PricingModel = PricingModel.Cpc, StartDate = null, EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date { Month = 12, Day = 31, Year = 2016 }, Language = "English", Status = AdGroupStatus.Active }, }; /* * Create a product ad. You must add at least one ProductAd to the corresponding ad group. * A ProductAd is not used directly for delivered ad copy. Instead, the delivery engine generates * product ads from the product details that it finds in your Bing Merchant Center store's product catalog. * The primary purpose of the ProductAd object is to provide promotional text that the delivery engine * adds to the product ads that it generates. For example, if the promotional text is set to * “Free shipping on $99 purchases”, the delivery engine will set the product ad’s description to * “Free shipping on $99 purchases.” */ var bulkProductAd = new BulkProductAd { AdGroupId = adGroupIdKey, ProductAd = new ProductAd { PromotionalText = "Free shipping on $99 purchases." } }; uploadEntities.Add(bulkCampaign); uploadEntities.Add(bulkAdGroup); uploadEntities.Add(bulkCampaignProductScope); uploadEntities.Add(bulkProductAd); // Write the upload output var Reader = await UploadEntities(uploadEntities); var bulkEntities = Reader.ReadEntities().ToList(); var campaignResults = bulkEntities.OfType<BulkCampaign>().ToList(); OutputBulkCampaigns(campaignResults); var adGroupResults = bulkEntities.OfType<BulkAdGroup>().ToList(); OutputBulkAdGroups(adGroupResults); var productAdResults = bulkEntities.OfType<BulkProductAd>().ToList(); OutputBulkProductAds(productAdResults); var campaignProductScopeResults = bulkEntities.OfType<BulkCampaignProductScope>().ToList(); OutputBulkCampaignProductScopes(campaignProductScopeResults); Reader.Dispose(); #endregion CampaignThroughAdGroupSetup #region BidAllProducts var adGroupId = (long)adGroupResults[0].AdGroup.Id; var helper = new ProductPartitionHelper(adGroupId); var root = helper.AddUnit( null, new ProductCondition { Operand = "All", Attribute = null }, 0.35, false, "root" ); OutputStatusMessage("Applying only the root as a Unit with a bid . . . \n"); var applyBulkProductPartitionActionsResults = await ApplyBulkProductPartitionActions(helper.PartitionActions); var productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId); OutputStatusMessage("The ad group's product partition only has a tree root node: \n"); OutputProductPartitions(productPartitions); /* * Let's update the bid of the root Unit we just added. */ var updatedRoot = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root"); var bid = new FixedBid { Bid = new Bid { Amount = 0.45 } }; ((BiddableAdGroupCriterion)(updatedRoot.AdGroupCriterion)).CriterionBid = bid; helper = new ProductPartitionHelper(adGroupId); helper.UpdatePartition(updatedRoot); OutputStatusMessage("Updating the bid for the tree root node . . . \n"); await ApplyBulkProductPartitionActions(helper.PartitionActions); productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId); OutputStatusMessage("Updated the bid for the tree root node: \n"); OutputProductPartitions(productPartitions); #endregion BidAllProducts #region InitializeTree /* * Now we will overwrite any existing tree root, and build a product partition group tree structure in multiple steps. * You could build the entire tree in a single call since there are less than 20,000 nodes; however, * we will build it in steps to demonstrate how to use the results from bulk upload to update the tree. * * For a list of validation rules, see the Bing Shopping Campaigns technical guide: * https://msdn.microsoft.com/en-US/library/bing-ads-campaign-management-bing-shopping-campaigns.aspx */ helper = new ProductPartitionHelper(adGroupId); /* * Check whether a root node exists already. */ var existingRoot = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root"); if (existingRoot != null) { existingRoot.ClientId = "deletedroot"; helper.DeletePartition(existingRoot); } root = helper.AddSubdivision( null, new ProductCondition { Operand = "All", Attribute = null }, "root" ); /* * The direct children of any node must have the same Operand. * For this example we will use CategoryL1 nodes as children of the root. * For a list of valid CategoryL1 through CategoryL5 values, see the Bing Category Taxonomy: * http://advertise.bingads.microsoft.com/en-us/WWDocs/user/search/en-us/Bing_Category_Taxonomy.txt */ var animalsSubdivision = helper.AddSubdivision( root, new ProductCondition { Operand = "CategoryL1", Attribute = "Animals & Pet Supplies" }, "animalsSubdivision" ); /* * If you use a CategoryL2 node, it must be a descendant (child or later) of a CategoryL1 node. * In other words you cannot have a CategoryL2 node as parent of a CategoryL1 node. * For this example we will a CategoryL2 node as child of the CategoryL1 Animals & Pet Supplies node. */ var petSuppliesSubdivision = helper.AddSubdivision( animalsSubdivision, new ProductCondition { Operand = "CategoryL2", Attribute = "Pet Supplies" }, "petSuppliesSubdivision" ); var brandA = helper.AddUnit( petSuppliesSubdivision, new ProductCondition { Operand = "Brand", Attribute = "Brand A" }, 0.35, false, "brandA" ); /* * If you won't bid on Brand B, set the helper method's bidAmount to '0' and isNegative to true. * The helper method will create a NegativeAdGroupCriterion and apply the condition. */ var brandB = helper.AddUnit( petSuppliesSubdivision, new ProductCondition { Operand = "Brand", Attribute = "Brand B" }, 0, true, "brandB" ); var otherBrands = helper.AddUnit( petSuppliesSubdivision, new ProductCondition { Operand = "Brand", Attribute = null }, 0.35, false, "otherBrands" ); var otherPetSupplies = helper.AddUnit( animalsSubdivision, new ProductCondition { Operand = "CategoryL2", Attribute = null }, 0.35, false, "otherPetSupplies" ); var electronics = helper.AddUnit( root, new ProductCondition { Operand = "CategoryL1", Attribute = "Electronics" }, 0.35, false, "electronics" ); var otherCategoryL1 = helper.AddUnit( root, new ProductCondition { Operand = "CategoryL1", Attribute = null }, 0.35, false, "otherCategoryL1" ); OutputStatusMessage("Applying product partitions to the ad group . . . \n"); applyBulkProductPartitionActionsResults = await ApplyBulkProductPartitionActions(helper.PartitionActions); productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId); /* * The product partition group tree now has 9 nodes. All other (Root Node) | +-- Animals & Pet Supplies (CategoryL1) | | | +-- Pet Supplies (CategoryL2) | | | | | +-- Brand A | | | | | +-- Brand B | | | | | +-- All other (Brand) | | | +-- All other (CategoryL2) | +-- Electronics (CategoryL1) | +-- All other (CategoryL1) */ OutputStatusMessage("The product partition group tree now has 9 nodes: \n"); OutputProductPartitions(productPartitions); #endregion InitializeTree #region UpdateTree /* * Let's replace the Electronics (CategoryL1) node created above with an Electronics (CategoryL1) node that * has children i.e. Brand C (Brand), Brand D (Brand), and All other (Brand) as follows: Electronics (CategoryL1) | +-- Brand C (Brand) | +-- Brand D (Brand) | +-- All other (Brand) */ helper = new ProductPartitionHelper(adGroupId); /* * To replace a node we must know its Id and its ParentCriterionId. In this case the parent of the node * we are replacing is All other (Root Node). The node that we are replacing is Electronics (CategoryL1). */ var rootId = GetNodeByClientId(applyBulkProductPartitionActionsResults, "root").AdGroupCriterion.Id; electronics.AdGroupCriterion.Id = GetNodeByClientId(applyBulkProductPartitionActionsResults, "electronics").AdGroupCriterion.Id; helper.DeletePartition(electronics); var parent = new BulkAdGroupProductPartition { AdGroupCriterion = new BiddableAdGroupCriterion() { Id = rootId } }; var electronicsSubdivision = helper.AddSubdivision( parent, new ProductCondition { Operand = "CategoryL1", Attribute = "Electronics" }, "electronicsSubdivision" ); var brandC = helper.AddUnit( electronicsSubdivision, new ProductCondition { Operand = "Brand", Attribute = "Brand C" }, 0.35, false, "brandC" ); var brandD = helper.AddUnit( electronicsSubdivision, new ProductCondition { Operand = "Brand", Attribute = "Brand D" }, 0.35, false, "brandD" ); var otherElectronicsBrands = helper.AddUnit( electronicsSubdivision, new ProductCondition { Operand = "Brand", Attribute = null }, 0.35, false, "otherElectronicsBrands" ); OutputStatusMessage( "Updating the product partition group to refine Electronics (CategoryL1) with 3 child nodes . . . \n" ); applyBulkProductPartitionActionsResults = await ApplyBulkProductPartitionActions(helper.PartitionActions); productPartitions = await GetBulkAdGroupProductPartitionTree(adGroupId); /* * The product partition group tree now has 12 nodes, including the children of Electronics (CategoryL1): All other (Root Node) | +-- Animals & Pet Supplies (CategoryL1) | | | +-- Pet Supplies (CategoryL2) | | | | | +-- Brand A | | | | | +-- Brand B | | | | | +-- All other (Brand) | | | +-- All other (CategoryL2) | +-- Electronics (CategoryL1) | | | +-- Brand C (Brand) | | | +-- Brand D (Brand) | | | +-- All other (Brand) | +-- All other (CategoryL1) */ OutputStatusMessage( "The product partition group tree now has 12 nodes, including the children of Electronics (CategoryL1): \n" ); OutputProductPartitions(productPartitions); #endregion UpdateTree var Service = new ServiceClient<ICampaignManagementService>(authorizationData); var getCampaignIds = new List<long>(); getCampaignIds.Add((long)campaignResults[0].Campaign.Id); var request = new GetCampaignsByIdsRequest { AccountId = authorizationData.AccountId, CampaignIds = getCampaignIds, CampaignType = CampaignType.Shopping }; await Service.CallAsync((s, r) => s.GetCampaignsByIdsAsync(r), request); #region CleanUp /* Delete the campaign, ad group, criterion, and ad that were previously added. * You should remove this region if you want to view the added entities in the * Bing Ads web application or another tool. */ var campaignId = campaignResults[0].Campaign.Id; bulkCampaign = new BulkCampaign { Campaign = new Campaign { Id = campaignId, Status = CampaignStatus.Deleted } }; uploadEntities = new List<BulkEntity>(); uploadEntities.Add(bulkCampaign); // Write the upload output Reader = await UploadEntities(uploadEntities); bulkEntities = Reader.ReadEntities().ToList(); campaignResults = bulkEntities.OfType<BulkCampaign>().ToList(); OutputBulkCampaigns(campaignResults); Reader.Dispose(); OutputStatusMessage(String.Format("Deleted CampaignId {0}\n", campaignResults[0].Campaign.Id)); #endregion Cleanup } // Catch Microsoft Account authorization exceptions. catch (OAuthTokenRequestException ex) { OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description)); } // Catch Bulk service exceptions catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } // Catch Campaign Management service exceptions catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.AdApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (FaultException<Microsoft.BingAds.V10.CampaignManagement.ApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (BulkOperationInProgressException ex) { OutputStatusMessage("The result file for the bulk operation is not yet available for download."); OutputStatusMessage(ex.Message); } catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex) { OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex) { OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (Exception ex) { OutputStatusMessage(ex.Message); } finally { if (Reader != null) { Reader.Dispose(); } if (Writer != null) { Writer.Dispose(); } } }
public async override Task RunAsync(AuthorizationData authorizationData) { try { BulkService = new BulkServiceManager(authorizationData); var progress = new Progress<BulkOperationProgressInfo>(x => OutputStatusMessage(String.Format("{0} % Complete", x.PercentComplete.ToString(CultureInfo.InvariantCulture)))); var downloadParameters = new DownloadParameters { Entities = BulkDownloadEntity.RemarketingLists, ResultFileDirectory = FileDirectory, ResultFileName = DownloadFileName, OverwriteResultFile = true, LastSyncTimeInUTC = null }; var bulkFilePath = await BulkService.DownloadFileAsync(downloadParameters); OutputStatusMessage("Downloaded all remarketing lists that the current user can associate with ad groups.\n"); Reader = new BulkFileReader(bulkFilePath, ResultFileType.FullDownload, FileType); var downloadEntities = Reader.ReadEntities().ToList(); var remarketingListResults = downloadEntities.OfType<BulkRemarketingList>().ToList(); OutputBulkRemarketingLists(remarketingListResults); Reader.Dispose(); // You must already have at least one remarketing list. The Bing Ads API does not support // remarketing list add, update, or delete operations. if (remarketingListResults.Count < 1) { OutputStatusMessage("You do not have any remarketing lists that the current user can associate with ad groups.\n"); return; } var uploadEntities = new List<BulkEntity>(); #region Add // Prepare the bulk entities that you want to upload. var bulkCampaign = new BulkCampaign { Campaign = new Campaign { Id = campaignIdKey, Name = "Women's Shoes " + DateTime.UtcNow, Description = "Red shoes line.", // You must choose to set either the shared budget ID or daily amount. // You can set one or the other, but you may not set both. BudgetId = null, DailyBudget = 50, BudgetType = BudgetLimitType.DailyBudgetStandard, BiddingScheme = new EnhancedCpcBiddingScheme(), TimeZone = "PacificTimeUSCanadaTijuana", // DaylightSaving is not supported in the Bulk file schema. Whether or not you specify it in a BulkCampaign, // the value is not written to the Bulk file, and by default DaylightSaving is set to true. DaylightSaving = true, TrackingUrlTemplate = null } }; // Specify one or more ad groups. var bulkAdGroup = new BulkAdGroup { // ClientId may be used to associate records in the bulk upload file with records in the results file. The value of this field // is not used or stored by the server; it is simply copied from the uploaded record to the corresponding result record. // Note: This bulk file Client Id is not related to an application Client Id for OAuth. ClientId = "YourClientIdGoesHere", CampaignId = campaignIdKey, AdGroup = new AdGroup { // When using the Campaign Management service, the Id cannot be set. In the context of a BulkAdGroup, the Id is optional // and may be used as a negative reference key during bulk upload. For example the same negative value set for the // ad group Id will be used when associating this new ad group with a new ad group remarketing list association // in the BulkAdGroupRemarketingListAssociation object below. Id = adGroupIdKey, Name = "Women's Red Shoe Sale", AdDistribution = AdDistribution.Search, BiddingModel = BiddingModel.Keyword, BiddingScheme = new InheritFromParentBiddingScheme(), PricingModel = PricingModel.Cpc, StartDate = null, EndDate = new Microsoft.BingAds.V10.CampaignManagement.Date { Month = 12, Day = 31, Year = DateTime.UtcNow.Year + 1 }, Language = "English", Status = AdGroupStatus.Active, TrackingUrlTemplate = null, // Applicable for all remarketing lists that are associated with this ad group. TargetAndBid indicates // that you want to show ads only to people included in the remarketing list, with the option to change // the bid amount. Ads in this ad group will only show to people included in the remarketing list. RemarketingTargetingSetting = RemarketingTargetingSetting.TargetAndBid, }, }; uploadEntities.Add(bulkCampaign); uploadEntities.Add(bulkAdGroup); // This example associates all of the remarketing lists with the new ad group. foreach (var remarketingList in remarketingListResults) { if (remarketingList.RemarketingList != null && remarketingList.RemarketingList.Id != null) { var BulkAdGroupRemarketingListAssociation = new BulkAdGroupRemarketingListAssociation { ClientId = "MyBulkAdGroupRemarketingListAssociation " + remarketingList.RemarketingList.Id, AdGroupRemarketingListAssociation = new AdGroupRemarketingListAssociation { AdGroupId = adGroupIdKey, BidAdjustment = 20.00, RemarketingListId = (long)remarketingList.RemarketingList.Id, Status = AdGroupRemarketingListAssociationStatus.Paused }, }; uploadEntities.Add(BulkAdGroupRemarketingListAssociation); } } // Upload and write the output OutputStatusMessage("\nAdding campaign, ad group, and ad group remarketing list associations...\n"); Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities); downloadEntities = Reader.ReadEntities().ToList(); var campaignResults = downloadEntities.OfType<BulkCampaign>().ToList(); OutputBulkCampaigns(campaignResults); var adGroupResults = downloadEntities.OfType<BulkAdGroup>().ToList(); OutputBulkAdGroups(adGroupResults); var adGroupRemarketingListResults = downloadEntities.OfType<BulkAdGroupRemarketingListAssociation>().ToList(); OutputBulkAdGroupRemarketingListAssociations(adGroupRemarketingListResults); Reader.Dispose(); #endregion Add #region CleanUp // Delete the campaign, ad group, and ad group remarketing list associations that were previously added. // The remarketing lists will not be deleted. // You should remove this region if you want to view the added entities in the // Bing Ads web application or another tool. // You must set the Id field to the corresponding entity identifier, and the Status field to Deleted. // When you delete a BulkCampaign, the dependent entities such as BulkAdGroup and BulkAdGroupRemarketingListAssociation // are deleted without being specified explicitly. uploadEntities = new List<BulkEntity>(); foreach (var campaignResult in campaignResults) { campaignResult.Campaign.Status = CampaignStatus.Deleted; uploadEntities.Add(campaignResult); } // Upload and write the output OutputStatusMessage("\nDeleting campaign, ad group, and ad group remarketing list associations . . .\n"); Reader = await WriteEntitiesAndUploadFileAsync(uploadEntities); downloadEntities = Reader.ReadEntities().ToList(); OutputBulkCampaigns(downloadEntities.OfType<BulkCampaign>().ToList()); Reader.Dispose(); #endregion Cleanup } // Catch Microsoft Account authorization exceptions. catch (OAuthTokenRequestException ex) { OutputStatusMessage(string.Format("Couldn't get OAuth tokens. Error: {0}. Description: {1}", ex.Details.Error, ex.Details.Description)); } // Catch Bulk service exceptions catch (FaultException<Microsoft.BingAds.V10.Bulk.AdApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (FaultException<Microsoft.BingAds.V10.Bulk.ApiFaultDetail> ex) { OutputStatusMessage(string.Join("; ", ex.Detail.OperationErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); OutputStatusMessage(string.Join("; ", ex.Detail.BatchErrors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (BulkOperationInProgressException ex) { OutputStatusMessage("The result file for the bulk operation is not yet available for download."); OutputStatusMessage(ex.Message); } catch (BulkOperationCouldNotBeCompletedException<DownloadStatus> ex) { OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (BulkOperationCouldNotBeCompletedException<UploadStatus> ex) { OutputStatusMessage(string.Join("; ", ex.Errors.Select(error => string.Format("{0}: {1}", error.Code, error.Message)))); } catch (Exception ex) { OutputStatusMessage(ex.Message); } finally { if (Reader != null) { Reader.Dispose(); } if (Writer != null) { Writer.Dispose(); } } }